package com.hapiware.asm.log4j; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import static org.objectweb.asm.Opcodes.ACC_STATIC; /** * Initialises {@link Log4jJmxSupportAdapter} for class manipulation. * * @author <a href="http://www.hapiware.com" target="_blank">hapi</a> * */ public class Log4jJmxSupportTransformer implements ClassFileTransformer { private Pattern[] _includePatterns; private Pattern[] _excludePatterns; private Pattern[] _loggerPatterns; public Log4jJmxSupportTransformer(Pattern[] includePatterns, Pattern[] excludePatterns) { _includePatterns = includePatterns; _excludePatterns = excludePatterns; _loggerPatterns = new Pattern[] { Pattern.compile("Lorg/apache/log4j/Logger;") }; } public byte[] transform( ClassLoader loader, final String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classFileBuffer) throws IllegalClassFormatException { for(Pattern p : _excludePatterns) if(p.matcher(className).matches()) return null; for(Pattern p : _includePatterns) { if(p.matcher(className).matches()) { try { final List<LoggerDesc> loggerDescs = new ArrayList<LoggerDesc>(); ClassReader cr = new ClassReader(classFileBuffer); ClassWriter cw = new ClassWriter(0); cr.accept( new ClassAdapter(cw) { public FieldVisitor visitField( int access, String name, String desc, String signature, Object value ) { FieldVisitor fv = super.visitField(access, name, desc, signature, value); for(Pattern p : _loggerPatterns) { if((access & ACC_STATIC) == ACC_STATIC && p.matcher(desc).matches()) loggerDescs.add(new LoggerDesc(name, desc)); } return fv; } public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions ) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); if(name.equals("<clinit>")) return new Log4jJmxSupportAdapter(className, loggerDescs, mv); else return mv; } }, 0 ); return cw.toByteArray(); } catch(Throwable e) { throw new Error("Instrumentation of a class " + className + " failed.", e); } } } return null; } public static class LoggerDesc { private final String _name; private final String _desc; public LoggerDesc(String name, String desc) { _name = name; _desc = desc; } public String getName() { return _name; } public String getDesc() { return _desc; } } }