View Javadoc
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