001 /* 002 @license.text@ 003 */ 004 package biz.hammurapi.util; 005 006 import java.lang.reflect.InvocationHandler; 007 import java.lang.reflect.Method; 008 import java.lang.reflect.Proxy; 009 010 /** 011 * Creates a proxy which combines several classes and sequentially searches for 012 * matching method to invoke. This allows to implement lazy instantiation for 013 * situations where you have part of object data in cheaply accessible storage (cache or DB) 014 * and the other part in expensively accessible storage (e.g. XML file shall be 015 * parsed to access all object data). 016 * @author Pavel Vlasov 017 * @version $Revision: 1.1 $ 018 */ 019 public class CompositeProxyFactory { 020 021 /** 022 * @author Pavel Vlasov 023 * @version $Revision: 1.1 $ 024 */ 025 public interface TargetFactory { 026 027 /** 028 * @return target class for the proxy to know which methods it implements. 029 * You might want to return only one of class interfaces or base classes 030 * to limit number of exposed methods. 031 */ 032 Class getTargetClass(); 033 034 /** 035 * @return target itself to perform invocation. 036 */ 037 Object getTarget(); 038 } 039 040 private ClassLoader classLoader; 041 042 /** 043 * Creates factory which uses default classloader. 044 */ 045 public CompositeProxyFactory() { 046 super(); 047 classLoader=getClass().getClassLoader(); 048 } 049 050 /** 051 * Creates factory whith specified classloader which will be 052 * passed to createProxy(ClassLoader, Class[], TargetFactory[]) 053 */ 054 public CompositeProxyFactory(ClassLoader classLoader) { 055 super(); 056 this.classLoader=classLoader; 057 } 058 059 public static Object createProxy(ClassLoader classLoader, Class[] interfaces, final TargetFactory[] targetFactories) { 060 return Proxy.newProxyInstance( 061 classLoader, 062 interfaces, 063 new InvocationHandler() { 064 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 065 for (int i=0; i<targetFactories.length; i++) { 066 try { 067 return targetFactories[i] 068 .getTargetClass() 069 .getMethod(method.getName(), method.getParameterTypes()) 070 .invoke(targetFactories[i].getTarget(), args); 071 } catch (NoSuchMethodException e) { 072 // Ignore it. 073 } 074 } 075 076 throw new NoSuchMethodException("Method not found in targets: "+method); 077 } 078 }); 079 080 } 081 082 public Object createProxy(Class[] interfaces, TargetFactory[] targetFactories) { 083 return createProxy(classLoader, interfaces, targetFactories); 084 } 085 }