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    }