KickJava   Java API By Example, From Geeks To Geeks.

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


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
26 import javassist.CannotCompileException;
27 import javassist.CtClass;
28 import javassist.CtConstructor;
29 import javassist.CtField;
30 import javassist.CtMethod;
31 import javassist.CtNewConstructor;
32 import javassist.CtNewMethod;
33 import javassist.Modifier;
34 import javassist.NotFoundException;
35
36 import org.jboss.aop.GeneratedClassAdvisor;
37 import org.jboss.aop.JoinPointInfo;
38 import org.jboss.aop.MethodByMethodInfo;
39 import org.jboss.aop.advice.AdviceMethodProperties;
40 import org.jboss.aop.joinpoint.MethodCalledByMethodInvocation;
41 import org.jboss.aop.util.ReflectToJavassist;
42
43 public class MethodByMethodJoinPointGenerator extends JoinPointGenerator
44 {
45    public static final String JavaDoc GENERATOR_PREFIX = JoinPointGenerator.GENERATOR_PREFIX + "MByM_";
46    public static final String JavaDoc JOINPOINT_CLASS_PREFIX = JoinPointGenerator.JOINPOINT_CLASS_PREFIX + "MByM_";
47    public static final String JavaDoc JOINPOINT_FIELD_PREFIX = JoinPointGenerator.JOINPOINT_FIELD_PREFIX + "MByM_";
48    private static final Class JavaDoc INVOCATION_TYPE = MethodCalledByMethodInvocation.class;
49    private static final CtClass INVOCATION_CT_TYPE;
50    static
51    {
52       try
53       {
54          INVOCATION_CT_TYPE = ReflectToJavassist.classToJavassist(INVOCATION_TYPE);
55       }
56       catch (NotFoundException e)
57       {
58          throw new RuntimeException JavaDoc(e);
59       }
60    }
61
62    public MethodByMethodJoinPointGenerator(GeneratedClassAdvisor advisor, JoinPointInfo info)
63    {
64       super(advisor, info);
65    }
66
67    protected void initialiseJoinPointNames()
68    {
69       joinpointClassName = getInfoClassName(
70                callingMethodHash(),
71                calledClass(),
72                calledMethodHash());
73
74       joinpointFieldName = getInfoFieldName(
75             callingMethodHash(),
76             calledClass(),
77             calledMethodHash());
78    }
79
80    private long callingMethodHash()
81    {
82       return ((MethodByMethodInfo)info).getCallingMethodHash();
83    }
84
85    private String JavaDoc calledClass()
86    {
87       return ((MethodByMethodInfo)info).getCalledClass().getName();
88    }
89
90    private long calledMethodHash()
91    {
92       return ((MethodByMethodInfo)info).getCalledMethodHash();
93    }
94
95    protected boolean isVoid()
96    {
97       return ((MethodByMethodInfo)info).getMethod().getReturnType().equals(Void.TYPE);
98    }
99
100    protected Class JavaDoc getReturnType()
101    {
102       if (isVoid()) return null;
103       return ((MethodByMethodInfo)info).getMethod().getReturnType();
104    }
105
106    protected AdviceMethodProperties getAdviceMethodProperties(AdviceSetup setup)
107    {
108       Method JavaDoc method = ((MethodByMethodInfo)info).getMethod();
109       return new AdviceMethodProperties(
110             setup.getAspectClass(),
111             setup.getAdviceName(),
112             info.getClass(),
113             INVOCATION_TYPE,
114             method.getReturnType(),
115             method.getParameterTypes(),
116             method.getExceptionTypes());
117    }
118
119    protected boolean isCaller()
120    {
121       return true;
122    }
123
124    protected boolean hasCallingObject()
125    {
126       return !java.lang.reflect.Modifier.isStatic(((MethodByMethodInfo)info).getCallingMethod().getModifiers());
127    }
128
129    protected boolean hasTargetObject()
130    {
131       return !java.lang.reflect.Modifier.isStatic(((MethodByMethodInfo)info).getMethod().getModifiers());
132    }
133
134    protected static CtClass createJoinpointBaseClass(
135          GeneratedAdvisorInstrumentor instrumentor,
136          long callingHash,
137          boolean hasCallingObject,
138          CtClass callingClass,
139          CtMethod targetMethod,
140          String JavaDoc classname,
141          long calledHash,
142          String JavaDoc ciname) throws NotFoundException, CannotCompileException
143    {
144       instrumentor.addJoinPointGeneratorFieldToGenAdvisor(
145             getJoinPointGeneratorFieldName(callingHash, classname, calledHash));
146
147       BaseClassGenerator generator = new BaseClassGenerator(instrumentor, callingClass, callingHash, hasCallingObject, classname, targetMethod, calledHash, ciname);
148       return generator.generate();
149    }
150
151    protected String JavaDoc getJoinPointGeneratorFieldName()
152    {
153       return getJoinPointGeneratorFieldName(callingMethodHash(), calledClass(), calledMethodHash());
154    }
155
156    protected static String JavaDoc getInfoClassName(long callingHash, String JavaDoc classname, long calledHash)
157    {
158       return JOINPOINT_CLASS_PREFIX + CallerTransformer.getUniqueInvocationFieldname(callingHash, classname, calledHash);
159    }
160
161    protected static String JavaDoc getInfoFieldName(long callingHash, String JavaDoc classname, long calledHash)
162    {
163       return JOINPOINT_FIELD_PREFIX + CallerTransformer.getUniqueInvocationFieldname(callingHash, classname, calledHash);
164    }
165
166    protected static String JavaDoc getJoinPointGeneratorFieldName(long callingHash, String JavaDoc classname, long calledHash)
167    {
168       return GENERATOR_PREFIX + CallerTransformer.getUniqueInvocationFieldname(callingHash, classname, calledHash);
169    }
170
171    private static class BaseClassGenerator
172    {
173       GeneratedAdvisorInstrumentor instrumentor;
174       CtClass callingClass;
175       long callingHash;
176       boolean hasCallingObject;
177       String JavaDoc classname;
178       CtClass targetClass;
179       CtMethod targetMethod;
180       long calledHash;
181       String JavaDoc ciname;
182       boolean hasTargetObject;
183
184       CtClass jp;
185       CtMethod invokeJoinpointMethod;
186       CtConstructor publicConstructor;
187       CtConstructor protectedConstructor;
188       CtField targetField;
189       CtClass[] params;
190       CtClass methodInfoClass;
191
192       BaseClassGenerator(
193             GeneratedAdvisorInstrumentor instrumentor,
194             CtClass callingClass,
195             long callingHash,
196             boolean hasCallingObject,
197             String JavaDoc classname,
198             CtMethod targetMethod,
199             long calledHash,
200             String JavaDoc ciname) throws NotFoundException
201       {
202          this.instrumentor = instrumentor;
203          this.callingClass = callingClass;
204          this.callingHash = callingHash;
205          this.classname = classname;
206          this.hasCallingObject = hasCallingObject;
207          this.targetClass = instrumentor.forName(classname);
208          this.targetMethod = targetMethod;
209          this.calledHash = calledHash;
210          this.ciname = ciname;
211          this.params = targetMethod.getParameterTypes();
212          methodInfoClass = instrumentor.forName(CallerTransformer.METHOD_BY_METHOD_INFO_CLASS_NAME);
213          hasTargetObject = !Modifier.isStatic(targetMethod.getModifiers());
214       }
215
216       protected CtClass generate() throws CannotCompileException, NotFoundException
217       {
218          jp = setupClass();
219          addArgumentsFieldsAndAccessors();
220          if (hasTargetObject)
221          {
222             addTypedTargetField();
223          }
224          addInvokeJoinpointMethod();
225          addMethodInfoField();
226          addPublicConstructor();
227          addProtectedConstructor();
228          addDispatchMethods();
229
230          TransformerCommon.compileOrLoadClass(callingClass, jp);
231          return jp;
232       }
233
234
235       private CtClass setupClass()throws NotFoundException, CannotCompileException
236       {
237          String JavaDoc className = getInfoClassName(callingHash, targetClass.getName(), calledHash);
238
239          //Create inner joinpoint class in advised class, super class is ConstructorInvocation
240
jp = TransformerCommon.makeNestedClass(callingClass, className, true);
241          int mod = jp.getModifiers();
242          jp.setModifiers(mod | Modifier.PUBLIC);
243
244          CtClass invocation = INVOCATION_CT_TYPE;
245          jp.setSuperclass(invocation);
246          addUntransformableInterface(instrumentor, jp);
247          return jp;
248       }
249
250       private void addArgumentsFieldsAndAccessors() throws NotFoundException, CannotCompileException
251       {
252          OptimizedBehaviourInvocations.addArgumentFieldsToInvocation(jp, params);
253          OptimizedBehaviourInvocations.addSetArguments(instrumentor.getClassPool(), jp, params);
254          OptimizedBehaviourInvocations.addGetArguments(instrumentor.getClassPool(), jp, params);
255       }
256
257       private void addTypedTargetField()throws CannotCompileException
258       {
259          targetField = new CtField(targetClass, TARGET_FIELD, jp);
260          jp.addField(targetField);
261          targetField.setModifiers(Modifier.PROTECTED);
262       }
263       /**
264        * This constructor is used by the advisor when we have regenerated the joinpoint.
265        * This just creates a generic JoinPoint instance with no data specific to the
266        * method call
267        */

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

283       protected void addProtectedConstructor() throws CannotCompileException
284       {
285          int offset = 1;
286          if (hasTargetObject) offset++;
287          if (hasCallingObject) offset++;
288          CtClass[] ctorParams = new CtClass[params.length + offset];
289
290          int index = 0;
291          ctorParams[index++] = jp;
292          if (hasTargetObject) ctorParams[index++] = targetClass;
293          if (hasCallingObject) ctorParams[index] = callingClass;
294          System.arraycopy(params, 0, ctorParams, offset, params.length);
295
296          StringBuffer JavaDoc body = new StringBuffer JavaDoc();
297          body.append("{");
298          body.append(" this($1." + INFO_FIELD + ");");
299          if (hasTargetObject)
300          {
301             body.append(" super.targetObject=$2;");
302             body.append(" this.tgt=$2;");
303          }
304          if (hasCallingObject) body.append(" super.callingObject=$" + (hasTargetObject ? 3 : 2) + ";");
305
306          for (int i = offset ; i < ctorParams.length ; i++)
307          {
308             body.append(" arg" + (i - offset) + " = $" + (i + 1) + ";");
309          }
310
311          body.append("}");
312          protectedConstructor = CtNewConstructor.make(
313                ctorParams,
314                new CtClass[0],
315                body.toString(),
316                jp);
317          protectedConstructor.setModifiers(Modifier.PROTECTED);
318
319          jp.addConstructor(protectedConstructor);
320
321       }
322
323       private CtClass[] getInvokeJoinpointParameters()
324       {
325          if (!hasCallingObject && ! hasTargetObject)
326          {
327             return params;
328          }
329
330          int offset = 0;
331          if (hasTargetObject) offset++;
332          if (hasCallingObject) offset++;
333          CtClass[] invokeParams = new CtClass[params.length + offset];
334
335          int index = 0;
336          if (hasTargetObject) invokeParams[index++] = targetClass;
337          if (hasCallingObject) invokeParams[index++] = callingClass;
338          System.arraycopy(params, 0, invokeParams, offset, params.length);
339
340          return invokeParams;
341       }
342       /**
343        * Add an empty invokeJoinpoint() method. This method will be overridden by generated subclasses,
344        * when the interceptors are rebuilt
345        */

346       private CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException
347       {
348          invokeJoinpointMethod = CtNewMethod.make(
349                targetMethod.getReturnType(),
350                INVOKE_JOINPOINT,
351                getInvokeJoinpointParameters(),
352                targetMethod.getExceptionTypes(),
353                null,
354                jp);
355
356          invokeJoinpointMethod.setModifiers(Modifier.PROTECTED);
357          jp.addMethod(invokeJoinpointMethod);
358          return invokeJoinpointMethod;
359        }
360
361       private void addMethodInfoField()throws CannotCompileException
362       {
363          CtField infoField = new CtField(methodInfoClass, INFO_FIELD, jp);
364          infoField.setModifiers(javassist.Modifier.PROTECTED);//Make visible to classes in child classloaders
365
jp.addField(infoField);
366       }
367
368       private void addDispatchMethods() throws CannotCompileException, NotFoundException
369       {
370          addInvokeNextDispatchMethod();
371          if (hasCallingObject || hasTargetObject || params.length > 0)
372          {
373             addInvokeJoinPointDispatchMethod();
374          }
375          
376          addInvokeTargetMethod();
377       }
378
379       private void addInvokeNextDispatchMethod() throws CannotCompileException, NotFoundException
380       {
381          //This dispatch method will be called by the invokeNext() methods for around advice
382
final boolean isVoid = targetMethod.getReturnType().equals(CtClass.voidType);
383
384          StringBuffer JavaDoc parameters = new StringBuffer JavaDoc();
385          for (int i = 0 ; i < params.length ; i++)
386          {
387             if (i > 0)parameters.append(", ");
388             parameters.append("arg" + i);
389          }
390
391          StringBuffer JavaDoc body = new StringBuffer JavaDoc("{");
392
393          if (hasTargetObject)
394          {
395             body.append(MethodExecutionTransformer.getAopReturnStr(isVoid) + TARGET_FIELD + "." + targetMethod.getName() + "(" + parameters + ");");
396          }
397          else
398          {
399             body.append(MethodExecutionTransformer.getReturnStr(isVoid) + targetClass.getName() + "." + targetMethod.getName() + "(" + parameters + ");");
400          }
401
402          body.append("}");
403          try
404          {
405             CtMethod dispatch = CtNewMethod.make(
406                   (isVoid) ? CtClass.voidType : targetMethod.getReturnType(),
407                   JoinPointGenerator.DISPATCH,
408                   EMPTY_CTCLASS_ARRAY,
409                   targetMethod.getExceptionTypes(),
410                   body.toString(),
411                   jp);
412             dispatch.setModifiers(Modifier.PROTECTED);
413             jp.addMethod(dispatch);
414          }
415          catch (CannotCompileException e)
416          {
417             throw new RuntimeException JavaDoc("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, EMPTY_CTCLASS_ARRAY), e);
418          }
419       }
420
421       private void addInvokeJoinPointDispatchMethod() throws CannotCompileException, NotFoundException
422       {
423          //This dispatch method will be called by the invokeJoinPoint() method if the joinpoint has no around advices
424
final boolean isVoid = targetMethod.getReturnType().equals(CtClass.voidType);
425          CtClass[] invokeParams = getInvokeJoinpointParameters();
426
427          final int offset = invokeParams.length - params.length;
428          StringBuffer JavaDoc parameters = new StringBuffer JavaDoc();
429          for (int i = 0 ; i < params.length ; i++)
430          {
431             if (i > 0)parameters.append(", ");
432             parameters.append("$" + (i + offset + 1));
433          }
434
435          StringBuffer JavaDoc body = new StringBuffer JavaDoc("{");
436
437          if (hasTargetObject)
438          {
439             body.append(MethodExecutionTransformer.getAopReturnStr(isVoid) + "$1." + targetMethod.getName() + "(" + parameters + ");");
440          }
441          else
442          {
443             body.append(MethodExecutionTransformer.getReturnStr(isVoid) + targetClass.getName() + "." + targetMethod.getName() + "(" + parameters + ");");
444          }
445
446          body.append("}");
447          try
448          {
449             CtMethod dispatch = CtNewMethod.make(
450                   (isVoid) ? CtClass.voidType : targetMethod.getReturnType(),
451                   JoinPointGenerator.DISPATCH,
452                   invokeParams,
453                   targetMethod.getExceptionTypes(),
454                   body.toString(),
455                   jp);
456             dispatch.setModifiers(Modifier.PROTECTED);
457             jp.addMethod(dispatch);
458          }
459          catch (CannotCompileException e)
460          {
461             throw new RuntimeException JavaDoc("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, invokeParams), e);
462          }
463       }
464
465       private void addInvokeTargetMethod() throws CannotCompileException, NotFoundException
466       {
467          CtMethod template = INVOCATION_CT_TYPE.getDeclaredMethod(INVOKE_TARGET);
468          
469          boolean isVoid = targetMethod.getReturnType().equals(CtClass.voidType);
470          String JavaDoc body = (isVoid) ? "{dispatch(); return null;}" : "{return ($w)dispatch();}";
471          
472          CtMethod invokeTarget = CtNewMethod.make(
473                template.getReturnType(),
474                template.getName(),
475                template.getParameterTypes(),
476                template.getExceptionTypes(),
477                body,
478                jp);
479          jp.addMethod(invokeTarget);
480       }
481    }
482 }
Popular Tags