com.newrelic.weave.weavepackage.CachedWeavePackage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of newrelic-weaver Show documentation
Show all versions of newrelic-weaver Show documentation
The Weaver of the Java agent.
/*
*
* * Copyright 2020 New Relic Corporation. All rights reserved.
* * SPDX-License-Identifier: Apache-2.0
*
*/
package com.newrelic.weave.weavepackage;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import com.newrelic.weave.utils.ClassCache;
import com.newrelic.weave.utils.Streams;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
/**
* Rather than process the entire weave jar, this weave package stores a list of reference and illegal class names. When
* a validation is requested, the reference and illegal names are used to fail the validation fast. If it is not
* possible to fail fast, the weave package jar is processed.
*
* Since most internal WeavePackages will not load, this allows us to fail invalid packages faster and avoid unnecessary
* work around jar processing for failed packages.
*
* This class exists for performance reasons. To see the functionality of the weaver look at {@link WeavePackage}
*/
public class CachedWeavePackage extends WeavePackage {
public static final String REFERENCE_CLASSES_MANIFEST_ATTRIBUTE_NAME = "Reference-Classes";
public static final String ILLEGAL_CLASSES_MANIFEST_ATTRIBUTE_NAME = "Illegal-Classes";
public static final String WEAVE_CLASSES_MANIFEST_ATTRIBUTE_NAME = "Weave-Classes";
public static final String WEAVE_METHODS_MANIFEST_ATTRIBUTE_NAME = "Weave-Methods";
public static final String CLASS_REQUIRED_ANNOTATIONS_MANIFEST_ATTRIBUTE_NAME = "Class-Required-Annotations";
public static final String METHOD_REQUIRED_ANNOTATIONS_MANIFEST_ATTRIBUTE_NAME = "Method-Required-Annotations";
private final Set referenceClasses;
private final Set weaveClasses;
private final Set weaveMethods;
private final Set illegalClasses;
private final Set classRequiredAnnotations;
private final Set methodRequiredAnnotations;
private final URL jarLocation;
private volatile boolean loaded = false;
private static final Splitter splitter = Splitter.on(',').omitEmptyStrings().trimResults();
public static WeavePackage createWeavePackage(URL jarLocation, JarInputStream jarStream, WeavePackageConfig config)
throws Exception {
Attributes attributes = jarStream.getManifest().getMainAttributes();
String weaveMethods = attributes.getValue(WEAVE_METHODS_MANIFEST_ATTRIBUTE_NAME);
String weaveClasses = attributes.getValue(WEAVE_CLASSES_MANIFEST_ATTRIBUTE_NAME);
String classRequiredAnnotations = attributes.getValue(CLASS_REQUIRED_ANNOTATIONS_MANIFEST_ATTRIBUTE_NAME);
String methodRequiredAnnotations = attributes.getValue(METHOD_REQUIRED_ANNOTATIONS_MANIFEST_ATTRIBUTE_NAME);
if (weaveMethods == null || weaveClasses == null || classRequiredAnnotations == null || methodRequiredAnnotations == null) {
return WeavePackage.createWeavePackage(jarStream, config);
} else {
String referenceClasses = attributes.getValue(REFERENCE_CLASSES_MANIFEST_ATTRIBUTE_NAME);
String illegalClasses = attributes.getValue(ILLEGAL_CLASSES_MANIFEST_ATTRIBUTE_NAME);
Set weaveMethodsList = new HashSet<>();
for (String weaveMethod : splitter.split(weaveMethods)) {
weaveMethodsList.add(weaveMethod.replaceAll("\"", ""));
}
Set weaveClassesList = Sets.newHashSet(splitter.split(weaveClasses));
Set referenceList = Sets.newHashSet(splitter.split(referenceClasses));
Set classAnnotationsList = Sets.newHashSet(splitter.split(classRequiredAnnotations));
Set methodAnnotationsList = Sets.newHashSet(splitter.split(methodRequiredAnnotations));
Set illegalList = illegalClasses == null ? null : Sets.newHashSet(splitter.split(illegalClasses));
return new CachedWeavePackage(jarLocation, config, weaveMethodsList, weaveClassesList, referenceList,
illegalList, classAnnotationsList, methodAnnotationsList);
}
}
CachedWeavePackage(URL jarLocation, WeavePackageConfig config, Set weaveMethods, Set weaveClasses,
Set referenceClasses, Set illegalClasses, Set classRequiredAnnotations,
Set methodRequiredAnnotations) {
super(config, new ArrayList());
this.weaveMethods = weaveMethods;
this.weaveClasses = weaveClasses;
this.referenceClasses = referenceClasses;
this.illegalClasses = illegalClasses;
this.classRequiredAnnotations = classRequiredAnnotations;
this.methodRequiredAnnotations = methodRequiredAnnotations;
this.jarLocation = jarLocation;
if (isBootstrapClassName(this.weaveClasses)) {
this.setWeavesBootstrap();
}
}
@Override
public boolean hasMatcher(String className, String[] superNames, String[] interfaceNames,
Set classAnnotations, Set methodAnnotations, ClassCache classCache) throws IOException {
Set matchClassNames = Sets.newHashSet(className);
if (superNames != null && superNames.length > 0) {
Collections.addAll(matchClassNames, superNames);
}
if (interfaceNames != null && interfaceNames.length > 0) {
Collections.addAll(matchClassNames, interfaceNames);
}
boolean isClassAnnotationMatch = classRequiredAnnotations != null && !classRequiredAnnotations.isEmpty();
boolean isMethodAnnotationMatch = methodRequiredAnnotations != null && !methodRequiredAnnotations.isEmpty();
matchClassNames.retainAll(weaveClasses);
if (!isClassAnnotationMatch && !isMethodAnnotationMatch && matchClassNames.isEmpty()) {
return false;
}
this.load();
return super.hasMatcher(className, superNames, interfaceNames, classAnnotations, methodAnnotations, classCache);
}
@Override
public PackageValidationResult validate(ClassCache cache) throws IOException {
if (loaded) {
return super.validate(cache);
} else {
PackageValidationResult fastResult = new PackageValidationResult(this, cache, referenceClasses,
illegalClasses);
if (fastResult.succeeded()) {
load();
return super.validate(cache);
} else {
return fastResult;
}
}
}
@Override
public Set getRequiredClasses() {
Set requiredClasses = new HashSet<>();
requiredClasses.addAll(weaveClasses);
requiredClasses.addAll(referenceClasses);
return requiredClasses;
}
@Override
public Set getMethodSignatures() {
return new HashSet<>(weaveMethods);
}
@Override
public Set getAllRequiredAnnotationClasses() {
return new HashSet<>(classRequiredAnnotations);
}
@Override
public Set getAllRequiredMethodAnnotationClasses() {
return new HashSet<>(methodRequiredAnnotations);
}
/**
* Fully load the WeavePackage from the JAR file.
*/
private void load() throws IOException {
if (!loaded) {
synchronized (this) {
if (!loaded) {
JarInputStream jarStream = null;
try {
List classBytes = new ArrayList<>();
jarStream = new JarInputStream(jarLocation.openStream());
JarEntry entry = null;
while ((entry = jarStream.getNextJarEntry()) != null) {
if (entry.getName().endsWith(".class")) {
classBytes.add(Streams.read(jarStream, false));
}
}
super.processWeaveBytes(classBytes);
this.loaded = true;
} finally {
if (jarStream != null) {
jarStream.close();
}
}
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy