[jffi-next] 40/49: Rework stub library loading, to always try and load the stub lib using the system classloader.
Tim Potter
tpot-guest at moszumanska.debian.org
Wed Mar 4 04:51:15 UTC 2015
This is an automated email from the git hooks/post-receive script.
tpot-guest pushed a commit to annotated tag upstream/1.0.10
in repository jffi-next.
commit 52968fa6b6910a81935ca5e9c1660ca4d2efeeff
Author: Wayne Meissner <wmeissner at gmail.com>
Date: Wed Apr 27 16:56:26 2011 +1000
Rework stub library loading, to always try and load the stub lib using the system classloader.
---
src/com/kenai/jffi/Init.java | 222 ++++++-------------
.../jffi/{Init.java => internal/StubLoader.java} | 238 +++++++++++++++++----
2 files changed, 252 insertions(+), 208 deletions(-)
diff --git a/src/com/kenai/jffi/Init.java b/src/com/kenai/jffi/Init.java
index fab03b6..956c034 100644
--- a/src/com/kenai/jffi/Init.java
+++ b/src/com/kenai/jffi/Init.java
@@ -33,201 +33,99 @@
package com.kenai.jffi;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.channels.Channels;
-import java.nio.channels.ReadableByteChannel;
-import java.util.Arrays;
-import java.util.Properties;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
/**
* Utility class to load the jffi stub library
*/
final class Init {
- private static final String bootPropertyFilename = "boot.properties";
- private static final String bootLibraryPropertyName = "jffi.boot.library.path";
- private static final String stubLibraryName
- = String.format("jffi-%d.%d", Foreign.VERSION_MAJOR, Foreign.VERSION_MINOR);
-
private static volatile boolean loaded = false;
+ static final String stubLoaderClassName = Init.class.getPackage().getName() + ".internal.StubLoader";
+
// prevent instantiation
private Init() {}
/**
* Loads the stub library
*/
- static final void load() {
+ static void load() {
if (loaded) {
return;
}
-
- final String libName = getStubLibraryName();
- String bootPath = getBootPath();
- if (bootPath != null && loadFromBootPath(libName, bootPath)) {
- return;
- }
+ List<Throwable> failureCauses = new ArrayList<Throwable>();
+ List<ClassLoader> loaders = getClassLoaders();
- try {
- System.loadLibrary(libName);
- return;
- } catch (UnsatisfiedLinkError ex) {}
-
- loadFromJar();
- }
-
- private static final String getBootPath() {
-
- String bootPath = System.getProperty(bootLibraryPropertyName);
- if (bootPath != null) {
- return bootPath;
- }
-
- InputStream is = getResourceAsStream(bootPropertyFilename);
- if (is != null) {
- Properties p = new Properties();
+ for (ClassLoader cl : loaders) {
try {
- p.load(is);
- return p.getProperty(bootLibraryPropertyName);
- } catch (IOException ex) {
- } finally {
- try {
- is.close();
- } catch (IOException ex) {
- throw new RuntimeException(ex);
+ Class<?> c = Class.forName(stubLoaderClassName, true, cl);
+ Method isLoaded = c.getDeclaredMethod("isLoaded", new Class[0]);
+ loaded |= Boolean.class.cast(isLoaded.invoke(c, new Object[0]));
+ if (!loaded) {
+ Method getFailureCause = c.getDeclaredMethod("getFailureCause", new Class[0]);
+ throw new RuntimeException(Throwable.class.cast(getFailureCause.invoke(c, new Object[0])));
}
+
+ } catch (IllegalAccessException ex) {
+ failureCauses.add(ex);
+
+ } catch (InvocationTargetException ex) {
+ failureCauses.add(ex);
+
+ } catch (ClassNotFoundException ex) {
+ failureCauses.add(ex);
+
+ } catch (IllegalArgumentException ex) {
+ throw new RuntimeException(ex);
+
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException(ex);
}
}
- return null;
- }
-
- private static final boolean loadFromBootPath(String libName, String bootPath) {
- String[] dirs = bootPath.split(File.pathSeparator);
- for (int i = 0; i < dirs.length; ++i) {
- String path = new File(new File(dirs[i]), System.mapLibraryName(libName)).getAbsolutePath();
- try {
- System.load(path);
- return true;
- } catch (UnsatisfiedLinkError ex) {
- }
- if (Platform.getPlatform().getOS() == Platform.OS.DARWIN) {
- String orig, ext;
- if (path.endsWith("dylib")) {
- orig = "dylib";
- ext = "jnilib";
- } else {
- orig = "jnilib";
- ext = "dylib";
- }
- try {
- System.load(path.substring(0, path.lastIndexOf(orig)) + ext);
- return true;
- } catch (UnsatisfiedLinkError ex) {
- }
+ if (!loaded && !failureCauses.isEmpty()) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ for (Throwable t : failureCauses) {
+ t.printStackTrace(pw);
}
+
+ throw new RuntimeException(sw.toString());
}
- return false;
}
- private static final void loadFromJar() {
- InputStream is = getStubLibraryStream();
- File dstFile = null;
- FileOutputStream os = null;
-
+ private static List<ClassLoader> getClassLoaders() {
+ List<ClassLoader> loaders = new ArrayList<ClassLoader>();
+ ClassLoader cl = Init.class.getClassLoader();
+
try {
- dstFile = File.createTempFile("jffi", null);
- dstFile.deleteOnExit();
- os = new FileOutputStream(dstFile);
- ReadableByteChannel srcChannel = Channels.newChannel(is);
-
- for (long pos = 0; is.available() > 0; ) {
- pos += os.getChannel().transferFrom(srcChannel, pos, Math.max(4096, is.available()));
- }
-
- } catch (IOException ex) {
- throw new UnsatisfiedLinkError(ex.getMessage());
-
- } finally {
- try {
- if (os != null) {
- os.close();
- }
- is.close();
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
+ loaders.add(ClassLoader.getSystemClassLoader());
+ } catch (SecurityException ex) {
}
- System.load(dstFile.getAbsolutePath());
- }
-
- /**
- * Gets an <tt>InputStream</tt> representing the stub library image stored in
- * the jar file.
- *
- * @return A new <tt>InputStream</tt>
- */
- private static final InputStream getStubLibraryStream() {
- String stubPath = getStubLibraryPath();
- String[] paths = { stubPath, "/" + stubPath };
-
- for (String path : paths) {
- InputStream is = getResourceAsStream(path);
-
- // On MacOS, the stub might be named .dylib or .jnilib - cater for both
- if (is == null && Platform.getPlatform().getOS() == Platform.OS.DARWIN) {
- is = getResourceAsStream(path.replaceAll("dylib", "jnilib"));
- }
- if (is != null) {
- return is;
- }
+ try {
+ loaders.add(Thread.currentThread().getContextClassLoader());
+ } catch (SecurityException ex) {
}
-
- throw new UnsatisfiedLinkError("could not locate stub library"
- + " in jar file. Tried " + Arrays.deepToString(paths));
- }
-
- private static final InputStream getResourceAsStream(String resourceName) {
- // try both our classloader and context classloader
- ClassLoader[] cls = new ClassLoader[] {
- Init.class.getClassLoader(),
- Thread.currentThread().getContextClassLoader()
- };
- for (ClassLoader cl : cls) {
- // skip null classloader (e.g. boot or null context loader)
- if (cl == null) {
- continue;
- }
-
- InputStream is;
- if ((is = cl.getResourceAsStream(resourceName)) != null) {
- return is;
+ loaders.add(Init.class.getClassLoader());
+
+ // Remove all the nulls except one - in the case where this is loaded
+ // from the bootstrap classloader
+ int nullCount = 0;
+ for (Iterator<ClassLoader> it = loaders.iterator(); it.hasNext(); ) {
+ if (it.next() == null && ++nullCount > 1) {
+ it.remove();
}
}
- return null;
- }
-
- /**
- * Gets the name of the stub library.
- *
- * @return The name of the stub library as a <tt>String</tt>
- */
- private static final String getStubLibraryName() {
- return stubLibraryName;
+ return Collections.unmodifiableList(loaders);
}
-
- /**
- * Gets the path within the jar file of the stub native library.
- *
- * @return The path of the jar file.
- */
- private static final String getStubLibraryPath() {
- return "jni/" + Platform.getPlatform().getName() + "/"+ System.mapLibraryName(stubLibraryName);
- }
-
}
diff --git a/src/com/kenai/jffi/Init.java b/src/com/kenai/jffi/internal/StubLoader.java
similarity index 53%
copy from src/com/kenai/jffi/Init.java
copy to src/com/kenai/jffi/internal/StubLoader.java
index fab03b6..4b00fa9 100644
--- a/src/com/kenai/jffi/Init.java
+++ b/src/com/kenai/jffi/internal/StubLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Wayne Meissner
+ * Copyright (C) 2011 Wayne Meissner
*
* This file is part of jffi.
*
@@ -14,24 +14,8 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
- *
- * Alternatively, you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this work. If not, see <http://www.gnu.org/licenses/>.
*/
-
-
-package com.kenai.jffi;
+package com.kenai.jffi.internal;
import java.io.File;
import java.io.FileOutputStream;
@@ -43,27 +27,189 @@ import java.util.Arrays;
import java.util.Properties;
/**
- * Utility class to load the jffi stub library
+ * Loads the native stub library. This is intended to only ever be called
+ * reflectively, so it cannot access other jffi classes.
*/
-final class Init {
+public class StubLoader {
+ public final static int VERSION_MAJOR = getVersionField("MAJOR");
+ public final static int VERSION_MINOR = getVersionField("MINOR");
+ private static final String versionClassName = "com.kenai.jffi.Version";
+
private static final String bootPropertyFilename = "boot.properties";
private static final String bootLibraryPropertyName = "jffi.boot.library.path";
private static final String stubLibraryName
- = String.format("jffi-%d.%d", Foreign.VERSION_MAJOR, Foreign.VERSION_MINOR);
+ = String.format("jffi-%d.%d", VERSION_MAJOR, VERSION_MINOR);
+ private static final OS OS_ = determineOS();
+ private static final CPU CPU_ = determineCPU();
+ private static volatile Throwable failureCause = null;
private static volatile boolean loaded = false;
+
+
+ public static final boolean isLoaded() {
+ return loaded;
+ }
+
+ public static final Throwable getFailureCause() {
+ return failureCause;
+ }
+
+
+ public enum OS {
+ /** MacOSX */
+ DARWIN,
+ /** FreeBSD */
+ FREEBSD,
+ /** NetBSD */
+ NETBSD,
+ /** OpenBSD */
+ OPENBSD,
+ /** Linux */
+ LINUX,
+ /** Solaris (and OpenSolaris) */
+ SOLARIS,
+ /** The evil borg operating system */
+ WINDOWS,
+ /** IBM AIX */
+ AIX,
+ /** IBM zOS **/
+ ZLINUX,
+
+ /** No idea what the operating system is */
+ UNKNOWN;
+
+ @Override
+ public String toString() { return name().toLowerCase(); }
+ }
+
+ /**
+ * The common names of cpu architectures.
+ *
+ * <b>Note</b> The names of the enum values are used in other parts of the
+ * code to determine where to find the native stub library. Do not rename.
+ */
+ public enum CPU {
+ /** Intel ia32 */
+ I386,
+ /** AMD 64 bit (aka EM64T/X64) */
+ X86_64,
+ /** Power PC 32 bit */
+ PPC,
+ /** Power PC 64 bit */
+ PPC64,
+ /** Sun sparc 32 bit */
+ SPARC,
+ /** Sun sparc 64 bit */
+ SPARCV9,
+ /** IBM zSeries S/390 64 bit */
+ S390X,
+ /** Unknown CPU */
+ UNKNOWN;
+
+ @Override
+ public String toString() { return name().toLowerCase(); }
+ }
- // prevent instantiation
- private Init() {}
+ /**
+ * Determines the operating system jffi is running on
+ *
+ * @return An member of the <tt>OS</tt> enum.
+ */
+ private static final OS determineOS() {
+ String osName = System.getProperty("os.name").split(" ")[0].toLowerCase();
+ if (osName.startsWith("mac") || osName.startsWith("darwin")) {
+ return OS.DARWIN;
+ } else if (osName.startsWith("linux")) {
+ return OS.LINUX;
+ } else if (osName.startsWith("sunos") || osName.startsWith("solaris")) {
+ return OS.SOLARIS;
+ } else if (osName.startsWith("aix")) {
+ return OS.AIX;
+ } else if (osName.startsWith("openbsd")) {
+ return OS.OPENBSD;
+ } else if (osName.startsWith("freebsd")) {
+ return OS.FREEBSD;
+ } else if (osName.startsWith("windows")) {
+ return OS.WINDOWS;
+ } else {
+ return OS.UNKNOWN;
+ }
+ }
/**
- * Loads the stub library
+ * Determines the CPU architecture the JVM is running on.
+ *
+ * This normalizes all the variations that are equivalent (e.g. i386, x86, i86pc)
+ * into a common cpu type.
+ *
+ * @return A member of the <tt>CPU</tt> enum.
*/
- static final void load() {
- if (loaded) {
- return;
+ private static final CPU determineCPU() {
+ String archString = System.getProperty("os.arch", "unknown").toLowerCase();
+ if ("x86".equals(archString) || "i386".equals(archString) || "i86pc".equals(archString)) {
+ return CPU.I386;
+ } else if ("x86_64".equals(archString) || "amd64".equals(archString)) {
+ return CPU.X86_64;
+ } else if ("ppc".equals(archString) || "powerpc".equals(archString)) {
+ return CPU.PPC;
+ } else if ("powerpc64".equals(archString)) {
+ return CPU.PPC64;
+ }
+
+ // Try to find by lookup up in the CPU list
+ try {
+ return CPU.valueOf(archString.toUpperCase());
+ } catch (IllegalArgumentException ex) {
+ return CPU.UNKNOWN;
}
+ }
+
+ public static final CPU getCPU() {
+ return CPU_;
+ }
+
+ public static OS getOS() {
+ return OS_;
+ }
+ /**
+ * Gets the name of the stub library.
+ *
+ * @return The name of the stub library as a <tt>String</tt>
+ */
+ private static final String getStubLibraryName() {
+ return stubLibraryName;
+ }
+
+ /**
+ * Gets the name of this <tt>Platform</tt>.
+ *
+ * @return The name of this platform.
+ */
+ public static String getPlatformName() {
+ if (getOS().equals(OS.DARWIN)) {
+ return "Darwin";
+ }
+
+
+ String osName = System.getProperty("os.name").split(" ")[0];
+ return getCPU().name().toLowerCase() + "-" + osName;
+ }
+ /**
+ * Gets the path within the jar file of the stub native library.
+ *
+ * @return The path of the jar file.
+ */
+ private static final String getStubLibraryPath() {
+ return "jni/" + getPlatformName() + "/"+ System.mapLibraryName(stubLibraryName);
+ }
+
+ public StubLoader() {}
+
+ /**
+ * Loads the stub library
+ */
+ static final void load() {
final String libName = getStubLibraryName();
String bootPath = getBootPath();
if (bootPath != null && loadFromBootPath(libName, bootPath)) {
@@ -113,7 +259,7 @@ final class Init {
return true;
} catch (UnsatisfiedLinkError ex) {
}
- if (Platform.getPlatform().getOS() == Platform.OS.DARWIN) {
+ if (getOS() == OS.DARWIN) {
String orig, ext;
if (path.endsWith("dylib")) {
orig = "dylib";
@@ -178,7 +324,7 @@ final class Init {
InputStream is = getResourceAsStream(path);
// On MacOS, the stub might be named .dylib or .jnilib - cater for both
- if (is == null && Platform.getPlatform().getOS() == Platform.OS.DARWIN) {
+ if (is == null && getOS() == OS.DARWIN) {
is = getResourceAsStream(path.replaceAll("dylib", "jnilib"));
}
if (is != null) {
@@ -193,7 +339,8 @@ final class Init {
private static final InputStream getResourceAsStream(String resourceName) {
// try both our classloader and context classloader
ClassLoader[] cls = new ClassLoader[] {
- Init.class.getClassLoader(),
+ StubLoader.class.getClassLoader().getSystemClassLoader(),
+ StubLoader.class.getClassLoader(),
Thread.currentThread().getContextClassLoader()
};
@@ -211,23 +358,22 @@ final class Init {
return null;
}
-
- /**
- * Gets the name of the stub library.
- *
- * @return The name of the stub library as a <tt>String</tt>
- */
- private static final String getStubLibraryName() {
- return stubLibraryName;
+
+ private final static int getVersionField(String name) {
+ try {
+ Class c = Class.forName(versionClassName);
+ return (Integer) c.getField(name).get(c);
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
}
- /**
- * Gets the path within the jar file of the stub native library.
- *
- * @return The path of the jar file.
- */
- private static final String getStubLibraryPath() {
- return "jni/" + Platform.getPlatform().getName() + "/"+ System.mapLibraryName(stubLibraryName);
+ static {
+ try {
+ load();
+ loaded = true;
+ } catch (Throwable t) {
+ failureCause = t;
+ }
}
-
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jffi-next.git
More information about the pkg-java-commits
mailing list