Refactor code to allow loading of arbitrary libraries from group and name of artifact

This commit is contained in:
2014-11-09 21:28:51 +00:00
parent 6d80bdcca6
commit 0a41017b02
6 changed files with 41 additions and 116 deletions

View File

@@ -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.");
}
}
}

View File

@@ -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);
}
}

View File

@@ -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(".", "/");
}
}

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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();
}
}
}
}