aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java52
1 files changed, 47 insertions, 5 deletions
diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
index f889161..b4cd315 100644
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
@@ -123,11 +123,17 @@ public class JNLPClassLoader extends URLClassLoader {
private boolean isSignedJNLP = false;
/** map from JNLPFile unique key to shared classloader */
- private static Map<String, JNLPClassLoader> uniqueKeyToLoader = new ConcurrentHashMap<String, JNLPClassLoader>();
+ private static final Object uniqueKeyMapLock = new Object();
+ /** Cached ClassLoaders in active state */
+ private static final Map<String, JNLPClassLoader> uniqueKeyToLoaderActive = new HashMap<String, JNLPClassLoader>();
+ /** Cached ClassLoaders which removal is pending, i.e. {@link #PENDING_REMOVAL_TO} */
+ private static final Map<String, JNLPClassLoader> uniqueKeyToLoaderPending = new HashMap<String, JNLPClassLoader>();
+ /** Period in milliseconds to wait until removing pending ClassLoaders, i.e. {@value} ms */
+ private static final long PENDING_REMOVAL_TO = 60*1000;
/** map from JNLPFile unique key to lock, the lock is needed to enforce correct
* initialization of applets that share a unique key*/
- private static Map<String, ReentrantLock> uniqueKeyToLock = new HashMap<String, ReentrantLock>();
+ private static final Map<String, ReentrantLock> uniqueKeyToLock = new HashMap<String, ReentrantLock>();
/** Provides a search path & temporary storage for native code */
private final NativeLibraryStorage nativeLibraryStorage;
@@ -435,6 +441,21 @@ public class JNLPClassLoader extends URLClassLoader {
final JNLPFile f = getJNLPFile();
return "JNLPClassLoader@"+hashCode()+"[refCnt "+useCount+", file "+f.getFileLocation()+", code "+f.getCodeBase()+"]";
}
+
+ private static JNLPClassLoader getCached(final String uniqueKey) {
+ synchronized(uniqueKeyMapLock) {
+ JNLPClassLoader res = uniqueKeyToLoaderActive.get(uniqueKey);
+ if( null == res ) {
+ res = uniqueKeyToLoaderPending.remove(uniqueKey);
+ if( null != res ) {
+ uniqueKeyToLoaderActive.put(uniqueKey, res);
+ OutputController.getLogger().log("JNLPClassLoader.Cache.reactivated: key "+uniqueKey +" -> "+res);
+ }
+ }
+ return res;
+ }
+ }
+
/**
* Returns a JNLP classloader for the specified JNLP file.
*
@@ -449,7 +470,7 @@ public class JNLPClassLoader extends URLClassLoader {
final OutputController out = OutputController.getLogger();
synchronized ( getUniqueKeyLock(uniqueKey) ) {
- baseLoader = uniqueKeyToLoader.get(uniqueKey);
+ baseLoader = getCached(uniqueKey);
out.log("JNLPClassLoader.Cache: file isApp "+file.isApplication()+", file "+file.getFileLocation()+", code "+file.getCodeBase());
out.log("JNLPClassLoader.Cache: key "+uniqueKey +" -> "+baseLoader);
final int mode;
@@ -513,7 +534,7 @@ public class JNLPClassLoader extends URLClassLoader {
JNLPClassLoader loader;
synchronized ( getUniqueKeyLock(uniqueKey) ) {
- loader = uniqueKeyToLoader.get(uniqueKey);
+ loader = getCached(uniqueKey);
if (loader == null || !location.equals(loader.getJNLPFile().getFileLocation())) {
JNLPFile jnlpFile = new JNLPFile(location, uniqueKey, version, settings, policy);
@@ -2230,7 +2251,28 @@ public class JNLPClassLoader extends URLClassLoader {
useCount--;
if (useCount <= 0) {
- uniqueKeyToLoader.remove(uniqueKey);
+ synchronized(uniqueKeyMapLock) {
+ final JNLPClassLoader pending = uniqueKeyToLoaderActive.remove(uniqueKey);
+ uniqueKeyToLoaderPending.put(uniqueKey, pending);
+ OutputController.getLogger().log("JNLPClassLoader.Cache.removed: Pending "+pending);
+ final Thread removePendingThread = new Thread("Pending removal of "+pending.toString()) {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(PENDING_REMOVAL_TO);
+ } catch (InterruptedException e) { }
+ final JNLPClassLoader removed = uniqueKeyToLoaderPending.remove(uniqueKey);
+ if( null != removed ) {
+ OutputController.getLogger().log("JNLPClassLoader.Cache.removed: Terminated "+removed);
+ }
+ } };
+ removePendingThread.setDaemon(true);
+ removePendingThread.start();
+ /** FIXME: When to remove the uniqueKeyToLock ?
+ synchronized (uniqueKeyToLock) {
+ uniqueKeyToLock.remove(uniqueKey);
+ } */
+ }
}
}
}