From dd8d5471ea139e6f59c3f4e589260ea74e707ffd Mon Sep 17 00:00:00 2001 From: Adam Retter Date: Sat, 31 Jan 2015 22:24:35 +0000 Subject: [PATCH] Adjustment to NativeLibraryLoader to allow native library to be loaded from either java.library.path or from extracting from the Jar. Means that the test in the build do not need to rely on the Jar, useful when creating similar builds (and executing tests) from Maven --- .../java/org/rocksdb/NativeLibraryLoader.java | 40 ++++++++++++++++--- java/src/main/java/org/rocksdb/RocksDB.java | 6 +-- .../java/org/rocksdb/util/Environment.java | 24 ++++++++--- .../org/rocksdb/util/EnvironmentTest.java | 36 ++++++++--------- 4 files changed, 74 insertions(+), 32 deletions(-) diff --git a/java/src/main/java/org/rocksdb/NativeLibraryLoader.java b/java/src/main/java/org/rocksdb/NativeLibraryLoader.java index fb09d3600..06ae773cb 100644 --- a/java/src/main/java/org/rocksdb/NativeLibraryLoader.java +++ b/java/src/main/java/org/rocksdb/NativeLibraryLoader.java @@ -15,7 +15,9 @@ public class NativeLibraryLoader { private static final NativeLibraryLoader instance = new NativeLibraryLoader(); private static boolean initialized = false; - private static final String sharedLibraryName = Environment.getJniLibraryName("rocksdb"); + private static final String sharedLibraryName = Environment.getSharedLibraryName("rocksdb"); + private static final String jniLibraryName = Environment.getJniLibraryName("rocksdb"); + private static final String jniLibraryFileName = Environment.getJniLibraryFileName("rocksdb"); private static final String tempFilePrefix = "librocksdbjni"; private static final String tempFileSuffix = "." + Environment.getJniLibraryExtension(); @@ -28,6 +30,34 @@ public class NativeLibraryLoader { return instance; } + /** + * Firstly attempts to load the library from java.library.path, + * if that fails then it falls back to extracting + * the library from the classpath + * {@link org.rocksdb.NativeLibraryLoader#loadLibraryFromJar(java.lang.String)} + * + * @param tmpDir A temporary directory to use + * to copy the native library to when loading from the classpath. + * If null, or the empty string, we rely on Java's + * {@link java.io.File#createTempFile(String, String)} + * function to provide a temporary location. + * The temporary file will be registered for deletion + * on exit. + * + * @throws java.io.IOException if a filesystem operation fails. + */ + public synchronized void loadLibrary(final String tmpDir) throws IOException { + try { + System.loadLibrary(sharedLibraryName); + } catch(final UnsatisfiedLinkError ule1) { + try { + System.loadLibrary(jniLibraryName); + } catch(final UnsatisfiedLinkError ule2) { + loadLibraryFromJar(tmpDir); + } + } + } + /** * Attempts to extract the native RocksDB library * from the classpath and load it @@ -42,14 +72,14 @@ public class NativeLibraryLoader { * * @throws java.io.IOException if a filesystem operation fails. */ - public synchronized void loadLibraryFromJar(final String tmpDir) + private void loadLibraryFromJar(final String tmpDir) throws IOException { if (!initialized) { final File temp; if (tmpDir == null || tmpDir.equals("")) { temp = File.createTempFile(tempFilePrefix, tempFileSuffix); } else { - temp = new File(tmpDir, sharedLibraryName); + temp = new File(tmpDir, jniLibraryFileName); } if (!temp.exists()) { @@ -60,9 +90,9 @@ public class NativeLibraryLoader { // attempt to copy the library from the Jar file to the temp destination try (final InputStream is = getClass().getClassLoader(). - getResourceAsStream(sharedLibraryName)) { + getResourceAsStream(jniLibraryFileName)) { if (is == null) { - throw new RuntimeException(sharedLibraryName + " was not found inside JAR."); + throw new RuntimeException(jniLibraryFileName + " was not found inside JAR."); } else { Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING); } diff --git a/java/src/main/java/org/rocksdb/RocksDB.java b/java/src/main/java/org/rocksdb/RocksDB.java index ea3824196..ed8b05b93 100644 --- a/java/src/main/java/org/rocksdb/RocksDB.java +++ b/java/src/main/java/org/rocksdb/RocksDB.java @@ -44,7 +44,7 @@ public class RocksDB extends RocksObject { } try { - NativeLibraryLoader.getInstance().loadLibraryFromJar(tmpDir); + NativeLibraryLoader.getInstance().loadLibrary(tmpDir); } catch (IOException e) { @@ -66,7 +66,7 @@ public class RocksDB extends RocksObject { } for (String path : paths) { try { - System.load(path + "/" + Environment.getSharedLibraryName( + System.load(path + "/" + Environment.getSharedLibraryFileName( compressionType.getLibraryName())); break; } catch (UnsatisfiedLinkError e) { @@ -78,7 +78,7 @@ public class RocksDB extends RocksObject { UnsatisfiedLinkError err = null; for (String path : paths) { try { - System.load(path + "/" + Environment.getJniLibraryName("rocksdbjni")); + System.load(path + "/" + Environment.getJniLibraryFileName("rocksdbjni")); success = true; break; } catch (UnsatisfiedLinkError e) { diff --git a/java/src/main/java/org/rocksdb/util/Environment.java b/java/src/main/java/org/rocksdb/util/Environment.java index c121adb17..6b5a9f2c8 100644 --- a/java/src/main/java/org/rocksdb/util/Environment.java +++ b/java/src/main/java/org/rocksdb/util/Environment.java @@ -23,20 +23,32 @@ public class Environment { } public static String getSharedLibraryName(String name) { + return name + "jni"; + } + + public static String getSharedLibraryFileName(String name) { + return appendLibOsSuffix("lib" + getSharedLibraryName(name), true); + } + + public static String getJniLibraryName(final String name) { if (isUnix()) { - return String.format("lib%sjni.so", name); + final String arch = (is64Bit()) ? "64" : "32"; + return String.format("%sjni-linux%s", name, arch); } else if (isMac()) { - return String.format("lib%sjni.dylib", name); + return String.format("%sjni-osx", name); } throw new UnsupportedOperationException(); } - public static String getJniLibraryName(String name) { + public static String getJniLibraryFileName(final String name) { + return appendLibOsSuffix("lib" + getJniLibraryName(name), false); + } + + private static String appendLibOsSuffix(final String libraryFileName, final boolean shared) { if (isUnix()) { - String arch = (is64Bit()) ? "64" : "32"; - return String.format("lib%sjni-linux%s.so", name, arch); + return libraryFileName + ".so"; } else if (isMac()) { - return String.format("lib%sjni-osx.jnilib", name); + return libraryFileName + (shared ? ".dylib" : ".jnilib"); } throw new UnsupportedOperationException(); } diff --git a/java/src/test/java/org/rocksdb/util/EnvironmentTest.java b/java/src/test/java/org/rocksdb/util/EnvironmentTest.java index b8e22bce1..741effebb 100644 --- a/java/src/test/java/org/rocksdb/util/EnvironmentTest.java +++ b/java/src/test/java/org/rocksdb/util/EnvironmentTest.java @@ -23,9 +23,9 @@ public class EnvironmentTest { assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). isEqualTo(".jnilib"); - assertThat(Environment.getJniLibraryName("rocksdb")). + assertThat(Environment.getJniLibraryFileName("rocksdb")). isEqualTo("librocksdbjni-osx.jnilib"); - assertThat(Environment.getSharedLibraryName("rocksdb")). + assertThat(Environment.getSharedLibraryFileName("rocksdb")). isEqualTo("librocksdbjni.dylib"); } @@ -35,9 +35,9 @@ public class EnvironmentTest { assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). isEqualTo(".jnilib"); - assertThat(Environment.getJniLibraryName("rocksdb")). + assertThat(Environment.getJniLibraryFileName("rocksdb")). isEqualTo("librocksdbjni-osx.jnilib"); - assertThat(Environment.getSharedLibraryName("rocksdb")). + assertThat(Environment.getSharedLibraryFileName("rocksdb")). isEqualTo("librocksdbjni.dylib"); } @@ -48,27 +48,27 @@ public class EnvironmentTest { assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). isEqualTo(".so"); - assertThat(Environment.getJniLibraryName("rocksdb")). + assertThat(Environment.getJniLibraryFileName("rocksdb")). isEqualTo("librocksdbjni-linux32.so"); - assertThat(Environment.getSharedLibraryName("rocksdb")). + assertThat(Environment.getSharedLibraryFileName("rocksdb")). isEqualTo("librocksdbjni.so"); // UNIX setEnvironmentClassFields("Unix", "32"); assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). isEqualTo(".so"); - assertThat(Environment.getJniLibraryName("rocksdb")). + assertThat(Environment.getJniLibraryFileName("rocksdb")). isEqualTo("librocksdbjni-linux32.so"); - assertThat(Environment.getSharedLibraryName("rocksdb")). + assertThat(Environment.getSharedLibraryFileName("rocksdb")). isEqualTo("librocksdbjni.so"); // AIX setEnvironmentClassFields("aix", "32"); assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). isEqualTo(".so"); - assertThat(Environment.getJniLibraryName("rocksdb")). + assertThat(Environment.getJniLibraryFileName("rocksdb")). isEqualTo("librocksdbjni-linux32.so"); - assertThat(Environment.getSharedLibraryName("rocksdb")). + assertThat(Environment.getSharedLibraryFileName("rocksdb")). isEqualTo("librocksdbjni.so"); } @@ -78,27 +78,27 @@ public class EnvironmentTest { assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). isEqualTo(".so"); - assertThat(Environment.getJniLibraryName("rocksdb")). + assertThat(Environment.getJniLibraryFileName("rocksdb")). isEqualTo("librocksdbjni-linux64.so"); - assertThat(Environment.getSharedLibraryName("rocksdb")). + assertThat(Environment.getSharedLibraryFileName("rocksdb")). isEqualTo("librocksdbjni.so"); // UNIX setEnvironmentClassFields("Unix", "x64"); assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). isEqualTo(".so"); - assertThat(Environment.getJniLibraryName("rocksdb")). + assertThat(Environment.getJniLibraryFileName("rocksdb")). isEqualTo("librocksdbjni-linux64.so"); - assertThat(Environment.getSharedLibraryName("rocksdb")). + assertThat(Environment.getSharedLibraryFileName("rocksdb")). isEqualTo("librocksdbjni.so"); // AIX setEnvironmentClassFields("aix", "x64"); assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). isEqualTo(".so"); - assertThat(Environment.getJniLibraryName("rocksdb")). + assertThat(Environment.getJniLibraryFileName("rocksdb")). isEqualTo("librocksdbjni-linux64.so"); - assertThat(Environment.getSharedLibraryName("rocksdb")). + assertThat(Environment.getSharedLibraryFileName("rocksdb")). isEqualTo("librocksdbjni.so"); } @@ -111,13 +111,13 @@ public class EnvironmentTest { @Test(expected = UnsupportedOperationException.class) public void failWinJniLibraryName(){ setEnvironmentClassFields("win", "x64"); - Environment.getJniLibraryName("rocksdb"); + Environment.getJniLibraryFileName("rocksdb"); } @Test(expected = UnsupportedOperationException.class) public void failWinSharedLibrary(){ setEnvironmentClassFields("win", "x64"); - Environment.getSharedLibraryName("rocksdb"); + Environment.getSharedLibraryFileName("rocksdb"); } private void setEnvironmentClassFields(String osName,