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 }