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.lang.reflect.InvocationTargetException;
014    import java.lang.reflect.Method;
015    import java.util.concurrent.Callable;
016    import java.util.concurrent.ExecutorService;
017    
018    import com.thoughtworks.proxy.Invoker;
019    import com.thoughtworks.proxy.ProxyFactory;
020    import com.thoughtworks.proxy.toys.hotswap.HotSwapping;
021    import com.thoughtworks.proxy.toys.hotswap.Swappable;
022    import com.thoughtworks.proxy.toys.nullobject.Null;
023    
024    
025    /**
026     * {@link com.thoughtworks.proxy.Invoker Invoker} that implements transparent asynchronous
027     * method calls. The invoked method will return immediately with a result that can be
028     * {@linkplain HotSwapping hot swapped}. This result proxy contains first a {@linkplain Null
029     * null object} and will automatically replaced later on when the asynchronous method call
030     * returns the correct result.
031     * 
032     * @author Aslak Hellesøy
033     * @since 1.0
034     */
035    public class FutureInvoker implements Invoker {
036        private static final long serialVersionUID = 1L;
037        private final Object target;
038        private final ProxyFactory proxyFactory;
039        private final ExecutorService executor;
040    
041        /**
042         * Construct the invoker.
043         * 
044         * @param target the instance that will have its methods called asynchronously
045         * @param proxyFactory the proxy factory used to create the proxy for the target instance
046         *            and all return types of the called methods
047         * @param executor the executor used to call the method asynchronously
048         * @since 1.0
049         */
050        public FutureInvoker(Object target, ProxyFactory proxyFactory, ExecutorService executor) {
051            this.target = target;
052            this.proxyFactory = proxyFactory;
053            this.executor = executor;
054        }
055    
056        public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
057            Class<?> returnType = method.getReturnType();
058            Object result = null;
059            if (!returnType.equals(void.class)) {
060                Object nullResult = Null.proxy(returnType).build(proxyFactory);
061                final Swappable swappableResult = Swappable.class.cast(HotSwapping.proxy(returnType).with(nullResult).build(proxyFactory));
062                result = swappableResult;
063                final Callable<Swappable> callable = new Callable<Swappable>() {
064                    public Swappable call() throws IllegalAccessException, InvocationTargetException {
065                        Object invocationResult = method.invoke(target, args);
066                        swappableResult.hotswap(invocationResult);
067                        return swappableResult;
068                    }
069                };
070                executor.submit(callable);
071            }
072    
073            return result;
074        }
075    }