1 /************************************************* 2 * Copyright (c) Shen Li. All rights reserved. * 3 * http://joyaop.sourceforge.net * 4 * -------------------------------------------- * 5 * Distributable under LGPL license. * 6 * See terms of license at gnu.org. * 7 ************************************************/ 8 package net.sf.joyaop.impl; 9 10 import net.sf.cglib.proxy.Callback; 11 import net.sf.cglib.proxy.CallbackFilter; 12 import net.sf.cglib.proxy.MethodInterceptor; 13 import net.sf.cglib.proxy.MethodProxy; 14 import net.sf.joyaop.AspectRuntimeException; 15 import net.sf.joyaop.framework.AspectizedClass; 16 import net.sf.joyaop.framework.InterceptorAspect; 17 import net.sf.joyaop.framework.MixinAspect; 18 import net.sf.joyaop.framework.RuntimeAspect; 19 import net.sf.joyaop.impl.aspect.BaseInterceptorAspectImpl; 20 import net.sf.joyaop.impl.aspect.MixinAspectImpl; 21 22 import java.io.NotSerializableException; 23 import java.io.Serializable; 24 import java.lang.reflect.Method; 25 import java.util.ArrayList; 26 import java.util.Collections; 27 import java.util.Iterator; 28 import java.util.List; 29 import java.util.Set; 30 31 /*** 32 * @author Shen Li 33 */ 34 public abstract class CallbackFactory { 35 public static CallbackFactory forInterceptor(AspectizedClass aspectizedClass, Method method, Set interceptorAspects) { 36 return new InterceptorCallbackFactory(aspectizedClass, method, interceptorAspects); 37 } 38 39 public static CallbackFactory forMixin(AspectizedClass aspectizedClass, MixinAspectImpl mixinAspect) { 40 return new MixinCallbackFactory(aspectizedClass, mixinAspect); 41 } 42 43 public static CallbackFactory forAspectProxy(Class[] interfaceClasses, CallbackFilter callbackFilter) { 44 return new AspectProxyCallbackFactory(interfaceClasses, callbackFilter); 45 } 46 47 public static CallbackFactory forOriginalClass() { 48 return new OriginalClassCallbackFactory(); 49 } 50 51 public abstract Callback getCallback(RuntimeAspectInstanceFactory factory); 52 53 public static class InterceptorCallbackFactory extends CallbackFactory { 54 private Callback cachedCallback; 55 private List cachedInterceptorAspectInstances; 56 private Method method; 57 private Set interceptorAspects; 58 private AspectizedClass aspectizedClass; 59 60 public InterceptorCallbackFactory(AspectizedClass aspectizedClass, Method method, Set interceptorAspects) { 61 this.aspectizedClass = aspectizedClass; 62 this.method = method; 63 this.interceptorAspects = interceptorAspects; 64 boolean hasInstanceScopeInterceptor = hasInstanceScopeInterceptors(); 65 RuntimeAspectInstanceFactory factory = new RuntimeAspectInstanceFactory(aspectizedClass.getOriginalClass()); 66 if (!hasInstanceScopeInterceptor && !hasInstanceScopeMixin()) { 67 cachedCallback = new InvocationHandler(getInterceptorAspectInstances(factory), getTargetInstance(factory)); 68 } else if (!hasInstanceScopeInterceptor) { 69 cachedInterceptorAspectInstances = getInterceptorAspectInstances(factory); 70 } 71 } 72 73 public Callback getCallback(RuntimeAspectInstanceFactory factory) { 74 if (cachedCallback != null) { 75 return cachedCallback; 76 } 77 if (cachedInterceptorAspectInstances != null) { 78 return new InvocationHandler(cachedInterceptorAspectInstances, getTargetInstance(factory)); 79 } 80 return new InvocationHandler(getInterceptorAspectInstances(factory), getTargetInstance(factory)); 81 } 82 83 private RuntimeInstance getTargetInstance(RuntimeAspectInstanceFactory factory) { 84 Class clazz = method.getDeclaringClass(); 85 if (aspectizedClass.getOriginalClass() == clazz || Object.class == clazz) { 86 return OriginalClassInstance.instance(); 87 } 88 MixinAspectImpl aspect = (MixinAspectImpl) aspectizedClass.getMixin(clazz); 89 if (aspect != null) { 90 return factory.getRuntimeAspectInstance(aspect); 91 } 92 throw new AspectRuntimeException("Can't find the target object for method " + method.getName()); 93 } 94 95 private boolean hasInstanceScopeMixin() { 96 Class clazz = method.getDeclaringClass(); 97 if (aspectizedClass.getOriginalClass() == clazz || Object.class == clazz) { 98 return false; 99 } 100 MixinAspect aspect = (MixinAspect) aspectizedClass.getMixin(clazz); 101 if (aspect != null) { 102 return (RuntimeAspect.INSTANCE_SCOPE.equals(aspect.getScope())); 103 } 104 throw new AspectRuntimeException("Can't find the target object for method " + method.getName()); 105 } 106 107 private boolean hasInstanceScopeInterceptors() { 108 for (Iterator i = interceptorAspects.iterator(); i.hasNext();) { 109 if (RuntimeAspect.INSTANCE_SCOPE.equals(((InterceptorAspect) i.next()).getScope())) { 110 return true; 111 } 112 } 113 return false; 114 } 115 116 private List getInterceptorAspectInstances(RuntimeAspectInstanceFactory factory) { 117 List refs = new ArrayList(interceptorAspects.size()); 118 for (Iterator i = interceptorAspects.iterator(); i.hasNext();) { 119 refs.add(factory.getRuntimeAspectInstance((BaseInterceptorAspectImpl) i.next())); 120 } 121 return refs; 122 } 123 } 124 125 public static class MixinCallbackFactory extends CallbackFactory { 126 private Callback cachedCallback; 127 private MixinAspectImpl aspect; 128 private AspectizedClass aspectizedClass; 129 130 public MixinCallbackFactory(AspectizedClass aspectizedClass, MixinAspectImpl aspect) { 131 this.aspect = aspect; 132 this.aspectizedClass = aspectizedClass; 133 if (!RuntimeAspect.INSTANCE_SCOPE.equals(aspect.getScope())) { 134 cachedCallback = new InvocationHandler(Collections.EMPTY_LIST, 135 new RuntimeAspectInstanceFactory(aspectizedClass.getOriginalClass()).getRuntimeAspectInstance(aspect)); 136 } 137 } 138 139 public Callback getCallback(RuntimeAspectInstanceFactory factory) { 140 if (cachedCallback == null) { 141 return new InvocationHandler(Collections.EMPTY_LIST, 142 new RuntimeAspectInstanceFactory(aspectizedClass.getOriginalClass()).getRuntimeAspectInstance(aspect)); 143 } 144 return cachedCallback; 145 } 146 } 147 148 public static class AspectProxyCallbackFactory extends CallbackFactory { 149 private final AspectProxyHandler callback; 150 151 public AspectProxyCallbackFactory(Class[] interfaceClasses, CallbackFilter callbackFilter) { 152 callback = new AspectProxyHandler(interfaceClasses, callbackFilter); 153 } 154 155 public Callback getCallback(RuntimeAspectInstanceFactory factory) { 156 return callback; 157 } 158 159 public Callback getCallback() { 160 return callback; 161 } 162 163 private static class AspectProxyHandler implements MethodInterceptor, Serializable { 164 private final Class[] interfacesClass; 165 private final CallbackFilter callbackFilter; 166 167 public AspectProxyHandler(Class[] interfacesClass, CallbackFilter callbackFilter) { 168 this.interfacesClass = interfacesClass; 169 this.callbackFilter = callbackFilter; 170 } 171 172 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 173 if (Serializable.class.isAssignableFrom(proxy.getClass().getSuperclass())) { 174 return new SerializableProxy(proxy, interfacesClass, callbackFilter); 175 } 176 throw new NotSerializableException(proxy.getClass().getSuperclass().getName() + " is not serializable."); 177 } 178 } 179 } 180 181 public static class OriginalClassCallbackFactory extends CallbackFactory { 182 private final Callback cachedCallback = 183 new InvocationHandler(Collections.EMPTY_LIST, OriginalClassInstance.instance()); 184 185 public Callback getCallback(RuntimeAspectInstanceFactory factory) { 186 return cachedCallback; 187 } 188 } 189 }