More robust native library discovery in Mac OS X

Motivation:

Some JDK versions of Mac OS X generates a JNI dynamic library with '.jnilib' extension rather than with '.dynlib' extension.  However, System.mapLibraryName() always returns 'lib<name>.dynlib'. As a result, NativeLibraryLoader fails to load the native library whose extension is .jnilib.

Modification:

Try to find both '.jnilib' and '.dynlib' resources on OS X.

Result:

Dynamic libraries are loaded correctly in Mac OS X, and thus we can continue the OpenSslEngine work.
This commit is contained in:
Trustin Lee 2014-05-11 18:53:15 +09:00
parent e26bbfd4a7
commit 2bc0eac704

View File

@ -24,6 +24,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Locale;
/**
* Helper class to load JNI resources.
@ -33,9 +34,13 @@ public final class NativeLibraryLoader {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NativeLibraryLoader.class);
private static final String NATIVE_RESOURCE_HOME = "META-INF/native/";
private static final String OSNAME;
private static final File WORKDIR;
static {
OSNAME = SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
String workdir = SystemPropertyUtil.get("io.netty.native.workdir");
if (workdir != null) {
File f = new File(workdir);
@ -52,25 +57,124 @@ public final class NativeLibraryLoader {
}
WORKDIR = f;
logger.debug("-Dio.netty.netty.workdir: {}", WORKDIR);
logger.debug("-Dio.netty.netty.workdir: " + WORKDIR);
} else {
WORKDIR = PlatformDependent.tmpdir();
logger.debug("-Dio.netty.netty.workdir: {} (io.netty.tmpdir)", WORKDIR);
WORKDIR = tmpdir();
logger.debug("-Dio.netty.netty.workdir: " + WORKDIR + " (io.netty.tmpdir)");
}
}
private static File tmpdir() {
File f;
try {
f = toDirectory(SystemPropertyUtil.get("io.netty.tmpdir"));
if (f != null) {
logger.debug("-Dio.netty.tmpdir: " + f);
return f;
}
f = toDirectory(SystemPropertyUtil.get("java.io.tmpdir"));
if (f != null) {
logger.debug("-Dio.netty.tmpdir: " + f + " (java.io.tmpdir)");
return f;
}
// This shouldn't happen, but just in case ..
if (isWindows()) {
f = toDirectory(System.getenv("TEMP"));
if (f != null) {
logger.debug("-Dio.netty.tmpdir: " + f + " (%TEMP%)");
return f;
}
String userprofile = System.getenv("USERPROFILE");
if (userprofile != null) {
f = toDirectory(userprofile + "\\AppData\\Local\\Temp");
if (f != null) {
logger.debug("-Dio.netty.tmpdir: " + f + " (%USERPROFILE%\\AppData\\Local\\Temp)");
return f;
}
f = toDirectory(userprofile + "\\Local Settings\\Temp");
if (f != null) {
logger.debug("-Dio.netty.tmpdir: " + f + " (%USERPROFILE%\\Local Settings\\Temp)");
return f;
}
}
} else {
f = toDirectory(System.getenv("TMPDIR"));
if (f != null) {
logger.debug("-Dio.netty.tmpdir: " + f + " ($TMPDIR)");
return f;
}
}
} catch (Exception ignored) {
// Environment variable inaccessible
}
// Last resort.
if (isWindows()) {
f = new File("C:\\Windows\\Temp");
} else {
f = new File("/tmp");
}
logger.warn("Failed to get the temporary directory; falling back to: " + f);
return f;
}
@SuppressWarnings("ResultOfMethodCallIgnored")
private static File toDirectory(String path) {
if (path == null) {
return null;
}
File f = new File(path);
if (!f.exists()) {
f.mkdirs();
}
if (!f.isDirectory()) {
return null;
}
try {
return f.getAbsoluteFile();
} catch (Exception ignored) {
return f;
}
}
private static boolean isWindows() {
return OSNAME.startsWith("windows");
}
private static boolean isOSX() {
return OSNAME.startsWith("macosx") || OSNAME.startsWith("osx");
}
/**
* Load the given library with the specified {@link java.lang.ClassLoader}
*/
public static void load(String name, ClassLoader loader) {
String libname = System.mapLibraryName(name);
String path = "META-INF/native/" + libname;
String path = NATIVE_RESOURCE_HOME + libname;
URL url = loader.getResource(path);
if (url == null && isOSX()) {
if (path.endsWith(".jnilib")) {
url = loader.getResource(NATIVE_RESOURCE_HOME + "lib" + name + ".dynlib");
} else {
url = loader.getResource(NATIVE_RESOURCE_HOME + "lib" + name + ".jnilib");
}
}
if (url == null) {
// Fall back to normal loading of JNI stuff
System.loadLibrary(name);
} else {
return;
}
int index = libname.lastIndexOf('.');
String prefix = libname.substring(0, index);
String suffix = libname.substring(index, libname.length());
@ -123,7 +227,6 @@ public final class NativeLibraryLoader {
}
}
}
}
private NativeLibraryLoader() {
// Utility