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.Dispatcher;
13  import net.sf.cglib.proxy.Enhancer;
14  import net.sf.cglib.proxy.Factory;
15  import net.sf.cglib.proxy.MethodInterceptor;
16  import net.sf.cglib.proxy.MethodProxy;
17  import net.sf.cglib.proxy.NoOp;
18  import net.sf.joyaop.AbstractInterceptor;
19  import net.sf.joyaop.AspectRuntimeException;
20  import net.sf.joyaop.framework.AspectFactory;
21  import net.sf.joyaop.util.ClassUtils;
22  
23  import java.io.Serializable;
24  import java.lang.reflect.Method;
25  import java.lang.reflect.Modifier;
26  
27  /***
28   * The default instantiation strategy for the aspects.
29   * Other implementations could subclass it. 
30   *
31   * @author Shen Li
32   */
33  public class DefaultAspectFactory implements AspectFactory {
34      private static final Class[] interfaceClasses = new Class[]{AspectProxy.class};
35  
36      public Object newInstance(Class implementationClass) {
37          return newInstance(implementationClass, new Class[0], new Object[0]);
38      }
39  
40      public Object newInstance(Class implementaionClass, Class[] argTypes, Object[] args) {
41          if (!Modifier.isAbstract(implementaionClass.getModifiers())) {
42              return ClassUtils.newInstance(implementaionClass, argTypes, args);
43          }
44          Factory factory = ClassUtils.getProxyFactory(implementaionClass);
45          if (factory == null) {
46              CallbackFilter callbackFilter = new CallbackFilterImpl(implementaionClass);
47              Enhancer enhancer = new Enhancer();
48              enhancer.setSuperclass(implementaionClass);
49              enhancer.setInterfaces(interfaceClasses);
50              enhancer.setClassLoader(ClassUtils.getClassLoader());
51              enhancer.setCallbacks(new Callback[]{
52                  new SelfCallback(),
53                  new ProxyCallback(),
54                  new GetterCallback(),
55                  CallbackFactory.forAspectProxy(interfaceClasses, callbackFilter).getCallback(null),
56                  new AbstractInterceptorCallback()
57              });
58              enhancer.setCallbackFilter(callbackFilter);
59              factory = (Factory) enhancer.create(argTypes, args);
60              ClassUtils.putProxyFactory(implementaionClass, factory);
61              return factory;
62          }
63          return factory.newInstance(argTypes, args, factory.getCallbacks());
64      }
65  
66      private static class GetterCallback implements MethodInterceptor, Serializable {
67          public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
68              String name = method.getName();
69              if (!name.startsWith("get")) {
70                  throw new AspectRuntimeException();
71              }
72              Object proxy = InvocationImpl.getCurrentInvocation().getProxy();
73              if (method.getReturnType().isAssignableFrom(proxy.getClass())) {
74                  return proxy;
75              }
76              if (name.length() > 3) {
77                  name = new StringBuffer(name.length() - 3)
78                          .append(name.substring(3, 4).toLowerCase())
79                          .append(name.substring(4)).toString();
80                  return InvocationImpl.getCurrentInvocation().getParameter(name);
81  
82              }
83              throw new AspectRuntimeException("Method " + method.getName() + " is not a getter method.");
84          }
85      }
86  
87      private static class ProxyCallback implements Dispatcher, Serializable {
88          public Object loadObject() throws Exception {
89              return InvocationImpl.getCurrentInvocation().getProxy();
90          }
91      }
92  
93      private static class AbstractInterceptorCallback implements Dispatcher, Serializable {
94          public Object loadObject() throws Exception {
95              return InvocationImpl.getCurrentInvocation();
96          }
97      }
98  
99      private static class SelfCallback implements NoOp, Serializable {
100     }
101 
102     private static class CallbackFilterImpl implements CallbackFilter, Serializable {
103         private Class implementationClass;
104 
105         public CallbackFilterImpl(Class implementationClass) {
106             this.implementationClass = implementationClass;
107         }
108 
109         public int accept(Method method) {
110             // NOTE the abstract parameter and target getter methods must be defined in the impl class itself.
111             if (!Modifier.isAbstract(method.getModifiers())) {
112                 return 0;
113             }
114             Class clazz = method.getDeclaringClass();
115             if (implementationClass == clazz) {
116                 if (method.getName().startsWith("get")) {
117                     return 2;
118                 } else {
119                     throw new AspectRuntimeException();
120                 }
121             } else if (AspectProxy.class == clazz) {
122                 return 3;
123             } else if (clazz.isAssignableFrom(AbstractInterceptor.class)) {
124                 return 4;
125             } else { // TODO
126                 return 1;
127             }
128         }
129     }
130 }