KickJava   Java API By Example, From Geeks To Geeks.

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


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

47 public abstract class MethodExecutionTransformer
48 {
49    public static final String JavaDoc METHOD_INFO_CLASS_NAME = "org.jboss.aop.MethodInfo";
50    private static final WrapperTransformer wrapper = new WrapperTransformer(WrapperTransformer.SINGLE_TRANSFORMATION);
51    protected Instrumentor instrumentor;
52    private JoinpointClassifier classifier;
53
54    protected MethodExecutionTransformer(Instrumentor instrumentor)
55    {
56       this.instrumentor = instrumentor;
57       this.classifier = instrumentor.joinpointClassifier;
58    }
59
60    protected static WrapperTransformer getWrapper()
61    {
62       return wrapper;
63    }
64
65    protected JoinpointClassifier getClassifier()
66    {
67       return classifier;
68    }
69
70    /**
71     * Adds a MethodInfo field to the passed in class
72     */

73    protected String JavaDoc addMethodInfoField(int modifiers, CtClass addTo, MethodTransformation trans) throws NotFoundException, CannotCompileException
74    {
75       return addMethodInfoField(modifiers, addTo, trans, null);
76    }
77
78    /**
79     * Adds a MethodInfo field to the passed in class
80     */

81    protected String JavaDoc addMethodInfoField(int modifiers, CtClass addTo, MethodTransformation trans, CtField.Initializer init) throws NotFoundException, CannotCompileException
82    {
83       String JavaDoc name = getMethodInfoFieldName(trans.getOriginalName(), trans.getHash());
84       TransformerCommon.addInfoField(instrumentor, METHOD_INFO_CLASS_NAME, name, modifiers, addTo, addInfoAsWeakReference(), init);
85
86       return name;
87    }
88
89    protected boolean addInfoAsWeakReference()
90    {
91       return true;
92    }
93
94    public static String JavaDoc getMethodNameHash(String JavaDoc methodName, long methodHash)
95    {
96       String JavaDoc hash;
97       if (methodHash < 0)
98          hash = "_N_" + (-1 * methodHash);
99       else
100          hash = "" + methodHash;
101       return methodName + hash;
102    }
103
104    public static String JavaDoc getMethodInfoFieldName(String JavaDoc methodName, long methodHash)
105    {
106       String JavaDoc name = "aop$MethodInfo_" + getMethodNameHash(methodName, methodHash);
107       return name;
108    }
109
110    protected static String JavaDoc methodInfoFromWeakReference(String JavaDoc localName, String JavaDoc methodInfoName)
111    {
112       return TransformerCommon.infoFromWeakReference(METHOD_INFO_CLASS_NAME, localName, methodInfoName);
113    }
114
115    /**
116     * Classifies the method execution joinpoints.
117     *
118     * @param clazz the clazz whose methods will be classified.
119     * @param advisor the advisor associated to <code>clazz</code>.
120     * @return a classification array.
121     */

122    protected JoinpointClassification[] classifyMethods(CtClass clazz, ClassAdvisor advisor) throws NotFoundException
123    {
124       CtMethod[] methods = clazz.getDeclaredMethods();
125       JoinpointClassification[] classification = new JoinpointClassification[methods.length];
126       for (int i = 0; i < methods.length; i++)
127       {
128          classification[i] = classifier.classifyMethodExecution(methods[i], advisor);
129       }
130       return classification;
131    }
132
133    public void instrument(CtClass clazz, ClassAdvisor advisor)throws NotFoundException, CannotCompileException
134    {
135       JoinpointClassification[] classification = classifyMethods(clazz, advisor);
136       CtMethod[] methods = clazz.getDeclaredMethods();
137       for (int i = 0; i < methods.length; i++)
138       {
139          if (classification[i] == JoinpointClassification.NOT_INSTRUMENTED)
140          {
141             continue;
142          }
143          instrumentor.setupBasics(clazz);
144          MethodTransformation trans = new MethodTransformation(instrumentor, clazz, methods[i]);
145          boolean wrap = (classification[i].equals(JoinpointClassification.WRAPPED));
146          transformMethod(trans, wrap);
147
148          int modifier = trans.getWMethod().getModifiers();
149          if (Modifier.isNative(modifier))
150          {
151             modifier &=~Modifier.NATIVE;
152             trans.getWMethod().setModifiers(modifier);
153          }
154       }
155    }
156
157    /**
158     * Wraps the method executions contained in <code>methodInfos</code>.
159     *
160     * @param clazz the class being instrumented.
161     * @param constructorIndexes a collection of <code>org.jboss.aop.MethodInfo</code> indentifying
162     * the methods to be wrapped.
163     */

164    public void wrap(CtClass clazz, Collection JavaDoc methodInfos) throws Exception JavaDoc
165    {
166       for (Iterator JavaDoc iterator = methodInfos.iterator(); iterator.hasNext();)
167       {
168          org.jboss.aop.MethodInfo methodInfo = (org.jboss.aop.MethodInfo) iterator.next();
169          Method JavaDoc method = methodInfo.getAdvisedMethod();
170          AOPClassPool classPool = (AOPClassPool) clazz.getClassPool();
171          Class JavaDoc[] parameterTypes = method.getParameterTypes();
172          CtClass[] javassistParameterTypes = new CtClass[parameterTypes.length];
173          for (int i = 0; i < parameterTypes.length; i++)
174          {
175             classPool.getLocally(parameterTypes[i].getName());
176          }
177          if (method.getName().indexOf("access$") >= 0)
178          {
179             continue;
180          }
181
182          String JavaDoc wrappedName = ClassAdvisor.notAdvisedMethodName(clazz.getName(), method.getName());
183          CtMethod wmethod = clazz.getDeclaredMethod(method.getName(), javassistParameterTypes);
184          if (wrapper.isNotPrepared(wmethod, WrapperTransformer.SINGLE_TRANSFORMATION_INDEX))
185          {
186             continue;
187          }
188          MethodTransformation trans = new MethodTransformation(
189                instrumentor,
190                clazz,
191                clazz.getDeclaredMethod(wrappedName, javassistParameterTypes),
192                method.getName(),
193                clazz.getDeclaredMethod(method.getName(), javassistParameterTypes),
194                wrappedName);
195
196          // wrap
197
wrapper.wrap(trans.getWMethod(), WrapperTransformer.SINGLE_TRANSFORMATION_INDEX);
198          // executeWrapping
199
String JavaDoc methodInfoFieldName = getMethodInfoFieldName(trans.getOriginalName(), trans.getHash());
200          doWrap(trans, methodInfoFieldName);
201       }
202    }
203
204    /**
205     * Unwraps the method executions contained in <code>methodInfos</code>.
206     *
207     * @param clazz the class being instrumented.
208     * @param constructorIndexes a collection of <code>org.jboss.aop.MethodInfo</code> indentifying
209     * the methods to be unwrapped.
210     */

211    public void unwrap(CtClass clazz, Collection JavaDoc methodInfos) throws Exception JavaDoc
212    {
213       for (Iterator JavaDoc iterator = methodInfos.iterator(); iterator.hasNext();)
214       {
215          org.jboss.aop.MethodInfo methodInfo = (org.jboss.aop.MethodInfo) iterator.next();
216          Method JavaDoc method = methodInfo.getAdvisedMethod();
217          AOPClassPool classPool = (AOPClassPool) clazz.getClassPool();
218          Class JavaDoc[] parameterTypes = method.getParameterTypes();
219          CtClass[] javassistParameterTypes = new CtClass[parameterTypes.length];
220          for (int i = 0; i < parameterTypes.length; i++)
221          {
222             classPool.getLocally(parameterTypes[i].getName());
223          }
224          CtMethod javassistWMethod = clazz.getDeclaredMethod(method.getName(), javassistParameterTypes);
225          if (wrapper.isNotPrepared(javassistWMethod, WrapperTransformer.SINGLE_TRANSFORMATION_INDEX))
226          {
227             continue;
228          }
229          CtMethod javassistMethod = clazz.getDeclaredMethod(ClassAdvisor.notAdvisedMethodName(clazz.getName(), method.getName()),
230                                                             javassistParameterTypes);
231          // wrap
232
wrapper.unwrap(javassistWMethod, WrapperTransformer.SINGLE_TRANSFORMATION_INDEX);
233          // executeUnwrapping
234
javassistWMethod.setBody(javassistMethod, null);
235       }
236    }
237
238    protected void copyAnnotations(CtMethod src, CtMethod dest)
239    {
240       MethodInfo mi = src.getMethodInfo2();
241       MethodInfo wmi = dest.getMethodInfo2();
242       AnnotationsAttribute invisible = (AnnotationsAttribute) mi.getAttribute(AnnotationsAttribute.invisibleTag);
243       if (invisible != null)
244       {
245          wmi.addAttribute(invisible.copy(wmi.getConstPool(), new HashMap JavaDoc()));
246       }
247       AnnotationsAttribute visible = (AnnotationsAttribute) mi.getAttribute(AnnotationsAttribute.visibleTag);
248       if (visible != null)
249       {
250          wmi.addAttribute(visible.copy(wmi.getConstPool(), new HashMap JavaDoc()));
251       }
252    }
253
254    protected static String JavaDoc getAopReturnStr(CtMethod method)throws NotFoundException
255    {
256       return getAopReturnStr(method.getReturnType().equals(CtClass.voidType));
257    }
258
259    protected static String JavaDoc getAopReturnStr(boolean isVoid)throws NotFoundException
260    {
261       return isVoid ? "" : "return ($r)";
262    }
263
264    protected static String JavaDoc getReturnStr(CtMethod method)throws NotFoundException
265    {
266       return getReturnStr(method.getReturnType().equals(CtClass.voidType));
267    }
268
269    protected static String JavaDoc getReturnStr(boolean isVoid)throws NotFoundException
270    {
271       return isVoid ? "" : "return ";
272    }
273
274    protected abstract void transformMethod(MethodTransformation trans, boolean wrap) throws CannotCompileException, NotFoundException;
275    protected abstract void doWrap(MethodTransformation trans, String JavaDoc methodInfoFieldName)throws NotFoundException, Exception JavaDoc;
276
277    protected class MethodTransformation
278    {
279       Instrumentor instrumentor;
280       CtClass clazz;
281       CtMethod method;
282       String JavaDoc originalName;
283       CtMethod wmethod;
284       String JavaDoc wrappedName;
285       long hash;
286
287       public MethodTransformation(Instrumentor instrumentor, CtClass clazz, CtMethod method)
288       {
289          this.instrumentor = instrumentor;
290          this.clazz = clazz;
291          this.method = method;
292          this.originalName = method.getName();
293          hash = JavassistMethodHashing.methodHash(method);
294       }
295
296       public MethodTransformation(Instrumentor instrumentor,
297             CtClass clazz,
298             CtMethod method,
299             String JavaDoc originalName,
300             CtMethod wmethod,
301             String JavaDoc wrappedName)
302       {
303          this.instrumentor = instrumentor;
304          this.clazz = clazz;
305          this.method = method;
306          this.originalName = originalName;
307          this.wmethod = wmethod;
308          this.wrappedName = wrappedName;
309          hash = JavassistMethodHashing.methodHash(wmethod);
310       }
311
312       public MethodTransformation(Instrumentor instrumentor,
313             CtClass clazz,
314             CtMethod method,
315             String JavaDoc originalName,
316             CtMethod wmethod,
317             String JavaDoc wrappedName,
318             long hash)
319       {
320          this.instrumentor = instrumentor;
321          this.clazz = clazz;
322          this.method = method;
323          this.originalName = originalName;
324          this.wmethod = wmethod;
325          this.wrappedName = wrappedName;
326          this.hash = hash;
327       }
328
329
330       public void setWMethod(CtMethod wmethod, String JavaDoc wrappedName)
331       {
332          this.wmethod = wmethod;
333          this.wrappedName = wrappedName;
334       }
335
336       public void setWMethodBody(String JavaDoc code)throws CannotCompileException
337       {
338          wmethod.setBody(code);
339       }
340
341       public String JavaDoc getOriginalName()
342       {
343          return originalName;
344       }
345
346       public String JavaDoc getWrappedName()
347       {
348          return wrappedName;
349       }
350
351       public CtClass getClazz()
352       {
353          return clazz;
354       }
355
356       public String JavaDoc getClazzName()
357       {
358          return clazz.getName();
359       }
360
361       public CtMethod getMethod()
362       {
363          return method;
364       }
365
366       public CtMethod getWMethod()
367       {
368          return wmethod;
369       }
370
371       public long getHash()
372       {
373          return hash;
374       }
375
376       public Instrumentor getInstrumentor()
377       {
378          return instrumentor;
379       }
380    }
381 }
Popular Tags