/hg/icedtea-web: 2 new changesets

adomurad at icedtea.classpath.org adomurad at icedtea.classpath.org
Mon Jun 3 07:52:18 PDT 2013


changeset 8e6aa48abeba in /hg/icedtea-web
details: http://icedtea.classpath.org/hg/icedtea-web?cmd=changeset;node=8e6aa48abeba
author: Adam Domurad <adomurad at redhat.com>
date: Mon Jun 03 10:34:36 2013 -0400

	Extract NativeLibraryStorage class from JNLPClassLoader


changeset d6f6c5524acc in /hg/icedtea-web
details: http://icedtea.classpath.org/hg/icedtea-web?cmd=changeset;node=d6f6c5524acc
author: Adam Domurad <adomurad at redhat.com>
date: Mon Jun 03 10:51:47 2013 -0400

	Add NativeLibraryStorageTEst


diffstat:

 ChangeLog                                                                |   19 +
 netx/net/sourceforge/jnlp/cache/NativeLibraryStorage.java                |  162 +++++++++
 netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java                   |  139 +-------
 netx/net/sourceforge/jnlp/util/StreamUtils.java                          |   22 +-
 tests/netx/unit/net/sourceforge/jnlp/cache/NativeLibraryStorageTest.java |  172 ++++++++++
 tests/netx/unit/net/sourceforge/jnlp/runtime/JNLPClassLoaderTest.java    |  120 +-----
 tests/test-extensions/net/sourceforge/jnlp/util/FileTestUtils.java       |  129 +++++++
 7 files changed, 546 insertions(+), 217 deletions(-)

diffs (truncated from 927 to 500 lines):

diff -r 2566a700bd86 -r d6f6c5524acc ChangeLog
--- a/ChangeLog	Wed May 29 15:43:21 2013 -0400
+++ b/ChangeLog	Mon Jun 03 10:51:47 2013 -0400
@@ -1,3 +1,22 @@
+2013-06-03  Adam Domurad  <adomurad at redhat.com>
+
+	* netx/net/sourceforge/jnlp/util/StreamUtils.java
+	(copyStream): New, copies input stream to output stream
+	* tests/netx/unit/net/sourceforge/jnlp/cache/NativeLibraryStorageTest.java:
+	New, tests lookup of native libraries from folders and jars.
+	* tests/test-extensions/net/sourceforge/jnlp/util/FileTestUtils.java:
+	New, contains utilities for testing open file descriptors, creating temporary
+	directories, and creating jars.
+	* tests/netx/unit/net/sourceforge/jnlp/runtime/JNLPClassLoaderTest.java:
+	Replace jar creation methods with ones from FileTestUtils. 
+
+2013-06-03  Adam Domurad  <adomurad at redhat.com>
+
+	* netx/net/sourceforge/jnlp/cache/NativeLibraryStorage.java: New,
+	stores and searches for native library files that are loaded from jars.
+	* netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: Move code
+	that handled native jar caching to NativeLibraryStorage. 
+
 2013-05-29  Adam Domurad  <adomurad at redhat.com>
 
 	* tests/netx/unit/net/sourceforge/jnlp/runtime/JNLPClassLoaderTest.java:
diff -r 2566a700bd86 -r d6f6c5524acc netx/net/sourceforge/jnlp/cache/NativeLibraryStorage.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/cache/NativeLibraryStorage.java	Mon Jun 03 10:51:47 2013 -0400
@@ -0,0 +1,162 @@
+package net.sourceforge.jnlp.cache;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import net.sourceforge.jnlp.util.FileUtils;
+
+/**
+ * Handles loading and access of native code loading through a JNLP application or applet.
+ * Stores native code in a temporary folder.
+ * Be sure to call cleanupTemporayFolder when finished with the object.
+ */
+public class NativeLibraryStorage {
+    private ResourceTracker tracker;
+    private List<File> nativeSearchDirectories = new ArrayList<File>();
+
+    /* Temporary directory to store native jar entries, added to our search path */
+    private File jarEntryDirectory = null;
+
+    public NativeLibraryStorage(ResourceTracker tracker) {
+        this.tracker = tracker;
+    }
+
+    /**
+     * Clean up our temporary folder if we created one.
+     */
+    public void cleanupTemporaryFolder() {
+        if (jarEntryDirectory != null) {
+            if (JNLPRuntime.isDebug()) {
+                System.out.println("Cleaning up native directory" + jarEntryDirectory.getAbsolutePath());
+            }
+            try {
+                FileUtils.recursiveDelete(jarEntryDirectory,
+                        new File(System.getProperty("java.io.tmpdir")));
+                jarEntryDirectory = null;
+            } catch (IOException e) {
+                /*
+                 * failed to delete a file in tmpdir, no big deal (as well the VM 
+                 * might be shutting down at this point so no much we can do)
+                 */
+            }
+        }
+    }
+
+    /**
+     * Adds the {@link File} to the search path of this {@link NativeLibraryStorage}
+     * when trying to find a native library
+     */
+    public void addSearchDirectory(File directory) {
+        nativeSearchDirectories.add(directory);
+    }
+
+    public List<File> getSearchDirectories() {
+        return nativeSearchDirectories;
+    }
+
+    /**
+     * Looks in the search directories for 'fileName',
+     * returning a path to the found file if it exists.
+     * Returns null otherwise.
+     */
+    public File findLibrary(String fileName) {
+        for (File dir : getSearchDirectories()) {
+            File target = new File(dir, fileName);
+            if (target.exists())
+                return target;
+        }
+        return null;
+    }
+
+    public static final String[] NATIVE_LIBRARY_EXTENSIONS = { ".so", ".dylib", ".jnilib", ".framework", ".dll" };
+
+    /**
+     * Search for and enable any native code contained in a JAR by copying the
+     * native files into the filesystem. Called in the security context of the
+     * classloader.
+     */
+    public void addSearchJar(URL jarLocation) {
+        if (JNLPRuntime.isDebug())
+            System.out.println("Activate native: " + jarLocation);
+
+        File localFile = tracker.getCacheFile(jarLocation);
+        if (localFile == null)
+            return;
+
+        try {
+            JarFile jarFile = new JarFile(localFile, false);
+            Enumeration<JarEntry> entries = jarFile.entries();
+
+            while (entries.hasMoreElements()) {
+                JarEntry e = entries.nextElement();
+
+                if (e.isDirectory()) {
+                    continue;
+                }
+
+                String name = new File(e.getName()).getName();
+                boolean isLibrary = false;
+
+                for (String suffix : NATIVE_LIBRARY_EXTENSIONS) {
+                    if (name.endsWith(suffix)) {
+                        isLibrary = true;
+                        break;
+                    }
+                }
+                if (!isLibrary) {
+                    continue;
+                }
+
+                ensureNativeStoreDirectory();
+
+                File outFile = new File(jarEntryDirectory, name);
+                if (!outFile.isFile()) {
+                    FileUtils.createRestrictedFile(outFile, true);
+                }
+                CacheUtil.streamCopy(jarFile.getInputStream(e),
+                                     new FileOutputStream(outFile));
+            }
+
+            jarFile.close();
+        } catch (IOException ex) {
+            if (JNLPRuntime.isDebug())
+                ex.printStackTrace();
+        }
+    }
+
+    void ensureNativeStoreDirectory() {
+        if (jarEntryDirectory == null) {
+            jarEntryDirectory = createNativeStoreDirectory();
+            addSearchDirectory(jarEntryDirectory);
+        }
+    }
+
+    /**
+     * Create a random base directory to store native code files in.
+     */
+    private static File createNativeStoreDirectory() {
+        final int rand = (int)((Math.random()*2 - 1) * Integer.MAX_VALUE);
+        File nativeDir = new File(System.getProperty("java.io.tmpdir")
+                             + File.separator + "netx-native-"
+                             + (rand & 0xFFFF));
+        File parent = nativeDir.getParentFile();
+        if (!parent.isDirectory() && !parent.mkdirs()) {
+            return null;
+        }
+
+        try {
+            FileUtils.createRestrictedDirectory(nativeDir);
+            return nativeDir;
+        } catch (IOException e) {
+            return null;
+        }
+    }
+}
diff -r 2566a700bd86 -r d6f6c5524acc netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Wed May 29 15:43:21 2013 -0400
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Mon Jun 03 10:51:47 2013 -0400
@@ -82,6 +82,7 @@
 import net.sourceforge.jnlp.Version;
 import net.sourceforge.jnlp.cache.CacheUtil;
 import net.sourceforge.jnlp.cache.IllegalResourceDescriptorException;
+import net.sourceforge.jnlp.cache.NativeLibraryStorage;
 import net.sourceforge.jnlp.cache.ResourceTracker;
 import net.sourceforge.jnlp.cache.UpdatePolicy;
 import net.sourceforge.jnlp.security.AppVerifier;
@@ -127,11 +128,8 @@
      * initialization of applets that share a unique key*/
     private static Map<String, ReentrantLock> uniqueKeyToLock = new HashMap<String, ReentrantLock>();
 
-    /** the directory for native code */
-    private File nativeDir = null; // if set, some native code exists
-
-    /** a list of directories that contain native libraries */
-    private List<File> nativeDirectories = Collections.synchronizedList(new LinkedList<File>());
+    /** Provides a search path & temporary storage for native code */
+    private NativeLibraryStorage nativeLibraryStorage;
 
     /** security context */
     private AccessControlContext acc = AccessController.getContext();
@@ -231,6 +229,8 @@
         this.updatePolicy = policy;
         this.resources = file.getResources();
 
+        this.nativeLibraryStorage = new NativeLibraryStorage(tracker);
+
         this.mainClass = mainName;
 
         AppVerifier verifier;
@@ -270,21 +270,7 @@
                  * there is one). Other classloaders (parent, peers) will all
                  * cleanup things they created
                  */
-                if (nativeDir != null) {
-                    if (JNLPRuntime.isDebug()) {
-                        System.out.println("Cleaning up native directory" + nativeDir.getAbsolutePath());
-                    }
-                    try {
-                        FileUtils.recursiveDelete(nativeDir,
-                                new File(System.getProperty("java.io.tmpdir")));
-                    } catch (IOException e) {
-                        /*
-                         * failed to delete a file in tmpdir, no big deal (not
-                         * to mention that the VM is shutting down at this
-                         * point so no much we can do)
-                         */
-                    }
-                }
+                nativeLibraryStorage.cleanupTemporaryFolder();
             }
         });
     }
@@ -1349,7 +1335,7 @@
                     }
 
                     // some programs place a native library in any jar
-                    activateNative(jar);
+                    nativeLibraryStorage.addSearchJar(jar.getLocation());
                 }
 
                 return null;
@@ -1360,114 +1346,14 @@
     }
 
     /**
-     * Search for and enable any native code contained in a JAR by copying the
-     * native files into the filesystem. Called in the security context of the
-     * classloader.
-     */
-    protected void activateNative(JARDesc jar) {
-        if (JNLPRuntime.isDebug())
-            System.out.println("Activate native: " + jar.getLocation());
-
-        File localFile = tracker.getCacheFile(jar.getLocation());
-        if (localFile == null)
-            return;
-
-        String[] librarySuffixes = { ".so", ".dylib", ".jnilib", ".framework", ".dll" };
-
-        try {
-            JarFile jarFile = new JarFile(localFile, false);
-            Enumeration<JarEntry> entries = jarFile.entries();
-
-            while (entries.hasMoreElements()) {
-                JarEntry e = entries.nextElement();
-
-                if (e.isDirectory()) {
-                    continue;
-                }
-
-                String name = new File(e.getName()).getName();
-                boolean isLibrary = false;
-
-                for (String suffix : librarySuffixes) {
-                    if (name.endsWith(suffix)) {
-                        isLibrary = true;
-                        break;
-                    }
-                }
-                if (!isLibrary) {
-                    continue;
-                }
-
-                if (nativeDir == null)
-                    nativeDir = getNativeDir();
-
-                File outFile = new File(nativeDir, name);
-                if (!outFile.isFile()) {
-                    FileUtils.createRestrictedFile(outFile, true);
-                }
-                CacheUtil.streamCopy(jarFile.getInputStream(e),
-                                     new FileOutputStream(outFile));
-
-            }
-            jarFile.close();
-        } catch (IOException ex) {
-            if (JNLPRuntime.isDebug())
-                ex.printStackTrace();
-        }
-    }
-
-    /**
-     * Return the base directory to store native code files in.
-     * This method does not need to return the same directory across
-     * calls.
-     */
-    protected File getNativeDir() {
-        final int rand = (int)((Math.random()*2 - 1) * Integer.MAX_VALUE);
-        nativeDir = new File(System.getProperty("java.io.tmpdir")
-                             + File.separator + "netx-native-"
-                             + (rand & 0xFFFF));
-        File parent = nativeDir.getParentFile();
-        if (!parent.isDirectory() && !parent.mkdirs()) {
-            return null;
-        }
-
-        try {
-            FileUtils.createRestrictedDirectory(nativeDir);
-            // add this new native directory to the search path
-            addNativeDirectory(nativeDir);
-            return nativeDir;
-        } catch (IOException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Adds the {@link File} to the search path of this {@link JNLPClassLoader}
-     * when trying to find a native library
-     */
-    protected void addNativeDirectory(File nativeDirectory) {
-        nativeDirectories.add(nativeDirectory);
-    }
-
-    /**
-     * Returns a list of all directories in the search path of the current classloader
-     * when it tires to find a native library.
-     * @return a list of directories in the search path for native libraries
-     */
-    protected List<File> getNativeDirectories() {
-        return nativeDirectories;
-    }
-
-    /**
      * Return the absolute path to the native library.
      */
     protected String findLibrary(String lib) {
         String syslib = System.mapLibraryName(lib);
+        File libFile = nativeLibraryStorage.findLibrary(syslib);
 
-        for (File dir : getNativeDirectories()) {
-            File target = new File(dir, syslib);
-            if (target.exists())
-                return target.toString();
+        if (libFile != null) {
+            return libFile.toString();
         }
 
         String result = super.findLibrary(lib);
@@ -2044,8 +1930,9 @@
         addToCodeBaseLoader(extLoader.file.getCodeBase());
 
         // native search paths
-        for (File nativeDirectory : extLoader.getNativeDirectories())
-            addNativeDirectory(nativeDirectory);
+        for (File nativeDirectory : extLoader.nativeLibraryStorage.getSearchDirectories()) {
+            nativeLibraryStorage.addSearchDirectory(nativeDirectory);
+        }
 
         // security descriptors
         for (URL key : extLoader.jarLocationSecurityMap.keySet()) {
diff -r 2566a700bd86 -r d6f6c5524acc netx/net/sourceforge/jnlp/util/StreamUtils.java
--- a/netx/net/sourceforge/jnlp/util/StreamUtils.java	Wed May 29 15:43:21 2013 -0400
+++ b/netx/net/sourceforge/jnlp/util/StreamUtils.java	Mon Jun 03 10:51:47 2013 -0400
@@ -42,16 +42,17 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 
 public class StreamUtils {
 
-    /***
+    /**
      * Closes a stream, without throwing IOException.
      * In case of IOException, prints the stack trace to System.err.
      * 
      * @param stream the stream that will be closed
      */
-    public static void closeSilently (Closeable stream) {
+    public static void closeSilently(Closeable stream) {
         if (stream != null) {
             try {
                 stream.close();
@@ -61,8 +62,23 @@
         }
     }
 
+    /**
+     * Copy an input stream's contents into an output stream.
+     */
+    public static void copyStream(InputStream input, OutputStream output)
+            throws IOException {
+        byte[] buffer = new byte[1024];
+        while (true) {
+            int bytesRead = input.read(buffer);
+            if (bytesRead == -1) {
+                break;
+            }
+            output.write(buffer, 0, bytesRead);
+        }
+    }
 
-    public static String readStreamAsString(InputStream stream) throws IOException {
+    public static String readStreamAsString(InputStream stream)
+            throws IOException {
         InputStreamReader is = new InputStreamReader(stream);
         StringBuilder sb = new StringBuilder();
         BufferedReader br = new BufferedReader(is);
diff -r 2566a700bd86 -r d6f6c5524acc tests/netx/unit/net/sourceforge/jnlp/cache/NativeLibraryStorageTest.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/netx/unit/net/sourceforge/jnlp/cache/NativeLibraryStorageTest.java	Mon Jun 03 10:51:47 2013 -0400
@@ -0,0 +1,172 @@
+/*
+Copyright (C) 2013 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+package net.sourceforge.jnlp.cache;
+
+import static net.sourceforge.jnlp.util.FileTestUtils.assertNoFileLeak;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sourceforge.jnlp.Version;
+import net.sourceforge.jnlp.util.FileTestUtils;
+
+import org.junit.Test;
+
+public class NativeLibraryStorageTest {
+
+    /**************************************************************************
+     *                          Test helpers                                    *
+     **************************************************************************/
+



More information about the distro-pkg-dev mailing list