[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