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:
parent
35ab47a5d5
commit
10ab0db8f5
@ -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,73 +57,171 @@ 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 {
|
||||
int index = libname.lastIndexOf('.');
|
||||
String prefix = libname.substring(0, index);
|
||||
String suffix = libname.substring(index, libname.length());
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
File tmpFile = null;
|
||||
boolean loaded = false;
|
||||
try {
|
||||
tmpFile = File.createTempFile(prefix, suffix, WORKDIR);
|
||||
in = url.openStream();
|
||||
out = new FileOutputStream(tmpFile);
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int length;
|
||||
while ((length = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, length);
|
||||
}
|
||||
out.flush();
|
||||
out.close();
|
||||
out = null;
|
||||
int index = libname.lastIndexOf('.');
|
||||
String prefix = libname.substring(0, index);
|
||||
String suffix = libname.substring(index, libname.length());
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
File tmpFile = null;
|
||||
boolean loaded = false;
|
||||
try {
|
||||
tmpFile = File.createTempFile(prefix, suffix, WORKDIR);
|
||||
in = url.openStream();
|
||||
out = new FileOutputStream(tmpFile);
|
||||
|
||||
System.load(tmpFile.getPath());
|
||||
loaded = true;
|
||||
} catch (Exception e) {
|
||||
throw (UnsatisfiedLinkError) new UnsatisfiedLinkError(
|
||||
"could not load a native library: " + name).initCause(e);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ignore) {
|
||||
// ignore
|
||||
}
|
||||
byte[] buffer = new byte[8192];
|
||||
int length;
|
||||
while ((length = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, length);
|
||||
}
|
||||
out.flush();
|
||||
out.close();
|
||||
out = null;
|
||||
|
||||
System.load(tmpFile.getPath());
|
||||
loaded = true;
|
||||
} catch (Exception e) {
|
||||
throw (UnsatisfiedLinkError) new UnsatisfiedLinkError(
|
||||
"could not load a native library: " + name).initCause(e);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ignore) {
|
||||
// ignore
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ignore) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ignore) {
|
||||
// ignore
|
||||
}
|
||||
if (tmpFile != null) {
|
||||
if (loaded) {
|
||||
}
|
||||
if (tmpFile != null) {
|
||||
if (loaded) {
|
||||
tmpFile.deleteOnExit();
|
||||
} else {
|
||||
if (!tmpFile.delete()) {
|
||||
tmpFile.deleteOnExit();
|
||||
} else {
|
||||
if (!tmpFile.delete()) {
|
||||
tmpFile.deleteOnExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user