Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
3ceefd3
Introducing NativeLoader
dougqh Sep 26, 2025
bf8a301
spotless
dougqh Sep 26, 2025
67fc018
Eliminate var-args warning
dougqh Sep 26, 2025
e59a283
Remove unused import
dougqh Sep 26, 2025
77b5c42
Added preloaded test
dougqh Sep 26, 2025
972f5c3
Javadoc and misc clean-up
dougqh Sep 26, 2025
8534a4d
Removed errant comment
dougqh Sep 26, 2025
cfb4285
Tweaking Javadoc
dougqh Sep 26, 2025
63eefcd
More tests & javadoc
dougqh Sep 29, 2025
814e4c1
Solidifying exception handling
dougqh Sep 29, 2025
621c6ab
CapturingPathResolver -> CapturingPathLocator
dougqh Sep 29, 2025
d564cb5
nativeloader -> native-loader
dougqh Sep 30, 2025
7aadebc
Adding FunctionalInterface
dougqh Sep 30, 2025
ad2866f
Removing public from function
dougqh Sep 30, 2025
7655ce0
Merge branch 'master' into dougqh/library-loader
dougqh Sep 30, 2025
92a0def
Forbidden API fix
dougqh Sep 30, 2025
840d32a
Merge branch 'dougqh/library-loader' of github.com:DataDog/dd-trace-j…
dougqh Sep 30, 2025
34ca3b3
Overloading withPreloaded to take a Set
dougqh Oct 1, 2025
bf4f1fe
Merge branch 'master' into dougqh/library-loader
dougqh Oct 1, 2025
2b899aa
Hooking into arch detection code relocated to :components:environment
dougqh Oct 1, 2025
4b3ba71
Code coverage - PathUtils
dougqh Oct 1, 2025
8d6b2d0
spotless
dougqh Oct 1, 2025
3c12ae6
More PathUtils coverage
dougqh Oct 1, 2025
e0b7b85
PathLocatorHelper coverage
dougqh Oct 1, 2025
ae4aad6
Coverage PlatformSpec
dougqh Oct 1, 2025
0e8c405
Adding ability to record multiple locate requests to CapturingPathLoc…
dougqh Oct 1, 2025
dadb822
Coverage of LibraryResolvers
dougqh Oct 1, 2025
fe7ae49
Coverage PathLocators
dougqh Oct 1, 2025
45a71f3
Coverage LibDirBasedPathLocator
dougqh Oct 1, 2025
ccf73f0
PathLocators coverage
dougqh Oct 2, 2025
d04985d
Fixed bug with subResource loading in ClassLoaderResourcePathLocator
dougqh Oct 2, 2025
6b79e46
More coverage
dougqh Oct 2, 2025
8d04747
NativeLoader.Builder coverage
dougqh Oct 2, 2025
065b3cf
spotless
dougqh Oct 2, 2025
6d66b39
ClassLoaderBasedPathLocator coverage
dougqh Oct 2, 2025
79f0c89
LibFile coverage
dougqh Oct 2, 2025
a76f79d
Coverage NativeLoader.Builder - added tempDir tests
dougqh Oct 2, 2025
00fa98a
Testing tempDir functionality
dougqh Oct 2, 2025
6540109
Coverage - Testing PlatformSpec override variations of resolveDynamic
dougqh Oct 2, 2025
d4743f1
Temp file coverage
dougqh Oct 2, 2025
0336fd0
spotless
dougqh Oct 3, 2025
8a747b2
Update components/native-loader/src/main/java/datadog/nativeloader/Fl…
dougqh Oct 3, 2025
7ac11d7
Addressing review comments - lowering visibility on a few classes
dougqh Oct 3, 2025
ef880c5
Addressing review comments - explicit equals call in test
dougqh Oct 3, 2025
87800f0
Addressing review comments - be more explicit about equivalence tests
dougqh Oct 3, 2025
eab2dbb
Merge branch 'dougqh/library-loader' of github.com:DataDog/dd-trace-j…
dougqh Oct 3, 2025
589a1d2
fixing merge conflict
dougqh Oct 3, 2025
28d3578
spotless
dougqh Oct 3, 2025
65e47bf
Addressing review comments - LibraryResolver test clean up
dougqh Oct 3, 2025
940a69a
Addressing review comments - removing redundant final on methods
dougqh Oct 3, 2025
36a219b
Addressing review comments - removing final on methods
dougqh Oct 3, 2025
8e3280a
spotless
dougqh Oct 3, 2025
17627f1
Addressing review comments - check a not preloaded case for Builder
dougqh Oct 3, 2025
6b586ba
spotless
dougqh Oct 3, 2025
dcb5749
Adding explanatory comment for review question
dougqh Oct 3, 2025
818a1be
Tweaking assertions for readability
dougqh Oct 3, 2025
8401635
Improving path concatenation handling
dougqh Oct 3, 2025
25af560
Removed test jar file
dougqh Oct 7, 2025
fa0f8a8
Merge branch 'master' into dougqh/library-loader
dougqh Oct 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions components/nativeloader/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
plugins {
`java-library`
}

apply(from = "$rootDir/gradle/java.gradle")

dependencies {
implementation(project(":components:environment"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package datadog.nativeloader;

import java.net.URL;
import java.util.Objects;

public final class ClassLoaderResourcePathLocator implements PathLocator {
private final ClassLoader classLoader;
private final String baseResource;

public ClassLoaderResourcePathLocator(
final ClassLoader classLoader,
final String baseResource)
{
this.classLoader = classLoader;
this.baseResource = baseResource;
}

@Override
public URL locate(String component, String path) {
String fullPath = component == null ? "" : component;
fullPath = this.baseResource == null ? fullPath : fullPath + "/" + this.baseResource;
fullPath = fullPath.isEmpty() ? path : fullPath + "/" + path;

return this.classLoader.getResource(fullPath);
}

@Override
public int hashCode() {
return Objects.hash(this.classLoader, this.baseResource);
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof ClassLoaderResourcePathLocator)) return false;

ClassLoaderResourcePathLocator that = (ClassLoaderResourcePathLocator)obj;
return this.classLoader.equals(that.classLoader) && Objects.equals(this.baseResource, that.baseResource);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package datadog.nativeloader;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Objects;

public final class FileBasedPathLocator implements PathLocator {
private final File[] libDirs;

public FileBasedPathLocator(File... libDirs) {
this.libDirs = libDirs;
}

@Override
public URL locate(String component, String path) {
String fullPath = component == null ? path : component + "/" + path;

for ( File libDir: this.libDirs ) {
File libFile = new File(libDir, fullPath);
if ( libFile.exists() ) return toUrl(libFile);
}

return null;
}

@SuppressWarnings("deprecation")
private static final URL toUrl(File file) {
try {
return file.toURL();
} catch ( MalformedURLException e ) {
return null;
}
}

@Override
public int hashCode() {
return Objects.hash(this.libDirs);
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof FileBasedPathLocator)) return false;

FileBasedPathLocator that = (FileBasedPathLocator)obj;
return Arrays.equals(this.libDirs, that.libDirs);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package datadog.nativeloader;

import java.net.URL;

public final class FlatDirLibraryResolver implements LibraryResolver {
public static final LibraryResolver INSTANCE = new FlatDirLibraryResolver();

private FlatDirLibraryResolver() {}

@Override
public final URL resolve(PathLocator pathLocator, String component, PlatformSpec platformSpec, String libName) {
String libFileName = PathUtils.libFileName(platformSpec, libName);

String osPath = PathUtils.osPartOf(platformSpec);
String archPath = PathUtils.archPartOf(platformSpec);
String libcPath = PathUtils.libcPartOf(platformSpec);

URL url;
String regularPath = osPath + "-" + archPath;

if ( libcPath != null ) {
String specializedPath = regularPath + "-" + libcPath;
url = pathLocator.locate(component, specializedPath + "/" + libFileName);
if ( url != null ) return url;
}

url = pathLocator.locate(component, regularPath + "/" + libFileName);
if ( url != null ) return url;

// fallback to searching at top-level, mostly concession to good out-of-box behavior
// with java.library.path
url = pathLocator.locate(component, libFileName);
if ( url != null ) return url;

if ( component != null ) {
url = pathLocator.locate(null, libFileName);
if ( url != null ) return url;
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package datadog.nativeloader;

import java.io.File;

/**
* Represents a resolved library
* <ul>
* <li>library may be preloaded - with no backing file</li>
* <li>regular file - that doesn't require clean-up</li>
* <li>temporary file - copying from another source - that does require clean-up</li>
* </ul>
*/
public final class LibFile implements AutoCloseable {
static final boolean NO_CLEAN_UP = false;
static final boolean CLEAN_UP = true;

static final LibFile preloaded(String libName) {
return new LibFile(libName, null, NO_CLEAN_UP);
}

static final LibFile fromFile(String libName, File file) {
return new LibFile(libName, file, NO_CLEAN_UP);
}

static final LibFile fromTempFile(String libName, File file) {
return new LibFile(libName, file, CLEAN_UP);
}

final String libName;

final File file;
final boolean needsCleanup;

LibFile(String libName, File file, boolean needsCleanup) {
this.libName = libName;

this.file = file;
this.needsCleanup = needsCleanup;
}

public boolean isPreloaded() {
return (this.file == null);
}

public void load() throws LibraryLoadException {
if ( this.isPreloaded() ) return;

try {
Runtime.getRuntime().load(this.getAbsolutePath());
} catch ( Throwable t ) {
throw new LibraryLoadException(this.libName, t);
}
}

public final String getAbsolutePath() {
return this.file.getAbsolutePath();
}

@Override
public void close() {
if ( this.needsCleanup ) {
NativeLoader.delete(this.file);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package datadog.nativeloader;

/**
* Exception raised when NativeLoader fails to resolve or load a library
*/
public class LibraryLoadException extends Exception {
private static final long serialVersionUID = 1L;

public LibraryLoadException(String libName) {
super(message(libName));
}

public LibraryLoadException(String libName, Throwable cause) {
this(message(libName), cause.getMessage(), cause);
}

public LibraryLoadException(String libName, String message) {
super(message(libName) + " - " + message);
}

public LibraryLoadException(String libName, String message, Throwable cause) {
super(message(libName) + " - " + message, cause);
}

static final String message(String libName) {
return "Unable to resolve library " + libName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package datadog.nativeloader;

import java.net.URL;

public interface LibraryResolver {
default boolean isPreloaded(
PlatformSpec platform,
String libName)
{
return false;
}

URL resolve(
PathLocator pathLocator,
String component,
PlatformSpec platformSpec,
String libName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package datadog.nativeloader;

import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public final class LibraryResolvers {
private LibraryResolvers() {}

public static final LibraryResolver defaultLibraryResolver() {
return flatDirs();
}

public static final LibraryResolver withPreloaded(LibraryResolver baseResolver, String... preloadedLibNames) {
Set<String> preloadedSet = new HashSet<>(Arrays.asList(preloadedLibNames));
return new LibraryResolver() {
@Override
public boolean isPreloaded(PlatformSpec platform, String libName) {
return preloadedSet.contains(libName);
}

@Override
public URL resolve(PathLocator pathLocator, String component, PlatformSpec platformSpec, String libName) {
return baseResolver.resolve(pathLocator, component, platformSpec, libName);
}
};
}

public static final LibraryResolver flatDirs() {
return FlatDirLibraryResolver.INSTANCE;
}

public static final LibraryResolver nestedDirs() {
return NestedDirLibraryResolver.INSTANCE;
}
}
Loading
Loading