Search in sources :

Example 11 with ClassInformation

use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.

the class WeavePackageManager method containsPossibleClassOrMethodMatch.

/**
 * Quickly checks to see if the class/super class/interfaces or any of the methods in the Class represented by the
 * "classByte" parameter match the Set of known classes/method signatures that constitute all of our weave classes.
 * If a potential match is found it means we should continue with the normal validation process. If no match was
 * found, then it's certain that this class would never match and we should end transformation of this class via the
 * weaver here.
 *
 * @param classBytes the byte[] representing the class to check
 * @param requiredClasses the set of known classes/superclasses/interfaces to compare against
 * @param methodSignatures the set of all method signatures to compare against
 * @param cache class cache to lookup interface annotations
 * @return true if this contains a possible match, false otherwise
 */
private boolean containsPossibleClassOrMethodMatch(final String className, final byte[] classBytes, final Set<String> requiredClasses, final Set<String> methodSignatures, final ClassCache cache) {
    final AtomicBoolean containsPossibleMatch = new AtomicBoolean(false);
    ClassReader originalBytesReader = new ClassReader(classBytes);
    originalBytesReader.accept(new ClassVisitor(WeaveUtils.ASM_API_LEVEL) {

        public String[] interfaces;

        private boolean isInterface = false;

        @Override
        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
            this.interfaces = interfaces;
            isInterface = (access & Opcodes.ACC_INTERFACE) == Opcodes.ACC_INTERFACE;
            // Figure out if this exact class or the super class is a match
            if (requiredClasses.contains(name) || requiredClasses.contains(superName)) {
                containsPossibleMatch.set(true);
                return;
            }
            super.visit(version, access, name, signature, superName, interfaces);
        }

        @Override
        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
            String annotationClass = Type.getType(desc).getClassName();
            if (!isInterface && requiredAnnotationClasses.contains(annotationClass)) {
                // Adding class name here allows us to catch interfaces
                containsPossibleMatch.set(true);
                requiredClasses.add(className);
                // Found a potential match. Exit early.
                return null;
            }
            return super.visitAnnotation(desc, visible);
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            if (containsPossibleMatch.get()) {
                // This means we found a class/superclass/interface match so we should exit early here
                return null;
            }
            // Default constructor and static initializer will be matched by visit() method above
            if (!(name.equals(WeaveUtils.INIT_NAME) && desc.equals(WeaveUtils.INIT_DESC)) && !(name.equals(WeaveUtils.CLASS_INIT_NAME) && desc.equals(WeaveUtils.INIT_DESC)) && methodSignatures.contains(name + desc)) {
                // If any method matches this is a potential match so we should return "true"
                containsPossibleMatch.set(true);
                // Skip out of this method visitor early since we've found a match
                return null;
            }
            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
            if (!requiredMethodAnnotationClasses.isEmpty()) {
                return new MethodVisitor(WeaveUtils.ASM_API_LEVEL, mv) {

                    @Override
                    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
                        String annotationClass = Type.getType(desc).getClassName();
                        if (requiredMethodAnnotationClasses.contains(annotationClass)) {
                            containsPossibleMatch.set(true);
                            // Found a potential match. Exit early.
                            return null;
                        }
                        return super.visitAnnotation(desc, visible);
                    }
                };
            }
            return mv;
        }

        @Override
        public void visitEnd() {
            // If nothing has matched, check interface annotations
            if (!isInterface && !requiredAnnotationClasses.isEmpty()) {
                try {
                    for (String interfaceName : interfaces) {
                        ClassInformation interfaceInfo = cache.getClassInformation(interfaceName);
                        if (interfaceInfo == null) {
                            continue;
                        }
                        for (String interfaceAnnotationName : interfaceInfo.classAnnotationNames) {
                            if (requiredAnnotationClasses.contains(WeaveUtils.getClassBinaryName(interfaceAnnotationName))) {
                                containsPossibleMatch.set(true);
                                return;
                            }
                        }
                    }
                } catch (IOException ignored) {
                }
            }
        }
    }, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE);
    return containsPossibleMatch.get();
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ClassInformation(com.newrelic.weave.utils.ClassInformation) AnnotationVisitor(org.objectweb.asm.AnnotationVisitor) ClassReader(org.objectweb.asm.ClassReader) ClassVisitor(org.objectweb.asm.ClassVisitor) IOException(java.io.IOException) MethodVisitor(org.objectweb.asm.MethodVisitor)

Aggregations

ClassInformation (com.newrelic.weave.utils.ClassInformation)11 IOException (java.io.IOException)5 AnnotationNode (org.objectweb.asm.tree.AnnotationNode)3 ClassCache (com.newrelic.weave.utils.ClassCache)2 HashSet (java.util.HashSet)2 Method (org.objectweb.asm.commons.Method)2 MethodNode (org.objectweb.asm.tree.MethodNode)2 MemberInformation (com.newrelic.weave.utils.ClassInformation.MemberInformation)1 ClassLoaderFinder (com.newrelic.weave.utils.ClassLoaderFinder)1 SynchronizedFieldNode (com.newrelic.weave.utils.SynchronizedFieldNode)1 SynchronizedMethodNode (com.newrelic.weave.utils.SynchronizedMethodNode)1 WeaveViolation (com.newrelic.weave.violation.WeaveViolation)1 ClassWeavedListener (com.newrelic.weave.weavepackage.ClassWeavedListener)1 PackageWeaveResult (com.newrelic.weave.weavepackage.PackageWeaveResult)1 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)1 Instrumentation (java.lang.instrument.Instrumentation)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 Test (org.junit.Test)1