View Javadoc

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 }