diff --git a/src/main/java/net/rubygrapefruit/platform/Native.java b/src/main/java/net/rubygrapefruit/platform/Native.java index a8f673d..4416d3c 100755 --- a/src/main/java/net/rubygrapefruit/platform/Native.java +++ b/src/main/java/net/rubygrapefruit/platform/Native.java @@ -1,5 +1,6 @@ package net.rubygrapefruit.platform; +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; @@ -13,7 +14,7 @@ import java.util.Map; */ @ThreadSafe public class Native { - private static boolean loaded; + private static NativeLibraryLoader loader; private static final Map, Object> integrations = new HashMap, Object>(); private Native() { @@ -31,19 +32,15 @@ public class Native { @ThreadSafe static public void init(File extractDir) throws NativeIntegrationUnavailableException, NativeException { synchronized (Native.class) { - if (!loaded) { + if (loader == null) { Platform platform = Platform.current(); try { - File libFile = new NativeLibraryLocator(extractDir).find(platform.getLibraryName()); - if (libFile == null) { - throw new NativeIntegrationUnavailableException(String.format("Native library is not available for this operating system and architecture.")); - } - System.load(libFile.getCanonicalPath()); + loader = new NativeLibraryLoader(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.", nativeVersion, NativeLibraryFunctions.VERSION)); } - loaded = true; } catch (NativeException e) { throw e; } catch (Throwable t) { @@ -69,7 +66,7 @@ public class Native { Object instance = integrations.get(type); if (instance == null) { try { - instance = Platform.current().get(type); + instance = Platform.current().get(type, loader); } catch (NativeException e) { throw e; } catch (Throwable t) { diff --git a/src/main/java/net/rubygrapefruit/platform/internal/NativeLibraryLoader.java b/src/main/java/net/rubygrapefruit/platform/internal/NativeLibraryLoader.java new file mode 100644 index 0000000..5f96e17 --- /dev/null +++ b/src/main/java/net/rubygrapefruit/platform/internal/NativeLibraryLoader.java @@ -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 loaded = new HashSet(); + 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); + } +} diff --git a/src/main/java/net/rubygrapefruit/platform/internal/Platform.java b/src/main/java/net/rubygrapefruit/platform/internal/Platform.java index 884532f..f25c455 100755 --- a/src/main/java/net/rubygrapefruit/platform/internal/Platform.java +++ b/src/main/java/net/rubygrapefruit/platform/internal/Platform.java @@ -10,12 +10,11 @@ public abstract class Platform { synchronized (Platform.class) { if (platform == null) { String osName = getOperatingSystem().toLowerCase(); - String arch = getArchitecture(); if (osName.contains("windows")) { platform = new Windows(); } else if (osName.contains("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(); } else if (osName.contains("sunos")) { platform = new Solaris(); @@ -31,12 +30,28 @@ public abstract class Platform { return false; } - public T get(Class type) { - throw new NativeIntegrationUnavailableException(String.format("Native integration %s is not supported on this operating system (%s %s)", - type.getSimpleName(), getOperatingSystem(), getArchitecture())); + @Override + public String toString() { + return String.format("%s %s", getOperatingSystem(), getArchitecture()); } - public abstract String getLibraryName() throws NativeIntegrationUnavailableException; + public T get(Class 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 { @Override @@ -52,12 +67,11 @@ public abstract class Platform { if (getArchitecture().equals("amd64")) { return "native-platform-windows-amd64.dll"; } - throw new NativeIntegrationUnavailableException(String.format( - "Native integration is not available for this architecture (%s) on Windows.", getArchitecture())); + return super.getLibraryName(); } @Override - public T get(Class type) { + public T get(Class type, NativeLibraryLoader nativeLibraryLoader) { if (type.equals(Process.class)) { return type.cast(new DefaultProcess()); } @@ -70,13 +84,13 @@ public abstract class Platform { if (type.equals(FileSystems.class)) { return type.cast(new PosixFileSystems()); } - return super.get(type); + return super.get(type, nativeLibraryLoader); } } private static abstract class Posix extends Platform { @Override - public T get(Class type) { + public T get(Class type, NativeLibraryLoader nativeLibraryLoader) { if (type.equals(PosixFile.class)) { return type.cast(new DefaultPosixFile()); } @@ -89,7 +103,7 @@ public abstract class Platform { if (type.equals(SystemInfo.class)) { 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 { @Override - public T get(Class type) { + public T get(Class type, NativeLibraryLoader nativeLibraryLoader) { if (type.equals(FileSystems.class)) { return type.cast(new PosixFileSystems()); } - return super.get(type); + return super.get(type, nativeLibraryLoader); } @Override @@ -113,14 +127,10 @@ public abstract class Platform { if (getArchitecture().equals("i386") || getArchitecture().equals("x86")) { return "libnative-platform-linux-i386.so"; } - throw new NativeIntegrationUnavailableException(String.format( - "Native integration is not available for this architecture (%s) on Linux.", getArchitecture())); + return super.getLibraryName(); } } - private static String getArchitecture() { - return System.getProperty("os.arch"); - } private static class Solaris extends Unix { @Override @@ -131,28 +141,24 @@ public abstract class Platform { private static class OsX extends Posix { @Override - public T get(Class type) { + public T get(Class type, NativeLibraryLoader nativeLibraryLoader) { if (type.equals(FileSystems.class)) { return type.cast(new PosixFileSystems()); } - return super.get(type); + return super.get(type, nativeLibraryLoader); } @Override public String getLibraryName() { - return "libnative-platform-osx-universal.dylib"; + String arch = getArchitecture(); + if (arch.equals("i386") || arch.equals("x86_64") || arch.equals("amd64")) { + return "libnative-platform-osx-universal.dylib"; + } + return super.getLibraryName(); } } 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"); - } }