From 1157b913a068167062c853b4b525954b223a5509 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
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 ++++++++++++++++-----
 6 files changed, 130 insertions(+), 40 deletions(-)

(limited to 'src/java/com')

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 <code>individualTmpDir</code>. */
+    /** 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 <code>individualTmpDir</code> 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}.
      *
      * <p>
-     * Lifecycle: For one user's JVMs, ClassLoader and time.
+     * Lifecycle: For one user's concurrently running JVMs and ClassLoader
      * </p>
      *
      * 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.
+     * <p>
+     * This directory is a sub-folder to {@link #getBaseDir()}.
+     * </p>
      *
      * <p>
      * 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:
+     * <p>
+     * This directory is a sub-folder to {@link #getRootDir()}.
+     * </p>
      *
      * <p>
-     * Lifecycle: Within each JVM .. use case dependent, ie. per ClassLoader
+     * Lifecycle: Within each JVM .. use case dependent, ie. per ClassLoader <b>and</b> per {@link TempFileCache} instance!
      * </p>
+     * <p>
+     * The directory name is:
      *
      * <pre>
      *   tmpRootDir/jlnMMMMM
@@ -514,7 +539,7 @@ public class TempFileCache {
      *
      * where jlnMMMMM is the unique filename created by File.createTempFile()
      * without the ".tmp" extension.
-     *
+     * </p>
      *
      * @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);
-- 
cgit v1.2.3