KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.Collection JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27
28 import javassist.CannotCompileException;
29 import javassist.CtClass;
30 import javassist.CtConstructor;
31 import javassist.CtField;
32 import javassist.CtMember;
33 import javassist.CtMethod;
34 import javassist.CtNewMethod;
35 import javassist.Modifier;
36 import javassist.NotFoundException;
37
38 import org.jboss.aop.ClassAdvisor;
39 import org.jboss.aop.pointcut.Pointcut;
40
41 /**
42  * Comment
43  *
44  * @author <a HREF="mailto:bill@jboss.org">Bill Burke</a>
45  * @version $Revision: 44253 $
46  */

47 public abstract class ConstructorExecutionTransformer implements CodeConversionObserver
48 {
49    protected static final String JavaDoc CONSTRUCTOR_INFO_CLASS_NAME = "org.jboss.aop.ConstructorInfo";
50    
51    protected Instrumentor instrumentor;
52    protected Codifier codifier;
53    private JoinpointClassifier classifier;
54    //private JoinpointClassifier advisenessClassifier;
55
private static final WrapperTransformer wrapper =
56       new WrapperTransformer(new String JavaDoc[]{"wrapperStatus", "constructorsWrapped"});
57    protected static final int CONSTRUCTOR_STATUS = 0;
58    private static final int ALL_CONSTRUCTORS_STATUS = 1;
59    
60    protected ConstructorExecutionTransformer(Instrumentor instrumentor)
61    {
62       this.instrumentor = instrumentor;
63       this.codifier = new Codifier();
64       this.classifier = instrumentor.joinpointClassifier;
65       //this.advisenessClassifier = new JoinpointSimpleClassifier();
66
}
67    
68    protected Instrumentor getInstrumentor()
69    {
70       return instrumentor;
71    }
72
73    protected WrapperTransformer getWrapper()
74    {
75       return wrapper;
76    }
77
78    public static String JavaDoc constructorFactory(String JavaDoc className)
79    {
80       if (className.indexOf('.') >= 0)throw new RuntimeException JavaDoc("constructorFactory() takes a simple class name: " + className);
81       return className + "_new_" + ClassAdvisor.NOT_TRANSFORMABLE_SUFFIX;
82    }
83
84    /**
85     * Adds a ConstructorInfo field to the passed in class
86     */

87    protected String JavaDoc addConstructorInfoField(int modifiers, CtClass addTo, String JavaDoc infoName) throws NotFoundException, CannotCompileException
88    {
89       return addConstructorInfoField(modifiers, addTo, infoName, null);
90    }
91    
92    /**
93     * Adds a ConstructorInfo field to the passed in class
94     */

95    protected String JavaDoc addConstructorInfoField(int modifiers, CtClass addTo, String JavaDoc infoName, CtField.Initializer init) throws NotFoundException, CannotCompileException
96    {
97       //Instrumentor claspool will be null during hotswap, in which case we
98
//already will have created the field
99
if (instrumentor.getClassPool() != null)
100       {
101          try
102          {
103             addTo.getDeclaredField(infoName);
104             return infoName;
105          }
106          catch(NotFoundException e)
107          {
108          }
109          TransformerCommon.addInfoField(instrumentor, CONSTRUCTOR_INFO_CLASS_NAME, infoName, modifiers, addTo, addInfoAsWeakReference(), init);
110
111       }
112       return infoName;
113    }
114
115    protected boolean addInfoAsWeakReference()
116    {
117       return true;
118    }
119    
120    public static String JavaDoc getConstructorInfoFieldName(String JavaDoc classname, int index)
121    {
122       if (classname.indexOf('.') >= 0)throw new RuntimeException JavaDoc("Simple name should be used: " + classname);
123       return "aop$constructorInfo_" + index;
124    }
125       
126    protected static String JavaDoc constructorInfoFromWeakReference(String JavaDoc localName, String JavaDoc ctorInfoName)
127    {
128       return TransformerCommon.infoFromWeakReference(CONSTRUCTOR_INFO_CLASS_NAME, localName, ctorInfoName);
129    }
130    
131    /**
132     * Transforms the constructor executions of this class according to the pointcuts
133     * registered in <code>AspectManager</code>.
134     * @param clazz the clazz to be transformed.
135     * @param classAdvisor the advisor associated to <code>clazz</code>.
136     * @return <code>true</code> is <code>clazz</code> is instrumented.
137     */

138    public boolean transform(CtClass clazz, ClassAdvisor classAdvisor) throws Exception JavaDoc
139    {
140       List JavaDoc constructors = instrumentor.getConstructors(clazz);
141       JoinpointClassification[] classification = classifyConstructor(constructors, classAdvisor);
142       boolean wrappersGenerated = false;
143       boolean oneOrMoreWrapped = false;
144       int i = 0;
145       boolean dynamicallyWrapped = false;
146       boolean notDynamicallyWrapped = false;
147       CtConstructor firstConstructor = null;
148       if (!constructors.isEmpty())
149       {
150          firstConstructor = (CtConstructor) constructors.get(0);
151       }
152       for (Iterator JavaDoc iterator = constructors.iterator(); iterator.hasNext(); i++)
153       {
154          CtConstructor constructor = (CtConstructor) iterator.next();
155          if (classification[i] == JoinpointClassification.NOT_INSTRUMENTED
156                && !oneOrMoreWrapped)
157          {
158             continue;
159          }
160          else if (!wrappersGenerated)
161          {
162             //generateWrapper + prepareForWrapping
163
buildConstructorWrappers(clazz, classAdvisor);
164             wrappersGenerated = true;
165             wrapper.prepareForWrapping(firstConstructor, ALL_CONSTRUCTORS_STATUS);
166          }
167          
168          if (classification[i].equals(JoinpointClassification.WRAPPED))
169          {
170             if (!oneOrMoreWrapped)
171             {
172                for (int j = 0; j < i; j++)
173                {
174                   this.setEmptyWrapperCodeLater((CtConstructor) constructors.get(j));
175                }
176                oneOrMoreWrapped = true;
177             }
178             wrap(clazz, constructor, i);
179             dynamicallyWrapped = dynamicallyWrapped || classification[i].equals(JoinpointClassification.DYNAMICALY_WRAPPED);
180             notDynamicallyWrapped = notDynamicallyWrapped || !classification[i].equals(JoinpointClassification.DYNAMICALY_WRAPPED);
181          }
182          else if (oneOrMoreWrapped)
183          {
184             this.setEmptyWrapperCodeLater(constructor);
185          }
186       }
187       
188       if (oneOrMoreWrapped)
189       {
190          wrapAllConstructors(clazz, firstConstructor, null);
191       }
192       if (dynamicallyWrapped && !notDynamicallyWrapped)
193       {
194          instrumentor.dynamicTransformationObserver.constructorDynamicalyWrapped();
195       }
196       return wrappersGenerated;
197    }
198
199
200    /**
201     * This method is responsible for replacing all invocations of constructors
202     * by wrapper calls. Because we are using CodeConverter, either all constructor
203     * calls are invoked, or none. This means that when there are one or more constructors
204     * WRAPPED, all constructor calls are replaced by ivocations to a constructor wrapper, in
205     * which case unwrapped constructors must provide a wrapper method.
206     * This method updates the ALL_CONSTRUCTORS_STATUS to WRAPPED.
207     * @param clazz the target class
208     * @param firstConstructor the ALL_CONSTRUCTORS_STATUS is registered in the first
209     * constructor (index 0) of <code>clazz</code>. So, this constructor is needed for
210     * ALL_CONSTRUCTORS_STATUS update.
211     * @param constructors provide this list if you want to assure wrapper methods associated
212     * with UNWRAPPED constructors keep unchanged (avoid infinite recursion in this wrappers).
213     */

214    private void wrapAllConstructors(final CtClass clazz, CtConstructor firstConstructor, List JavaDoc constructors) throws NotFoundException, CannotCompileException
215    {
216       wrapper.wrap(firstConstructor, ALL_CONSTRUCTORS_STATUS);
217       if (constructors == null)
218       {
219          return;
220       }
221       for (Iterator JavaDoc i = constructors.iterator(); i.hasNext();)
222       {
223          CtConstructor constructor = (CtConstructor) i.next();
224          if (!wrapper.isWrapped(constructor, CONSTRUCTOR_STATUS))
225          {
226             setEmptyWrapperCodeLater(constructor);
227          }
228       }
229       instrumentor.converter.replaceNew(clazz, clazz, constructorFactory(clazz.getSimpleName()));
230    }
231
232    /**
233     * Wraps the constructor executions contained in <code>constructorIndexes</code>.
234     * @param clazz the class being instrumented.
235     * @param constructorIndexes a collection of <code>java.lang.Integer</code> indentifying
236     * the constructors to be wrapped.
237     */

238    public void wrap(CtClass clazz, Collection JavaDoc constructorIndexes) throws Exception JavaDoc
239    {
240       List JavaDoc constructors = instrumentor.getConstructors(clazz);
241       // if none constructor has been prepared, do nothing
242
CtConstructor firstConstructor = (CtConstructor) constructors.get(0);
243       if (wrapper.isNotPrepared(firstConstructor , ALL_CONSTRUCTORS_STATUS))
244       {
245          return;
246       }
247       // generate wrapper code
248
for (Iterator JavaDoc iterator = constructorIndexes.iterator(); iterator.hasNext(); )
249       {
250          int constructorIndex = ((Integer JavaDoc) iterator.next()).intValue();
251          CtConstructor constructor = (CtConstructor) constructors.get(constructorIndex);
252          wrap(clazz, constructor, constructorIndex);
253       }
254       // if none constructors have been wrapped until now, replace constructors calls
255
// by wrapper invocations
256
if (!wrapper.isWrapped(firstConstructor, ALL_CONSTRUCTORS_STATUS))
257       {
258          wrapAllConstructors(clazz, firstConstructor, constructors);
259       }
260    }
261
262    /**
263     * Wraps the <code>constructor</code> execution.
264     * @param clazz the class being instrumented.
265     * @param constructor the constructor to be wrapped.
266     * @param constructorIndex the index that identifies <code>constructor</code>.
267     */

268    private void wrap(CtClass clazz, CtConstructor constructor, int constructorIndex) throws NotFoundException, Exception JavaDoc, CannotCompileException
269    {
270       //CtClass type = constructor.getDeclaringClass();
271
if (wrapper.isNotPrepared(constructor, CONSTRUCTOR_STATUS))
272       {
273          return;
274       }
275       //wrap
276
wrapper.wrap(constructor, CONSTRUCTOR_STATUS);
277       // executeWrapping
278
CtMethod wrapperMethod = clazz.getDeclaredMethod(constructorFactory(clazz.getSimpleName()), constructor.getParameterTypes());
279       setTemporaryWrapperCode(constructor.getDeclaringClass(), wrapperMethod);
280       ConstructorTransformation trans = new ConstructorTransformation(clazz, constructor, wrapperMethod, constructorIndex);
281       createWrapper(trans);
282    }
283
284    /**
285     * Unwraps the constructor executions contained in <code>constructorIndexes</code>.
286     * @param clazz the class being instrumented.
287     * @param constructorIndexes a collection of <code>java.lang.Integer</code> indentifying
288     * the constructors to be unwrapped.
289     */

290    public void unwrap(CtClass clazz, Collection JavaDoc constructorIndexes) throws NotFoundException
291    {
292       List JavaDoc constructors = instrumentor.getConstructors(clazz);
293       // the joinpoint is not prepared for wrapping
294
if (wrapper.isNotPrepared((CtMember) constructors.get(0), ALL_CONSTRUCTORS_STATUS))
295       {
296          return;
297       }
298       for (Iterator JavaDoc iterator = constructorIndexes.iterator(); iterator.hasNext(); )
299       {
300          int constructorIndex = ((Integer JavaDoc) iterator.next()).intValue();
301          CtConstructor constructor = (CtConstructor) constructors.get(constructorIndex);
302          if (wrapper.isNotPrepared(constructor, CONSTRUCTOR_STATUS))
303          {
304             continue;
305          }
306          //unwrap
307
wrapper.unwrap(constructor, CONSTRUCTOR_STATUS);
308          // executeUnwrapping
309

310          setEmptyWrapperCode(constructor);
311       }
312    }
313    
314    /**
315     * Notifies this transformer that the code conversion is done.
316     */

317    public void codeConverted() throws CannotCompileException
318    {
319       this.codifier.codifyPending();
320    }
321
322    public boolean replaceConstructorAccess(ClassAdvisor sourceAdvisor, CtClass source) throws NotFoundException
323    {
324       if (!isAnyConstructorAdvised(source, sourceAdvisor))
325       {
326          return false;
327       }
328       instrumentor.converter.replaceNew(source, source, constructorFactory(source.getSimpleName()));
329       return true;
330    }
331
332    // generateWrapper + prepareForWrapping
333
protected void buildConstructorWrappers(CtClass clazz, ClassAdvisor advisor)
334    throws Exception JavaDoc
335    {
336       instrumentor.setupBasics(clazz);
337       List JavaDoc constructors = instrumentor.getConstructors(clazz);
338
339       Iterator JavaDoc it = constructors.iterator();
340       for (int index = 0; it.hasNext(); index++)
341       {
342          // generate wrapper
343
CtConstructor constructor = (CtConstructor) it.next();
344          int mod = Modifier.STATIC;
345          if ((constructor.getModifiers() & Modifier.PUBLIC) != 0)
346          {
347             mod |= Modifier.PUBLIC;
348          }
349          else if ((constructor.getModifiers() & Modifier.PROTECTED) != 0)
350          {
351             mod |= Modifier.PROTECTED;
352          }
353          else if ((constructor.getModifiers() & Modifier.PRIVATE) != 0)
354          {
355             mod |= Modifier.PRIVATE;
356          }
357          else
358          {
359             mod |= Modifier.PUBLIC;
360          }
361
362          initialiseWrapper(mod, constructor, index);
363          generateConstructorInfoField(clazz, constructor, index);
364       }
365    }
366    
367    protected void generateConstructorInfoField(CtClass clazz, CtConstructor constructor, int index) throws CannotCompileException, NotFoundException
368    {
369       String JavaDoc name = getConstructorInfoFieldName(clazz.getSimpleName(), index);
370       addConstructorInfoField(Modifier.PRIVATE | Modifier.STATIC, clazz, name);
371    }
372    
373    /**
374     * Sets a temporary wrapper method code. Later, the wrapper method body
375     * must be replaced by it's definitive implementation.
376     * @param type
377     * @param wrapperMethod
378     */

379    protected void setTemporaryWrapperCode(CtClass type, CtMethod wrapperMethod)
380    {
381       String JavaDoc code = "{" +
382       " return null;" +
383       "}";
384       try
385       {
386         wrapperMethod.setBody(code);
387       }
388       catch (CannotCompileException e)
389       {
390         System.out.println(code);
391         throw new RuntimeException JavaDoc(e); //To change body of catch statement use Options | File Templates.
392
}
393    }
394
395    /**
396     * Sets the wrapper method code as an empty wrapper, i.e., a wrapper that simply
397     * invokes the constructor.
398     * @param type the class being instrumented.
399     * @param wrapperMethod the wrapper method.
400     */

401    protected void setEmptyWrapperCode(CtConstructor constructor)throws NotFoundException
402    {
403       CtMethod wrapperMethod = getWrapperMethod(constructor);
404       String JavaDoc code =
405          "{ " +
406          " return new " + constructor.getDeclaringClass().getName() + "($$); " +
407          "}";
408       try
409       {
410         wrapperMethod.setBody(code);
411       }
412       catch (CannotCompileException e)
413       {
414         System.out.println(code);
415         throw new RuntimeException JavaDoc(e); //To change body of catch statement use Options | File Templates.
416
}
417    }
418
419    /**
420     * Sets the wrapper method code as an empty wrapper, i.e., a wrapper that simply
421     * invokes the constructor.
422     * @param type the class being instrumented.
423     * @param wrapperMethod the wrapper method.
424     * @throws NotFoundException
425     */

426    protected void setEmptyWrapperCodeLater(CtConstructor constructor) throws NotFoundException
427    {
428       CtMethod wrapperMethod = getWrapperMethod(constructor);
429       String JavaDoc code =
430          "{ " +
431          " return new " + constructor.getDeclaringClass().getName() + "($$); " +
432          "}";
433         this.codifier.addPendingCode(wrapperMethod, code);
434    }
435    
436
437    /**
438     * Returns true if there is at least one constructor that is classified as WRAPPED.
439     * @param clazz the clazz whose constructors will be classified.
440     * @param advisor the advisor associated with <code>clazz</code>
441     * @return <code>true</code> only if one or more <code>clazz</code> constructors are
442     * classified as WRAPPED.
443     */

444    protected boolean isAnyConstructorAdvised(CtClass clazz, ClassAdvisor advisor) throws NotFoundException
445    {
446       CtConstructor[] constructors = clazz.getDeclaredConstructors();
447       for (int i = 0; i < constructors.length; i++)
448       {
449          JoinpointClassification classification = classifier.classifyConstructorExecution(constructors[i], advisor);
450          if (classification.equals(JoinpointClassification.WRAPPED))
451             return true;
452       }
453       return false;
454    }
455
456    // currently used by CallerTransformer
457
public static boolean isAdvisableConstructor(CtConstructor con, ClassAdvisor advisor) throws NotFoundException
458    {
459       Iterator JavaDoc pointcuts = advisor.getManager().getPointcuts().values().iterator();
460       while (pointcuts.hasNext())
461       {
462          Pointcut pointcut = (Pointcut) pointcuts.next();
463          if (pointcut.matchesExecution(advisor, con))
464          {
465             return true;
466          }
467       }
468       return false;
469    }
470
471    /**
472     * Classifies the constructor execution joinpoints.
473     * @param clazz the clazz whose constructors will be classified.
474     * @param advisor the advisor associated to <code>clazz</code>.
475     * @return a classification array.
476     */

477    protected JoinpointClassification[] classifyConstructor(List JavaDoc constructors, ClassAdvisor advisor) throws NotFoundException
478    {
479       JoinpointClassification[] classification = new JoinpointClassification[constructors.size()];
480       int index = 0;
481       for (Iterator JavaDoc iterator = constructors.iterator(); iterator.hasNext(); index++)
482       {
483          CtConstructor constructor = (CtConstructor) iterator.next();
484          classification[index] = classifier.classifyConstructorExecution(constructor, advisor);
485       }
486       return classification;
487    }
488    
489    protected abstract void createWrapper(ConstructorTransformation trans) throws CannotCompileException, NotFoundException;
490
491    protected void initialiseWrapper(int mod, CtConstructor constructor, int index) throws NotFoundException, CannotCompileException
492    {
493       CtClass clazz = constructor.getDeclaringClass();
494       CtClass[] exceptions = constructor.getExceptionTypes();
495       String JavaDoc name = clazz.getSimpleName();
496       CtClass type = constructor.getDeclaringClass();
497
498       CtMethod wmethod = CtNewMethod.make(type, constructorFactory(name), constructor.getParameterTypes(), exceptions, null, clazz);
499       wmethod.setModifiers(mod);
500       setTemporaryWrapperCode(type, wmethod);
501       clazz.addMethod(wmethod);
502       
503       // prepare ForWrapping
504
getWrapper().prepareForWrapping(constructor, CONSTRUCTOR_STATUS);
505    }
506
507    protected CtMethod getWrapperMethod(CtConstructor constructor) throws NotFoundException
508    {
509       CtClass clazz = constructor.getDeclaringClass();
510       return clazz.getDeclaredMethod(
511             constructorFactory(clazz.getSimpleName()),
512             constructor.getParameterTypes());
513    }
514
515    protected class ConstructorTransformation
516    {
517       CtClass clazz;
518       CtConstructor constructor;
519       CtMethod wrapperMethod;
520       int index;
521       
522       public ConstructorTransformation(CtClass clazz, CtConstructor constructor, CtMethod wrapper, int index)
523       {
524          this.clazz = clazz;
525          this.constructor = constructor;
526          this.wrapperMethod = wrapper;
527          this.index = index;
528       }
529
530       public CtMethod getWrapperMethod()
531       {
532          return wrapperMethod;
533       }
534       
535       public void setWrapperMethod(CtMethod wrapperMethod)
536       {
537          this.wrapperMethod = wrapperMethod;
538       }
539       
540       public CtClass getClazz()
541       {
542          return clazz;
543       }
544       
545       public CtConstructor getConstructor()
546       {
547          return constructor;
548       }
549       
550       public int getIndex()
551       {
552          return index;
553       }
554
555       public String JavaDoc getClassName()
556       {
557          return clazz.getName();
558       }
559
560       public String JavaDoc getSimpleName()
561       {
562          return clazz.getSimpleName();
563       }
564    }
565 }
Popular Tags