1 /*
2 * Nanning Aspects
3 *
4 * Distributable under LGPL license.
5 * See terms of license at gnu.org.
6 * (C) 2003 Jon Tirsen
7 */
8 package org.codehaus.nanning;
9
10 import java.io.IOException;
11 import java.io.ObjectInputStream;
12 import java.io.Serializable;
13 import java.lang.reflect.InvocationHandler;
14 import java.lang.reflect.Method;
15 import java.lang.reflect.Proxy;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.LinkedHashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 /***
27 * The central concept of the Nanning Core, contains mixins.
28 * Use like this:
29 * <pre><code>
30 AspectInstance instance = new AspectInstance();
31 Mixin mixin = new Mixin();
32 mixin.setInterfaceClass(Intf.class);
33 mixin.addInterceptor(new MockInterceptor());
34 mixin.addInterceptor(new NullInterceptor());
35 mixin.setTarget(new Impl());
36 instance.addMixin(mixin);
37 </pre></code>
38 *
39 * <!-- $Id: AspectInstance.java,v 1.2 2003/07/12 16:48:16 lecando Exp $ -->
40 *
41 * @author $Author: lecando $
42 * @version $Revision: 1.2 $
43 */
44 public final class AspectInstance implements InvocationHandler, Serializable {
45 static final long serialVersionUID = 5462785783512485056L;
46
47 private Map mixins = new HashMap();
48 private List mixinsList = new ArrayList();
49 private Class classIdentifier;
50
51 private Object proxy;
52 private transient List constructionInterceptors = new ArrayList();
53 private transient AspectFactory aspectFactory;
54
55 public AspectInstance() {
56 }
57
58 public AspectInstance(AspectFactory aspectFactory, Class classIdentifier) {
59 this.aspectFactory = aspectFactory;
60 this.classIdentifier = classIdentifier;
61 }
62
63 public AspectInstance(Class classIdentifier) {
64 this.classIdentifier = classIdentifier;
65 }
66
67 private Set getInterfaceClasses() {
68 Set interfaces = new HashSet();
69 for (Iterator iterator = mixinsList.iterator(); iterator.hasNext();) {
70 Mixin mixinInstance = (Mixin) iterator.next();
71 interfaces.add(mixinInstance.getInterfaceClass());
72 }
73 if (classIdentifier != null) {
74 interfaces.add(classIdentifier);
75 }
76 return interfaces;
77 }
78
79 public Object invoke(Object proxy, Method method, Object[] args)
80 throws Throwable {
81 Class interfaceClass = method.getDeclaringClass();
82
83 if (interfaceClass != Object.class) {
84 Object prevThis = Aspects.getThis();
85 try {
86 Aspects.setThis(proxy);
87 Mixin mixin = getMixinForInterface(interfaceClass);
88 return mixin.invokeMethod(proxy, method, args);
89 } finally {
90 Aspects.setThis(prevThis);
91 }
92
93 } else {
94 // for methods defined on Object:
95 // change all proxies into AspectInstances and the call this aspect instance
96 if (args != null) {
97 for (int i = 0; i < args.length; i++) {
98 Object arg = args[i];
99 if (Aspects.isAspectObject(arg)) {
100 args[i] = Aspects.getAspectInstance(arg);
101 }
102 }
103 }
104 return method.invoke(this, args);
105 }
106 }
107
108 Object getTarget(Class interfaceClass) {
109 Mixin interfaceInstance = getMixinForInterface(interfaceClass);
110 return interfaceInstance.getTarget();
111 }
112
113 Set getInterceptors(Class interfaceClass) {
114 Mixin interfaceInstance = getMixinForInterface(interfaceClass);
115 return interfaceInstance.getAllInterceptors();
116 }
117
118 /***
119 * Returns the mixin with the specified interface.
120 * @param interfaceClass
121 * @return
122 */
123 public Mixin getMixinForInterface(Class interfaceClass) {
124 Mixin mixinInstance = (Mixin) mixins.get(interfaceClass);
125 assert mixinInstance != null : "there is no mixin for interface " + interfaceClass + " mixins were " + mixins;
126 return mixinInstance;
127 }
128
129 public boolean hasMixinForInterface(Class interfaceClass) {
130 return mixins.containsKey(interfaceClass);
131 }
132
133 public void setTarget(Class interfaceClass, Object target) {
134 Mixin mixinInstance = getMixinForInterface(interfaceClass);
135 mixinInstance.setTarget(target);
136 }
137
138 public Object[] getTargets() {
139 Object[] targets = new Object[mixinsList.size()];
140 for (int i = 0; i < targets.length; i++) {
141 targets[i] = ((Mixin) mixinsList.get(i)).getTarget();
142 }
143 return targets;
144 }
145
146 private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
147 objectInputStream.defaultReadObject();
148 AspectFactory currentAspectFactory = Aspects.getCurrentAspectFactory();
149 assert currentAspectFactory != null : "context AspectFactory not specified, it is not possible to deserialize " + this;
150 aspectFactory = currentAspectFactory;
151 aspectFactory.reinitialize(this);
152 }
153
154 public Class getClassIdentifier() {
155 return classIdentifier;
156 }
157
158 /***
159 * Adds a mixin.
160 * @param mixin
161 */
162 public void addMixin(Mixin mixin) {
163 assert proxy == null : "Can't add mixins when proxy has been created.";
164 Class interfaceClass = mixin.getInterfaceClass();
165 bindMixinToInterface(interfaceClass, mixin);
166 mixinsList.add(mixin);
167 }
168
169 public void setMixins(List mixinsList) {
170 this.mixinsList = mixinsList;
171 mixins.clear();
172 for (Iterator i = mixinsList.iterator(); i.hasNext();) {
173 Mixin mixinInstance = (Mixin) i.next();
174 bindMixinToInterface(mixinInstance.getInterfaceClass(), mixinInstance);
175 }
176 }
177
178 /***
179 * Binds the mixin to the specified interface and all of it's superclasses, overrides any other bindings
180 * to that interface (and superclasses).
181 * @param interfaceClass
182 * @param mixinInstance
183 */
184 private void bindMixinToInterface(Class interfaceClass, Mixin mixinInstance) {
185 mixins.put(interfaceClass, mixinInstance);
186 Class superclass = interfaceClass.getSuperclass();
187 if (superclass != null) {
188 bindMixinToInterface(superclass, mixinInstance);
189 }
190 Class[] interfaces = interfaceClass.getInterfaces();
191 if (interfaces != null) {
192 for (int i = 0; i < interfaces.length; i++) {
193 Class anInterface = interfaces[i];
194 bindMixinToInterface(anInterface, mixinInstance);
195 }
196 }
197 }
198
199 /***
200 * Returns all the interceptors referenced by this aspect instance. That is all interceptors of all methods of
201 * all mixins, invluding the construction-interceptors.
202 * @return
203 */
204 public Set getAllInterceptors() {
205 Set result = new LinkedHashSet();
206 if (constructionInterceptors != null) {
207 result.addAll(constructionInterceptors);
208 }
209
210 for (Iterator mixinIterator = mixinsList.iterator(); mixinIterator.hasNext();) {
211 Mixin mixinInstance = (Mixin) mixinIterator.next();
212 Set allInterceptors = mixinInstance.getAllInterceptors();
213 for (Iterator interceptorIterator = allInterceptors.iterator(); interceptorIterator.hasNext();) {
214 Interceptor interceptor = (Interceptor) interceptorIterator.next();
215 result.add(interceptor);
216 }
217 }
218 return result;
219 }
220
221 /***
222 * Returns the interceptors of the specified method, searches in the mixin for the interface that the method
223 * has been declared on.
224 * @param method
225 * @return
226 */
227 public List getInterceptorsForMethod(Method method) {
228 return getMixinForInterface(method.getDeclaringClass()).getInterceptorsForMethod(method);
229 }
230
231 /***
232 * Returns the AspectFactory used to create and configure this AspectInstance (if set by the AspectFactory).
233 * @return
234 */
235 public final AspectFactory getAspectFactory() {
236 return aspectFactory;
237 }
238
239 public final class ConstructionInvocationImpl implements ConstructionInvocation {
240 private Object proxy;
241 private Class interfaceClass;
242
243 public ConstructionInvocationImpl(Object proxy, Class interfaceClass) {
244 this.proxy = proxy;
245 this.interfaceClass = interfaceClass;
246 }
247
248 public Object getProxy() {
249 return proxy;
250 }
251
252 public Object getTarget() {
253 return Aspects.getTarget(proxy, interfaceClass);
254 }
255
256 public void setTarget(Object target) {
257 Aspects.setTarget(proxy, interfaceClass, target);
258 }
259 }
260
261 public Object getProxy() {
262 if (proxy == null) {
263 Set interfaces = getInterfaceClasses();
264 proxy = Proxy.newProxyInstance(getClass().getClassLoader(),
265 (Class[]) interfaces.toArray(new Class[0]),
266 this);
267 }
268 proxy = executeConstructionInterceptors(proxy);
269 return proxy;
270 }
271
272 private Object executeConstructionInterceptors(Object proxy) {
273 Object prevThis = Aspects.getThis();
274 try {
275 Aspects.setThis(proxy);
276
277 if (constructionInterceptors != null) {
278 for (Iterator iterator = constructionInterceptors.iterator(); iterator.hasNext();) {
279 ConstructionInterceptor constructionInterceptor = (ConstructionInterceptor) iterator.next();
280 proxy = constructionInterceptor.construct(new ConstructionInvocationImpl(proxy, getClassIdentifier()));
281 }
282 }
283
284 } finally {
285 constructionInterceptors = null;
286 Aspects.setThis(prevThis);
287 }
288 return proxy;
289 }
290
291 public String toString() {
292 if (mixinsList.size() == 1) {
293 return "aspect{" + mixinsList.get(0).toString() + "}";
294 }
295 return "aspect{class=" + classIdentifier + "," +
296 "mixins=" + mixinsList + "}";
297 }
298
299 /***
300 * Returns all mixins defined on this AspectInstance.
301 * @return
302 */
303 public List getMixins() {
304 return Collections.unmodifiableList(mixinsList);
305 }
306
307 /***
308 * Adds a ConstructionInterceptor, the interceptor will be invoked when creating the proxy in {@link #getProxy()}.
309 */
310 public void addConstructionInterceptor(ConstructionInterceptor constructionInterceptor) {
311 if (constructionInterceptors == null) {
312 constructionInterceptors = new ArrayList();
313 }
314 constructionInterceptors.add(constructionInterceptor);
315 }
316
317 public void addInterceptor(MethodInterceptor interceptor) {
318 for (Iterator iterator = mixinsList.iterator(); iterator.hasNext();) {
319 Mixin mixin = (Mixin) iterator.next();
320 mixin.addInterceptor(interceptor);
321 }
322 }
323 }
This page was automatically generated by Maven