package org.oddjob.framework; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Generates a Proxy for a wrapped component. The proxy provided * will implement all interfaces from the original component as well * as those provided by the {@link WrapperFactory}. * <p> * If the wrapped component is an instance of an {@link ComponentAdapter} the * underlying component interface will be used instead. * * @author rob * * @param <T> The type of the component being wrapped. */ public class ProxyGenerator<T> { /** * Generate the proxy. * * @param wrapped The component being wrapped. * @param wrapperFactory * @param classLoader * * @return A proxy implementing all the interface of factory and * component. */ public Object generate(T wrapped, WrapperFactory<T> wrapperFactory, ClassLoader classLoader) { Object component; if (wrapped instanceof ComponentAdapter) { component = ((ComponentAdapter) wrapped).getComponent(); } else { component = wrapped; } Class<?>[] wrappedInterfaces = interfacesFor(component); Class<?>[] wrappingInterfaces = wrapperFactory.wrappingInterfacesFor(wrapped); Set<Class<?>> proxyInterfaces = new HashSet<Class<?>>(); proxyInterfaces.addAll(Arrays.asList(wrappedInterfaces)); proxyInterfaces.addAll(Arrays.asList(wrappingInterfaces)); proxyInterfaces.remove(Object.class); Class<?>[] interfaceArray = (Class[]) proxyInterfaces.toArray(new Class[proxyInterfaces.size()]); DefaultInvocationHandler handler = new DefaultInvocationHandler(); Object proxy = Proxy.newProxyInstance(classLoader, interfaceArray, handler); ComponentWrapper wrapper = wrapperFactory.wrapperFor(wrapped, proxy); handler.initialise(wrapper, wrappingInterfaces, component, wrappedInterfaces); return proxy; } /** * Find all the interfaces an object implements. * * @param object The object. * @return All the interfaces it implements */ public static Class<?>[] interfacesFor(Object object) { List<Class<?>> results = new ArrayList<Class<?>>(); for (Class<?> cl = object.getClass(); cl != null; cl = cl.getSuperclass()) { results.addAll(Arrays.asList((Class<?>[]) cl.getInterfaces())); } return (Class[]) results.toArray(new Class[0]); } }