Change packaging of internal jars to be exploded in a subfolder
MODIFY
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java
@@ -51,7 +51,7 @@ public class DatadogClassLoader extends URLClassLoader {
null,
0,
"/",
- new InternalJarURLHandler(internalJarFileName, bootstrapProxy));
+ new InternalJarURLHandler(internalJarFileName, bootstrapJarLocation));
addURL(internalJarURL);
} catch (final MalformedURLException e) {

MODIFY
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/InternalJarURLHandler.java
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/InternalJarURLHandler.java
@@ -2,58 +2,63 @@ package datadog.trace.bootstrap;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.nio.file.NoSuchFileException;
import java.security.Permission;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
+import java.util.jar.JarFile;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class InternalJarURLHandler extends URLStreamHandler {
- private final Map<String, byte[]> filenameToBytes = new HashMap<>();
-
- InternalJarURLHandler(
- final String internalJarFileName, final ClassLoader classloaderForJarResource) {
-
- // "/" is used as the default url of the jar
- // This is called by the SecureClassLoader trying to obtain permissions
- filenameToBytes.put("/", new byte[] {});
-
- final InputStream jarStream =
- internalJarFileName == null
- ? null
- : classloaderForJarResource.getResourceAsStream(internalJarFileName);
-
- if (jarStream != null) {
- try (final JarInputStream inputStream = new JarInputStream(jarStream)) {
- JarEntry entry = inputStream.getNextJarEntry();
-
- while (entry != null) {
- filenameToBytes.put("/" + entry.getName(), getBytes(inputStream));
-
- entry = inputStream.getNextJarEntry();
+ private final Map<String, JarEntry> filenameToEntry = new HashMap<>();
+ private JarFile bootstrapJarFile;
+
+ InternalJarURLHandler(final String internalJarFileName, final URL bootstrapJarLocation) {
+ try {
+ if (bootstrapJarLocation != null) {
+ bootstrapJarFile = new JarFile(new File(bootstrapJarLocation.toURI()));
+ final Enumeration<JarEntry> entries = bootstrapJarFile.entries();
+ while (entries.hasMoreElements()) {
+ final JarEntry entry = entries.nextElement();
+
+ if (!entry.isDirectory() && entry.getName().startsWith(internalJarFileName + "/")) {
+ filenameToEntry.put(entry.getName().substring(internalJarFileName.length()), entry);
}
-
- } catch (final IOException e) {
+ }
+ }
+ } catch (final URISyntaxException | IOException e) {
log.error("Unable to read internal jar", e);
}
- } else {
- log.error("Internal jar not found");
+
+ if (filenameToEntry.isEmpty()) {
+ log.warn("Internal jar entries found");
}
}
@Override
protected URLConnection openConnection(final URL url) throws IOException {
- final byte[] bytes = filenameToBytes.get(url.getFile());
- if (bytes == null) {
+ final byte[] bytes;
+
+ final String filename = url.getFile().replaceAll("\\.class$", ".classdata");
+ if ("/".equals(filename)) {
+ // "/" is used as the default url of the jar
+ // This is called by the SecureClassLoader trying to obtain permissions
+ bytes = new byte[0];
+ } else if (filenameToEntry.containsKey(filename)) {
+ final JarEntry entry = filenameToEntry.get(filename);
+ bytes = getBytes(bootstrapJarFile.getInputStream(entry));
+ } else {
throw new NoSuchFileException(url.getFile(), null, url.getFile() + " not in internal jar");
}

MODIFY
dd-java-agent/dd-java-agent.gradle
dd-java-agent/dd-java-agent.gradle
@@ -26,13 +26,12 @@ def includeShadowJar(subproject, jarname) {
def agent_project = project
subproject.afterEvaluate {
agent_project.processResources {
- from(subproject.tasks.shadowJar)
- rename {
- it.equals(subproject.shadowJar.archivePath.getName()) ?
- jarname :
- it
+ from(zipTree(subproject.tasks.shadowJar.archivePath)) {
+ into jarname
+ rename '(^.*)\\.class$', '$1.classdata'
}
}
+
agent_project.processResources.dependsOn subproject.tasks.shadowJar
subproject.shadowJar {
classifier null
@@ -59,8 +58,8 @@ def includeShadowJar(subproject, jarname) {
}
}
-includeShadowJar(project(':dd-java-agent:instrumentation'), 'agent-tooling-and-instrumentation.jar.zip')
-includeShadowJar(project(':dd-java-agent:agent-jmxfetch'), 'agent-jmxfetch.jar.zip')
+includeShadowJar(project(':dd-java-agent:instrumentation'), 'agent-tooling-and-instrumentation.jar')
+includeShadowJar(project(':dd-java-agent:agent-jmxfetch'), 'agent-jmxfetch.jar')
jar {
classifier = 'unbundled'

MODIFY
dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java
dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java
@@ -94,7 +94,7 @@ public class TracingAgent {
if (AGENT_CLASSLOADER == null) {
final ClassLoader agentClassLoader =
- createDatadogClassLoader("agent-tooling-and-instrumentation.jar.zip", bootstrapURL);
+ createDatadogClassLoader("agent-tooling-and-instrumentation.jar", bootstrapURL);
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(agentClassLoader);
@@ -126,7 +126,7 @@ public class TracingAgent {
throws Exception {
if (JMXFETCH_CLASSLOADER == null) {
final ClassLoader jmxFetchClassLoader =
- createDatadogClassLoader("agent-jmxfetch.jar.zip", bootstrapURL);
+ createDatadogClassLoader("agent-jmxfetch.jar", bootstrapURL);
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(jmxFetchClassLoader);

Change packaging of internal jars to be exploded in a subfolder