Hi,
as a User of this Library i want to be able to control access of IO. In particular i want to be able to specify the path the native library is beeing written to.
For example i attached the following Class "Native" that emulates the behavior i want to implement.
Unfortunately this requires alot of copy-paste and hackish workarounds.
I would propose extracting the necessary functionality into atleast two parts:
- General Utility Class providing init() and load() delegating to implementation
- Strategy API -> Allows to implement a System.load() strategy
By default i suggest implementing the following Strategies:
- tryLoadFromLibraryPath -> Same as the corresponding method
- loadFromTempFile -> Same as current Implementation provided by libraryPath()
Order is provided by each Strategy. As such tryLoadFromLibraryPath would return -1 and loadFromTempfile 1. Other Implementations can then use 0 easily. ServiceLoader would allow to reduce implementation.
The API should provide access to atleast fileName and extension in order to allow writing correctly.
I did not yet start working on a Pull Request, because i feel like this RfC is disruptive to the current implementation and as such I feel @kawamuray you as a Maintainer should first give your Opinion.
Alternatively one could use an Environment Variable, but i feel that is too restrictive for other use cases. Especially when one wants to validate DLL using an out of band signing process.
import io.github.kawamuray.wasmtime.NativeLibraryLoader;
import lombok.AllArgsConstructor;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Objects;
import java.util.Properties;
/**
* This is a copy of {@link NativeLibraryLoader} that is needed to extract to a well known location instead of a temp file.
*/
@Slf4j
@UtilityClass
public final class Native {
private static final String SANDBOX_NATIVE_OVERRIDE = "SANDBOX_NATIVE_OVERRIDE";
private static final String LOCATION = ".native";
private boolean loaded = false;
public void load() {
if (loaded) {
return;
}
if (Native.isAutoLoadDisabled()) {
log.error("Please set Environment Variable {} to a Value", DISABLE_AUTO_LOAD_ENV);
System.exit(1);
}
try {
final var nativeLibraryDir = Paths.get(LOCATION);
if (!Files.exists(nativeLibraryDir)) {
Files.createDirectory(nativeLibraryDir);
}
final var libraryPath = libraryPath(nativeLibraryDir);
log.debug("Loading Wasmtime JNI library from {}", libraryPath);
System.load(libraryPath);
loaded = true;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private boolean isAutoLoadDisabled() {
return System.getenv(DISABLE_AUTO_LOAD_ENV) == null;
}
private boolean isOverridingNative() {
return System.getenv(SANDBOX_NATIVE_OVERRIDE) != null;
}
// Copied and changed
private static String libraryPath(final Path root) throws IOException {
final var platform = detectPlatform();
String version = libVersion();
String ext = platform.ext;
String fileName = platform.prefix + NATIVE_LIBRARY_NAME + '_' + version + '_' + platform.classifier;
final var name = fileName + ext;
final var p = root.resolve(name);
final var ovr = isOverridingNative();
if (ovr) {
log.warn("Overriding existing stuff yadda yaadda");
}
if (ovr || !Files.exists(p)) {
try (final var in = NativeLibraryLoader.class.getResourceAsStream('/' + name)) {
// Added to copied struct
Objects.requireNonNull(in, "Could not find Library");
final var options = ovr
? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING}
: new CopyOption[]{};
Files.copy(in, p, options);
}
}
return p.toRealPath().toAbsolutePath().toString();
}
// Rest is copied from Version 0.9.0
private static final String DISABLE_AUTO_LOAD_ENV = "WASMTIME_JNI_LOAD_DISABLED";
private static final String NATIVE_LIBRARY_NAME = "wasmtime_jni";
private static final String META_PROPS_FILE = "wasmtime-java-meta.properties";
private static final String JNI_LIB_VERSION_PROP = "jnilib.version";
@AllArgsConstructor
private enum Platform {
LINUX("linux", "lib", ".so"),
MACOS("macos", "lib", ".dylib"),
WINDOWS("windows", "", ".dll");
final String classifier;
final String prefix;
final String ext;
}
private static Platform detectPlatform() {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("linux")) {
return Platform.LINUX;
}
if (os.contains("mac os") || os.contains("darwin")) {
return Platform.MACOS;
}
if (os.toLowerCase().contains("windows")) {
return Platform.WINDOWS;
}
throw new RuntimeException("platform not supported: " + os);
}
private static String libVersion() throws IOException {
final Properties props;
try (InputStream in = NativeLibraryLoader.class.getResourceAsStream('/' + META_PROPS_FILE)) {
props = new Properties();
props.load(in);
}
return props.getProperty(JNI_LIB_VERSION_PROP);
}
}
Hi,
as a User of this Library i want to be able to control access of IO. In particular i want to be able to specify the path the native library is beeing written to.
For example i attached the following Class "Native" that emulates the behavior i want to implement.
Unfortunately this requires alot of copy-paste and hackish workarounds.
I would propose extracting the necessary functionality into atleast two parts:
By default i suggest implementing the following Strategies:
Order is provided by each Strategy. As such tryLoadFromLibraryPath would return -1 and loadFromTempfile 1. Other Implementations can then use 0 easily. ServiceLoader would allow to reduce implementation.
The API should provide access to atleast fileName and extension in order to allow writing correctly.
I did not yet start working on a Pull Request, because i feel like this RfC is disruptive to the current implementation and as such I feel @kawamuray you as a Maintainer should first give your Opinion.
Alternatively one could use an Environment Variable, but i feel that is too restrictive for other use cases. Especially when one wants to validate DLL using an out of band signing process.