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;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import net.rubygrapefruit.platform.internal.NativeLibraryLoader;
|
||||
import net.rubygrapefruit.platform.internal.NativeLibraryLocator;
|
||||
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.
|
||||
@@ -31,7 +28,6 @@ import java.util.Map;
|
||||
@ThreadSafe
|
||||
public class Native {
|
||||
private static NativeLibraryLoader loader;
|
||||
private static final Map<Class<?>, Object> integrations = new HashMap<Class<?>, Object>();
|
||||
|
||||
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
|
||||
* selected.
|
||||
*
|
||||
* @throws NativeIntegrationUnavailableException When native integration is not available on the current machine.
|
||||
* @throws NativeException On failure to load the native integration.
|
||||
* @throws NativeLibraryUnavailableException When the native library is not available on the current machine.
|
||||
* @throws NativeException On failure to load the native library.
|
||||
*/
|
||||
@ThreadSafe
|
||||
static public void init(File extractDir) throws NativeIntegrationUnavailableException, NativeException {
|
||||
static public void init(File extractDir) throws NativeLibraryUnavailableException, NativeException {
|
||||
synchronized (Native.class) {
|
||||
if (loader == null) {
|
||||
Platform platform = Platform.current();
|
||||
try {
|
||||
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) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
@@ -66,31 +57,14 @@ public class Native {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates a native integration of the given type.
|
||||
*
|
||||
* @return The native integration. Never returns null.
|
||||
* @throws NativeIntegrationUnavailableException When the given native integration is not available on the current
|
||||
* machine.
|
||||
* @throws NativeException On failure to load the native integration.
|
||||
*/
|
||||
@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);
|
||||
public static void load(String group, String name) {
|
||||
init(null);
|
||||
try {
|
||||
loader.load(group, Platform.current().getLibraryName(name));
|
||||
} catch (NativeException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new NativeException("Failed to load native library.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ package net.rubygrapefruit.platform;
|
||||
/**
|
||||
* Thrown when a given integration is not available for the current machine.
|
||||
*/
|
||||
public class NativeIntegrationUnavailableException extends NativeException {
|
||||
public NativeIntegrationUnavailableException(String message) {
|
||||
public class NativeLibraryUnavailableException extends NativeException {
|
||||
public NativeLibraryUnavailableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package net.rubygrapefruit.platform.internal;
|
||||
|
||||
public class LibraryDef {
|
||||
final String group;
|
||||
final String name;
|
||||
final String platform;
|
||||
|
||||
public LibraryDef(String name, String platform) {
|
||||
public LibraryDef(String group, String name, String platform) {
|
||||
this.group = group;
|
||||
this.name = name;
|
||||
this.platform = platform;
|
||||
}
|
||||
@@ -25,4 +27,8 @@ public class LibraryDef {
|
||||
public int hashCode() {
|
||||
return name.hashCode() ^ platform.hashCode();
|
||||
}
|
||||
|
||||
public String getGroupPath() {
|
||||
return group.replace(".", "/");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package net.rubygrapefruit.platform.internal;
|
||||
|
||||
import net.rubygrapefruit.platform.NativeException;
|
||||
import net.rubygrapefruit.platform.NativeIntegrationUnavailableException;
|
||||
import net.rubygrapefruit.platform.NativeLibraryUnavailableException;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
@@ -33,14 +33,14 @@ public class NativeLibraryLoader {
|
||||
this.nativeLibraryLocator = nativeLibraryLocator;
|
||||
}
|
||||
|
||||
public void load(String libraryFileName) {
|
||||
public void load(String libraryGroupName, String libraryFileName) {
|
||||
if (loaded.contains(libraryFileName)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
File libFile = nativeLibraryLocator.find(new LibraryDef(libraryFileName, platform.getId()));
|
||||
File libFile = nativeLibraryLocator.find(new LibraryDef(libraryGroupName, libraryFileName, platform.getId()));
|
||||
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());
|
||||
} catch (NativeException e) {
|
||||
|
||||
@@ -31,7 +31,8 @@ public class NativeLibraryLocator {
|
||||
}
|
||||
|
||||
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) {
|
||||
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");
|
||||
@@ -62,7 +63,7 @@ public class NativeLibraryLocator {
|
||||
URL resource = getClass().getClassLoader().getResource(resourceName);
|
||||
if (resource != null) {
|
||||
File libFile;
|
||||
File libDir = File.createTempFile("native-platform", "dir");
|
||||
File libDir = File.createTempFile(libraryDef.name, "dir");
|
||||
libDir.delete();
|
||||
libDir.mkdirs();
|
||||
libFile = new File(libDir, libraryDef.name);
|
||||
|
||||
@@ -16,10 +16,8 @@
|
||||
|
||||
package net.rubygrapefruit.platform.internal;
|
||||
|
||||
import net.rubygrapefruit.platform.*;
|
||||
import net.rubygrapefruit.platform.Process;
|
||||
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
||||
import net.rubygrapefruit.platform.internal.jni.TerminfoFunctions;
|
||||
import net.rubygrapefruit.platform.NativeIntegration;
|
||||
import net.rubygrapefruit.platform.NativeLibraryUnavailableException;
|
||||
|
||||
public abstract class Platform {
|
||||
private static Platform platform;
|
||||
@@ -77,11 +75,11 @@ public abstract class Platform {
|
||||
}
|
||||
|
||||
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() {
|
||||
throw new NativeIntegrationUnavailableException(String.format("Native integration is not available for %s.", toString()));
|
||||
public String getLibraryName(String name) {
|
||||
throw new NativeLibraryUnavailableException(String.format("Native integration is not available for %s.", toString()));
|
||||
}
|
||||
|
||||
public abstract String getId();
|
||||
@@ -101,30 +99,12 @@ public abstract class Platform {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLibraryName() {
|
||||
return "native-platform.dll";
|
||||
public String getLibraryName(String name) {
|
||||
return String.format("%s.dll", name);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -144,46 +124,16 @@ public abstract class Platform {
|
||||
}
|
||||
|
||||
private static abstract class Posix extends Platform {
|
||||
abstract String getCursesLibraryName();
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class Unix extends Posix {
|
||||
@Override
|
||||
public String getLibraryName() {
|
||||
return "libnative-platform.so";
|
||||
}
|
||||
|
||||
@Override
|
||||
String getCursesLibraryName() {
|
||||
return "libnative-platform-curses.so";
|
||||
public String getLibraryName(String name) {
|
||||
return String.format("lib%s.so", name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,13 +167,8 @@ public abstract class Platform {
|
||||
|
||||
private static abstract class OsX extends Posix {
|
||||
@Override
|
||||
public String getLibraryName() {
|
||||
return "libnative-platform.dylib";
|
||||
}
|
||||
|
||||
@Override
|
||||
String getCursesLibraryName() {
|
||||
return "libnative-platform-curses.dylib";
|
||||
public String getLibraryName(String name) {
|
||||
return String.format("lib%s.dylib", name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,5 +192,4 @@ public abstract class Platform {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user