/* * JLibs: Common Utilities for Java * Copyright (C) 2009 Santhosh Kumar T <santhosh.tekuri@gmail.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package jlibs.nio; import javassist.*; import javassist.bytecode.AnnotationsAttribute; import javassist.bytecode.AttributeInfo; import java.util.LinkedHashSet; import java.util.Set; /** * @author Santhosh Kumar Tekuri */ public class Tracer implements Translator{ @Override public void start(ClassPool pool){} @Override public void onLoad(ClassPool pool, String className) throws NotFoundException, CannotCompileException{ if(!className.startsWith("jlibs.nio.")) return; CtClass clazz = pool.get(className); if(clazz.isEnum() || clazz.isInterface() || clazz.isAnnotation()) return; try{ Set<CtClass> classes = getClasses(clazz, new LinkedHashSet<>()); CtMethod[] methods = clazz.getDeclaredMethods(); for(CtMethod method: methods){ if(Modifier.isAbstract(method.getModifiers())) continue; Trace trace = getTraceAnnotation(method, classes); if(trace!=null && trace.condition()){ CtMethod copy = CtNewMethod.copy(method, clazz, null); // copy annotations from original method AttributeInfo attr = method.getMethodInfo().getAttribute(AnnotationsAttribute.invisibleTag); if(attr!=null) copy.getMethodInfo().addAttribute(attr); attr = method.getMethodInfo().getAttribute(AnnotationsAttribute.visibleTag); if(attr!=null) copy.getMethodInfo().addAttribute(attr); method.setName(method.getName()+"_orig"); StringBuilder body = new StringBuilder(); body.append("{\n"); body.append("jlibs.nio.Debugger.enter(this+\"."+copy.getName()+"(\"+"+trace.args()+"+\")\");\n"); body.append("try{\n"); if(method.getReturnType().getName().equals("void")){ body.append("$proceed($$);\n"); body.append("jlibs.nio.Debugger.exit();\n"); }else{ body.append(method.getReturnType().getName()+" returnValue = $proceed($$);\n"); body.append("jlibs.nio.Debugger.exit(\"return \"+returnValue);\n"); body.append("return returnValue;\n"); } body.append("}catch(Throwable thr){\n"); body.append("jlibs.nio.Debugger.exit(\"throw \"+thr);\n"); body.append("throw thr;\n"); body.append("}\n"); body.append("}"); copy.setBody(body.toString(), "this", method.getName()); clazz.addMethod(copy); } } }catch(Throwable e){ e.printStackTrace(); } } private Set<CtClass> getClasses(CtClass clazz, Set<CtClass> classes){ while(clazz!=null){ classes.add(clazz); try{ for(CtClass interfase: clazz.getInterfaces()) getClasses(interfase, classes); }catch(NotFoundException ignore){ // ignore.printStackTrace(); } try{ clazz = clazz.getSuperclass(); }catch(NotFoundException ignore){ break; } } return classes; } private Trace getTraceAnnotation(CtMethod method, Set<CtClass> classes) throws ClassNotFoundException{ for(CtClass clazz: classes){ try{ CtMethod m = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); Trace trace = (Trace)m.getAnnotation(Trace.class); if(trace!=null) return trace; }catch(NotFoundException ignore){ // ignore.printStackTrace(); } } return null; } public static boolean runWithTrace(Class clazz, String args[]){ if(clazz.getClassLoader() instanceof Loader) return false; if(!Debugger.DEBUG && !Debugger.IO && !Debugger.HTTP) return false; try{ Loader loader = new Loader(); loader.addTranslator(ClassPool.getDefault(), new Tracer()); loader.run(clazz.getName(), args); return true; }catch(Throwable thr){ throw new RuntimeException(thr); } } }