View Javadoc
1 /****************************************************************************** 2 * Copyright (C) PicoContainer Organization. All rights reserved. * 3 * ------------------------------------------------------------------------- * 4 * The software in this package is published under the terms of the BSD * 5 * style license a copy of which has been included with this distribution in * 6 * the license.html file. * 7 * * 8 * Idea by Rachel Davies, Original code by Aslak Hellesoy * 9 *****************************************************************************/ 10 11 package org.picocontainer.defaults; 12 13 import org.picocontainer.extras.CompositeProxyFactory; 14 15 import java.util.List; 16 import java.util.ArrayList; 17 import java.util.Collections; 18 import java.util.Set; 19 import java.util.HashSet; 20 import java.util.Arrays; 21 import java.util.Iterator; 22 import java.lang.reflect.Proxy; 23 import java.lang.reflect.InvocationHandler; 24 import java.lang.reflect.Method; 25 import java.lang.reflect.InvocationTargetException; 26 import java.io.Serializable; 27 28 /*** 29 * 30 * @author Aslak Hellesøy 31 * @version $Revision: 1.1 $ 32 */ 33 public class DefaultCompositeProxyFactory implements CompositeProxyFactory, Serializable { 34 35 private static Method equals; 36 private static Method hashCode; 37 38 static { 39 try { 40 equals = Object.class.getMethod("equals", new Class[]{Object.class}); 41 hashCode = Object.class.getMethod("hashCode", null); 42 } catch (NoSuchMethodException e) { 43 ///CLOVER:OFF 44 throw new InternalError(); 45 ///CLOVER:ON 46 } catch (SecurityException e) { 47 ///CLOVER:OFF 48 throw new InternalError(); 49 ///CLOVER:ON 50 } 51 } 52 53 public Object createCompositeProxy( 54 ClassLoader classLoader, 55 List objectsToAggregateCallFor, 56 boolean callInReverseOrder 57 ) { 58 Class[] interfaces = getInterfaces(objectsToAggregateCallFor); 59 List copy = new ArrayList(objectsToAggregateCallFor); 60 61 if (!callInReverseOrder) { 62 // reverse the list 63 Collections.reverse(copy); 64 } 65 Object[] objects = copy.toArray(); 66 67 Object result = Proxy.newProxyInstance( 68 classLoader, 69 interfaces, 70 new AggregatingInvocationHandler(classLoader, objects) 71 ); 72 73 return result; 74 } 75 76 private class AggregatingInvocationHandler implements InvocationHandler { 77 private Object[] children; 78 private ClassLoader classLoader; 79 80 public AggregatingInvocationHandler(ClassLoader classLoader, Object[] children) { 81 this.classLoader = classLoader; 82 this.children = children; 83 } 84 85 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 86 Class declaringClass = method.getDeclaringClass(); 87 if (declaringClass.equals(Object.class)) { 88 if (method.equals(hashCode)) { 89 // Return the hashCode of ourself, as Proxy.newProxyInstance() may 90 // return cached proxies. We want a unique hashCode for each created proxy! 91 return new Integer(System.identityHashCode(AggregatingInvocationHandler.this)); 92 } 93 if (method.equals(equals)) { 94 return new Boolean(proxy == args[0]); 95 } 96 // If the method is defined by Object (like hashCode or equals), call 97 // on ourself. This is a bit of a hack, but actually ok in most cases. 98 return method.invoke(AggregatingInvocationHandler.this, args); 99 } else { 100 return invokeOnTargetsOfSameTypeAsDeclaringClass(declaringClass, children, method, args); 101 } 102 } 103 104 private Object invokeOnTargetsOfSameTypeAsDeclaringClass(Class declaringClass, Object[] targets, Method method, Object[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException { 105 Class returnType = method.getReturnType(); 106 107 // Lazily created list holding all results. 108 List results = null; 109 for (int i = 0; i < targets.length; i++) { 110 boolean isValidType = declaringClass.isAssignableFrom(targets[i].getClass()); 111 if (isValidType) { 112 // It's ok to call the method on this one 113 Object componentResult = method.invoke(targets[i], args); 114 if (results == null) { 115 results = new ArrayList(); 116 } 117 results.add(componentResult); 118 } 119 } 120 121 Object result; 122 123 if (results.size() == 1) { 124 // Got exactly one result. Just return that. 125 result = results.get(0); 126 } else if (returnType.isInterface()) { 127 // We have two or more results 128 // We can make a new proxy that aggregates all the results. 129 //Class[] resultInterfaces = getInterfaces(results.toArray()); 130 result = createCompositeProxy( 131 classLoader, 132 results, 133 true 134 ); 135 } else { 136 // Got multiple results that can't be wrapped in a proxy. Try to instantiate a default object. 137 result = returnType.equals(Void.TYPE) ? null : returnType.newInstance(); 138 } 139 140 return result; 141 } 142 } 143 144 /*** 145 * Get all the interfaces implemented by an array of objects. 146 * @return an array of interfaces. 147 */ 148 private final Class[] getInterfaces(List objects) { 149 Set interfaces = new HashSet(); 150 for (Iterator iterator = objects.iterator(); iterator.hasNext();) { 151 Object o = iterator.next(); 152 Class componentClass = o.getClass(); 153 // Strangely enough Class.getInterfaces() does not include the interfaces 154 // implemented by superclasses. So we must loop up the hierarchy. 155 while (componentClass != null) { 156 Class[] implemeted = componentClass.getInterfaces(); 157 List implementedList = Arrays.asList(implemeted); 158 interfaces.addAll(implementedList); 159 componentClass = componentClass.getSuperclass(); 160 } 161 } 162 163 Class[] result = (Class[]) interfaces.toArray(new Class[interfaces.size()]); 164 return result; 165 } 166 167 }

This page was automatically generated by Maven