1 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 21 public class TracingClassLoader extends ClassLoader { 22 23 24 private ClassMethodFilter filter; 25 26 29 public TracingClassLoader(ClassMethodFilter filter) { 30 this.filter=filter; 31 } 32 33 35 public TracingClassLoader() { 36 this.filter=new ClassMethodFilter() { 37 public boolean classHasAdvice(String className) { 38 return true; 39 } 40 public boolean methodHasAdvice(String className, String methodName, String signature) { 41 return true; 42 } 43 }; 44 } 45 46 53 protected Class loadClass(String name, boolean resolve) throws java.lang.ClassNotFoundException { 54 Class 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 75 protected Class findClass(String 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 89 public static JavaClass classWithTracing(ClassMethodFilter filter, String className) { 90 JavaClass clazz; 91 try { 92 clazz= Repository.lookupClass(className); 93 } catch (ClassNotFoundException 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 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 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 name = m.getName(); 143 String 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 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 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 il.append(new GETSTATIC(out)); 194 il.append(new ALOAD(0)); 195 il.append(printInstruction(cp,Type.OBJECT,"print")); 196 il.append(new GETSTATIC(out)); 198 il.append(new PUSH(cp, ".")); 199 il.append(new INVOKEVIRTUAL(printString)); 200 } 201 il.append(new GETSTATIC(out)); 203 il.append(new PUSH(cp, name)); 204 il.append(new INVOKEVIRTUAL(printString)); 205 il.append(new GETSTATIC(out)); 207 il.append(new PUSH(cp, "(")); 208 il.append(new INVOKEVIRTUAL(printString)); 209 for(int iarg=0; iarg<argNum; iarg++) { 211 if(iarg!=0) { 212 il.append(new GETSTATIC(out)); 214 il.append(new PUSH(cp, ",")); 215 il.append(new INVOKEVIRTUAL(printString)); 216 } 217 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 il.append(new GETSTATIC(out)); 225 il.append(new PUSH(cp, ")")); 226 il.append(new INVOKEVIRTUAL(printlnString)); 227 228 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 il.append(new GETSTATIC(out)); 245 il.append(new INVOKESTATIC(currentThread)); 246 il.append(printInstruction(cp,Type.OBJECT,"print")); 247 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 il.append(new GETSTATIC(out)); 256 il.append(new PUSH(cp, "=>")); 257 il.append(new INVOKEVIRTUAL(printString)); 258 il.append(new GETSTATIC(out)); 260 il.append(InstructionFactory.createLoad(returnType,slotOfArg(argNum,argTypes)+argOffset)); 261 il.append(printInstruction(cp,returnType,"println")); 262 il.append(InstructionFactory.createLoad(returnType,slotOfArg(argNum,argTypes)+argOffset)); 264 endHd=il.append(InstructionFactory.createReturn(Type.getReturnType(signature))); 265 } else { 266 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 il.append(new GETSTATIC(out)); 277 il.append(new INVOKESTATIC(currentThread)); 278 il.append(printInstruction(cp,Type.OBJECT,"print")); 279 il.append(new GETSTATIC(out)); 281 il.append(new PUSH(cp, name)); 282 il.append(new INVOKEVIRTUAL(printString)); 283 284 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 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 330 private static Instruction printInstruction(ConstantPoolGen cp, Type t, String method) { 331 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 { 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 |