use of com.newrelic.agent.instrumentation.ClassLoaderClassFinder in project newrelic-java-agent by newrelic.
the class ClassLoaderClassTransformer method transform.
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer, final InstrumentationContext context, Match match) throws IllegalClassFormatException {
if (classloadersToSkip.contains(className)) {
Agent.LOG.log(Level.FINEST, "ClassLoaderClassTransformer: classloadersToSkip contains {0}", className);
return null;
}
// For any new ClassLoaders that we encounter, we should add them to the map
if (!observedClassLoaders.containsKey(className)) {
observedClassLoaders.put(className, classfileBuffer);
}
try {
if (loader == null) {
loader = BootstrapLoader.PLACEHOLDER;
}
Agent.LOG.log(Level.FINER, "ClassLoaderClassTransformer transforming: {0} -- {1}", loader, className);
// This ClassCache will only consult the map of the observedClassLoaders that we pass in, so
// we don't need to worry about it possibly using findResource() when we call validate(cache).
ClassCache cache = new ClassCache(new ClassLoaderClassFinder(observedClassLoaders));
PackageValidationResult result;
if (className.equals("java/lang/ClassLoader")) {
// For "java.lang.ClassLoader" we only want to instrument one of the loadClass() methods
result = classloaderPackage.validate(cache);
} else {
// For every other ClassLoader that extends "java.lang.ClassLoader" we want to instrument both loadClass() methods
result = classloaderBasePackage.validate(cache);
}
if (result.succeeded()) {
Map<String, byte[]> utilityClassBytes = result.computeUtilityClassBytes(cache);
if (utilityClassBytes != null && !utilityClassBytes.isEmpty()) {
// Note: This is a duplication of code from the WeavePackageManager. This is duplicated here because we are
// not using WeavePackageManager directly.
NewClassAppender.appendClassesToBootstrapClassLoader(instrumentation, utilityClassBytes);
}
// Since we know that this class validated we are assured that this class extends
// "java.lang.ClassLoader" so we can manually set the super class name to "java/lang/ClassLoader" or
// to empty if it's the java.lang.ClassLoader instance itself.
final String[] superNames;
if (className.equals("java/lang/ClassLoader")) {
superNames = new String[0];
} else {
superNames = new String[] { "java/lang/ClassLoader" };
}
Map<Method, Collection<String>> skipMethods = (context != null) ? context.getSkipMethods() : Collections.emptyMap();
// This applies the "checkPackageAccess" weaved code only if it should be enabled from the constructor above
byte[] newBytes = classfileBuffer;
if (checkPackageAccessPackage != null && newBytes != null && className.equals("java/lang/ClassLoader")) {
PackageValidationResult checkPackageAccessResult = checkPackageAccessPackage.validate(cache);
if (checkPackageAccessResult.succeeded()) {
newBytes = checkPackageAccessResult.weave(className, superNames, new String[0], newBytes, cache, skipMethods).getCompositeBytes(cache);
} else {
logClassLoaderWeaveViolations(checkPackageAccessResult, className);
}
if (newBytes == null) {
newBytes = classfileBuffer;
}
}
PackageWeaveResult packageWeaveResult = result.weave(className, superNames, new String[0], newBytes, cache, skipMethods);
// Do the weaving and use our "non-findResource" cache from above
newBytes = packageWeaveResult.getCompositeBytes(cache);
if (newBytes != null) {
Agent.LOG.log(Level.FINE, "ClassLoaderClassTransformer patched {0} -- {1}", loader, className);
return newBytes;
}
} else {
logClassLoaderWeaveViolations(result, className);
}
} catch (Throwable t) {
Agent.LOG.log(Level.FINE, t, "ClassLoaderClassTransformer unable to instrument classloader {0} -- {1}", loader, className);
}
Agent.LOG.log(Level.FINE, "ClassLoaderClassTransformer skipped transformation: {0} -- {1}", loader, className);
return null;
}
Aggregations