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