001    package org.shiftone.jrat.inject.bytecode.asm;
002    
003    
004    import org.objectweb.asm.*;
005    import org.shiftone.jrat.core.criteria.MethodCriteria;
006    import org.shiftone.jrat.util.log.Logger;
007    
008    
009    /**
010     * @author jeff@shiftone.org (Jeff Drost)
011     */
012    public class MethodCriteriaClassVisitor implements ClassVisitor {
013    
014        private static final Logger LOG = Logger.getLogger(MethodCriteriaClassVisitor.class);
015        private final ClassVisitor injector;
016        private final ClassVisitor bypass;
017        private MethodCriteria criteria;
018        private String className;
019        private ClassVisitor defaultClassVisitor;
020    
021        public MethodCriteriaClassVisitor(ClassVisitor injector, ClassVisitor bypass) {
022            this.injector = injector;
023            this.bypass = bypass;
024        }
025    
026    
027        public void setCriteria(MethodCriteria criteria) {
028            this.criteria = criteria;
029        }
030    
031    
032        /**
033         * when this method is called MethodCriteria.isMatch(className) is checked
034         * to see if any injection is necessary. If not, then the default visitor is
035         * set to bypass the injection process.
036         */
037        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
038    
039            className = name.replace('/', '.');
040    
041            if (criteria.isMatch(className, access)) {
042                defaultClassVisitor = injector;
043    
044                LOG.debug("not filtering class " + className);
045            } else {
046                defaultClassVisitor = bypass;
047            }
048    
049            defaultClassVisitor.visit(version, access, name, signature, superName, interfaces);
050        }
051    
052    
053        /**
054         * when this method is called MethodCriteria.isMatch(className, methodName,
055         * ...) is checked to see if any injection is necessary for this method. If
056         * not, then the bypass visitor is used. Otherwise, the default visitor is
057         * used (which was set in the class visit method).
058         */
059        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
060    
061            if (criteria.isMatch(className, name, desc, access)) {
062                return defaultClassVisitor.visitMethod(access, name, desc, signature, exceptions);
063            } else {
064                return bypass.visitMethod(access, name, desc, signature, exceptions);
065            }
066        }
067    
068    
069        public void visitSource(String source, String debug) {
070            defaultClassVisitor.visitSource(source, debug);
071        }
072    
073    
074        public void visitOuterClass(String owner, String name, String desc) {
075            defaultClassVisitor.visitOuterClass(owner, name, desc);
076        }
077    
078    
079        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
080            return defaultClassVisitor.visitAnnotation(desc, visible);
081        }
082    
083    
084        public void visitAttribute(Attribute attr) {
085            defaultClassVisitor.visitAttribute(attr);
086        }
087    
088    
089        public void visitInnerClass(String name, String outerName, String innerName, int access) {
090            defaultClassVisitor.visitInnerClass(name, outerName, innerName, access);
091        }
092    
093    
094        public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
095            return defaultClassVisitor.visitField(access, name, desc, signature, value);
096        }
097    
098    
099        public void visitEnd() {
100    
101            defaultClassVisitor.visitEnd();
102    
103            defaultClassVisitor = null;
104            className = null;
105        }
106    }