Refactor code to allow loading of arbitrary libraries from group and name of artifact
This commit is contained in:
@@ -16,14 +16,11 @@
|
|||||||
|
|
||||||
package net.rubygrapefruit.platform;
|
package net.rubygrapefruit.platform;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.NativeLibraryLoader;
|
import net.rubygrapefruit.platform.internal.NativeLibraryLoader;
|
||||||
import net.rubygrapefruit.platform.internal.NativeLibraryLocator;
|
import net.rubygrapefruit.platform.internal.NativeLibraryLocator;
|
||||||
import net.rubygrapefruit.platform.internal.Platform;
|
import net.rubygrapefruit.platform.internal.Platform;
|
||||||
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
@@ -31,7 +28,6 @@ import java.util.Map;
|
|||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
public class Native {
|
public class Native {
|
||||||
private static NativeLibraryLoader loader;
|
private static NativeLibraryLoader loader;
|
||||||
private static final Map<Class<?>, Object> integrations = new HashMap<Class<?>, Object>();
|
|
||||||
|
|
||||||
private Native() {
|
private Native() {
|
||||||
}
|
}
|
||||||
@@ -42,21 +38,16 @@ public class Native {
|
|||||||
* @param extractDir The directory to extract native resources into. May be null, in which case a default is
|
* @param extractDir The directory to extract native resources into. May be null, in which case a default is
|
||||||
* selected.
|
* selected.
|
||||||
*
|
*
|
||||||
* @throws NativeIntegrationUnavailableException When native integration is not available on the current machine.
|
* @throws NativeLibraryUnavailableException When the native library is not available on the current machine.
|
||||||
* @throws NativeException On failure to load the native integration.
|
* @throws NativeException On failure to load the native library.
|
||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
static public void init(File extractDir) throws NativeIntegrationUnavailableException, NativeException {
|
static public void init(File extractDir) throws NativeLibraryUnavailableException, NativeException {
|
||||||
synchronized (Native.class) {
|
synchronized (Native.class) {
|
||||||
if (loader == null) {
|
if (loader == null) {
|
||||||
Platform platform = Platform.current();
|
Platform platform = Platform.current();
|
||||||
try {
|
try {
|
||||||
loader = new NativeLibraryLoader(platform, new NativeLibraryLocator(extractDir));
|
loader = new NativeLibraryLoader(platform, new NativeLibraryLocator(extractDir));
|
||||||
loader.load(platform.getLibraryName());
|
|
||||||
int nativeVersion = NativeLibraryFunctions.getVersion();
|
|
||||||
if (nativeVersion != NativeLibraryFunctions.VERSION) {
|
|
||||||
throw new NativeException(String.format("Unexpected native library version loaded. Expected %s, was %s.", NativeLibraryFunctions.VERSION, nativeVersion));
|
|
||||||
}
|
|
||||||
} catch (NativeException e) {
|
} catch (NativeException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
@@ -66,31 +57,14 @@ public class Native {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static void load(String group, String name) {
|
||||||
* Locates a native integration of the given type.
|
init(null);
|
||||||
*
|
try {
|
||||||
* @return The native integration. Never returns null.
|
loader.load(group, Platform.current().getLibraryName(name));
|
||||||
* @throws NativeIntegrationUnavailableException When the given native integration is not available on the current
|
} catch (NativeException e) {
|
||||||
* machine.
|
throw e;
|
||||||
* @throws NativeException On failure to load the native integration.
|
} catch (Throwable t) {
|
||||||
*/
|
throw new NativeException("Failed to load native library.");
|
||||||
@ThreadSafe
|
|
||||||
public static <T extends NativeIntegration> T get(Class<T> type)
|
|
||||||
throws NativeIntegrationUnavailableException, NativeException {
|
|
||||||
init(null);
|
|
||||||
synchronized (Native.class) {
|
|
||||||
Object instance = integrations.get(type);
|
|
||||||
if (instance == null) {
|
|
||||||
try {
|
|
||||||
instance = Platform.current().get(type, loader);
|
|
||||||
} catch (NativeException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (Throwable t) {
|
|
||||||
throw new NativeException(String.format("Failed to load native integration %s.", type.getSimpleName()), t);
|
|
||||||
}
|
|
||||||
integrations.put(type, instance);
|
|
||||||
}
|
|
||||||
return type.cast(instance);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ package net.rubygrapefruit.platform;
|
|||||||
/**
|
/**
|
||||||
* Thrown when a given integration is not available for the current machine.
|
* Thrown when a given integration is not available for the current machine.
|
||||||
*/
|
*/
|
||||||
public class NativeIntegrationUnavailableException extends NativeException {
|
public class NativeLibraryUnavailableException extends NativeException {
|
||||||
public NativeIntegrationUnavailableException(String message) {
|
public NativeLibraryUnavailableException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package net.rubygrapefruit.platform.internal;
|
package net.rubygrapefruit.platform.internal;
|
||||||
|
|
||||||
public class LibraryDef {
|
public class LibraryDef {
|
||||||
|
final String group;
|
||||||
final String name;
|
final String name;
|
||||||
final String platform;
|
final String platform;
|
||||||
|
|
||||||
public LibraryDef(String name, String platform) {
|
public LibraryDef(String group, String name, String platform) {
|
||||||
|
this.group = group;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.platform = platform;
|
this.platform = platform;
|
||||||
}
|
}
|
||||||
@@ -25,4 +27,8 @@ public class LibraryDef {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return name.hashCode() ^ platform.hashCode();
|
return name.hashCode() ^ platform.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getGroupPath() {
|
||||||
|
return group.replace(".", "/");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
package net.rubygrapefruit.platform.internal;
|
package net.rubygrapefruit.platform.internal;
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
import net.rubygrapefruit.platform.NativeException;
|
||||||
import net.rubygrapefruit.platform.NativeIntegrationUnavailableException;
|
import net.rubygrapefruit.platform.NativeLibraryUnavailableException;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -33,14 +33,14 @@ public class NativeLibraryLoader {
|
|||||||
this.nativeLibraryLocator = nativeLibraryLocator;
|
this.nativeLibraryLocator = nativeLibraryLocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void load(String libraryFileName) {
|
public void load(String libraryGroupName, String libraryFileName) {
|
||||||
if (loaded.contains(libraryFileName)) {
|
if (loaded.contains(libraryFileName)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
File libFile = nativeLibraryLocator.find(new LibraryDef(libraryFileName, platform.getId()));
|
File libFile = nativeLibraryLocator.find(new LibraryDef(libraryGroupName, libraryFileName, platform.getId()));
|
||||||
if (libFile == null) {
|
if (libFile == null) {
|
||||||
throw new NativeIntegrationUnavailableException(String.format("Native library '%s' is not available for %s.", libraryFileName, platform));
|
throw new NativeLibraryUnavailableException(String.format("Native library '%s' is not available for %s.", libraryFileName, platform));
|
||||||
}
|
}
|
||||||
System.load(libFile.getCanonicalPath());
|
System.load(libFile.getCanonicalPath());
|
||||||
} catch (NativeException e) {
|
} catch (NativeException e) {
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ public class NativeLibraryLocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public File find(LibraryDef libraryDef) throws IOException {
|
public File find(LibraryDef libraryDef) throws IOException {
|
||||||
String resourceName = String.format("net/rubygrapefruit/platform/%s/%s", libraryDef.platform, libraryDef.name);
|
String resourceName = String.format("%s/%s/%s", libraryDef.getGroupPath(), libraryDef.platform, libraryDef.name);
|
||||||
|
System.out.println(resourceName);
|
||||||
if (extractDir != null) {
|
if (extractDir != null) {
|
||||||
File libFile = new File(extractDir, String.format("%s/%s/%s", NativeLibraryFunctions.VERSION, libraryDef.platform, libraryDef.name));
|
File libFile = new File(extractDir, String.format("%s/%s/%s", NativeLibraryFunctions.VERSION, libraryDef.platform, libraryDef.name));
|
||||||
File lockFile = new File(libFile.getParentFile(), libFile.getName() + ".lock");
|
File lockFile = new File(libFile.getParentFile(), libFile.getName() + ".lock");
|
||||||
@@ -62,7 +63,7 @@ public class NativeLibraryLocator {
|
|||||||
URL resource = getClass().getClassLoader().getResource(resourceName);
|
URL resource = getClass().getClassLoader().getResource(resourceName);
|
||||||
if (resource != null) {
|
if (resource != null) {
|
||||||
File libFile;
|
File libFile;
|
||||||
File libDir = File.createTempFile("native-platform", "dir");
|
File libDir = File.createTempFile(libraryDef.name, "dir");
|
||||||
libDir.delete();
|
libDir.delete();
|
||||||
libDir.mkdirs();
|
libDir.mkdirs();
|
||||||
libFile = new File(libDir, libraryDef.name);
|
libFile = new File(libDir, libraryDef.name);
|
||||||
|
|||||||
@@ -16,10 +16,8 @@
|
|||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
package net.rubygrapefruit.platform.internal;
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.*;
|
import net.rubygrapefruit.platform.NativeIntegration;
|
||||||
import net.rubygrapefruit.platform.Process;
|
import net.rubygrapefruit.platform.NativeLibraryUnavailableException;
|
||||||
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.TerminfoFunctions;
|
|
||||||
|
|
||||||
public abstract class Platform {
|
public abstract class Platform {
|
||||||
private static Platform platform;
|
private static Platform platform;
|
||||||
@@ -77,11 +75,11 @@ public abstract class Platform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
|
public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
|
||||||
throw new NativeIntegrationUnavailableException(String.format("Native integration %s is not supported for %s.", type.getSimpleName(), toString()));
|
throw new NativeLibraryUnavailableException(String.format("Native integration %s is not supported for %s.", type.getSimpleName(), toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLibraryName() {
|
public String getLibraryName(String name) {
|
||||||
throw new NativeIntegrationUnavailableException(String.format("Native integration is not available for %s.", toString()));
|
throw new NativeLibraryUnavailableException(String.format("Native integration is not available for %s.", toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract String getId();
|
public abstract String getId();
|
||||||
@@ -101,30 +99,12 @@ public abstract class Platform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLibraryName() {
|
public String getLibraryName(String name) {
|
||||||
return "native-platform.dll";
|
return String.format("%s.dll", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
|
public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
|
||||||
if (type.equals(Process.class)) {
|
|
||||||
return type.cast(new WrapperProcess(new DefaultProcess(), true));
|
|
||||||
}
|
|
||||||
if (type.equals(Terminals.class)) {
|
|
||||||
return type.cast(new WindowsTerminals());
|
|
||||||
}
|
|
||||||
if (type.equals(ProcessLauncher.class)) {
|
|
||||||
return type.cast(new WrapperProcessLauncher(new WindowsProcessLauncher(new DefaultProcessLauncher())));
|
|
||||||
}
|
|
||||||
if (type.equals(SystemInfo.class)) {
|
|
||||||
return type.cast(new DefaultSystemInfo());
|
|
||||||
}
|
|
||||||
if (type.equals(FileSystems.class)) {
|
|
||||||
return type.cast(new PosixFileSystems());
|
|
||||||
}
|
|
||||||
if (type.equals(WindowsRegistry.class)) {
|
|
||||||
return type.cast(new DefaultWindowsRegistry());
|
|
||||||
}
|
|
||||||
return super.get(type, nativeLibraryLoader);
|
return super.get(type, nativeLibraryLoader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,46 +124,16 @@ public abstract class Platform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static abstract class Posix extends Platform {
|
private static abstract class Posix extends Platform {
|
||||||
abstract String getCursesLibraryName();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
|
public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
|
||||||
if (type.equals(PosixFiles.class)) {
|
|
||||||
return type.cast(new DefaultPosixFiles());
|
|
||||||
}
|
|
||||||
if (type.equals(Process.class)) {
|
|
||||||
return type.cast(new WrapperProcess(new DefaultProcess(), false));
|
|
||||||
}
|
|
||||||
if (type.equals(ProcessLauncher.class)) {
|
|
||||||
return type.cast(new WrapperProcessLauncher(new DefaultProcessLauncher()));
|
|
||||||
}
|
|
||||||
if (type.equals(Terminals.class)) {
|
|
||||||
nativeLibraryLoader.load(getCursesLibraryName());
|
|
||||||
int nativeVersion = TerminfoFunctions.getVersion();
|
|
||||||
if (nativeVersion != NativeLibraryFunctions.VERSION) {
|
|
||||||
throw new NativeException(String.format("Unexpected native library version loaded. Expected %s, was %s.", nativeVersion, NativeLibraryFunctions.VERSION));
|
|
||||||
}
|
|
||||||
return type.cast(new TerminfoTerminals());
|
|
||||||
}
|
|
||||||
if (type.equals(SystemInfo.class)) {
|
|
||||||
return type.cast(new DefaultSystemInfo());
|
|
||||||
}
|
|
||||||
if (type.equals(FileSystems.class)) {
|
|
||||||
return type.cast(new PosixFileSystems());
|
|
||||||
}
|
|
||||||
return super.get(type, nativeLibraryLoader);
|
return super.get(type, nativeLibraryLoader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract static class Unix extends Posix {
|
private abstract static class Unix extends Posix {
|
||||||
@Override
|
@Override
|
||||||
public String getLibraryName() {
|
public String getLibraryName(String name) {
|
||||||
return "libnative-platform.so";
|
return String.format("lib%s.so", name);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String getCursesLibraryName() {
|
|
||||||
return "libnative-platform-curses.so";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,13 +167,8 @@ public abstract class Platform {
|
|||||||
|
|
||||||
private static abstract class OsX extends Posix {
|
private static abstract class OsX extends Posix {
|
||||||
@Override
|
@Override
|
||||||
public String getLibraryName() {
|
public String getLibraryName(String name) {
|
||||||
return "libnative-platform.dylib";
|
return String.format("lib%s.dylib", name);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String getCursesLibraryName() {
|
|
||||||
return "libnative-platform-curses.dylib";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,5 +192,4 @@ public abstract class Platform {
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user