KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > aop > instrument > MethodJoinPointGenerator


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.aop.instrument;
23
24 import java.lang.reflect.Method JavaDoc;
25 import java.lang.reflect.Modifier JavaDoc;
26
27 import javassist.CannotCompileException;
28 import javassist.CtClass;
29 import javassist.CtConstructor;
30 import javassist.CtField;
31 import javassist.CtMethod;
32 import javassist.CtNewConstructor;
33 import javassist.CtNewMethod;
34 import javassist.NotFoundException;
35
36 import org.jboss.aop.GeneratedClassAdvisor;
37 import org.jboss.aop.MethodInfo;
38 import org.jboss.aop.advice.AdviceMethodProperties;
39 import org.jboss.aop.joinpoint.MethodInvocation;
40 import org.jboss.aop.util.ReflectToJavassist;
41
42 /** Creates the Joinpoint invocation replacement classes used with Generated advisors
43  *
44  * @author <a HREF="kabir.khan@jboss.com">Kabir Khan</a>
45  * @version $Revision$
46  */

47 public class MethodJoinPointGenerator extends JoinPointGenerator
48 {
49    private static final Class JavaDoc INVOCATION_TYPE = MethodInvocation.class;
50    private static final CtClass INVOCATION_CT_TYPE;
51    static
52    {
53       try
54       {
55          INVOCATION_CT_TYPE = ReflectToJavassist.classToJavassist(INVOCATION_TYPE);
56       }
57       catch (NotFoundException e)
58       {
59          throw new RuntimeException JavaDoc(e);
60       }
61    }
62
63    public MethodJoinPointGenerator(GeneratedClassAdvisor advisor, MethodInfo info)
64    {
65       super(advisor, info);
66    }
67
68    protected void initialiseJoinPointNames()
69    {
70       joinpointClassName = getInfoClassName(
71                advisedMethodName(),
72                methodHash());
73       
74       joinpointFieldName = getInfoFieldName(
75                advisedMethodName(),
76                methodHash());
77    }
78    
79    private String JavaDoc advisedMethodName()
80    {
81       return ((MethodInfo)info).getAdvisedMethod().getName();
82    }
83    
84    private long methodHash()
85    {
86       return ((MethodInfo)info).getHash();
87    }
88       
89    protected boolean isVoid()
90    {
91       return ((MethodInfo)info).getUnadvisedMethod().getReturnType().equals(Void.TYPE);
92    }
93
94    protected Class JavaDoc getReturnType()
95    {
96       if (isVoid()) return null;
97       return ((MethodInfo)info).getUnadvisedMethod().getReturnType();
98    }
99
100    protected AdviceMethodProperties getAdviceMethodProperties(AdviceSetup setup)
101    {
102       Method JavaDoc method = ((MethodInfo)info).getAdvisedMethod();
103       return new AdviceMethodProperties(
104             setup.getAspectClass(),
105             setup.getAdviceName(),
106             info.getClass(),
107             INVOCATION_TYPE,
108             method.getReturnType(),
109             method.getParameterTypes(),
110             method.getExceptionTypes());
111    }
112    
113
114    protected boolean hasTargetObject()
115    {
116       return !Modifier.isStatic(((MethodInfo)info).getAdvisedMethod().getModifiers());
117    }
118
119    protected String JavaDoc getInfoName()
120    {
121       return MethodExecutionTransformer.getMethodInfoFieldName(
122             ((MethodInfo)info).getAdvisedMethod().getName(), ((MethodInfo)info).getHash());
123    }
124
125    protected static CtClass createJoinpointBaseClass(
126          GeneratedAdvisorInstrumentor instrumentor,
127          CtClass advisedClass,
128          CtMethod targetMethod,
129          String JavaDoc miname,
130          String JavaDoc originalMethodName,
131          String JavaDoc wrappedMethodName,
132          long hash) throws CannotCompileException, NotFoundException
133    {
134       instrumentor.addJoinPointGeneratorFieldToGenAdvisor(
135             getJoinPointGeneratorFieldName(originalMethodName, hash));
136
137       BaseClassGenerator factory = new BaseClassGenerator(instrumentor, advisedClass, targetMethod, miname, originalMethodName, wrappedMethodName, hash);
138       return factory.generate();
139    }
140
141    protected String JavaDoc getJoinPointGeneratorFieldName()
142    {
143       return getJoinPointGeneratorFieldName(advisedMethodName(), methodHash());
144    }
145    
146    protected static String JavaDoc getInfoFieldName(String JavaDoc methodName, long hash)
147    {
148       return JOINPOINT_FIELD_PREFIX + MethodExecutionTransformer.getMethodNameHash(methodName, hash);
149    }
150
151    private static String JavaDoc getInfoClassName(String JavaDoc methodName, long hash)
152    {
153       return JOINPOINT_CLASS_PREFIX + MethodExecutionTransformer.getMethodNameHash(methodName, hash);
154    }
155    
156    protected static String JavaDoc getJoinPointGeneratorFieldName(String JavaDoc methodName, long hash)
157    {
158       return GENERATOR_PREFIX + MethodExecutionTransformer.getMethodNameHash(methodName, hash);
159    }
160    
161    private static class BaseClassGenerator
162    {
163       GeneratedAdvisorInstrumentor instrumentor;
164       CtClass advisedClass;
165       CtMethod advisedMethod;
166       String JavaDoc miname;
167       String JavaDoc originalMethodName;
168       String JavaDoc wrappedMethodName;
169       long hash;
170       boolean hasTargetObject;
171       
172       CtClass jp;
173       CtMethod invokeJoinpointMethod;
174       CtConstructor publicConstructor;
175       CtConstructor protectedConstructor;
176       CtField targetField;
177       CtClass[] originalParams;
178       CtClass[] params;
179       CtClass methodInfoClass;
180       
181       BaseClassGenerator(GeneratedAdvisorInstrumentor instrumentor, CtClass advisedClass,
182                         CtMethod targetMethod, String JavaDoc miname,
183                        String JavaDoc originalMethodName, String JavaDoc wrappedMethodName,long hash) throws NotFoundException
184       {
185          this.instrumentor = instrumentor;
186          this.advisedClass = advisedClass;
187          this.advisedMethod = targetMethod;
188          this.miname = miname;
189          this.originalMethodName = originalMethodName;
190          this.wrappedMethodName = wrappedMethodName;
191          this.hash = hash;
192          this.originalParams = targetMethod.getParameterTypes();
193          this.params = GeneratedAdvisorMethodExecutionTransformer.addTargetToParamsForNonStaticMethod(advisedClass, targetMethod);
194          methodInfoClass = instrumentor.forName(MethodExecutionTransformer.METHOD_INFO_CLASS_NAME);
195          hasTargetObject = !Modifier.isStatic(advisedMethod.getModifiers());
196       }
197
198       protected CtClass generate() throws CannotCompileException, NotFoundException
199       {
200          jp = setupClass();
201          addArgumentsFieldsAndAccessors();
202          if (hasTargetObject)
203          {
204             addTypedTargetField();
205          }
206          addInvokeJoinpointMethod();
207          addMethodInfoField();
208          addDefaultConstructor();
209          addPublicConstructor();
210          addProtectedConstructor();
211          addDispatchMethods();
212          
213          TransformerCommon.compileOrLoadClass(advisedClass, jp);
214          return jp;
215       }
216
217       
218       private CtClass setupClass()throws NotFoundException, CannotCompileException
219       {
220          String JavaDoc className = getInfoClassName(originalMethodName, hash);
221          
222          //Create inner joinpoint class in advised class, super class is MethodInvocation
223
jp = TransformerCommon.makeNestedClass(advisedClass, className, true);
224          int mod = jp.getModifiers();
225          jp.setModifiers(mod | Modifier.PUBLIC);
226          
227          CtClass methodInvocation = INVOCATION_CT_TYPE;
228          jp.setSuperclass(methodInvocation);
229          addUntransformableInterface(instrumentor, jp);
230          
231          return jp;
232       }
233
234       private void addArgumentsFieldsAndAccessors() throws NotFoundException, CannotCompileException
235       {
236          OptimizedBehaviourInvocations.addArgumentFieldsToInvocation(jp, originalParams);
237          OptimizedBehaviourInvocations.addSetArguments(instrumentor.getClassPool(), jp, originalParams);
238          //We might be marshalled so add special get arguments code
239
OptimizedBehaviourInvocations.addGetArguments(instrumentor.getClassPool(), jp, originalParams, true);
240       }
241       
242       private void addTypedTargetField()throws CannotCompileException
243       {
244          targetField = new CtField(advisedClass, TARGET_FIELD, jp);
245          jp.addField(targetField);
246          targetField.setModifiers(Modifier.PROTECTED | Modifier.TRANSIENT);
247       }
248       
249       /**
250        * We need a default constructor so we can serialize
251        */

252       private void addDefaultConstructor() throws CannotCompileException
253       {
254          CtConstructor defaultConstructor = CtNewConstructor.defaultConstructor(jp);
255          jp.addConstructor(defaultConstructor);
256       }
257       
258       /**
259        * This constructor is used by the advisor when we have regenerated the joinpoint.
260        * This just creates a generic JoinPoint instance with no data specific to the
261        * method call
262        */

263       private void addPublicConstructor() throws CannotCompileException
264       {
265          publicConstructor = CtNewConstructor.make(
266                new CtClass[] {methodInfoClass},
267                new CtClass[0],
268                "{super($1, $1.getInterceptors()); this." + INFO_FIELD + " = $1;}",
269                jp);
270                
271          jp.addConstructor(publicConstructor);
272       }
273       
274       /**
275        * This constructor will be called by invokeJoinpoint in the generated subclass when we need to
276        * instantiate a joinpoint containing target and args
277        */

278       protected void addProtectedConstructor() throws CannotCompileException
279       {
280          CtClass[] ctorParams = new CtClass[params.length + 1];
281          ctorParams[0] = jp;
282          System.arraycopy(params, 0, ctorParams, 1, params.length);
283          
284          StringBuffer JavaDoc body = new StringBuffer JavaDoc();
285          body.append("{");
286          body.append(" this($1." + INFO_FIELD + ");");
287          
288          int offset = 1;
289          if (hasTargetObject)
290          {
291             body.append(" this." + TARGET_FIELD + " = $2;");
292             body.append(" super.setTargetObject($2);");
293             offset = 2;
294          }
295          
296          for (int i = offset ; i < ctorParams.length ; i++)
297          {
298             body.append(" arg" + (i - offset) + " = $" + (i + 1) + ";");
299          }
300          
301          body.append("}");
302          protectedConstructor = CtNewConstructor.make(
303                ctorParams,
304                new CtClass[0],
305                body.toString(),
306                jp);
307          protectedConstructor.setModifiers(Modifier.PROTECTED);
308                
309          jp.addConstructor(protectedConstructor);
310          
311       }
312       
313       /**
314        * Add an empty invokeJoinpoint() method. This method will be overridden by generated subclasses,
315        * when the interceptors are rebuilt
316        */

317       private CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException
318       {
319          invokeJoinpointMethod = CtNewMethod.make(
320                advisedMethod.getReturnType(),
321                INVOKE_JOINPOINT,
322                params,
323                advisedMethod.getExceptionTypes(),
324                null,
325                jp);
326          invokeJoinpointMethod.setModifiers(Modifier.PROTECTED);
327          jp.addMethod(invokeJoinpointMethod);
328          return invokeJoinpointMethod;
329        }
330       
331       private void addMethodInfoField()throws CannotCompileException
332       {
333          CtField infoField = new CtField(methodInfoClass, INFO_FIELD, jp);
334          jp.addField(infoField);
335          infoField.setModifiers(Modifier.PROTECTED | Modifier.TRANSIENT);//Make visible to classes in child classloaders
336
}
337       
338       private void addDispatchMethods() throws CannotCompileException, NotFoundException
339       {
340          addInvokeNextDispatchMethod();
341          
342          if (params.length > 0)
343          {
344             addInvokeJoinPointDispatchMethod();
345          }
346          
347          addInvokeTargetMethod();
348       }
349       
350       private void addInvokeNextDispatchMethod() throws CannotCompileException, NotFoundException
351       {
352          //This dispatch method will be called by the invokeNext() methods for around advice
353

354          StringBuffer JavaDoc parameters = new StringBuffer JavaDoc();
355          for (int i = 0 ; i < originalParams.length ; i++)
356          {
357             if (i > 0)parameters.append(", ");
358             parameters.append("arg" + i);
359          }
360          
361          String JavaDoc body = (!hasTargetObject) ?
362                "{" + MethodExecutionTransformer.getReturnStr(advisedMethod) + advisedClass.getName() + "." + wrappedMethodName + "(" + parameters + ");}" :
363                "{" + MethodExecutionTransformer.getAopReturnStr(advisedMethod) + TARGET_FIELD + "." + wrappedMethodName + "(" + parameters + ");}";
364       
365          try
366          {
367             CtMethod dispatch = CtNewMethod.make(
368                   advisedMethod.getReturnType(),
369                   JoinPointGenerator.DISPATCH,
370                   EMPTY_CTCLASS_ARRAY,
371                   advisedMethod.getExceptionTypes(),
372                   body,
373                   jp);
374             dispatch.setModifiers(Modifier.PROTECTED);
375             jp.addMethod(dispatch);
376          }
377          catch (CannotCompileException e)
378          {
379             throw new RuntimeException JavaDoc("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, EMPTY_CTCLASS_ARRAY), e);
380          }
381       }
382       
383       private void addInvokeJoinPointDispatchMethod() throws CannotCompileException, NotFoundException
384       {
385          //This dispatch method will be called by the invokeJoinPoint() method if the joinpoint has no around advices
386

387          int offset = hasTargetObject ? 1 : 0;
388          StringBuffer JavaDoc parameters = new StringBuffer JavaDoc();
389          for (int i = 0 ; i < originalParams.length ; i++)
390          {
391             if (i > 0)parameters.append(", ");
392             parameters.append("$" + (i + offset + 1));
393          }
394       
395          String JavaDoc body = (!hasTargetObject) ?
396                "{" + MethodExecutionTransformer.getReturnStr(advisedMethod) + advisedClass.getName() + "." + wrappedMethodName + "(" + parameters + ");}" :
397                "{" + MethodExecutionTransformer.getAopReturnStr(advisedMethod) + "$1." + wrappedMethodName + "(" + parameters + ");}";
398       
399          
400          try
401          {
402             CtMethod dispatch = CtNewMethod.make(
403                   advisedMethod.getReturnType(),
404                   JoinPointGenerator.DISPATCH,
405                   params,
406                   advisedMethod.getExceptionTypes(),
407                   body,
408                   jp);
409             dispatch.setModifiers(Modifier.PROTECTED);
410             jp.addMethod(dispatch);
411          }
412          catch (CannotCompileException e)
413          {
414             throw new RuntimeException JavaDoc("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, params), e);
415          }
416       }
417       
418       private void addInvokeTargetMethod() throws CannotCompileException, NotFoundException
419       {
420          CtMethod template = INVOCATION_CT_TYPE.getDeclaredMethod(INVOKE_TARGET);
421          
422          boolean isVoid = advisedMethod.getReturnType().equals(CtClass.voidType);
423          String JavaDoc body = (isVoid) ? "{dispatch(); return null;}" : "{return ($w)dispatch();}";
424          
425          CtMethod invokeTarget = CtNewMethod.make(
426                template.getReturnType(),
427                template.getName(),
428                template.getParameterTypes(),
429                template.getExceptionTypes(),
430                body,
431                jp);
432          jp.addMethod(invokeTarget);
433       }
434    }
435 }
436
Popular Tags