Search in sources :

Example 1 with PreparedMatch

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

the class PackageValidationResult method buildResults.

private void buildResults(ClassCache classCache, ClassNode originalClassNode, String weaveClassName, ClassNode weaveNode, Map<String, PreparedMatch> results, boolean isBaseMatch, Set<String> requiredClassAnnotations, Set<String> requiredMethodAnnotations, ClassNode errorHandler, Map<String, byte[]> annotationProxyClasses) throws IOException {
    ClassMatch match = ClassMatch.match(originalClassNode, weaveNode, isBaseMatch, requiredClassAnnotations, requiredMethodAnnotations, classCache);
    NewFieldValidator.validate(match, violations);
    // exit sooner to prevent further processing (avoids NPE when no default constructor exists)
    if (match.isFatalWeaveViolation()) {
        violations.addAll(match.getViolations());
        return;
    }
    PreparedMatch prepared = PreparedMatch.prepare(match, errorHandler, this.getWeavePackage().getExtensionTemplate(), true);
    results.put(weaveClassName, prepared);
    if (null != prepared.getExtension()) {
        ClassNode extension = prepared.getExtension().generateExtensionClass();
        utilClasses.put(extension.name, extension);
    }
    for (String newInnerClassName : prepared.getNewInnerClasses()) {
        if (utilClasses.containsKey(newInnerClassName)) {
            ClassNode newInnerClassNode = utilClasses.get(newInnerClassName);
            match.validateNewInnerClass(newInnerClassNode);
            newInnerClassNode = prepared.prepareNewInnerClass(newInnerClassNode);
            utilClasses.remove(newInnerClassName);
            String newInnerClassRenamed = prepared.nameNewInnerClass(newInnerClassName);
            utilClasses.put(newInnerClassRenamed, newInnerClassNode);
        }
    }
    for (Map.Entry<String, ClassNode> annotationProxyClass : prepared.getAnnotationProxyClasses().entrySet()) {
        annotationProxyClasses.put(annotationProxyClass.getKey(), WeaveUtils.convertToClassBytes(annotationProxyClass.getValue(), classCache));
    }
    violations.addAll(match.getViolations());
}
Also used : SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) ClassNode(org.objectweb.asm.tree.ClassNode) ClassMatch(com.newrelic.weave.ClassMatch) PreparedMatch(com.newrelic.weave.PreparedMatch) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 2 with PreparedMatch

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

the class PackageValidationResult method getSuperWeaves.

private List<PreparedMatch> getSuperWeaves(String superName) {
    List<PreparedMatch> superMatches = new ArrayList<>();
    String currentName = superName;
    while (null != currentName) {
        PreparedMatch superMatch = exactMatches.get(currentName);
        if (null == superMatch) {
            break;
        }
        superMatches.add(superMatch);
        currentName = superMatch.getWeaveSuperName();
    }
    currentName = superName;
    while (null != currentName) {
        PreparedMatch superMatch = baseMatches.get(currentName);
        if (null == superMatch) {
            break;
        }
        superMatches.add(superMatch);
        currentName = superMatch.getWeaveSuperName();
    }
    return superMatches;
}
Also used : ArrayList(java.util.ArrayList) PreparedMatch(com.newrelic.weave.PreparedMatch)

Example 3 with PreparedMatch

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

the class PackageValidationResult method rewriteAllNewFieldCalls.

/**
 * Rewrite all weave+util bytes to replace ops on newfields with extension class operations. See
 * {@link MethodProcessors#rewriteNewFieldCalls(String, Map, Set, Set, List, List)} for details.
 */
private void rewriteAllNewFieldCalls() {
    List<PreparedExtension> preparedExtensions = new ArrayList<>();
    Collection<PreparedMatch> allMatches = new HashSet<>(exactMatches.size() + baseMatches.size());
    allMatches.addAll(exactMatches.values());
    allMatches.addAll(baseMatches.values());
    for (PreparedMatch pmatch : allMatches) {
        if (null != pmatch.getExtension()) {
            preparedExtensions.add(pmatch.getExtension());
        }
    }
    if (preparedExtensions.size() > 0) {
        // rewrite weaves
        for (PreparedMatch pmatch : allMatches) {
            MethodProcessors.rewriteNewFieldCalls(pmatch.getWeaveName(), pmatch.getPreparedMatchedMethods(), pmatch.getNewFields(), pmatch.getMatchedFields(), preparedExtensions, getSuperWeaves(pmatch.getWeaveSuperName()));
        }
        // rewrite util classes
        for (Map.Entry<String, ClassNode> entry : utilClasses.entrySet()) {
            ClassNode utilNode = entry.getValue();
            Set<String> matchedFields;
            if (null == utilNode.fields) {
                matchedFields = new HashSet<>(0);
            } else {
                matchedFields = new HashSet<>(utilNode.fields.size());
                for (FieldNode field : utilNode.fields) {
                    matchedFields.add(field.name);
                }
            }
            Map<Method, MethodNode> methodMap;
            if (null == utilNode.methods) {
                methodMap = new HashMap<>(0);
            } else {
                methodMap = new HashMap<>(utilNode.methods.size());
                for (MethodNode methodNode : utilNode.methods) {
                    methodMap.put(new Method(methodNode.name, methodNode.desc), methodNode);
                }
            }
            MethodProcessors.rewriteNewFieldCalls(utilNode.name, methodMap, new HashSet<String>(0), matchedFields, preparedExtensions, getSuperWeaves(utilNode.superName));
            utilNode.methods = new ArrayList<>(methodMap.values());
        }
    }
}
Also used : SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) ClassNode(org.objectweb.asm.tree.ClassNode) FieldNode(org.objectweb.asm.tree.FieldNode) ArrayList(java.util.ArrayList) PreparedMatch(com.newrelic.weave.PreparedMatch) Method(org.objectweb.asm.commons.Method) MethodNode(org.objectweb.asm.tree.MethodNode) PreparedExtension(com.newrelic.weave.PreparedExtension) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashSet(java.util.HashSet)

Example 4 with PreparedMatch

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

the class PackageValidationResult method getAnnotationMatchComposite.

private ClassNode getAnnotationMatchComposite(ClassNode targetNode, ClassNode weaveNode, ClassNode composite, Map<String, List<Method>> weavedMethods, ClassCache cache, Map<String, byte[]> annotationProxyClasses, Map<Method, Collection<String>> skipMethods) {
    try {
        boolean isInterfaceMatch = WeaveUtils.isWeaveWithAnnotationInterfaceMatch(weaveNode);
        Map<String, PreparedMatch> results = new HashMap<>();
        buildResults(cache, targetNode, weaveNode.name, weaveNode, results, isInterfaceMatch, weavePackage.getRequiredAnnotationClassesForAnnotationWeave(weaveNode.name), weavePackage.getRequiredAnnotationClassesForMethodAnnotationWeave(weaveNode.name), errorHandler, annotationProxyClasses);
        if (!violations.isEmpty()) {
            return composite;
        }
        for (Map.Entry<String, PreparedMatch> result : results.entrySet()) {
            PreparedMatch prepared = result.getValue();
            if (prepared != null) {
                ClassWeave classWeave = ClassWeave.weave(prepared, composite, weavePackage, skipMethods);
                composite = classWeave.getComposite();
                // Key is only used for logging at the moment.
                final String key = prepared.getWeaveName();
                if (weavedMethods.containsKey(key)) {
                    weavedMethods.get(key).addAll(classWeave.getWeavedMethods());
                } else {
                    weavedMethods.put(key, classWeave.getWeavedMethods());
                }
            }
        }
    } catch (Exception ignored) {
    }
    return composite;
}
Also used : HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ClassWeave(com.newrelic.weave.ClassWeave) PreparedMatch(com.newrelic.weave.PreparedMatch) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) IOException(java.io.IOException)

Example 5 with PreparedMatch

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

the class PackageValidationResult method weave.

/**
 * Weave the target class and return a {@link PackageWeaveResult}.
 */
public PackageWeaveResult weave(String className, String[] superNames, String[] interfaceNames, ClassNode targetNode, ClassCache cache, Map<Method, Collection<String>> skipMethods) {
    ClassNode composite = targetNode;
    final Map<String, List<Method>> weavedMethods = new HashMap<>();
    // Locks during weaving are due to the non-thread safe nature of {@link ClassNode}.
    // first apply exact matches
    {
        PreparedMatch exactMatch = exactMatches.get(className);
        if (null != exactMatch) {
            ClassWeave classWeave;
            classWeave = ClassWeave.weave(exactMatch, composite, weavePackage, skipMethods);
            composite = classWeave.getComposite();
            final String key = exactMatch.getOriginalName();
            if (weavedMethods.containsKey(key)) {
                weavedMethods.get(key).addAll(classWeave.getWeavedMethods());
            } else {
                weavedMethods.put(key, classWeave.getWeavedMethods());
            }
        }
    }
    {
        // matcher for abstract class
        PreparedMatch exactMatch = baseMatches.get(className);
        if (null != exactMatch) {
            ClassWeave classWeave;
            classWeave = ClassWeave.weave(exactMatch, composite, weavePackage, skipMethods);
            composite = classWeave.getComposite();
            final String key = exactMatch.getOriginalName();
            if (weavedMethods.containsKey(key)) {
                weavedMethods.get(key).addAll(classWeave.getWeavedMethods());
            } else {
                weavedMethods.put(key, classWeave.getWeavedMethods());
            }
        }
    }
    // then apply super classes
    for (int i = 0; i < superNames.length; ++i) {
        PreparedMatch baseMatch = baseMatches.get(superNames[i]);
        if (null != baseMatch) {
            ClassWeave classWeave;
            classWeave = ClassWeave.weave(baseMatch, composite, weavePackage, skipMethods);
            composite = classWeave.getComposite();
            final String key = baseMatch.getOriginalName();
            if (weavedMethods.containsKey(key)) {
                weavedMethods.get(key).addAll(classWeave.getWeavedMethods());
            } else {
                weavedMethods.put(key, classWeave.getWeavedMethods());
            }
        }
    }
    // then apply interfaces
    for (int i = 0; i < interfaceNames.length; ++i) {
        PreparedMatch baseMatch = baseMatches.get(interfaceNames[i]);
        if (null != baseMatch) {
            ClassWeave classWeave;
            classWeave = ClassWeave.weave(baseMatch, composite, weavePackage, skipMethods);
            composite = classWeave.getComposite();
            final String key = baseMatch.getOriginalName();
            if (weavedMethods.containsKey(key)) {
                weavedMethods.get(key).addAll(classWeave.getWeavedMethods());
            } else {
                weavedMethods.put(key, classWeave.getWeavedMethods());
            }
        }
    }
    final Map<String, byte[]> annotationProxyClasses = new HashMap<>();
    // class annotation matches
    if (!allAnnotationClasses.isEmpty()) {
        Set<String> targetAnnotationsClasses = getAnnotationClasses(targetNode);
        Set<String> targetInterfacesAnnotationClasses = Collections.emptySet();
        if (!baseAnnotationClasses.isEmpty()) {
            targetInterfacesAnnotationClasses = getAllInterfaceAnnotationClasses(targetNode, cache);
        }
        // check for exact annotation matches
        for (Map.Entry<String, ClassNode> entry : allAnnotationClasses.entrySet()) {
            if (targetAnnotationsClasses.contains(entry.getKey())) {
                composite = getAnnotationMatchComposite(targetNode, entry.getValue(), composite, weavedMethods, cache, annotationProxyClasses, skipMethods);
            }
        }
        // check for base annotation matches
        for (Map.Entry<String, ClassNode> entry : baseAnnotationClasses.entrySet()) {
            if (targetInterfacesAnnotationClasses.contains(entry.getKey())) {
                composite = getAnnotationMatchComposite(targetNode, entry.getValue(), composite, weavedMethods, cache, annotationProxyClasses, skipMethods);
            }
        }
    }
    // method annotation matches
    if (!allMethodAnnotationClasses.isEmpty()) {
        Set<String> targetMethodAnnotationsClasses = getMethodAnnotationClasses(targetNode);
        for (Map.Entry<String, ClassNode> entry : allMethodAnnotationClasses.entrySet()) {
            if (targetMethodAnnotationsClasses.contains(entry.getKey())) {
                composite = getAnnotationMatchComposite(targetNode, entry.getValue(), composite, weavedMethods, cache, annotationProxyClasses, skipMethods);
                // due to having multiple matching annotations that have the same underlying weave code.
                break;
            }
        }
    }
    if (weavePackage != null) {
        // Run any postprocessors that were passed in. It's important that we do this before the inliner runs below
        ClassNode result = new SynchronizedClassNode(WeaveUtils.ASM_API_LEVEL);
        ClassVisitor postprocessChain = weavePackage.getConfig().getPostprocessor().postprocess(className, result, Collections.<String>emptySet(), weavePackage, false);
        composite.accept(postprocessChain);
        composite = result;
    }
    return new PackageWeaveResult(this, className, composite, weavedMethods, annotationProxyClasses);
}
Also used : SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) ClassNode(org.objectweb.asm.tree.ClassNode) HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ClassWeave(com.newrelic.weave.ClassWeave) PreparedMatch(com.newrelic.weave.PreparedMatch) ClassVisitor(org.objectweb.asm.ClassVisitor) SynchronizedClassNode(com.newrelic.weave.utils.SynchronizedClassNode) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Aggregations

PreparedMatch (com.newrelic.weave.PreparedMatch)5 HashMap (java.util.HashMap)4 Map (java.util.Map)4 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)4 SynchronizedClassNode (com.newrelic.weave.utils.SynchronizedClassNode)3 ArrayList (java.util.ArrayList)3 ClassNode (org.objectweb.asm.tree.ClassNode)3 ClassWeave (com.newrelic.weave.ClassWeave)2 ClassMatch (com.newrelic.weave.ClassMatch)1 PreparedExtension (com.newrelic.weave.PreparedExtension)1 IOException (java.io.IOException)1 HashSet (java.util.HashSet)1 List (java.util.List)1 ClassVisitor (org.objectweb.asm.ClassVisitor)1 Method (org.objectweb.asm.commons.Method)1 FieldNode (org.objectweb.asm.tree.FieldNode)1 MethodNode (org.objectweb.asm.tree.MethodNode)1