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 */
011package com.thoughtworks.proxy.toys.future;
012
013import java.util.Set;
014import java.util.concurrent.Executors;
015
016import com.thoughtworks.proxy.ProxyFactory;
017import com.thoughtworks.proxy.factory.StandardProxyFactory;
018import 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 */
034public 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}