- Bundle native library in jar and extract at runtime.
- Don't reinitialise terminal in TerminalAccess.getTerminal() if already initialised.
This commit is contained in:
10
build.gradle
10
build.gradle
@@ -64,6 +64,16 @@ task nativeHeaders {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task nativeJar(type: Jar) {
|
||||||
|
from compileMain
|
||||||
|
archiveName = 'native-platform-jni.jar'
|
||||||
|
}
|
||||||
|
|
||||||
|
startScripts.classpath += nativeJar.outputs.files
|
||||||
|
applicationDistribution.from(nativeJar) {
|
||||||
|
into 'lib'
|
||||||
|
}
|
||||||
|
|
||||||
compileMain.dependsOn nativeHeaders
|
compileMain.dependsOn nativeHeaders
|
||||||
test.dependsOn compileMain
|
test.dependsOn compileMain
|
||||||
|
|
||||||
|
|||||||
@@ -67,11 +67,6 @@ Java_net_rubygrapefruit_platform_internal_jni_PosixTerminalFunctions_isatty(JNIE
|
|||||||
switch (output) {
|
switch (output) {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
printf("=> checking file descriptor %d\n", output+1);
|
|
||||||
printf("=> isatty(): %d\n", isatty(output+1));
|
|
||||||
result = fstat(output+1, &fileInfo);
|
|
||||||
printf("=> fstat(): %d\n", result);
|
|
||||||
printf("=> mode: %o\n", fileInfo.st_mode);
|
|
||||||
return isatty(output+1) ? JNI_TRUE : JNI_FALSE;
|
return isatty(output+1) ? JNI_TRUE : JNI_FALSE;
|
||||||
default:
|
default:
|
||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package net.rubygrapefruit.platform;
|
|||||||
import net.rubygrapefruit.platform.internal.*;
|
import net.rubygrapefruit.platform.internal.*;
|
||||||
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to the native integrations. Use {@link #get(Class)} to load a particular integration.
|
* Provides access to the native integrations. Use {@link #get(Class)} to load a particular integration.
|
||||||
@@ -13,15 +13,34 @@ public class Native {
|
|||||||
private static final Object lock = new Object();
|
private static final Object lock = new Object();
|
||||||
private static boolean loaded;
|
private static boolean loaded;
|
||||||
|
|
||||||
static <T extends NativeIntegration> T get(Class<T> type) {
|
/**
|
||||||
Platform platform = Platform.current();
|
* 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) {
|
synchronized (lock) {
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
|
Platform platform = Platform.current();
|
||||||
if (!platform.isSupported()) {
|
if (!platform.isSupported()) {
|
||||||
throw new NativeException(String.format("The current platform is not supported."));
|
throw new NativeException(String.format("The current platform is not supported."));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
File libFile = new File("build/binaries/" + platform.getLibraryName());
|
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());
|
System.load(libFile.getCanonicalPath());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@@ -35,6 +54,12 @@ public class Native {
|
|||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T extends NativeIntegration> T get(Class<T> type) {
|
||||||
|
init(null);
|
||||||
|
Platform platform = Platform.current();
|
||||||
if (platform.isPosix()) {
|
if (platform.isPosix()) {
|
||||||
if (type.equals(PosixFile.class)) {
|
if (type.equals(PosixFile.class)) {
|
||||||
return type.cast(new DefaultPosixFile());
|
return type.cast(new DefaultPosixFile());
|
||||||
@@ -56,4 +81,29 @@ public class Native {
|
|||||||
throw new UnsupportedOperationException(String.format("Cannot load unsupported native integration %s.",
|
throw new UnsupportedOperationException(String.format("Cannot load unsupported native integration %s.",
|
||||||
type.getName()));
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package net.rubygrapefruit.platform;
|
package net.rubygrapefruit.platform;
|
||||||
|
|
||||||
public class NativeException extends RuntimeException {
|
public class NativeException extends RuntimeException {
|
||||||
|
public NativeException(String message, Throwable throwable) {
|
||||||
|
super(message, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
public NativeException(String message) {
|
public NativeException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import net.rubygrapefruit.platform.internal.jni.PosixTerminalFunctions;
|
|||||||
|
|
||||||
public class TerminfoTerminalAccess implements TerminalAccess {
|
public class TerminfoTerminalAccess implements TerminalAccess {
|
||||||
private static Output currentlyOpen;
|
private static Output currentlyOpen;
|
||||||
|
private static TerminfoTerminal current;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTerminal(Output output) {
|
public boolean isTerminal(Output output) {
|
||||||
@@ -14,14 +15,15 @@ public class TerminfoTerminalAccess implements TerminalAccess {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Terminal getTerminal(Output output) {
|
public Terminal getTerminal(Output output) {
|
||||||
if (currentlyOpen != null) {
|
if (currentlyOpen != null && currentlyOpen != output) {
|
||||||
throw new UnsupportedOperationException("Currently only one output can be used as a terminal.");
|
throw new UnsupportedOperationException("Currently only one output can be used as a terminal.");
|
||||||
}
|
}
|
||||||
|
if (current == null) {
|
||||||
TerminfoTerminal terminal = new TerminfoTerminal(output);
|
current = new TerminfoTerminal(output);
|
||||||
terminal.init();
|
current.init();
|
||||||
|
}
|
||||||
|
|
||||||
currentlyOpen = output;
|
currentlyOpen = output;
|
||||||
return terminal;
|
return current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import net.rubygrapefruit.platform.internal.jni.WindowsConsoleFunctions;
|
|||||||
|
|
||||||
public class WindowsTerminalAccess implements TerminalAccess {
|
public class WindowsTerminalAccess implements TerminalAccess {
|
||||||
private static Output currentlyOpen;
|
private static Output currentlyOpen;
|
||||||
|
private static WindowsTerminal current;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTerminal(Output output) {
|
public boolean isTerminal(Output output) {
|
||||||
@@ -21,14 +22,16 @@ public class WindowsTerminalAccess implements TerminalAccess {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Terminal getTerminal(Output output) {
|
public Terminal getTerminal(Output output) {
|
||||||
if (currentlyOpen != null) {
|
if (currentlyOpen !=null && currentlyOpen != output) {
|
||||||
throw new UnsupportedOperationException("Currently only one output can be used as a terminal.");
|
throw new UnsupportedOperationException("Currently only one output can be used as a terminal.");
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowsTerminal terminal = new WindowsTerminal(output);
|
if (current == null) {
|
||||||
terminal.init();
|
current = new WindowsTerminal(output);
|
||||||
|
current.init();
|
||||||
|
}
|
||||||
|
|
||||||
currentlyOpen = output;
|
currentlyOpen = output;
|
||||||
return terminal;
|
return current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user