KickJava   Java API By Example, From Geeks To Geeks.

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


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

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

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

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