Move DatadogClassloader to bootstrap
MODIFY
dd-java-agent-ittests/src/test/java/datadog/trace/agent/ClassLoaderTest.java
dd-java-agent-ittests/src/test/java/datadog/trace/agent/ClassLoaderTest.java
@@ -37,4 +37,6 @@ public class ClassLoaderTest {
}
// TODO: Write test: assert our agent resource locator can locate resources from the bootstrap jar
+
+ // TODO: Write test: ensure all classes are available on java 9 (vs the platform loader)
}

ADD
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/agent/bootstrap/DatadogClassLoader.java
+package datadog.trace.agent.bootstrap;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/** Classloader used to run the core datadog agent. */
+public class DatadogClassLoader extends URLClassLoader {
+ // Calling java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch
+ // adds a jar to the bootstrap class lookup, but not to the resource lookup.
+ // As a workaround, we keep a reference to the bootstrap jar
+ // to use only for resource lookups.
+ private final ClassLoader bootstrapResourceLocator;
+
+ /**
+ * Construct a new DatadogClassLoader
+ *
+ * <p>{@param bootstrapJarLocation} Location of the bootstrap jar. Will be used for resource
+ * lookups. {@param agentJarLocation} Location of the agent tooling and instrumentation jar. Will
+ * be the classpath of this classloader. {@param parent} Parent of this classloader. Should null
+ * (bootstrap), or the platform classloader for java 9+.
+ */
+ public DatadogClassLoader(URL bootstrapJarLocation, URL agentJarLocation, ClassLoader parent) {
+ super(new URL[] {agentJarLocation}, parent);
+ bootstrapResourceLocator = new URLClassLoader(new URL[] {bootstrapJarLocation}, null);
+ }
+
+ @Override
+ public URL getResource(String resourceName) {
+ final URL bootstrapResource = bootstrapResourceLocator.getResource(resourceName);
+ if (null == bootstrapResource) {
+ return super.getResource(resourceName);
+ } else {
+ return bootstrapResource;
+ }
+ }
+}

DELETE
dd-java-agent/src/main/java/datadog/trace/agent/DatadogClassLoader.java
-package datadog.trace.agent;
-
-import java.net.URL;
-import java.net.URLClassLoader;
-
-public class DatadogClassLoader extends URLClassLoader {
- // TODO: doc: explain why we need to use the bootstrap jar for resource lookup
- private final ClassLoader bootstrapResourceLocator;
-
- public DatadogClassLoader(URL bootstrapJarLocation, URL agentJarLocation, ClassLoader parent) {
- super(new URL[] {agentJarLocation}, parent);
- bootstrapResourceLocator = new URLClassLoader(new URL[] {bootstrapJarLocation}, null);
- }
-
- @Override
- public URL getResource(String resourceName) {
- final URL bootstrapResource = bootstrapResourceLocator.getResource(resourceName);
- if (null == bootstrapResource) {
- return super.getResource(resourceName);
- } else {
- return bootstrapResource;
- }
- }
-}

MODIFY
dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java
dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java
@@ -18,7 +18,9 @@ package datadog.trace.agent;
import java.io.*;
import java.lang.instrument.Instrumentation;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
+import java.net.URL;
import java.util.jar.JarFile;
/** Entry point for initializing the agent. */
@@ -48,20 +50,9 @@ public class TracingAgent {
"agent-bootstrap.jar.zip",
"agent-bootstrap.jar");
- final ClassLoader agentParent;
- final String javaVersion = System.getProperty("java.version");
- if (javaVersion.startsWith("1.7") || javaVersion.startsWith("1.8")) {
- agentParent = null; // bootstrap
- } else {
- // platform classloader is parent of system in java 9+
- agentParent = ClassLoader.getSystemClassLoader().getParent();
- }
- final ClassLoader agentClassLoader =
- new DatadogClassLoader(
- bootstrapJar.toURI().toURL(), toolingJar.toURI().toURL(), agentParent);
-
- // FIXME: ensure all classes are available on java 9 (vs the platform loader)
+ // bootstrap jar must be appended before agent classloader is created.
inst.appendToBootstrapClassLoaderSearch(new JarFile(bootstrapJar));
+ final ClassLoader agentClassLoader = createDatadogClassLoader(bootstrapJar, toolingJar);
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
try {
@@ -94,6 +85,34 @@ public class TracingAgent {
}
}
+ /**
+ * Create the datadog classloader. This must be called after the bootstrap jar has been appened to
+ * the bootstrap classpath.
+ *
+ * @param bootstrapJar datadog bootstrap jar which has been appended to the bootstrap loader
+ * @param toolingJar jar to use for the classpath of the datadog classloader
+ * @return Datadog Classloader
+ */
+ private static ClassLoader createDatadogClassLoader(File bootstrapJar, File toolingJar)
+ throws Exception {
+ final ClassLoader agentParent;
+ final String javaVersion = System.getProperty("java.version");
+ if (javaVersion.startsWith("1.7") || javaVersion.startsWith("1.8")) {
+ agentParent = null; // bootstrap
+ } else {
+ // platform classloader is parent of system in java 9+
+ agentParent = ClassLoader.getSystemClassLoader().getParent();
+ }
+ Class<?> loaderClass =
+ ClassLoader.getSystemClassLoader()
+ .loadClass("datadog.trace.agent.bootstrap.DatadogClassLoader");
+ Constructor constructor =
+ loaderClass.getDeclaredConstructor(URL.class, URL.class, ClassLoader.class);
+ return (ClassLoader)
+ constructor.newInstance(
+ bootstrapJar.toURI().toURL(), toolingJar.toURI().toURL(), agentParent);
+ }
+
/**
* Extract {@param loader}'s resource, {@param sourcePath}, to a temporary file named {@param
* destName}.

Move DatadogClassloader to bootstrap