diff --git a/java/src/main/java/org/rocksdb/NativeLibraryLoader.java b/java/src/main/java/org/rocksdb/NativeLibraryLoader.java index fb09d3600a..06ae773cb0 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 ea38241964..ed8b05b934 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 c121adb174..6b5a9f2c8c 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 b8e22bce1d..741effebb9 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,