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 }