KickJava   Java API By Example, From Geeks To Geeks.

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


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.Constructor 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.ConByMethodInfo;
37 import org.jboss.aop.GeneratedClassAdvisor;
38 import org.jboss.aop.JoinPointInfo;
39 import org.jboss.aop.advice.AdviceMethodProperties;
40 import org.jboss.aop.joinpoint.ConstructorCalledByMethodInvocation;
41 import org.jboss.aop.util.ReflectToJavassist;
42
43 /**
44  *
45  * @author <a HREF="kabir.khan@jboss.com">Kabir Khan</a>
46  * @version $Revision: 56807 $
47  */

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

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

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

334       private CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException
335       {
336          invokeJoinpointMethod = CtNewMethod.make(
337                targetClass,
338                INVOKE_JOINPOINT,
339                getInvokeJoinPointParams(),
340                targetCtor.getExceptionTypes(),
341                null,
342                jp);
343          invokeJoinpointMethod.setModifiers(Modifier.PROTECTED);
344          jp.addMethod(invokeJoinpointMethod);
345          return invokeJoinpointMethod;
346        }
347
348       private void addMethodInfoField()throws CannotCompileException
349       {
350          CtField infoField = new CtField(constructorInfoClass, INFO_FIELD, jp);
351          infoField.setModifiers(javassist.Modifier.PROTECTED);//Make visible to classes in child classloaders
352
jp.addField(infoField);
353       }
354
355       private void addDispatchMethods() throws CannotCompileException, NotFoundException
356       {
357          addInvokeNextDispatchMethod();
358
359          if (hasCallingObject || params.length > 0)
360          {
361             addInvokeJoinPointDispatchMethod();
362          }
363          
364          addInvokeTargetMethod();
365       }
366
367       private void addInvokeNextDispatchMethod() throws CannotCompileException, NotFoundException
368       {
369          //This dispatch method will be called by the invokeNext() methods for around advice
370

371          StringBuffer JavaDoc parameters = new StringBuffer JavaDoc("(");
372          for (int i = 0 ; i < params.length ; i++)
373          {
374             if (i > 0)parameters.append(", ");
375             parameters.append("arg" + i);
376          }
377          parameters.append(")");
378
379          String JavaDoc body =
380             "{" +
381             " " + targetClass.getName() + " obj = new " + targetClass.getName() + parameters + ";" +
382             " setTargetObject(obj);" +
383             " return obj;" +
384             "}";
385
386          try
387          {
388             CtMethod dispatch = CtNewMethod.make(
389                   targetClass,
390                   JoinPointGenerator.DISPATCH,
391                   EMPTY_CTCLASS_ARRAY,
392                   targetCtor.getExceptionTypes(),
393                   body,
394                   jp);
395             dispatch.setModifiers(Modifier.PROTECTED);
396             jp.addMethod(dispatch);
397          }
398          catch (CannotCompileException e)
399          {
400             throw new RuntimeException JavaDoc("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, EMPTY_CTCLASS_ARRAY), e);
401          }
402       }
403
404       private void addInvokeJoinPointDispatchMethod() throws CannotCompileException, NotFoundException
405       {
406          //This dispatch method will be called by the invokeJoinPoint() method if the joinpoint has no around advices
407

408          int offset = hasCallingObject ? 1 : 0;
409          StringBuffer JavaDoc parameters = new StringBuffer JavaDoc("(");
410          for (int i = 0 ; i < params.length ; i++)
411          {
412             if (i > 0)parameters.append(", ");
413             parameters.append("$" + (i + offset + 1));
414          }
415          parameters.append(")");
416
417          String JavaDoc body =
418             "{" +
419             " " + targetClass.getName() + " obj = new " + targetClass.getName() + parameters + ";" +
420             " setTargetObject(obj);" +
421             " return obj;" +
422             "}";
423
424          CtClass[] params = getInvokeJoinPointParams();
425          try
426          {
427             CtMethod dispatch = CtNewMethod.make(
428                   targetClass,
429                   JoinPointGenerator.DISPATCH,
430                   params,
431                   targetCtor.getExceptionTypes(),
432                   body,
433                   jp);
434             dispatch.setModifiers(Modifier.PROTECTED);
435             jp.addMethod(dispatch);
436          }
437          catch (CannotCompileException e)
438          {
439             throw new RuntimeException JavaDoc("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, params), e);
440          }
441       }
442
443       private void addInvokeTargetMethod() throws CannotCompileException, NotFoundException
444       {
445          CtMethod template = INVOCATION_CT_TYPE.getDeclaredMethod(INVOKE_TARGET);
446          
447          String JavaDoc body = "{return dispatch();}";
448          
449          CtMethod invokeTarget = CtNewMethod.make(
450                template.getReturnType(),
451                template.getName(),
452                template.getParameterTypes(),
453                template.getExceptionTypes(),
454                body,
455                jp);
456          jp.addMethod(invokeTarget);
457       }
458       
459    }
460
461 }
462
463
Popular Tags