KickJava   Java API By Example, From Geeks To Geeks.

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


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.Field 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.FieldInfo;
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.FieldReadInvocation;
41 import org.jboss.aop.joinpoint.FieldWriteInvocation;
42 import org.jboss.aop.util.JavassistToReflect;
43 import org.jboss.aop.util.ReflectToJavassist;
44
45 /**
46  *
47  * @author <a HREF="kabir.khan@jboss.com">Kabir Khan</a>
48  * @version $Revision$
49  */

50 public class FieldJoinPointGenerator extends JoinPointGenerator
51 {
52    public static final String JavaDoc WRITE_GENERATOR_PREFIX = GENERATOR_PREFIX + "w_";
53    public static final String JavaDoc READ_GENERATOR_PREFIX = GENERATOR_PREFIX + "r_";
54    public static final String JavaDoc WRITE_JOINPOINT_FIELD_PREFIX = JOINPOINT_FIELD_PREFIX + "w_";
55    public static final String JavaDoc READ_JOINPOINT_FIELD_PREFIX = JOINPOINT_FIELD_PREFIX + "r_";
56    public static final String JavaDoc WRITE_JOINPOINT_CLASS_PREFIX = JOINPOINT_CLASS_PREFIX + "w_";
57    public static final String JavaDoc READ_JOINPOINT_CLASS_PREFIX = JOINPOINT_CLASS_PREFIX + "r_";
58    private static final Class JavaDoc READ_INVOCATION_TYPE = FieldReadInvocation.class;
59    private static final Class JavaDoc WRITE_INVOCATION_TYPE = FieldWriteInvocation.class;
60    private static final CtClass READ_INVOCATION_CT_TYPE;
61    private static final CtClass WRITE_INVOCATION_CT_TYPE;
62    static
63    {
64       try
65       {
66          READ_INVOCATION_CT_TYPE = ReflectToJavassist.classToJavassist(READ_INVOCATION_TYPE);
67          WRITE_INVOCATION_CT_TYPE = ReflectToJavassist.classToJavassist(WRITE_INVOCATION_TYPE);
68       }
69       catch (NotFoundException e)
70       {
71          throw new RuntimeException JavaDoc(e);
72       }
73    }
74
75    public FieldJoinPointGenerator(GeneratedClassAdvisor advisor, JoinPointInfo info)
76    {
77       super(advisor, info);
78    }
79
80    protected void initialiseJoinPointNames()
81    {
82       joinpointClassName =
83          getInfoClassName(fieldName(), read());
84
85       joinpointFieldName =
86          getInfoFieldName(fieldName(), read());
87    }
88
89    private String JavaDoc fieldName()
90    {
91       return ((FieldInfo)info).getAdvisedField().getName();
92    }
93
94    private boolean read()
95    {
96       return ((FieldInfo)info).isRead();
97    }
98
99    protected boolean isVoid()
100    {
101       return !((FieldInfo)info).isRead();
102    }
103
104    protected Class JavaDoc getReturnType()
105    {
106       if (!read())
107       {
108          return null;
109       }
110       return ((FieldInfo)super.info).getAdvisedField().getType();
111    }
112
113    protected AdviceMethodProperties getAdviceMethodProperties(AdviceSetup setup)
114    {
115       Field JavaDoc field = ((FieldInfo)info).getAdvisedField();
116       return new AdviceMethodProperties(
117             setup.getAspectClass(),
118             setup.getAdviceName(),
119             info.getClass(),
120             (read()) ? READ_INVOCATION_TYPE : WRITE_INVOCATION_TYPE,
121             (read()) ? getReturnType() : Void.TYPE,
122             (read()) ? new Class JavaDoc[] {} : new Class JavaDoc[] {field.getType()},
123             null);
124    }
125
126    protected CtClass[] getJoinpointParameters() throws NotFoundException
127    {
128       if (isVoid()) return new CtClass[0];
129
130       CtClass type = ReflectToJavassist.fieldToJavassist(((FieldInfo)super.info).getAdvisedField()).getType();
131       return new CtClass[] {type};
132    }
133
134    protected boolean hasTargetObject()
135    {
136       return !Modifier.isStatic(((FieldInfo)info).getAdvisedField().getModifiers());
137    }
138
139    protected String JavaDoc getJoinPointGeneratorFieldName()
140    {
141       return getJoinPointGeneratorFieldName(fieldName(), read());
142    }
143
144    protected static String JavaDoc getInfoFieldName(String JavaDoc fieldName, boolean read)
145    {
146       if (read)
147       {
148          return READ_JOINPOINT_FIELD_PREFIX + fieldName;
149       }
150       else
151       {
152          return WRITE_JOINPOINT_FIELD_PREFIX + fieldName;
153       }
154    }
155
156    private static String JavaDoc getInfoClassName(String JavaDoc fieldName, boolean read)
157    {
158       if (read)
159       {
160          return READ_JOINPOINT_CLASS_PREFIX + fieldName;
161       }
162       else
163       {
164          return WRITE_JOINPOINT_CLASS_PREFIX + fieldName;
165       }
166    }
167
168    public static String JavaDoc getJoinPointGeneratorFieldName(String JavaDoc fieldName, boolean read)
169    {
170       if (read)
171       {
172          return READ_GENERATOR_PREFIX + fieldName;
173       }
174       else
175       {
176          return WRITE_GENERATOR_PREFIX + fieldName;
177       }
178    }
179
180    protected static CtClass createReadJoinpointBaseClass(
181          GeneratedAdvisorInstrumentor instrumentor,
182          CtClass advisedClass,
183          CtField advisedField,
184          String JavaDoc finame,
185          int index)throws NotFoundException, CannotCompileException
186    {
187       instrumentor.addJoinPointGeneratorFieldToGenAdvisor(
188             getJoinPointGeneratorFieldName(advisedField.getName(), true));
189
190       BaseClassGenerator factory = new ReadBaseClassGenerator(instrumentor, advisedClass, advisedField, finame, index);
191       return factory.generate();
192    }
193
194    protected static CtClass createWriteJoinpointBaseClass(
195          GeneratedAdvisorInstrumentor instrumentor,
196          CtClass advisedClass,
197          CtField advisedField,
198          String JavaDoc finame,
199          int index)throws NotFoundException, CannotCompileException
200    {
201       instrumentor.addJoinPointGeneratorFieldToGenAdvisor(
202             getJoinPointGeneratorFieldName(advisedField.getName(), false));
203
204       BaseClassGenerator factory = new WriteBaseClassGenerator(instrumentor, advisedClass, advisedField, finame, index);
205       return factory.generate();
206    }
207
208
209    static abstract class BaseClassGenerator
210    {
211       GeneratedAdvisorInstrumentor instrumentor;
212       CtClass advisedClass;
213       CtField advisedField;
214       String JavaDoc finame;
215       int index;
216       boolean hasTargetObject;
217
218       CtClass jp;
219       CtMethod invokeJoinpointMethod;
220       CtConstructor publicConstructor;
221       CtConstructor protectedConstructor;
222       CtField targetField;
223       CtClass fieldType;
224       CtClass fieldInfoClass;
225       boolean read;
226
227       BaseClassGenerator(GeneratedAdvisorInstrumentor instrumentor, CtClass advisedClass,
228                         CtField advisedField, String JavaDoc finame, int index, boolean read) throws NotFoundException
229       {
230          this.instrumentor = instrumentor;
231          this.advisedClass = advisedClass;
232          this.advisedField = advisedField;
233          this.finame = finame;
234          this.fieldType = advisedField.getType();
235          this.read = read;
236          fieldInfoClass = instrumentor.forName(FieldAccessTransformer.FIELD_INFO_CLASS_NAME);
237          hasTargetObject = !Modifier.isStatic(advisedField.getModifiers());
238       }
239
240       protected CtClass generate() throws CannotCompileException, NotFoundException
241       {
242          jp = setupClass();
243          if (hasTargetObject)
244          {
245             addTypedTargetField();
246          }
247          addInvokeJoinpointMethod();
248          addFieldInfoField();
249          addPublicConstructor();
250          addProtectedConstructor();
251          addDispatchMethods();
252
253          TransformerCommon.compileOrLoadClass(advisedClass, jp);
254          return jp;
255       }
256
257       private static String JavaDoc debugFields(CtClass clazz) throws NotFoundException
258       {
259          StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
260          sb.append(clazz.getName());
261          CtField[] fields = clazz.getFields();
262          for (int i = 0 ; i < fields.length ; i++)
263          {
264             sb.append("\n\t\t\t\t" + Modifier.toString(fields[i].getModifiers()) + " " + fields[i].getName() + " " + fields[i].getType());
265          }
266          
267          return sb.toString();
268       }
269
270       private CtClass setupClass()throws NotFoundException, CannotCompileException
271       {
272          String JavaDoc className = getInfoClassName(advisedField.getName(), read);
273
274          //Create inner joinpoint class in advised class, super class is
275
CtClass superClass = (read) ? READ_INVOCATION_CT_TYPE : WRITE_INVOCATION_CT_TYPE;
276          jp = TransformerCommon.makeNestedClass(advisedClass, className, true, Modifier.PUBLIC | Modifier.STATIC, superClass);
277          addUntransformableInterface(instrumentor, jp);
278          return jp;
279       }
280
281       protected abstract CtClass getSuperClass() throws NotFoundException;
282
283       private void addTypedTargetField()throws CannotCompileException
284       {
285          targetField = new CtField(advisedClass, TARGET_FIELD, jp);
286          jp.addField(targetField);
287          targetField.setModifiers(Modifier.PROTECTED);
288       }
289
290       /**
291        * This constructor is used by the advisor when we have regenerated the joinpoint.
292        * This just creates a generic JoinPoint instance with no data specific to the
293        * method call
294        */

295       private void addPublicConstructor() throws CannotCompileException
296       {
297          publicConstructor = CtNewConstructor.make(
298                new CtClass[] {fieldInfoClass},
299                new CtClass[0],
300                "{super($1, $1.getInterceptors()); this." + INFO_FIELD + " = $1;}",
301                jp);
302
303          jp.addConstructor(publicConstructor);
304       }
305
306       /**
307        * This constructor will be called by invokeJoinpoint in the generated subclass when we need to
308        * instantiate a joinpoint containing target and args
309        */

310       protected void addProtectedConstructor() throws CannotCompileException, NotFoundException
311       {
312
313          protectedConstructor = CtNewConstructor.make(
314                createProtectedCtorParams(),
315                new CtClass[0],
316                createProtectedCtorBody(),
317                jp);
318          protectedConstructor.setModifiers(Modifier.PROTECTED);
319
320          jp.addConstructor(protectedConstructor);
321       }
322
323       protected abstract CtClass[] createProtectedCtorParams() throws NotFoundException;
324       protected abstract String JavaDoc createProtectedCtorBody();
325       protected abstract CtClass[] getInvokeJoinPointParams() throws NotFoundException;
326       /**
327        * Add an empty invokeJoinpoint() method. This method will be overridden by generated subclasses,
328        * when the interceptors are rebuilt
329        */

330       protected abstract CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException;
331
332       private void addFieldInfoField()throws CannotCompileException
333       {
334          CtField infoField = new CtField(fieldInfoClass, INFO_FIELD, jp);
335          infoField.setModifiers(javassist.Modifier.PROTECTED);//Make visible to classes in child classloaders
336
jp.addField(infoField);
337       }
338
339       private void addDispatchMethods() throws CannotCompileException, NotFoundException
340       {
341          addInvokeNextDispatchMethod();
342          addInvokeJoinPointDispatchMethod();
343          addInvokeTargetMethod();
344       }
345
346       private void addInvokeNextDispatchMethod() throws CannotCompileException, NotFoundException
347       {
348          //This dispatch method will be called by the invokeNext() methods for around advice
349

350          String JavaDoc body = createInvokeNextDispatchMethodBody();
351
352          try
353          {
354             CtMethod dispatch = CtNewMethod.make(
355                   (read) ? advisedField.getType() : CtClass.voidType,
356                   JoinPointGenerator.DISPATCH,
357                   EMPTY_CTCLASS_ARRAY,
358                   EMPTY_CTCLASS_ARRAY,
359                   body,
360                   jp);
361             dispatch.setModifiers(Modifier.PROTECTED);
362             jp.addMethod(dispatch);
363          }
364          catch (CannotCompileException e)
365          {
366             throw new RuntimeException JavaDoc("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, EMPTY_CTCLASS_ARRAY), e);
367          }
368       }
369
370       protected abstract String JavaDoc createInvokeNextDispatchMethodBody() throws NotFoundException;
371
372       protected void addInvokeJoinPointDispatchMethod() throws NotFoundException, CannotCompileException
373       {
374          CtClass[] params = getInvokeJoinPointParams();
375          if (params.length == 0)
376          {
377             return;
378          }
379
380          //This dispatch method will be called by the invokeJoinPoint() method if the joinpoint has no around advices
381

382          String JavaDoc body = createInvokeJoinPointDispatchMethodBody();
383
384          try
385          {
386             CtMethod dispatch = CtNewMethod.make(
387                   (read) ? advisedField.getType() : CtClass.voidType,
388                   JoinPointGenerator.DISPATCH,
389                   params,
390                   new CtClass[0],
391                   body,
392                   jp);
393             dispatch.setModifiers(Modifier.PROTECTED);
394             jp.addMethod(dispatch);
395          }
396          catch (CannotCompileException e)
397          {
398             throw new RuntimeException JavaDoc("Could not compile code " + body + " for method " + getMethodString(jp, JoinPointGenerator.DISPATCH, params), e);
399          }
400       }
401
402       protected abstract String JavaDoc createInvokeJoinPointDispatchMethodBody() throws NotFoundException;
403       
404       private void addInvokeTargetMethod() throws CannotCompileException, NotFoundException
405       {
406          CtMethod template = READ_INVOCATION_CT_TYPE.getDeclaredMethod(INVOKE_TARGET);
407          
408          String JavaDoc body = (read) ? "{return ($w)dispatch();}" : "{dispatch(); return null;}" ;
409          
410          CtMethod invokeTarget = CtNewMethod.make(
411                template.getReturnType(),
412                template.getName(),
413                template.getParameterTypes(),
414                template.getExceptionTypes(),
415                body,
416                jp);
417          jp.addMethod(invokeTarget);
418       }
419       
420    }
421
422    private static class ReadBaseClassGenerator extends BaseClassGenerator
423    {
424       ReadBaseClassGenerator(GeneratedAdvisorInstrumentor instrumentor, CtClass advisedClass,
425             CtField advisedField, String JavaDoc finame, int index) throws NotFoundException
426       {
427          super(instrumentor, advisedClass, advisedField, finame, index, true);
428       }
429
430       protected CtClass getSuperClass() throws NotFoundException
431       {
432          return READ_INVOCATION_CT_TYPE;
433       }
434
435       protected CtClass[] createProtectedCtorParams() throws NotFoundException
436       {
437          CtClass[] ctorParams = (hasTargetObject) ? new CtClass[2] : new CtClass[1];
438          ctorParams[0] = jp;
439          if (hasTargetObject) ctorParams[1] = advisedClass;
440
441          return ctorParams;
442       }
443
444       protected String JavaDoc createProtectedCtorBody()
445       {
446          StringBuffer JavaDoc body = new StringBuffer JavaDoc();
447          body.append("{");
448          body.append(" this($1." + INFO_FIELD + ");");
449
450          if (hasTargetObject)
451          {
452             body.append(" this." + TARGET_FIELD + " = $2;");
453             body.append(" super.setTargetObject($2);");
454          }
455
456          body.append("}");
457          return body.toString();
458       }
459
460       protected CtClass[] getInvokeJoinPointParams() throws NotFoundException
461       {
462          return (hasTargetObject) ? new CtClass[] {advisedClass} : new CtClass[0];
463       }
464
465       protected CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException
466       {
467          invokeJoinpointMethod = CtNewMethod.make(
468                advisedField.getType(),
469                INVOKE_JOINPOINT,
470                getInvokeJoinPointParams(),
471                new CtClass[0],
472                null,
473                jp);
474          invokeJoinpointMethod.setModifiers(Modifier.PROTECTED);
475          jp.addMethod(invokeJoinpointMethod);
476
477          return invokeJoinpointMethod;
478       }
479
480       protected String JavaDoc createInvokeNextDispatchMethodBody()
481       {
482          return (hasTargetObject) ?
483             "{return " + TARGET_FIELD + "." + advisedField.getName() + ";}" :
484             "{return " + advisedClass.getName() + "." + advisedField.getName() + ";}";
485       }
486
487       protected String JavaDoc createInvokeJoinPointDispatchMethodBody()
488       {
489          return (hasTargetObject) ?
490             "{return " + "$1." + advisedField.getName() + ";}" :
491             "{return " + advisedClass.getName() + "." + advisedField.getName() + ";}";
492       }
493    }
494
495    private static class WriteBaseClassGenerator extends BaseClassGenerator
496    {
497       WriteBaseClassGenerator(GeneratedAdvisorInstrumentor instrumentor, CtClass advisedClass,
498             CtField advisedField, String JavaDoc finame, int index) throws NotFoundException
499       {
500          super(instrumentor, advisedClass, advisedField, finame, index, false);
501       }
502
503       protected CtClass getSuperClass() throws NotFoundException
504       {
505          return WRITE_INVOCATION_CT_TYPE;
506       }
507
508       protected CtClass[] createProtectedCtorParams() throws NotFoundException
509       {
510          CtClass[] ctorParams = (hasTargetObject) ? new CtClass[3] : new CtClass[2];
511          ctorParams[0] = jp;
512          if (hasTargetObject)
513          {
514             ctorParams[1] = advisedClass;
515             ctorParams[2] = advisedField.getType();
516          }
517          else
518          {
519             ctorParams[1] = advisedField.getType();
520          }
521
522          return ctorParams;
523       }
524
525       protected String JavaDoc createProtectedCtorBody()
526       {
527          StringBuffer JavaDoc body = new StringBuffer JavaDoc();
528          body.append("{");
529          body.append(" this($1." + INFO_FIELD + ");");
530
531          if (hasTargetObject)
532          {
533             body.append(" this." + TARGET_FIELD + " = $2;");
534             body.append(" super.setTargetObject($2);");
535             body.append(" super.value = ($w)$3;");
536          }
537          else
538          {
539             body.append(" super.value = ($w)$2;");
540          }
541
542          body.append("}");
543          return body.toString();
544       }
545
546       protected CtClass[] getInvokeJoinPointParams() throws NotFoundException
547       {
548          return (hasTargetObject) ? new CtClass[] {advisedClass, advisedField.getType()} : new CtClass[] {advisedField.getType()};
549       }
550
551       protected CtMethod addInvokeJoinpointMethod() throws CannotCompileException, NotFoundException
552       {
553          invokeJoinpointMethod = CtNewMethod.make(
554                CtClass.voidType,
555                JoinPointGenerator.INVOKE_JOINPOINT,
556                getInvokeJoinPointParams(),
557                new CtClass[0],
558                null,
559                jp);
560          invokeJoinpointMethod.setModifiers(Modifier.PROTECTED);
561          jp.addMethod(invokeJoinpointMethod);
562
563          return invokeJoinpointMethod;
564       }
565
566       protected String JavaDoc createInvokeNextDispatchMethodBody() throws NotFoundException
567       {
568          CtClass type = advisedField.getType();
569          String JavaDoc value = JavassistToReflect.castInvocationValueToTypeString(type);
570
571          return
572             "{" +
573             ((hasTargetObject) ?
574                   TARGET_FIELD + "." + advisedField.getName() + " = " + value:
575                      advisedClass.getName() + "." + advisedField.getName() + " = " + value) +
576
577             ((hasTargetObject) ?
578                   "return " + TARGET_FIELD + "." + advisedField.getName() + ";" :
579                      "return " + advisedClass.getName() + "." + advisedField.getName() + ";") +
580             "}";
581       }
582
583       protected String JavaDoc createInvokeJoinPointDispatchMethodBody()
584       {
585          return (hasTargetObject) ?
586             "{$1." + advisedField.getName() + " = $2;}" :
587             "{" + advisedClass.getName() + "." + advisedField.getName() + " = $1;}";
588       }
589    }
590 }
591
Popular Tags