KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > name > dsouflis > aop > tracing > TracingClassLoader


1 /*
2  * TracingClassLoader.java
3  *
4  * Created on April 2, 2002, 6:53 PM
5  */

6
7 package name.dsouflis.aop.tracing;
8 import org.apache.bcel.classfile.JavaClass;
9 import org.apache.bcel.classfile.Code;
10 import org.apache.bcel.classfile.Method;
11 import org.apache.bcel.classfile.LocalVariableTable;
12 import org.apache.bcel.Repository;
13 import org.apache.bcel.Constants;
14 import org.apache.bcel.generic.*;
15
16 /** Replacement for the system ClassLoader that instruments some classes on load-time with output
17  * statements that trace entering and exiting.
18  * @author dsouflis
19  * @version $Revision: 1.3 $
20  */

21 public class TracingClassLoader extends ClassLoader JavaDoc {
22
23     /** The filter determining the classes to instrument */
24     private ClassMethodFilter filter;
25
26     /** Creates new TracingClassLoader
27      * @param filter The filter that determines class names of classes to instrument.
28      */

29     public TracingClassLoader(ClassMethodFilter filter) {
30         this.filter=filter;
31     }
32
33     /** Creates new TracingClassLoader that traces everything by default
34      */

35     public TracingClassLoader() {
36         this.filter=new ClassMethodFilter() {
37             public boolean classHasAdvice(String JavaDoc className) {
38                 return true;
39             }
40             public boolean methodHasAdvice(String JavaDoc className, String JavaDoc methodName, String JavaDoc signature) {
41                 return true;
42             }
43         };
44     }
45
46     /** Loads the class, adding instrumentation if necessary.<br>
47      * Delegates to the parent ClassLoader system classes.
48      * @param name Guess what.
49      * @param resolve Whether the class should be resolved.
50      * @throws ClassNotFoundException If the class cannot be found.
51      * @return The loaded class.
52      */

53     protected Class JavaDoc loadClass(String JavaDoc name, boolean resolve) throws java.lang.ClassNotFoundException JavaDoc {
54         Class JavaDoc theClass=findLoadedClass(name);
55         if(theClass!=null) {
56             return theClass;
57         }
58         if(name.startsWith("java")) {
59             return getParent().loadClass(name);
60         }
61         theClass=findClass(name);
62         if(theClass==null) {
63             return null;
64         }
65         if(resolve) {
66             resolveClass(theClass);
67         }
68         return theClass;
69     }
70
71     /** Defines the class.
72      * @param className Guess what.
73      * @return The loaded class.
74      */

75     protected Class JavaDoc findClass(String JavaDoc className) {
76         JavaClass clazz=classWithTracing(filter,className);
77         if(clazz==null) {
78             return null;
79         }
80         byte[] b = clazz.getBytes();
81         return defineClass(className, b, 0, b.length);
82     }
83
84     /** Returns a JavaClass, instrumented if its name is contained in the list.
85      * @param filter The filter that determines class names of classes to instrument.
86      * @param className The class to modify.
87      * @return The resulting JavaClass.
88      */

89     public static JavaClass classWithTracing(ClassMethodFilter filter, String JavaDoc className) {
90         JavaClass clazz;
91         try {
92             clazz= Repository.lookupClass(className);
93         } catch (ClassNotFoundException JavaDoc e) {
94             clazz=null;
95         }
96         if(clazz==null) {
97             return null;
98         }
99         if(filter.classHasAdvice(className)) {
100             clazz=addTracing(filter, clazz);
101         }
102         return clazz;
103     }
104
105     /** Adds tracing instrumentation to a JavaClass.
106      * @param filter The filter that determines class names of classes to instrument.
107      * @param clazz The JavaClass.
108      * @return The resulting JavaClass.
109      */

110     public static JavaClass addTracing(ClassMethodFilter filter, JavaClass clazz) {
111         ClassGen cg=new ClassGen(clazz);
112         ConstantPoolGen cp = cg.getConstantPool();
113         Method[] methods=cg.getMethods();
114         int methodNum=methods.length;
115         for(int i=0; i<methodNum; i++) {
116             addMethodWithTracing(filter, cg, i);
117         }
118         clazz=cg.getJavaClass();
119         return clazz;
120     }
121
122     /** Adds a method that wraps a method of the original class, unless the
123      * method is a constructor, or is abstract.
124      * @param filter The filter that determines class names of classes to instrument.
125      * @param cg The ClassGen that represents the class under construction.
126      * @param i The method of the original class to wrap.
127      */

128     private static void addMethodWithTracing(ClassMethodFilter filter, ClassGen cg, int i) {
129         ConstantPoolGen cp = cg.getConstantPool();
130         int out = cp.addFieldref("java.lang.System", "out",
131         "Ljava/io/PrintStream;");
132         int printlnString = cp.addMethodref("java.io.PrintStream", "println",
133         "(Ljava/lang/String;)V");
134         int printString = cp.addMethodref("java.io.PrintStream", "print",
135         "(Ljava/lang/String;)V");
136         int currentThread = cp.addMethodref("java.lang.Thread", "currentThread",
137         "()Ljava/lang/Thread;");
138
139         Method m=cg.getMethodAt(i);
140         Code code = m.getCode();
141         int flags = m.getAccessFlags();
142         String JavaDoc name = m.getName();
143         String JavaDoc signature=m.getSignature();
144
145         if(name.equals("<init>") || code==null) {
146             return;
147         }
148         if(!filter.methodHasAdvice(cg.getClassName(),name,signature)) {
149             return;
150         }
151
152         String JavaDoc hiddenName="hidden$"+name;
153         int nameIndex=cp.addUtf8(hiddenName);
154         m.setNameIndex(nameIndex);
155
156         if(m.isPublic()) {
157             int newFlags=(flags&~Constants.ACC_PUBLIC)| Constants.ACC_PRIVATE;
158             m.setAccessFlags(newFlags);
159         }
160
161         cg.setMethodAt(m,i);
162
163         int originalMethodIndex=cp.addMethodref(cg.getClassName(),name,signature);
164         int hiddenMethodIndex=cp.addMethodref(cg.getClassName(),hiddenName,signature);
165         InstructionList il=new InstructionList();
166
167         Type[] argTypes=Type.getArgumentTypes(signature);
168         Type returnType=Type.getReturnType(signature);
169         int argNum=argTypes.length;
170         LocalVariableTable lvt=m.getLocalVariableTable();
171         int argOffset=0;
172         MethodGen newMethod=new MethodGen(
173         flags,
174         returnType,
175         argTypes,
176         null,
177         name,
178         cg.getClassName(),
179         il,
180         cp);
181         InstructionHandle startHd=null;
182         InstructionHandle endHd=null;
183         InstructionHandle exceptHd=null;
184
185         //System.out.print(java.lang.Thread.currentThread());
186
startHd=il.append(new GETSTATIC(out));
187         il.append(new INVOKESTATIC(currentThread));
188         il.append(printInstruction(cp, Type.OBJECT,"print"));
189
190         if(!m.isStatic()) {
191             argOffset++;
192             //System.out.print(this);
193
il.append(new GETSTATIC(out));
194             il.append(new ALOAD(0));
195             il.append(printInstruction(cp,Type.OBJECT,"print"));
196             //System.out.print(".");
197
il.append(new GETSTATIC(out));
198             il.append(new PUSH(cp, "."));
199             il.append(new INVOKEVIRTUAL(printString));
200         }
201         //System.out.print("<<name>>");
202
il.append(new GETSTATIC(out));
203         il.append(new PUSH(cp, name));
204         il.append(new INVOKEVIRTUAL(printString));
205         //System.out.print("(");
206
il.append(new GETSTATIC(out));
207         il.append(new PUSH(cp, "("));
208         il.append(new INVOKEVIRTUAL(printString));
209         //push args, one by one, invoking appropriate print
210
for(int iarg=0; iarg<argNum; iarg++) {
211             if(iarg!=0) {
212                 //System.out.print(",");
213
il.append(new GETSTATIC(out));
214                 il.append(new PUSH(cp, ","));
215                 il.append(new INVOKEVIRTUAL(printString));
216             }
217             //System.out.print(<<arg[iarg]>>);
218
il.append(new GETSTATIC(out));
219             Instruction instr=InstructionFactory.createLoad(argTypes[iarg],slotOfArg(iarg,argTypes)+argOffset);
220             il.append(instr);
221             il.append(printInstruction(cp,argTypes[iarg],"print"));
222         }
223         //System.out.println(")");
224
il.append(new GETSTATIC(out));
225         il.append(new PUSH(cp, ")"));
226         il.append(new INVOKEVIRTUAL(printlnString));
227
228         //T temp=<<originalMethod>>(<<original arguments>>);
229
if(!m.isStatic()) {
230             il.append(new ALOAD(0));
231             argOffset=1;
232         }
233         for(int iarg=0; iarg<argNum; iarg++) {
234             Instruction instr=InstructionFactory.createLoad(argTypes[iarg],slotOfArg(iarg,argTypes)+argOffset);
235             il.append(instr);
236         }
237         if(m.isStatic()){
238             il.append(new INVOKESTATIC(hiddenMethodIndex));
239         } else {
240             il.append(new INVOKESPECIAL(hiddenMethodIndex));
241         }
242
243         //System.out.print(java.lang.Thread.currentThread());
244
il.append(new GETSTATIC(out));
245         il.append(new INVOKESTATIC(currentThread));
246         il.append(printInstruction(cp,Type.OBJECT,"print"));
247         //System.out.print("<<name>>");
248
il.append(new GETSTATIC(out));
249         il.append(new PUSH(cp, name));
250         il.append(new INVOKEVIRTUAL(printString));
251
252         if(returnType!=Type.VOID) {
253             il.append(InstructionFactory.createStore(returnType,slotOfArg(argNum,argTypes)+argOffset));
254             //System.out.print("=>");
255
il.append(new GETSTATIC(out));
256             il.append(new PUSH(cp, "=>"));
257             il.append(new INVOKEVIRTUAL(printString));
258             //System.out.println(temp);
259
il.append(new GETSTATIC(out));
260             il.append(InstructionFactory.createLoad(returnType,slotOfArg(argNum,argTypes)+argOffset));
261             il.append(printInstruction(cp,returnType,"println"));
262             //return temp;
263
il.append(InstructionFactory.createLoad(returnType,slotOfArg(argNum,argTypes)+argOffset));
264             endHd=il.append(InstructionFactory.createReturn(Type.getReturnType(signature)));
265         } else {
266             //System.out.print("=>(void)");
267
il.append(new GETSTATIC(out));
268             il.append(new PUSH(cp, "=>(void)"));
269             il.append(new INVOKEVIRTUAL(printlnString));
270             endHd=il.append(new RETURN());
271         }
272
273         exceptHd=il.append(InstructionFactory.createStore(Type.OBJECT,slotOfArg(argNum,argTypes)+argOffset));
274
275         //System.out.print(java.lang.Thread.currentThread());
276
il.append(new GETSTATIC(out));
277         il.append(new INVOKESTATIC(currentThread));
278         il.append(printInstruction(cp,Type.OBJECT,"print"));
279         //System.out.print("<<name>>");
280
il.append(new GETSTATIC(out));
281         il.append(new PUSH(cp, name));
282         il.append(new INVOKEVIRTUAL(printString));
283
284         //System.out.print(" =>threw exception ");
285
il.append(new GETSTATIC(out));
286         il.append(new PUSH(cp, "=>threw exception "));
287         il.append(new INVOKEVIRTUAL(printString));
288
289         il.append(new GETSTATIC(out));
290         il.append(InstructionFactory.createLoad(Type.OBJECT,slotOfArg(argNum,argTypes)+argOffset));
291         il.append(printInstruction(cp,Type.OBJECT,"println"));
292
293         il.append(InstructionFactory.createLoad(Type.OBJECT,slotOfArg(argNum,argTypes)+argOffset));
294         il.append(new ATHROW());
295
296         newMethod.setInstructionList(il);
297         CodeExceptionGen exc=newMethod.addExceptionHandler(startHd,endHd,exceptHd,(ObjectType)null);
298         newMethod.setMaxLocals();
299         newMethod.setMaxStack(Math.max(4,code.getMaxStack()));
300         cg.addMethod(newMethod.getMethod());
301         il.dispose();
302     }
303
304     /** Computes the local slot of an argument, not taking into account
305      * the presence of <CODE>this</CODE>.
306      * @param n The argument ordinal number.
307      * @param types The types of the arguments.
308      * @return The argument slot, not taking into account <CODE>this</CODE>.
309      */

310     private static int slotOfArg(int n, Type[] types) {
311         int s=0;
312         for(int i=0; i<n; i++) {
313             if(types[i]==Type.LONG || types[i]==Type.DOUBLE) {
314                 s+=2;
315             } else {
316                 s++;
317             }
318         }
319         return s;
320     }
321
322     /** Creates a print instruction of the appropriate type.
323      * @param cp The ConstantPoolGen that represents the constant pool of the class
324      * under construction.
325      * @param t The type of the value to print.
326      * @param method The method to create calling instruction for (<CODE>print</CODE>
327      * or <CODE>println</CODE>.
328      * @return The instruction.
329      */

330     private static Instruction printInstruction(ConstantPoolGen cp, Type t, String JavaDoc method) {
331         //method is either "print" or "println"
332
int printX;
333         if(t==Type.BOOLEAN||t==Type.INT||t==Type.SHORT||t==Type.CHAR||t==Type.BYTE
334         ||t==Type.LONG||t==Type.FLOAT||t==Type.DOUBLE) {
335             printX=cp.addMethodref(
336             "java.io.PrintStream",
337             method,
338         Type.getMethodSignature(Type.VOID,new Type[]{t}));
339         } else { //Type.OBJECT and all others
340
printX=cp.addMethodref(
341             "java.io.PrintStream",
342             method,
343         Type.getMethodSignature(Type.VOID,new Type[]{Type.OBJECT}));
344         }
345         return new INVOKEVIRTUAL(printX);
346     }
347 }
Popular Tags