diff options
author | Sven Gothel <[email protected]> | 2013-10-01 13:16:59 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-10-01 13:16:59 +0200 |
commit | 4aa1478b2e4f1401b08d093461b37a14c9501c29 (patch) | |
tree | e609e8ad9633b69d431753650ec73080c2e11682 | |
parent | 1a8d2c627dbab5234aea72a458c00b6bba28add0 (diff) |
Bug 845: Add support for one big-fat jar file [java classes plus all native 'os.and.arch' libraries]
JNILibLoaderBase.addNativeJarLibsImpl(..):
If the modules's jar file contains the folder 'natives/<os.and.arch>/'
we assume a big-fat jar and attempt to load all native libraries from the same.
The test for above folder is performed via the class ClassLoader's getResource(..)
and is considered inexpensive.
If the folder exists and native libraries could be loaded, the method returns successfull.
Otherwise, the 'slim' jar file is attempted to be loaded, even if such folder exist.
4 files changed, 73 insertions, 33 deletions
diff --git a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java index 022ec0e..f0ff69d 100644 --- a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java +++ b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java @@ -44,6 +44,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; +import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; @@ -153,22 +154,38 @@ public class JNILibLoaderBase { msg.setLength(0); // reset msg.append("addNativeJarLibsImpl(classFromJavaJar ").append(classFromJavaJar).append(", classJarURI ").append(classJarURI).append(", nativeJarBaseName ").append(nativeJarBasename).append("): "); boolean ok = false; - if(TempJarCache.isInitialized()) { - final String nativeJarName = nativeJarBasename+"-natives-"+PlatformPropsImpl.os_and_arch+".jar"; - msg.append(nativeJarName); - final URI jarSubURI = JarUtil.getJarSubURI( classJarURI ); - if(null == jarSubURI) { - throw new IllegalArgumentException("JarSubURI is null of: "+classJarURI); + if(TempJarCache.isInitialized()) { + final String nativeLibraryPath = "natives/"+PlatformPropsImpl.os_and_arch+"/"; + final ClassLoader cl = classFromJavaJar.getClassLoader(); + final URL nativeLibraryURI = cl.getResource(nativeLibraryPath); + if( null != nativeLibraryURI ) { + // We probably have one big-fat jar file, containing java classes + // and all native platform libraries under 'natives/os.and.arch'! + if( TempJarCache.addNativeLibs(classFromJavaJar, classJarURI, nativeLibraryPath) ) { + ok = true; + msg.append(classJarURI).append(" (fat)"); + if(DEBUG) { + System.err.println(msg.toString()); + } + } } - final String jarUriRoot_s = IOUtil.getURIDirname( jarSubURI.toString() ); - msg.append(" + ").append(jarUriRoot_s); - final URI nativeJarURI = JarUtil.getJarFileURI(jarUriRoot_s+nativeJarName); - msg.append(" -> ").append(nativeJarURI); - if(DEBUG) { - System.err.println(msg.toString()); + if( !ok ) { + // We assume one slim native jar file per 'os.and.arch'! + final String nativeJarName = nativeJarBasename+"-natives-"+PlatformPropsImpl.os_and_arch+".jar"; + msg.append(nativeJarName); + final URI jarSubURI = JarUtil.getJarSubURI( classJarURI ); + if(null == jarSubURI) { + throw new IllegalArgumentException("JarSubURI is null of: "+classJarURI); + } + final String jarUriRoot_s = IOUtil.getURIDirname( jarSubURI.toString() ); + msg.append(" + ").append(jarUriRoot_s); + final URI nativeJarURI = JarUtil.getJarFileURI(jarUriRoot_s+nativeJarName); + msg.append(" -> ").append(nativeJarURI).append(" (slim)"); + if(DEBUG) { + System.err.println(msg.toString()); + } + ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, null /* nativeLibraryPath */); } - TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI); - ok = true; } return ok; } diff --git a/src/java/com/jogamp/common/util/JarUtil.java b/src/java/com/jogamp/common/util/JarUtil.java index 41d68d4..665e196 100644 --- a/src/java/com/jogamp/common/util/JarUtil.java +++ b/src/java/com/jogamp/common/util/JarUtil.java @@ -514,22 +514,23 @@ public class JarUtil { * @param dest * @param nativeLibMap * @param jarFile - * @param deepDirectoryTraversal + * @param nativeLibraryPath if not null, only extracts native libraries within this path. * @param extractNativeLibraries * @param extractClassFiles * @param extractOtherFiles + * @param deepDirectoryTraversal * @return * @throws IOException */ public static final int extract(File dest, Map<String, String> nativeLibMap, JarFile jarFile, + String nativeLibraryPath, boolean extractNativeLibraries, - boolean extractClassFiles, - boolean extractOtherFiles) throws IOException { + boolean extractClassFiles, boolean extractOtherFiles) throws IOException { if (DEBUG) { System.err.println("JarUtil: extract: "+jarFile.getName()+" -> "+dest+ - ", extractNativeLibraries "+extractNativeLibraries+ + ", extractNativeLibraries "+extractNativeLibraries+" ("+nativeLibraryPath+")"+ ", extractClassFiles "+extractClassFiles+ ", extractOtherFiles "+extractOtherFiles); } @@ -543,11 +544,29 @@ public class JarUtil { // Match entries with correct prefix and suffix (ignoring case) final String libBaseName = NativeLibrary.isValidNativeLibraryName(entryName, false); final boolean isNativeLib = null != libBaseName; - if(isNativeLib && !extractNativeLibraries) { - if (DEBUG) { - System.err.println("JarUtil: JarEntry : " + entryName + " native-lib skipped"); + if(isNativeLib) { + if(!extractNativeLibraries) { + if (DEBUG) { + System.err.println("JarUtil: JarEntry : " + entryName + " native-lib skipped, skip all native libs"); + } + continue; + } + if(null != nativeLibraryPath) { + final String nativeLibraryPathS; + final String dirnameS; + try { + nativeLibraryPathS = IOUtil.slashify(nativeLibraryPath, false /* startWithSlash */, true /* endWithSlash */); + dirnameS = IOUtil.getDirname(entryName); + } catch (URISyntaxException e) { + throw new IOException(e); + } + if( !nativeLibraryPathS.equals(dirnameS) ) { + if (DEBUG) { + System.err.println("JarUtil: JarEntry : " + entryName + " native-lib skipped, not in path: "+nativeLibraryPathS); + } + continue; + } } - continue; } final boolean isClassFile = entryName.endsWith(".class"); @@ -581,14 +600,14 @@ public class JarUtil { if (DEBUG) { System.err.println("JarUtil: MKDIR: " + entryName + " -> " + destFile ); } - destFile.mkdir(); + destFile.mkdirs(); } else { final File destFolder = new File(destFile.getParent()); if(!destFolder.exists()) { if (DEBUG) { System.err.println("JarUtil: MKDIR (parent): " + entryName + " -> " + destFolder ); } - destFolder.mkdir(); + destFolder.mkdirs(); } final InputStream in = new BufferedInputStream(jarFile.getInputStream(entry)); final OutputStream out = new BufferedOutputStream(new FileOutputStream(destFile)); diff --git a/src/java/com/jogamp/common/util/cache/TempJarCache.java b/src/java/com/jogamp/common/util/cache/TempJarCache.java index 3943633..e2a33e0 100644 --- a/src/java/com/jogamp/common/util/cache/TempJarCache.java +++ b/src/java/com/jogamp/common/util/cache/TempJarCache.java @@ -197,12 +197,14 @@ public class TempJarCache { * * @param certClass if class is certified, the JarFile entries needs to have the same certificate * @param jarURI + * @param nativeLibraryPath if not null, only extracts native libraries within this path. + * @return true if native libraries were added or previously loaded from given jarURI, otherwise false * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed * @throws SecurityException * @throws URISyntaxException * @throws IllegalArgumentException */ - public synchronized static final void addNativeLibs(Class<?> certClass, URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { + public synchronized static final boolean addNativeLibs(Class<?> certClass, URI jarURI, String nativeLibraryPath) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { final LoadState nativeLibJarsLS = nativeLibJars.get(jarURI); if( !testLoadState(nativeLibJarsLS, LoadState.LOOKED_UP) ) { nativeLibJars.put(jarURI, LoadState.LOOKED_UP); @@ -211,11 +213,13 @@ public class TempJarCache { System.err.println("TempJarCache: addNativeLibs: "+jarURI+": nativeJar "+jarFile.getName()); } validateCertificates(certClass, jarFile); - JarUtil.extract(tmpFileCache.getTempDir(), nativeLibMap, jarFile, true, false, false); + final int num = JarUtil.extract(tmpFileCache.getTempDir(), nativeLibMap, jarFile, nativeLibraryPath, true, false, false); nativeLibJars.put(jarURI, LoadState.LOADED); - } else if( !testLoadState(nativeLibJarsLS, LoadState.LOADED) ) { - throw new IOException("TempJarCache: addNativeLibs: "+jarURI+", previous load attempt failed"); + return num > 0; + } else if( testLoadState(nativeLibJarsLS, LoadState.LOADED) ) { + return true; } + throw new IOException("TempJarCache: addNativeLibs: "+jarURI+", previous load attempt failed"); } /** @@ -241,7 +245,7 @@ public class TempJarCache { } validateCertificates(certClass, jarFile); JarUtil.extract(tmpFileCache.getTempDir(), null, jarFile, - false, true, false); + null /* nativeLibraryPath */, false, true, false); classFileJars.put(jarURI, LoadState.LOADED); } else if( !testLoadState(classFileJarsLS, LoadState.LOADED) ) { throw new IOException("TempJarCache: addClasses: "+jarURI+", previous load attempt failed"); @@ -269,7 +273,7 @@ public class TempJarCache { } validateCertificates(certClass, jarFile); JarUtil.extract(tmpFileCache.getTempDir(), null, jarFile, - false, false, true); + null /* nativeLibraryPath */, false, false, true); resourceFileJars.put(jarURI, LoadState.LOADED); } else if( !testLoadState(resourceFileJarsLS, LoadState.LOADED) ) { throw new IOException("TempJarCache: addResources: "+jarURI+", previous load attempt failed"); @@ -323,7 +327,7 @@ public class TempJarCache { } validateCertificates(certClass, jarFile); JarUtil.extract(tmpFileCache.getTempDir(), nativeLibMap, jarFile, - extractNativeLibraries, extractClassFiles, extractOtherFiles); + null /* nativeLibraryPath */, extractNativeLibraries, extractClassFiles, extractOtherFiles); // mark loaded (those were just loaded) if(extractNativeLibraries) { diff --git a/src/junit/com/jogamp/common/util/TestTempJarCache.java b/src/junit/com/jogamp/common/util/TestTempJarCache.java index 29fe4c5..7ddf52a 100644 --- a/src/junit/com/jogamp/common/util/TestTempJarCache.java +++ b/src/junit/com/jogamp/common/util/TestTempJarCache.java @@ -147,7 +147,7 @@ public class TestTempJarCache extends JunitTracer { if(AndroidVersion.isAvailable) { System.err.println("n/a on Android"); return; } JarFile jarFile = JarUtil.getJarFile(GlueGenVersion.class.getName(), this.getClass().getClassLoader()); Assert.assertNotNull(jarFile); - JarUtil.extract(fileCache.getTempDir(), null, jarFile, false, true, true); + JarUtil.extract(fileCache.getTempDir(), null, jarFile, null, false, true, true); File f = new File(fileCache.getTempDir(), "META-INF/MANIFEST.MF"); Assert.assertTrue(f.exists()); f = new File(fileCache.getTempDir(), IOUtil.getClassFileName(GlueGenVersion.class.getName())); @@ -207,7 +207,7 @@ public class TestTempJarCache extends JunitTracer { URI nativeJarURI = JarUtil.getJarFileURI(jarUriRoot, nativeJarName); - TempJarCache.addNativeLibs(TempJarCache.class, nativeJarURI); + TempJarCache.addNativeLibs(TempJarCache.class, nativeJarURI, null /* nativeLibraryPath */); String libFullPath = TempJarCache.findLibrary(libBaseName); Assert.assertNotNull(libFullPath); Assert.assertEquals(libBaseName, NativeLibrary.isValidNativeLibraryName(libFullPath, true)); |