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 }