KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tcspring > FastAopProxy


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
3  * notice. All rights reserved.
4  */

5 package com.tcspring;
6
7 import org.aopalliance.aop.Advice;
8 import org.aopalliance.intercept.MethodInterceptor;
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11 import org.springframework.aop.Advisor;
12 import org.springframework.aop.AfterReturningAdvice;
13 import org.springframework.aop.IntroductionInterceptor;
14 import org.springframework.aop.MethodBeforeAdvice;
15 import org.springframework.aop.MethodMatcher;
16 import org.springframework.aop.Pointcut;
17 import org.springframework.aop.PointcutAdvisor;
18 import org.springframework.aop.ThrowsAdvice;
19 import org.springframework.aop.framework.AdvisedSupport;
20 import org.springframework.aop.framework.AopConfigException;
21 import org.springframework.aop.framework.AopProxy;
22 import org.springframework.aop.framework.ProxyFactoryBean;
23 import org.springframework.beans.factory.BeanFactory;
24
25 import com.tc.aspectwerkz.DeploymentModel;
26 import com.tc.aspectwerkz.aspect.container.AspectFactoryManager;
27 import com.tc.aspectwerkz.definition.AspectDefinition;
28 import com.tc.aspectwerkz.definition.DocumentParser;
29 import com.tc.aspectwerkz.definition.SystemDefinition;
30 import com.tc.aspectwerkz.definition.SystemDefinitionContainer;
31 import com.tc.aspectwerkz.definition.deployer.AspectDefinitionBuilder;
32 import com.tc.aspectwerkz.exception.WrappedRuntimeException;
33 import com.tc.aspectwerkz.proxy.Proxy;
34 import com.tc.aspectwerkz.proxy.ProxyDelegationStrategy;
35 import com.tc.aspectwerkz.proxy.ProxySubclassingStrategy;
36 import com.tc.aspectwerkz.proxy.Uuid;
37 import com.tc.aspectwerkz.reflect.MethodInfo;
38 import com.tc.aspectwerkz.reflect.impl.java.JavaClassInfo;
39 import com.tc.aspectwerkz.transform.TransformationConstants;
40 import com.tc.aspectwerkz.util.UuidGenerator;
41
42 import java.lang.reflect.Field JavaDoc;
43 import java.lang.reflect.Method JavaDoc;
44 import java.util.HashSet JavaDoc;
45 import java.util.Set JavaDoc;
46
47 /**
48  * Implementation of the Spring AOP proxy that is order of magnitude faster. Based on the AspectWerkz AWProxy
49  * architecture.
50  *
51  * @author Jonas Bonér
52  */

53 public class FastAopProxy implements AopProxy {
54   private final transient Log logger = LogFactory.getLog(getClass());
55
56   private static final boolean USE_CACHE = false;
57   private static final boolean MAKE_ADVISABLE = false;
58
59   private static final String JavaDoc SPRING_ASPECT_CONTAINER = SpringAspectContainer.class.getName();
60
61   private static final MethodInfo s_methodBeforeAdviceMethodInfo = JavaClassInfo
62                                                                        .getClassInfo(MethodBeforeAdvice.class)
63                                                                        .getMethods()[0];
64   private static final MethodInfo s_methodInterceptorMethodInfo = JavaClassInfo
65                                                                        .getClassInfo(MethodInterceptor.class)
66                                                                        .getMethods()[0];
67   private static final MethodInfo s_afterReturningAdviceMethodInfo = JavaClassInfo
68                                                                        .getClassInfo(AfterReturningAdvice.class)
69                                                                        .getMethods()[0];
70
71   private static final String JavaDoc s_throwsAdviceMethodName = "afterThrowing";
72
73   private final ProxyFactoryBean m_proxyFactory;
74   private final SystemDefinition m_systemDef;
75   private final ClassLoader JavaDoc m_loader;
76   private final Class JavaDoc m_targetClass;
77   private final String JavaDoc m_proxyName;
78   private final boolean m_isSubclassingProxy;
79   private final BeanFactory m_beanFactory;
80
81   // private final String[] m_interceptorNames;
82

83   public FastAopProxy(final ProxyFactoryBean proxyFactory) throws AopConfigException {
84     if (proxyFactory == null) { throw new AopConfigException("Cannot create AopProxy with null ProxyConfig"); }
85     if (proxyFactory.getAdvisors().length == 0 && proxyFactory.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { throw new AopConfigException(
86                                                                                                                                                        "Cannot create AopProxy with no advisors and no target source"); }
87     if (proxyFactory.getTargetSource().getTargetClass() == null) { throw new AopConfigException(
88                                                                                                 "Either an interface or a target is required for proxy creation"); }
89
90     // System.out.println("### creating Fast AOP proxy for " +
91
// proxyFactory.getTargetSource().getTargetClass().getName());
92
logger.info("Creating FastProxy for " + proxyFactory.getTargetSource().getTargetClass().getName());
93
94     m_proxyFactory = proxyFactory;
95     m_targetClass = m_proxyFactory.getTargetSource().getTargetClass();
96     m_loader = m_targetClass.getClassLoader();
97     m_isSubclassingProxy = m_proxyFactory.isProxyTargetClass() || m_proxyFactory.getProxiedInterfaces().length == 0;
98     m_proxyName = getProxyName();
99     m_systemDef = new SystemDefinition(m_proxyName + UuidGenerator.generate(m_proxyName));
100
101     try {
102       m_beanFactory = ((BeanFactoryAware) proxyFactory).tc$getBeanFactory();
103     } catch (Exception JavaDoc e) {
104       throw new WrappedRuntimeException(e);
105     }
106
107     prepareSystemDefinition();
108     parseSpringDefinition();
109   }
110
111   private String JavaDoc getProxyName() {
112     return m_targetClass.getName().replace('.', '/')
113            + (m_isSubclassingProxy ? ProxySubclassingStrategy.PROXY_SUFFIX : ProxyDelegationStrategy.PROXY_SUFFIX)
114            + Long.toString(Uuid.newUuid());
115   }
116
117   public Object JavaDoc getProxy() {
118     return getProxy(null);
119   }
120
121   public Object JavaDoc getProxy(final ClassLoader JavaDoc classLoader) {
122     final Object JavaDoc target;
123     try {
124       target = m_proxyFactory.getTargetSource().getTarget();
125     } catch (Exception JavaDoc e) {
126       throw new AopConfigException("ProxyFactory is not correctly initialized - target is NULL", e);
127     }
128
129     if (m_isSubclassingProxy) {
130       // create subclassing proxy (cglib style)
131
return Proxy.newInstance(target.getClass(), USE_CACHE, MAKE_ADVISABLE, m_systemDef);
132     } else {
133       // create delegating proxy (DP style)
134
final Class JavaDoc[] interfaces = m_proxyFactory.getProxiedInterfaces();
135       final Object JavaDoc[] implementations = new Object JavaDoc[interfaces.length];
136       for (int i = 0; i < implementations.length; i++) {
137         implementations[i] = target;
138       }
139       return Proxy.newInstance(interfaces, implementations, USE_CACHE, MAKE_ADVISABLE, m_systemDef);
140     }
141   }
142
143   private void prepareSystemDefinition() {
144     DocumentParser.addVirtualAspect(m_systemDef);
145     if (!SystemDefinitionContainer.s_classLoaderSystemDefinitions.containsKey(m_loader)) {
146       SystemDefinitionContainer.s_classLoaderSystemDefinitions.put(m_loader, new HashSet JavaDoc());
147     }
148     ((Set JavaDoc) SystemDefinitionContainer.s_classLoaderSystemDefinitions.get(m_loader)).add(m_systemDef);
149   }
150
151   private void parseSpringDefinition() {
152     Advisor[] advisors = m_proxyFactory.getAdvisors();
153
154     // loop over all aspects (advice/interceptors)
155
for (int i = 0; i < advisors.length; i++) {
156       Advisor advisor = advisors[i];
157       if (advisor instanceof PointcutAdvisor) {
158         PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
159
160         final Advice aspect = pointcutAdvisor.getAdvice();
161         // FIXME BAAAAAAAD!!! support IntroductionInterceptor
162
if (aspect instanceof IntroductionInterceptor) { throw new IllegalStateException JavaDoc(
163                                                                                          "IntroductionInterceptor is currently not supported by FastProxy"); }
164         // FIXME BAAAAAAAD!!! support ThrowsAdvice
165
if (aspect instanceof ThrowsAdvice) { throw new IllegalStateException JavaDoc(
166                                                                               "ThrowsAdvice is currently not supported by FastProxy"); }
167
168         final Class JavaDoc aspectClass = aspect.getClass();
169         final Pointcut pointcut = pointcutAdvisor.getPointcut();
170         if (!pointcut.getClassFilter().matches(m_targetClass)) {
171           continue;
172         }
173
174         // create AW version of the Spring pointcut
175
final StringBuffer JavaDoc pcd = new StringBuffer JavaDoc();
176         MethodMatcher methodMatcher = pointcut.getMethodMatcher();
177         Method JavaDoc[] methods = m_targetClass.getDeclaredMethods();
178         boolean hasAtLeastOneMatch = false;
179         for (int j = 0; j < methods.length; j++) {
180           Method JavaDoc method = methods[j];
181           if (methodMatcher.matches(method, m_targetClass)) {
182             buildPointcutForMethod(pcd, method);
183             hasAtLeastOneMatch = true;
184           }
185         }
186         if (hasAtLeastOneMatch) {
187           int length = pcd.length();
188           pcd.delete(length - 3, length);
189         } else {
190           continue;
191         }
192
193         // final AspectDefinition aspectDef = createAspectDefUsingXml(aspect, aspectClass, pcd);
194
final AspectDefinition aspectDef = buildAspectDefinition(aspect, aspectClass, pcd.toString());
195
196         initializeAspectFactory(aspect, aspectDef);
197       } else {
198         throw new IllegalStateException JavaDoc("introductions (mixins) are currently not supported");
199       }
200     }
201   }
202
203   private void buildPointcutForMethod(final StringBuffer JavaDoc pcd, final Method JavaDoc method) {
204     pcd.append("execution(");
205     pcd.append(method.getReturnType().getName());
206     pcd.append(" ");
207     pcd.append(m_targetClass.getName());
208     pcd.append(".");
209     pcd.append(method.getName());
210     pcd.append("(");
211     pcd.append("..");
212     pcd.append(")) || ");
213   }
214
215   private AspectDefinition buildAspectDefinition(final Advice aspect, final Class JavaDoc aspectClass, final String JavaDoc pcd) {
216     AspectDefinitionBuilder builder = new AspectDefinitionBuilder(aspectClass.getName(), DeploymentModel.PER_JVM,
217                                                                   SPRING_ASPECT_CONTAINER, m_systemDef, m_loader);
218
219     if (aspect instanceof MethodBeforeAdvice) {
220       builder.addAdvice("before", pcd.toString(), s_methodBeforeAdviceMethodInfo.getName());
221     } else if (aspect instanceof MethodInterceptor) {
222       builder.addAdvice("around", pcd.toString(), s_methodInterceptorMethodInfo.getName());
223     } else if (aspect instanceof AfterReturningAdvice) {
224       builder
225           .addAdvice("after returning(java.lang.Object)", pcd.toString(), s_afterReturningAdviceMethodInfo.getName());
226     } else if (aspect instanceof ThrowsAdvice) {
227       builder.addAdvice("after throwing(java.lang.Throwable+)", pcd.toString(), s_throwsAdviceMethodName);
228     }
229     builder.build();
230
231     final AspectDefinition aspectDef = builder.getAspectDefinition();
232     aspectDef.addParameter(SpringAspectContainer.BEAN_FACTORY_KEY, m_beanFactory);
233     m_systemDef.addAspect(aspectDef);
234     return aspectDef;
235   }
236
237   /**
238    * @param aspectDef
239    * @return the factory class name
240    */

241   private String JavaDoc createAspectFactory(final AspectDefinition aspectDef) {
242     String JavaDoc aspectFactoryClassName = AspectFactoryManager.getAspectFactoryClassName(aspectDef.getClassName(), aspectDef
243         .getQualifiedName());
244     String JavaDoc aspectFactoryJavaName = aspectFactoryClassName.replace('/', '.');
245     AspectFactoryManager.loadAspectFactory(aspectFactoryClassName, m_proxyName, aspectDef.getClassName().replace('.',
246                                                                                                                  '/'),
247                                            aspectDef.getQualifiedName(), null, null, m_loader, DeploymentModel.PER_JVM
248                                                .toString());
249     return aspectFactoryJavaName;
250   }
251
252   /**
253    * @param aspect
254    * @param aspectDef
255    */

256   private void initializeAspectFactory(final Advice aspect, final AspectDefinition aspectDef) {
257     // create and load the factory for the aspect
258
final String JavaDoc factoryName = createAspectFactory(aspectDef);
259     try {
260       Class JavaDoc factory = m_loader.loadClass(factoryName);
261       Field JavaDoc aspectField = factory.getDeclaredField(TransformationConstants.FACTORY_SINGLE_ASPECT_FIELD_NAME);
262       aspectField.set(null, aspect);
263     } catch (Exception JavaDoc e) {
264       throw new WrappedRuntimeException(e);
265     }
266   }
267 }
268
Popular Tags