From 1157b913a068167062c853b4b525954b223a5509 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 3 Apr 2019 01:00:29 +0200 Subject: Bug 1367: Make TempFileCache & TempJarCache even if temp folder can't handle executables --- .../com/jogamp/common/jvm/JNILibLoaderBase.java | 2 +- src/java/com/jogamp/common/os/NativeLibrary.java | 2 +- src/java/com/jogamp/common/os/Platform.java | 2 +- .../com/jogamp/common/util/cache/TempCacheReg.java | 8 +- .../jogamp/common/util/cache/TempFileCache.java | 51 +++++++--- .../com/jogamp/common/util/cache/TempJarCache.java | 105 ++++++++++++++++----- src/junit/com/jogamp/common/util/TestJarUtil.java | 14 +-- .../com/jogamp/common/util/TestTempJarCache.java | 10 +- 8 files changed, 142 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java index 4e62d54..eee65d8 100644 --- a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java +++ b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java @@ -405,7 +405,7 @@ public class JNILibLoaderBase { } boolean ok = false; - if (TempJarCache.isInitialized()) { + if ( TempJarCache.isInitialized(true) ) { ok = addNativeJarLibsWithTempJarCache(classesFromJavaJars, singleJarMarker); } else if(DEBUG) { System.err.println("JNILibLoaderBase: addNativeJarLibs0: disabled due to uninitialized TempJarCache"); diff --git a/src/java/com/jogamp/common/os/NativeLibrary.java b/src/java/com/jogamp/common/os/NativeLibrary.java index 2ba2581..7c6aeca 100644 --- a/src/java/com/jogamp/common/os/NativeLibrary.java +++ b/src/java/com/jogamp/common/os/NativeLibrary.java @@ -643,7 +643,7 @@ public final class NativeLibrary implements DynamicLookupHelper { } public static final String findLibrary(final String libName, final ClassLoader loader) { String res = null; - if(TempJarCache.isInitialized()) { + if( TempJarCache.isInitialized(true) ) { res = TempJarCache.findLibrary(libName); if (DEBUG) { System.err.println("NativeLibrary.findLibrary(<"+libName+">) (TempJarCache): "+res); diff --git a/src/java/com/jogamp/common/os/Platform.java b/src/java/com/jogamp/common/os/Platform.java index 2e63550..535b8a9 100644 --- a/src/java/com/jogamp/common/os/Platform.java +++ b/src/java/com/jogamp/common/os/Platform.java @@ -306,7 +306,7 @@ public class Platform extends PlatformPropsImpl { PropertyAccess.getBooleanProperty(useTempJarCachePropName, true, true); // load GluegenRT native library - if(_USE_TEMP_JAR_CACHE[0] && TempJarCache.initSingleton()) { + if(_USE_TEMP_JAR_CACHE[0] && TempJarCache.initSingleton() && TempJarCache.isInitialized(true) ) { try { JNILibLoaderBase.addNativeJarLibs(new Class[] { jogamp.common.Debug.class }, null); } catch (final Exception e0) { diff --git a/src/java/com/jogamp/common/util/cache/TempCacheReg.java b/src/java/com/jogamp/common/util/cache/TempCacheReg.java index 47ef584..b7c275c 100644 --- a/src/java/com/jogamp/common/util/cache/TempCacheReg.java +++ b/src/java/com/jogamp/common/util/cache/TempCacheReg.java @@ -31,7 +31,11 @@ public class TempCacheReg { public static boolean isTempFileCacheUsed() { return null != System.getProperty(TempFileCache.tmpRootPropName); } - public static boolean isTempJarCacheUsed() { - return TempJarCache.isInitialized(); + /** + * @param forExecutables if {@code true}, method also tests whether {@link TempJarCache}'s underlying cache is suitable to load native libraries or launch executables + * @return true if {@link TempJarCache} has been properly initialized, ie. is in use. Otherwise returns false. + */ + public static boolean isTempJarCacheUsed(final boolean forExecutables) { + return TempJarCache.isInitialized(forExecutables); } } diff --git a/src/java/com/jogamp/common/util/cache/TempFileCache.java b/src/java/com/jogamp/common/util/cache/TempFileCache.java index 44c7a11..0547f9a 100644 --- a/src/java/com/jogamp/common/util/cache/TempFileCache.java +++ b/src/java/com/jogamp/common/util/cache/TempFileCache.java @@ -45,6 +45,9 @@ public class TempFileCache { // Flag indicating that we got a fatal error in the static initializer. private static boolean staticInitError = false; + // Flag indicating that the temp root folder can be used for executable files + private static boolean staticTempIsExecutable = true; + private static final String tmpDirPrefix = "file_cache"; // Lifecycle: For one user's JVMs, ClassLoader and time. @@ -80,10 +83,19 @@ public class TempFileCache { try { _tmpBaseDir = new File(IOUtil.getTempDir(true /* executable */), tmpDirPrefix); _tmpBaseDir = IOUtil.testDir(_tmpBaseDir, true /* create */, false /* executable */); // executable already checked + staticTempIsExecutable = true; } catch (final Exception ex) { System.err.println("Warning: Caught Exception while retrieving executable temp base directory:"); ex.printStackTrace(); - staticInitError = true; + staticTempIsExecutable = false; + try { + _tmpBaseDir = new File(IOUtil.getTempDir(false /* executable */), tmpDirPrefix); + _tmpBaseDir = IOUtil.testDir(_tmpBaseDir, true /* create */, false /* executable */); + } catch (final Exception ex2) { + System.err.println("Warning: Caught Exception while retrieving non-executable temp base directory:"); + ex2.printStackTrace(); + staticInitError = true; + } } tmpBaseDir = _tmpBaseDir; @@ -92,7 +104,7 @@ public class TempFileCache { System.err.println("TempFileCache: Static Initialization ---------------------------------------------- OK: "+(!staticInitError)); System.err.println("TempFileCache: Thread: "+Thread.currentThread().getName()+ ", CL 0x"+Integer.toHexString(TempFileCache.class.getClassLoader().hashCode())+ - ", tempBaseDir "+tmpBaseDirAbsPath); + ", tempBaseDir "+tmpBaseDirAbsPath+", executable "+staticTempIsExecutable); } if(!staticInitError) { @@ -102,6 +114,7 @@ public class TempFileCache { System.err.println("Warning: Caught Exception due to initializing TmpRoot:"); ex.printStackTrace(); staticInitError = true; + staticTempIsExecutable = false; } } if (DEBUG) { @@ -414,7 +427,7 @@ public class TempFileCache { path.delete(); } - /** Create the individualTmpDir. */ + /** Create the {@link #getTempDir()} */ public TempFileCache () { if (DEBUG) { System.err.println("TempFileCache: new TempFileCache() --------------------- (static ok: "+(!staticInitError)+")"); @@ -434,7 +447,7 @@ public class TempFileCache { } } - /** Delete the individualTmpDir recursively and remove it's reference. */ + /** Delete the {@link #getTempDir()} recursively and remove it's reference. */ public void destroy() { if (DEBUG) { System.err.println("TempFileCache: destroy() --------------------- (static ok: "+(!staticInitError)+")"); @@ -454,15 +467,20 @@ public class TempFileCache { } /** - * @return true is static and object initialization was successful + * @param forExecutables if {@code true}, method also tests whether the underlying {@link #getBaseDir()} is suitable to load native libraries or launch executables + * @return true if static and object initialization was successful + * @see #isTempExecutable() + * @see #isValid() */ - public boolean isValid() { return !staticInitError && !initError; } + public boolean isValid(final boolean forExecutables) { + return !staticInitError && !initError && ( !forExecutables || staticTempIsExecutable ); + } /** - * Base temp directory used by TempFileCache. + * Base temp directory used by {@link TempFileCache}. * *

- * Lifecycle: For one user's JVMs, ClassLoader and time. + * Lifecycle: For one user's concurrently running JVMs and ClassLoader *

* * This is set to: @@ -472,11 +490,14 @@ public class TempFileCache { * * @return */ - public File getBaseDir() { return tmpBaseDir; } + public static File getBaseDir() { return tmpBaseDir; } /** * Root temp directory for this JVM instance. Used to store individual * directories. + *

+ * This directory is a sub-folder to {@link #getBaseDir()}. + *

* *

* Lifecycle: For one user's concurrently running JVMs and ClassLoader @@ -498,15 +519,19 @@ public class TempFileCache { * * @return */ - public File getRootDir() { return tmpRootDir; } + public static File getRootDir() { return tmpRootDir; } /** * Temporary directory for individual files (eg. native libraries of one ClassLoader instance). - * The directory name is: + *

+ * This directory is a sub-folder to {@link #getRootDir()}. + *

* *

- * Lifecycle: Within each JVM .. use case dependent, ie. per ClassLoader + * Lifecycle: Within each JVM .. use case dependent, ie. per ClassLoader and per {@link TempFileCache} instance! *

+ *

+ * The directory name is: * *

      *   tmpRootDir/jlnMMMMM
@@ -514,7 +539,7 @@ public class TempFileCache {
      *
      * where jlnMMMMM is the unique filename created by File.createTempFile()
      * without the ".tmp" extension.
-     *
+     * 

* * @return */ diff --git a/src/java/com/jogamp/common/util/cache/TempJarCache.java b/src/java/com/jogamp/common/util/cache/TempJarCache.java index 2ff5140..c5cca3a 100644 --- a/src/java/com/jogamp/common/util/cache/TempJarCache.java +++ b/src/java/com/jogamp/common/util/cache/TempJarCache.java @@ -37,6 +37,7 @@ import java.util.jar.JarFile; import jogamp.common.Debug; +import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.net.Uri; import com.jogamp.common.os.NativeLibrary; import com.jogamp.common.util.JarUtil; @@ -74,6 +75,7 @@ public class TempJarCache { private static TempFileCache tmpFileCache; private static volatile boolean staticInitError = false; + private static volatile boolean staticTempIsExecutable = true; private static volatile boolean isInit = false; /** @@ -89,7 +91,8 @@ public class TempJarCache { if(!staticInitError) { tmpFileCache = new TempFileCache(); - staticInitError = !tmpFileCache.isValid(); + staticInitError = !tmpFileCache.isValid(false); + staticTempIsExecutable = tmpFileCache.isValid(true); } if(!staticInitError) { @@ -102,7 +105,7 @@ public class TempJarCache { if(DEBUG) { final File tempDir = null != tmpFileCache ? tmpFileCache.getTempDir() : null; final String tempDirAbsPath = null != tempDir ? tempDir.getAbsolutePath() : null; - System.err.println("TempJarCache.initSingleton(): ok "+(false==staticInitError)+", "+ tempDirAbsPath); + System.err.println("TempJarCache.initSingleton(): ok "+(false==staticInitError)+", "+ tempDirAbsPath+", executable "+staticTempIsExecutable); } isInit = true; } @@ -163,44 +166,77 @@ public class TempJarCache { } /** - * @return true if this class has been properly initialized, ie. is in use, otherwise false. + * @param forExecutables if {@code true}, method also tests whether the underlying cache is suitable to load native libraries or launch executables + * @return true if this class has been properly initialized, ie. is in use. Otherwise returns false. */ - public static boolean isInitialized() { - return isInitializedImpl() && !staticInitError; + public static boolean isInitialized(final boolean forExecutables) { + return isInitializedImpl() && !staticInitError && ( !forExecutables || staticTempIsExecutable ); } - /* package */ static void checkInitialized() { + /** + * @param forExecutables if {@code true}, method also tests whether the underlying cache is suitable to load native libraries or launch executables + */ + /* package */ static void checkInitialized(final boolean forExecutables) { if(!isInitializedImpl()) { - throw new RuntimeException("initSingleton() has to be called first."); + throw new JogampRuntimeException("initSingleton() has to be called first."); } if(staticInitError) { - throw new RuntimeException("initSingleton() failed."); + throw new JogampRuntimeException("initSingleton() failed."); + } + if( forExecutables && !staticTempIsExecutable ) { + throw new JogampRuntimeException("TempJarCache folder not suitable for executables"); } } + /** + * @return the underlying {@link TempFileCache} + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(false)} + */ public static TempFileCache getTempFileCache() { - checkInitialized(); + checkInitialized(false); return tmpFileCache; } + /** + * @param jarUri + * @param exp + * @return + * @throws IOException + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(false)} + */ public synchronized static boolean checkNativeLibs(final Uri jarUri, final LoadState exp) throws IOException { - checkInitialized(); + checkInitialized(false); if(null == jarUri) { throw new IllegalArgumentException("jarUri is null"); } return testLoadState(nativeLibJars.get(jarUri), exp); } + /** + * @param jarUri + * @param exp + * @return + * @throws IOException + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(false)} + */ public synchronized static boolean checkClasses(final Uri jarUri, final LoadState exp) throws IOException { - checkInitialized(); + checkInitialized(false); if(null == jarUri) { throw new IllegalArgumentException("jarUri is null"); } return testLoadState(classFileJars.get(jarUri), exp); } + /** + * + * @param jarUri + * @param exp + * @return + * @throws IOException + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(false)} + */ public synchronized static boolean checkResources(final Uri jarUri, final LoadState exp) throws IOException { - checkInitialized(); + checkInitialized(false); if(null == jarUri) { throw new IllegalArgumentException("jarUri is null"); } @@ -218,9 +254,10 @@ public class TempJarCache { * @throws SecurityException * @throws URISyntaxException * @throws IllegalArgumentException + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(true)} */ public synchronized static final boolean addNativeLibs(final Class certClass, final Uri jarUri, final String nativeLibraryPath) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { - checkInitialized(); + checkInitialized(true); final LoadState nativeLibJarsLS = nativeLibJars.get(jarUri); if( !testLoadState(nativeLibJarsLS, LoadState.LOOKED_UP) ) { nativeLibJars.put(jarUri, LoadState.LOOKED_UP); @@ -253,9 +290,10 @@ public class TempJarCache { * @throws SecurityException * @throws URISyntaxException * @throws IllegalArgumentException + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(false)} */ public synchronized static final void addClasses(final Class certClass, final Uri jarUri) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { - checkInitialized(); + checkInitialized(false); final LoadState classFileJarsLS = classFileJars.get(jarUri); if( !testLoadState(classFileJarsLS, LoadState.LOOKED_UP) ) { classFileJars.put(jarUri, LoadState.LOOKED_UP); @@ -282,9 +320,10 @@ public class TempJarCache { * @throws SecurityException * @throws URISyntaxException * @throws IllegalArgumentException + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(false)} */ public synchronized static final void addResources(final Class certClass, final Uri jarUri) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { - checkInitialized(); + checkInitialized(false); final LoadState resourceFileJarsLS = resourceFileJars.get(jarUri); if( !testLoadState(resourceFileJarsLS, LoadState.LOOKED_UP) ) { resourceFileJars.put(jarUri, LoadState.LOOKED_UP); @@ -314,9 +353,10 @@ public class TempJarCache { * @throws SecurityException * @throws URISyntaxException * @throws IllegalArgumentException + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(false)} */ public synchronized static final void addAll(final Class certClass, final Uri jarUri) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { - checkInitialized(); + checkInitialized(false); if(null == jarUri) { throw new IllegalArgumentException("jarUri is null"); } @@ -327,7 +367,7 @@ public class TempJarCache { !testLoadState(classFileJarsLS, LoadState.LOOKED_UP) || !testLoadState(resourceFileJarsLS, LoadState.LOOKED_UP) ) { - final boolean extractNativeLibraries = !testLoadState(nativeLibJarsLS, LoadState.LOADED); + final boolean extractNativeLibraries = staticTempIsExecutable && !testLoadState(nativeLibJarsLS, LoadState.LOADED); final boolean extractClassFiles = !testLoadState(classFileJarsLS, LoadState.LOADED); final boolean extractOtherFiles = !testLoadState(resourceFileJarsLS, LoadState.LOOKED_UP); @@ -367,8 +407,18 @@ public class TempJarCache { } } + /** + * If {@link #isInitialized(boolean) isInitialized(true)} is false due to lack of executable support only, + * this method always returns false. + * @param libName + * @return the found native library path within this cache or null if not found + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(false)} + */ public synchronized static final String findLibrary(final String libName) { - checkInitialized(); + checkInitialized(false); + if( !staticTempIsExecutable ) { + return null; + } // try with mapped library basename first String path = nativeLibMap.get(libName); if(null == path) { @@ -398,9 +448,14 @@ public class TempJarCache { return null; } */ - /** Similar to {@link ClassLoader#getResource(String)}. */ + /** + * Similar to {@link ClassLoader#getResource(String)}. + * @param name + * @return + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(false)} + */ public synchronized static final String findResource(final String name) { - checkInitialized(); + checkInitialized(false); final File f = new File(tmpFileCache.getTempDir(), name); if(f.exists()) { return f.getAbsolutePath(); @@ -408,9 +463,15 @@ public class TempJarCache { return null; } - /** Similar to {@link ClassLoader#getResource(String)}. */ + /** + * Similar to {@link ClassLoader#getResource(String)}. + * @param name + * @return + * @throws URISyntaxException + * @throws JogampRuntimeException if not {@link #isInitialized(boolean) isInitialized(false)} + */ public synchronized static final Uri getResourceUri(final String name) throws URISyntaxException { - checkInitialized(); + checkInitialized(false); final File f = new File(tmpFileCache.getTempDir(), name); if(f.exists()) { return Uri.valueOf(f); diff --git a/src/junit/com/jogamp/common/util/TestJarUtil.java b/src/junit/com/jogamp/common/util/TestJarUtil.java index 747da8f..6cc38ed 100644 --- a/src/junit/com/jogamp/common/util/TestJarUtil.java +++ b/src/junit/com/jogamp/common/util/TestJarUtil.java @@ -73,7 +73,7 @@ public class TestJarUtil extends SingletonJunitCase { Assert.assertTrue(TempCacheReg.isTempFileCacheUsed()); fileCache = new TempFileCache(); - Assert.assertTrue(fileCache.isValid()); + Assert.assertTrue(fileCache.isValid(false)); System.err.println("tmp dir: "+fileCache.getTempDir()); } @@ -150,8 +150,8 @@ public class TestJarUtil extends SingletonJunitCase { System.err.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXX"); Assert.assertTrue(TempJarCache.initSingleton()); - Assert.assertTrue(TempCacheReg.isTempJarCacheUsed()); - Assert.assertTrue(TempJarCache.isInitialized()); + Assert.assertTrue(TempCacheReg.isTempJarCacheUsed(false)); + Assert.assertTrue(TempJarCache.isInitialized(false)); final ClassLoader rootCL = this.getClass().getClassLoader(); @@ -171,8 +171,8 @@ public class TestJarUtil extends SingletonJunitCase { System.err.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXX"); Assert.assertTrue(TempJarCache.initSingleton()); - Assert.assertTrue(TempCacheReg.isTempJarCacheUsed()); - Assert.assertTrue(TempJarCache.isInitialized()); + Assert.assertTrue(TempCacheReg.isTempJarCacheUsed(false)); + Assert.assertTrue(TempJarCache.isInitialized(false)); final ClassLoader rootCL = this.getClass().getClassLoader(); @@ -199,8 +199,8 @@ public class TestJarUtil extends SingletonJunitCase { System.err.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXX"); Assert.assertTrue(TempJarCache.initSingleton()); - Assert.assertTrue(TempCacheReg.isTempJarCacheUsed()); - Assert.assertTrue(TempJarCache.isInitialized()); + Assert.assertTrue(TempCacheReg.isTempJarCacheUsed(false)); + Assert.assertTrue(TempJarCache.isInitialized(false)); /** This classloader mimics what OSGi's does -- it takes jar: URLs and makes them into bundleresource: URLs * where the JAR is not directly accessible anymore. Here I leave the JAR name at the end of the URL so I can diff --git a/src/junit/com/jogamp/common/util/TestTempJarCache.java b/src/junit/com/jogamp/common/util/TestTempJarCache.java index 9cc855f..4507eb8 100644 --- a/src/junit/com/jogamp/common/util/TestTempJarCache.java +++ b/src/junit/com/jogamp/common/util/TestTempJarCache.java @@ -72,8 +72,8 @@ public class TestTempJarCache extends SingletonJunitCase { Assert.assertTrue(fileCache3.getTempDir().exists()); Assert.assertTrue(fileCache3.getTempDir().isDirectory()); - Assert.assertEquals(fileCache2.getBaseDir(), fileCache3.getBaseDir()); - Assert.assertEquals(fileCache2.getRootDir(), fileCache3.getRootDir()); + Assert.assertEquals(TempFileCache.getBaseDir(), TempFileCache.getBaseDir()); + Assert.assertEquals(TempFileCache.getRootDir(), TempFileCache.getRootDir()); if(shallBeSame) { Assert.assertTrue("file caches are not equal", fileCache2.getTempDir().equals(fileCache3.getTempDir())); @@ -122,7 +122,7 @@ public class TestTempJarCache extends SingletonJunitCase { Assert.assertTrue(TempCacheReg.isTempFileCacheUsed()); fileCache = new TempFileCache(); - Assert.assertTrue(fileCache.isValid()); + Assert.assertTrue(fileCache.isValid(false)); System.err.println("tmp dir: "+fileCache.getTempDir()); } @@ -167,8 +167,8 @@ public class TestTempJarCache extends SingletonJunitCase { // Assert.assertFalse(TempCacheReg.isTempJarCacheUsed()); // Assert.assertFalse(TempJarCache.isInitialized()); Assert.assertTrue(TempJarCache.initSingleton()); - Assert.assertTrue(TempCacheReg.isTempJarCacheUsed()); - Assert.assertTrue(TempJarCache.isInitialized()); + Assert.assertTrue(TempCacheReg.isTempJarCacheUsed(false)); + Assert.assertTrue(TempJarCache.isInitialized(false)); } @Test -- cgit v1.2.3