Extracted loading of native library out of Native into NativeLibraryLoader.

This commit is contained in:
Adam Murdoch
2012-11-12 17:00:29 +11:00
parent 1b4479a13e
commit c4a55e54e5
3 changed files with 72 additions and 39 deletions

View File

@@ -1,5 +1,6 @@
package net.rubygrapefruit.platform; package net.rubygrapefruit.platform;
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 net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
@@ -13,7 +14,7 @@ import java.util.Map;
*/ */
@ThreadSafe @ThreadSafe
public class Native { public class Native {
private static boolean loaded; private static NativeLibraryLoader loader;
private static final Map<Class<?>, Object> integrations = new HashMap<Class<?>, Object>(); private static final Map<Class<?>, Object> integrations = new HashMap<Class<?>, Object>();
private Native() { private Native() {
@@ -31,19 +32,15 @@ public class Native {
@ThreadSafe @ThreadSafe
static public void init(File extractDir) throws NativeIntegrationUnavailableException, NativeException { static public void init(File extractDir) throws NativeIntegrationUnavailableException, NativeException {
synchronized (Native.class) { synchronized (Native.class) {
if (!loaded) { if (loader == null) {
Platform platform = Platform.current(); Platform platform = Platform.current();
try { try {
File libFile = new NativeLibraryLocator(extractDir).find(platform.getLibraryName()); loader = new NativeLibraryLoader(new NativeLibraryLocator(extractDir));
if (libFile == null) { loader.load(platform.getLibraryName());
throw new NativeIntegrationUnavailableException(String.format("Native library is not available for this operating system and architecture."));
}
System.load(libFile.getCanonicalPath());
int nativeVersion = NativeLibraryFunctions.getVersion(); int nativeVersion = NativeLibraryFunctions.getVersion();
if (nativeVersion != NativeLibraryFunctions.VERSION) { if (nativeVersion != NativeLibraryFunctions.VERSION) {
throw new NativeException(String.format("Unexpected native library version loaded. Expected %s, was %s.", nativeVersion, NativeLibraryFunctions.VERSION)); throw new NativeException(String.format("Unexpected native library version loaded. Expected %s, was %s.", nativeVersion, NativeLibraryFunctions.VERSION));
} }
loaded = true;
} catch (NativeException e) { } catch (NativeException e) {
throw e; throw e;
} catch (Throwable t) { } catch (Throwable t) {
@@ -69,7 +66,7 @@ public class Native {
Object instance = integrations.get(type); Object instance = integrations.get(type);
if (instance == null) { if (instance == null) {
try { try {
instance = Platform.current().get(type); instance = Platform.current().get(type, loader);
} catch (NativeException e) { } catch (NativeException e) {
throw e; throw e;
} catch (Throwable t) { } catch (Throwable t) {

View File

@@ -0,0 +1,30 @@
package net.rubygrapefruit.platform.internal;
import net.rubygrapefruit.platform.NativeIntegrationUnavailableException;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
public class NativeLibraryLoader {
private final Set<String> loaded = new HashSet<String>();
private final NativeLibraryLocator locator;
public NativeLibraryLoader(NativeLibraryLocator locator) {
this.locator = locator;
}
public void load(String name) throws IOException {
if (loaded.contains(name)) {
return;
}
File libFile = locator.find(name);
if (libFile == null) {
throw new NativeIntegrationUnavailableException(String.format(
"Native library is not available for this operating system and architecture."));
}
System.load(libFile.getCanonicalPath());
loaded.add(name);
}
}

View File

@@ -10,12 +10,11 @@ public abstract class Platform {
synchronized (Platform.class) { synchronized (Platform.class) {
if (platform == null) { if (platform == null) {
String osName = getOperatingSystem().toLowerCase(); String osName = getOperatingSystem().toLowerCase();
String arch = getArchitecture();
if (osName.contains("windows")) { if (osName.contains("windows")) {
platform = new Windows(); platform = new Windows();
} else if (osName.contains("linux")) { } else if (osName.contains("linux")) {
platform = new Linux(); platform = new Linux();
} else if (osName.contains("os x") && (arch.equals("i386") || arch.equals("x86_64") || arch.equals("amd64"))) { } else if (osName.contains("os x")) {
platform = new OsX(); platform = new OsX();
} else if (osName.contains("sunos")) { } else if (osName.contains("sunos")) {
platform = new Solaris(); platform = new Solaris();
@@ -31,12 +30,28 @@ public abstract class Platform {
return false; return false;
} }
public <T extends NativeIntegration> T get(Class<T> type) { @Override
throw new NativeIntegrationUnavailableException(String.format("Native integration %s is not supported on this operating system (%s %s)", public String toString() {
type.getSimpleName(), getOperatingSystem(), getArchitecture())); return String.format("%s %s", getOperatingSystem(), getArchitecture());
} }
public abstract String getLibraryName() throws NativeIntegrationUnavailableException; public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
throw new NativeIntegrationUnavailableException(String.format("Native integration %s is not supported for the current operating system (%s)",
type.getSimpleName(), toString()));
}
public String getLibraryName() {
throw new NativeIntegrationUnavailableException(String.format(
"Native integration is not available for the current operating system (%s)", toString()));
}
private static String getOperatingSystem() {
return System.getProperty("os.name");
}
private static String getArchitecture() {
return System.getProperty("os.arch");
}
private static class Windows extends Platform { private static class Windows extends Platform {
@Override @Override
@@ -52,12 +67,11 @@ public abstract class Platform {
if (getArchitecture().equals("amd64")) { if (getArchitecture().equals("amd64")) {
return "native-platform-windows-amd64.dll"; return "native-platform-windows-amd64.dll";
} }
throw new NativeIntegrationUnavailableException(String.format( return super.getLibraryName();
"Native integration is not available for this architecture (%s) on Windows.", getArchitecture()));
} }
@Override @Override
public <T extends NativeIntegration> T get(Class<T> type) { public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
if (type.equals(Process.class)) { if (type.equals(Process.class)) {
return type.cast(new DefaultProcess()); return type.cast(new DefaultProcess());
} }
@@ -70,13 +84,13 @@ public abstract class Platform {
if (type.equals(FileSystems.class)) { if (type.equals(FileSystems.class)) {
return type.cast(new PosixFileSystems()); return type.cast(new PosixFileSystems());
} }
return super.get(type); return super.get(type, nativeLibraryLoader);
} }
} }
private static abstract class Posix extends Platform { private static abstract class Posix extends Platform {
@Override @Override
public <T extends NativeIntegration> T get(Class<T> type) { public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
if (type.equals(PosixFile.class)) { if (type.equals(PosixFile.class)) {
return type.cast(new DefaultPosixFile()); return type.cast(new DefaultPosixFile());
} }
@@ -89,7 +103,7 @@ public abstract class Platform {
if (type.equals(SystemInfo.class)) { if (type.equals(SystemInfo.class)) {
return type.cast(new DefaultSystemInfo()); return type.cast(new DefaultSystemInfo());
} }
return super.get(type); return super.get(type, nativeLibraryLoader);
} }
} }
@@ -98,11 +112,11 @@ public abstract class Platform {
private static class Linux extends Unix { private static class Linux extends Unix {
@Override @Override
public <T extends NativeIntegration> T get(Class<T> type) { public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
if (type.equals(FileSystems.class)) { if (type.equals(FileSystems.class)) {
return type.cast(new PosixFileSystems()); return type.cast(new PosixFileSystems());
} }
return super.get(type); return super.get(type, nativeLibraryLoader);
} }
@Override @Override
@@ -113,14 +127,10 @@ public abstract class Platform {
if (getArchitecture().equals("i386") || getArchitecture().equals("x86")) { if (getArchitecture().equals("i386") || getArchitecture().equals("x86")) {
return "libnative-platform-linux-i386.so"; return "libnative-platform-linux-i386.so";
} }
throw new NativeIntegrationUnavailableException(String.format( return super.getLibraryName();
"Native integration is not available for this architecture (%s) on Linux.", getArchitecture()));
} }
} }
private static String getArchitecture() {
return System.getProperty("os.arch");
}
private static class Solaris extends Unix { private static class Solaris extends Unix {
@Override @Override
@@ -131,28 +141,24 @@ public abstract class Platform {
private static class OsX extends Posix { private static class OsX extends Posix {
@Override @Override
public <T extends NativeIntegration> T get(Class<T> type) { public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
if (type.equals(FileSystems.class)) { if (type.equals(FileSystems.class)) {
return type.cast(new PosixFileSystems()); return type.cast(new PosixFileSystems());
} }
return super.get(type); return super.get(type, nativeLibraryLoader);
} }
@Override @Override
public String getLibraryName() { public String getLibraryName() {
String arch = getArchitecture();
if (arch.equals("i386") || arch.equals("x86_64") || arch.equals("amd64")) {
return "libnative-platform-osx-universal.dylib"; return "libnative-platform-osx-universal.dylib";
} }
return super.getLibraryName();
}
} }
private static class Unsupported extends Platform { private static class Unsupported extends Platform {
public String getLibraryName() {
throw new NativeIntegrationUnavailableException(String.format(
"Native integration is not available for this operating system (%s %s)", getOperatingSystem(),
getArchitecture()));
}
} }
private static String getOperatingSystem() {
return System.getProperty("os.name");
}
} }