001 /*
002 * (c) 2003-2004, 2009, 2010 ThoughtWorks Ltd
003 * All rights reserved.
004 *
005 * The software in this package is published under the terms of the BSD
006 * style license a copy of which has been included with this distribution in
007 * the LICENSE.txt file.
008 *
009 * Created on 29-May-2004
010 */
011 package com.thoughtworks.proxy.toys.future;
012
013 import java.util.Set;
014 import java.util.concurrent.Executors;
015
016 import com.thoughtworks.proxy.ProxyFactory;
017 import com.thoughtworks.proxy.factory.StandardProxyFactory;
018 import com.thoughtworks.proxy.kit.ReflectionUtils;
019
020
021 /**
022 * Factory for proxy instances that run any method call concurrently and return the method
023 * result later. Any method call for the proxied object will be called asynchronously. However,
024 * the call itself will return immediately with another proxy for the result object. This is a
025 * {@linkplain com.thoughtworks.proxy.toys.hotswap.HotSwapping hot swappable proxy} that
026 * contains a {@linkplain com.thoughtworks.proxy.toys.nullobject.Null null object} until the
027 * asynchronously called method returns. Then the result proxy is hot swapped with the real
028 * result of the method.
029 *
030 * @author Aslak Hellesøy
031 * @author Paul Hammant
032 * @since 1.0
033 */
034 public class Future<T> {
035
036 private Class<?>[] types;
037 private Object target;
038
039 private Future(Class<?>[] types) {
040 this.types = types;
041 }
042
043 /**
044 * Creates a proxy instance for asynchronous calls on a type.
045 *
046 * @param primaryType the type of the created proxy.
047 * @return the proxy of the specified type.
048 * @since 1.0
049 */
050 public static <T> FutureWith<T> proxy(Class<T> primaryType) {
051 Future<T> future = new Future<T>(new Class<?>[]{primaryType});
052 return new FutureWith<T>(future);
053 }
054
055 /**
056 * Creates a proxy instance for asynchronous calls on a type.
057 *
058 * @param primaryType the main type of the created proxy.
059 * @param types the other types of the created proxy.
060 * @return the proxy of the specified types
061 * @since 1.0
062 */
063 public static <T> FutureWith<T> proxy(Class<T> primaryType, Class<?>... types) {
064 Future<T> future = new Future<T>(ReflectionUtils.makeTypesArray(primaryType, types));
065 return new FutureWith<T>(future);
066 }
067
068 /**
069 * Creates a proxy instance for asynchronous calls on an object.
070 *
071 * @param target the proxied object.
072 * @return the proxy.
073 * @since 1.0
074 */
075 public static <T> FutureBuild<T> proxy(T target) {
076 Future<T> future = new Future<T>(null);
077 future.target = target;
078 return new FutureBuild<T>(future);
079 }
080
081 public static class FutureWith<T> {
082 private Future<T> future;
083 private FutureWith(Future<T> future) {
084 this.future = future;
085 }
086
087 /**
088 * Defines the object that shall be proxied. This object must implement the types used
089 * to create the proxy.
090 *
091 * @param target the object that shall be proxied.
092 * @return the factory that will proxy instances of the supplied type.
093 * @since upcoming
094 */
095 public FutureBuild<T> with(Object target) {
096 future.target = target;
097 return new FutureBuild<T>(future);
098 }
099 }
100
101 public static class FutureBuild<T> {
102 private Future<T> future;
103 private FutureBuild(Future<T> future) {
104 this.future = future;
105 }
106
107 public T build() {
108 return build(new StandardProxyFactory());
109 }
110
111 /**
112 * Create a proxy with asynchronously called methods. The delegate must implement the
113 * given types. The return values of the called methods must be non-final object types.
114 *
115 * @param factory the {@link ProxyFactory} to use.
116 * @return the created proxy implementing the <tt>types</tt> and {@link com.thoughtworks.proxy.toys.hotswap.Swappable}
117 * @since 1.0
118 */
119 public T build(ProxyFactory factory) {
120 if (future.types == null) {
121 Class<?> targetClass = future.target.getClass();
122 if (factory.canProxy(targetClass)) {
123 future.types = new Class[]{targetClass};
124 } else {
125 Set<Class<?>> classes = ReflectionUtils.getAllInterfaces(targetClass);
126 future.types = new Class[classes.size()];
127 classes.toArray(future.types);
128 }
129 }
130 FutureInvoker invoker = new FutureInvoker(future.target, factory, Executors.newCachedThreadPool());
131 return factory.<T>createProxy(invoker, future.types);
132 }
133 }
134 }