|
|||||||||||||||||||
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 | |||||||||||||||
ImplementationHidingComponentAdapter.java | 100% | 100% | 100% | 100% |
|
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.txt file. *
|
|
7 |
* *
|
|
8 |
* Original code by *
|
|
9 |
*****************************************************************************/
|
|
10 |
package org.picocontainer.alternatives;
|
|
11 |
|
|
12 |
import org.picocontainer.ComponentAdapter;
|
|
13 |
import org.picocontainer.PicoContainer;
|
|
14 |
import org.picocontainer.PicoInitializationException;
|
|
15 |
import org.picocontainer.PicoIntrospectionException;
|
|
16 |
import org.picocontainer.defaults.AssignabilityRegistrationException;
|
|
17 |
import org.picocontainer.defaults.DecoratingComponentAdapter;
|
|
18 |
import org.picocontainer.defaults.NotConcreteRegistrationException;
|
|
19 |
|
|
20 |
import java.lang.reflect.InvocationHandler;
|
|
21 |
import java.lang.reflect.InvocationTargetException;
|
|
22 |
import java.lang.reflect.Method;
|
|
23 |
import java.lang.reflect.Proxy;
|
|
24 |
import java.util.ArrayList;
|
|
25 |
import java.util.Arrays;
|
|
26 |
import java.util.HashSet;
|
|
27 |
import java.util.Iterator;
|
|
28 |
import java.util.List;
|
|
29 |
import java.util.Set;
|
|
30 |
|
|
31 |
/**
|
|
32 |
* This component adapter makes it possible to hide the implementation
|
|
33 |
* of a real subject (behind a proxy) provided the key is an interface.
|
|
34 |
* <p/>
|
|
35 |
* This class exists here, because a) it has no deps on external jars, b) dynamic proxy is quite easy.
|
|
36 |
* The user is prompted to look at nanocontainer-proxytoys for alternate and bigger implementations.
|
|
37 |
*
|
|
38 |
* @author Aslak Hellesøy
|
|
39 |
* @author Paul Hammant
|
|
40 |
* @version $Revision: 1.4 $
|
|
41 |
* @see org.nanocontainer.proxytoys.HotSwappingComponentAdapter for a more feature-rich version of this class.
|
|
42 |
* @see org.nanocontainer.proxytoys.HotSwappingComponentAdapterFactory
|
|
43 |
* @since 1.1
|
|
44 |
*/
|
|
45 |
public class ImplementationHidingComponentAdapter extends DecoratingComponentAdapter { |
|
46 |
private final boolean strict; |
|
47 |
|
|
48 | 108 |
public ImplementationHidingComponentAdapter(ComponentAdapter delegate, boolean strict) { |
49 | 108 |
super(delegate);
|
50 | 108 |
this.strict = strict;
|
51 |
} |
|
52 |
|
|
53 | 94 |
public Object getComponentInstance(final PicoContainer container)
|
54 |
throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
|
|
55 |
|
|
56 | 94 |
Object componentKey = getDelegate().getComponentKey(); |
57 | 94 |
Class[] classes = null;
|
58 | 94 |
if (componentKey instanceof Class && ((Class) getDelegate().getComponentKey()).isInterface()) { |
59 | 54 |
classes = new Class[]{(Class) getDelegate().getComponentKey()};
|
60 | 40 |
} else if (componentKey instanceof Class[]) { |
61 | 4 |
classes = (Class[]) componentKey; |
62 |
} else {
|
|
63 | 36 |
if(strict) {
|
64 | 2 |
throw new PicoIntrospectionException("In strict mode, " + getClass().getName() + " only allows components registered with interface keys (java.lang.Class or java.lang.Class[])"); |
65 |
} |
|
66 | 34 |
return getDelegate().getComponentInstance(container);
|
67 |
} |
|
68 |
|
|
69 | 58 |
Class[] interfaces = verifyInterfacesOnly(classes); |
70 | 56 |
return createProxy(interfaces, container);
|
71 |
} |
|
72 |
|
|
73 | 56 |
private Object createProxy(Class[] interfaces, final PicoContainer container) {
|
74 | 56 |
return Proxy.newProxyInstance(getClass().getClassLoader(),
|
75 |
interfaces, new InvocationHandler() {
|
|
76 | 24 |
public Object invoke(final Object proxy, final Method method,
|
77 |
final Object[] args) |
|
78 |
throws Throwable {
|
|
79 | 24 |
try {
|
80 | 24 |
Object componentInstance = getDelegate().getComponentInstance(container); |
81 | 24 |
return method.invoke(componentInstance, args);
|
82 |
} catch (final InvocationTargetException ite) {
|
|
83 | 6 |
throw ite.getTargetException();
|
84 |
} |
|
85 |
} |
|
86 |
}); |
|
87 |
} |
|
88 |
|
|
89 | 58 |
private Class[] verifyInterfacesOnly(Class[] classes) {
|
90 | 58 |
for (int i = 0; i < classes.length; i++) { |
91 | 60 |
if(!classes[i].isInterface()) {
|
92 | 2 |
throw new PicoIntrospectionException("Class keys must be interfaces. " + classes[i] + " is not an interface."); |
93 |
} |
|
94 |
} |
|
95 | 56 |
return classes;
|
96 |
} |
|
97 |
|
|
98 |
// These two methods are copied from ProxyToys' ClassHierarchyIntrospector
|
|
99 |
// TODO: Why? These two are currently not called in the complete Pico/Nano/Micro codebase ...
|
|
100 |
// they just decrease coverage significantly ...
|
|
101 |
/* *
|
|
102 |
* Get all interfaces of the given type.
|
|
103 |
* If the type is a class, the returned list contains any interface, that is
|
|
104 |
* implemented by the class. If the type is an interface, the all
|
|
105 |
* superinterfaces and the interface itself are included.
|
|
106 |
*
|
|
107 |
* @param clazz type to explore.
|
|
108 |
* @return an array with all interfaces. The array may be empty.
|
|
109 |
*/
|
|
110 |
/*
|
|
111 |
public static Class[] getAllInterfaces(Class clazz) {
|
|
112 |
Set interfaces = new HashSet();
|
|
113 |
getInterfaces(clazz, interfaces);
|
|
114 |
return (Class[]) interfaces.toArray(new Class[interfaces.size()]);
|
|
115 |
}
|
|
116 |
|
|
117 |
private static void getInterfaces(Class clazz, Set interfaces) {
|
|
118 |
if (clazz.isInterface()) {
|
|
119 |
interfaces.add(clazz);
|
|
120 |
}
|
|
121 |
// Class.getInterfaces will return only the interfaces that are
|
|
122 |
// implemented by the current class. Therefore we must loop up
|
|
123 |
// the hierarchy for the superclasses and the superinterfaces.
|
|
124 |
while (clazz != null) {
|
|
125 |
Class[] implemented = clazz.getInterfaces();
|
|
126 |
for (int i = 0; i < implemented.length; i++) {
|
|
127 |
if (!interfaces.contains(implemented[i])) {
|
|
128 |
getInterfaces(implemented[i], interfaces);
|
|
129 |
}
|
|
130 |
}
|
|
131 |
clazz = clazz.getSuperclass();
|
|
132 |
}
|
|
133 |
}
|
|
134 |
*/
|
|
135 |
} |
|
136 |
|
|