Files
jlibloader/src/main/java/net/rubygrapefruit/platform/Native.java

125 lines
4.9 KiB
Java
Executable File

package net.rubygrapefruit.platform;
import net.rubygrapefruit.platform.internal.*;
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
import java.io.*;
import java.net.URL;
/**
* Provides access to the native integrations. Use {@link #get(Class)} to load a particular integration.
*/
public class Native {
private static final Object lock = new Object();
private static boolean loaded;
/**
* Initialises the native integration, if not already initialized.
*
* @param extractDir The directory to extract native resources into. May be null.
*/
static void init(File extractDir) {
synchronized (lock) {
if (!loaded) {
Platform platform = Platform.current();
if (!platform.isSupported()) {
throw new NativeException(String.format("The current platform is not supported."));
}
try {
File libFile;
URL resource = Native.class.getClassLoader().getResource(platform.getLibraryName());
if (resource != null) {
File libDir = extractDir;
if (libDir == null) {
libDir = File.createTempFile("native-platform", "dir");
libDir.delete();
libDir.mkdirs();
}
libFile = new File(libDir, platform.getLibraryName());
libFile.deleteOnExit();
copy(resource, libFile);
} else {
libFile = new File("build/binaries/" + platform.getLibraryName());
}
System.load(libFile.getCanonicalPath());
} catch (IOException e) {
throw new RuntimeException(e);
}
int nativeVersion = NativeLibraryFunctions.getVersion();
if (nativeVersion != NativeLibraryFunctions.VERSION) {
throw new NativeException(String.format(
"Unexpected native library version loaded. Expected %s, was %s.", nativeVersion,
NativeLibraryFunctions.VERSION));
}
loaded = true;
}
}
}
static <T extends NativeIntegration> T get(Class<T> type) {
init(null);
Platform platform = Platform.current();
if (platform.isPosix()) {
if (type.equals(PosixFile.class)) {
return type.cast(new DefaultPosixFile());
}
if (type.equals(Process.class)) {
return type.cast(new DefaultProcess());
}
if (type.equals(TerminalAccess.class)) {
return type.cast(new TerminfoTerminalAccess());
}
if (type.equals(SystemInfo.class)) {
MutableSystemInfo systemInfo = new MutableSystemInfo();
FunctionResult result = new FunctionResult();
NativeLibraryFunctions.getSystemInfo(systemInfo, result);
if (result.isFailed()) {
throw new NativeException(String.format("Could not fetch system information: %s",
result.getMessage()));
}
System.out.println("=> CHARACTER ENCODING: " + systemInfo.characterEncoding);
return type.cast(systemInfo);
}
} else if (platform.isWindows()) {
if (type.equals(Process.class)) {
return type.cast(new DefaultProcess());
}
if (type.equals(TerminalAccess.class)) {
return type.cast(new WindowsTerminalAccess());
}
}
if (platform.isOsX()) {
if (type.equals(FileSystems.class)) {
return type.cast(new PosixFileSystems());
}
}
throw new UnsupportedOperationException(String.format("Cannot load unsupported native integration %s.",
type.getName()));
}
private static void copy(URL source, File dest) {
try {
InputStream inputStream = source.openStream();
try {
OutputStream outputStream = new FileOutputStream(dest);
try {
byte[] buffer = new byte[4096];
while (true) {
int nread = inputStream.read(buffer);
if (nread < 0) {
break;
}
outputStream.write(buffer, 0, nread);
}
} finally {
outputStream.close();
}
} finally {
inputStream.close();
}
} catch (IOException e) {
throw new NativeException(String.format("Could not extract native JNI library."), e);
}
}
}