diff options
author | Denis Lila <[email protected]> | 2011-04-29 16:58:05 -0400 |
---|---|---|
committer | Denis Lila <[email protected]> | 2011-04-29 16:58:05 -0400 |
commit | 56d85fafd578e28fc17211d28f4f0a701192e789 (patch) | |
tree | 163144e2f7b4a7dcf42d38e35decc0ece28a03fb /netx/net | |
parent | d11445dcf1ad408836766709c47f47ef2aec1d31 (diff) |
Fix appcontext related plugin bugs.
Diffstat (limited to 'netx/net')
-rw-r--r-- | netx/net/sourceforge/jnlp/Launcher.java | 17 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/NetxPanel.java | 89 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/PluginBridge.java | 32 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/AppThreadGroup.java | 63 |
4 files changed, 79 insertions, 122 deletions
diff --git a/netx/net/sourceforge/jnlp/Launcher.java b/netx/net/sourceforge/jnlp/Launcher.java index 2c0af48..988650b 100644 --- a/netx/net/sourceforge/jnlp/Launcher.java +++ b/netx/net/sourceforge/jnlp/Launcher.java @@ -32,7 +32,6 @@ import java.util.jar.JarFile; import net.sourceforge.jnlp.cache.CacheUtil; import net.sourceforge.jnlp.cache.UpdatePolicy; -import net.sourceforge.jnlp.runtime.AppThreadGroup; import net.sourceforge.jnlp.runtime.AppletInstance; import net.sourceforge.jnlp.runtime.ApplicationInstance; import net.sourceforge.jnlp.runtime.JNLPClassLoader; @@ -702,7 +701,7 @@ public class Launcher { throw new ClassNotFoundException("Can't do a codebase look up and there are no jars. Failing sooner rather than later"); } - AppThreadGroup group = (AppThreadGroup) Thread.currentThread().getThreadGroup(); + ThreadGroup group = Thread.currentThread().getThreadGroup(); String appletName = file.getApplet().getMainClass(); @@ -718,7 +717,6 @@ public class Launcher { else appletInstance = new AppletInstance(file, group, loader, applet, cont); - group.setApplication(appletInstance); loader.setApplication(appletInstance); setContextClassLoaderForAllThreads(appletInstance.getThreadGroup(), appletInstance.getClassLoader()); @@ -765,10 +763,9 @@ public class Launcher { protected ApplicationInstance createApplication(JNLPFile file) throws LaunchException { try { JNLPClassLoader loader = JNLPClassLoader.getInstance(file, updatePolicy); - AppThreadGroup group = (AppThreadGroup) Thread.currentThread().getThreadGroup(); + ThreadGroup group = Thread.currentThread().getThreadGroup(); ApplicationInstance app = new ApplicationInstance(file, group, loader); - group.setApplication(app); loader.setApplication(app); return app; @@ -784,16 +781,16 @@ public class Launcher { * then this method simply returns the existing ThreadGroup. The applet * ThreadGroup has to be created at an earlier point in the applet code. */ - protected AppThreadGroup createThreadGroup(JNLPFile file) { - AppThreadGroup appThreadGroup = null; + protected ThreadGroup createThreadGroup(JNLPFile file) { + ThreadGroup tg = null; if (file instanceof PluginBridge) { - appThreadGroup = (AppThreadGroup) Thread.currentThread().getThreadGroup(); + tg = Thread.currentThread().getThreadGroup(); } else { - appThreadGroup = new AppThreadGroup(mainGroup, file.getTitle()); + tg = new ThreadGroup(mainGroup, file.getTitle()); } - return appThreadGroup; + return tg; } /** diff --git a/netx/net/sourceforge/jnlp/NetxPanel.java b/netx/net/sourceforge/jnlp/NetxPanel.java index 2d723d4..e8d43cd 100644 --- a/netx/net/sourceforge/jnlp/NetxPanel.java +++ b/netx/net/sourceforge/jnlp/NetxPanel.java @@ -23,12 +23,13 @@ package net.sourceforge.jnlp; import net.sourceforge.jnlp.AppletLog; -import net.sourceforge.jnlp.runtime.AppThreadGroup; import net.sourceforge.jnlp.runtime.AppletInstance; import net.sourceforge.jnlp.runtime.JNLPRuntime; import java.net.URL; import java.util.Hashtable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import sun.applet.AppletViewerPanel; import sun.awt.SunToolkit; @@ -44,9 +45,58 @@ public class NetxPanel extends AppletViewerPanel { private boolean exitOnFailure = true; private AppletInstance appInst = null; private boolean appletAlive; + private final String uKey; + + // We use this so that we can create exactly one thread group + // for all panels with the same uKey. + private static final ConcurrentMap<String, ThreadGroup> uKeyToTG = + new ConcurrentHashMap<String, ThreadGroup>(); + + // This map is actually a set (unfortunately there is no ConcurrentSet + // in java.util.concurrent). If KEY is in this map, then we know that + // an app context has been created for the panel that has uKey.equals(KEY), + // so we avoid creating it a second time for panels with the same uKey. + // Because it's a set, only the keys matter. However, we can't insert + // null values in because if we did, we couldn't use null checks to see + // if a key was absent before a putIfAbsent. + private static final ConcurrentMap<String, Boolean> appContextCreated = + new ConcurrentHashMap<String, Boolean>(); public NetxPanel(URL documentURL, Hashtable<String, String> atts) { super(documentURL, atts); + + /* According to http://download.oracle.com/javase/6/docs/technotes/guides/deployment/deployment-guide/applet-compatibility.html, + * classloaders are shared iff these properties match: + * codebase, cache_archive, java_archive, archive + * + * To achieve this, we create the uniquekey based on those 4 values, + * always in the same order. The initial "<NAME>=" parts ensure a + * bad tag cannot trick the loader into getting shared with another. + */ + + // Firefox sometimes skips the codebase if it is default -- ".", + // so set it that way if absent + String codebaseAttr = atts.get("codebase") != null ? + atts.get("codebase") : "."; + + String cache_archiveAttr = atts.get("cache_archive") != null ? + atts.get("cache_archive") : ""; + + String java_archiveAttr = atts.get("java_archive") != null ? + atts.get("java_archive") : ""; + + String archiveAttr = atts.get("archive") != null ? + atts.get("archive") : ""; + + this.uKey = "codebase=" + codebaseAttr + + "cache_archive=" + cache_archiveAttr + + "java_archive=" + java_archiveAttr + + "archive=" + archiveAttr; + + // when this was being done (incorrectly) in Launcher, the call was + // new AppThreadGroup(mainGroup, file.getTitle()); + ThreadGroup tg = new ThreadGroup(Launcher.mainGroup, this.documentURL.toString()); + uKeyToTG.putIfAbsent(this.uKey, tg); } // overloaded constructor, called when initialized via plugin @@ -58,18 +108,6 @@ public class NetxPanel extends AppletViewerPanel { } @Override - public void run() { - /* - * create an AppContext for this thread associated with this particular - * plugin instance (which runs in a different thread group from the rest - * of the plugin). - */ - SunToolkit.createNewAppContext(); - - super.run(); - } - - @Override protected void showAppletException(Throwable t) { /* * Log any exceptions thrown while loading, initializing, starting, @@ -78,7 +116,7 @@ public class NetxPanel extends AppletViewerPanel { AppletLog.log(t); super.showAppletException(t); } - + //Overriding to use Netx classloader. You might need to relax visibility //in sun.applet.AppletPanel for runLoader(). protected void runLoader() { @@ -90,7 +128,7 @@ public class NetxPanel extends AppletViewerPanel { getCode(), getWidth(), getHeight(), - atts); + atts, uKey); doInit = true; dispatchAppletEvent(APPLET_LOADING, null); @@ -154,11 +192,7 @@ public class NetxPanel extends AppletViewerPanel { } } - // when this was being done (incorrectly) in Launcher, the call was - // new AppThreadGroup(mainGroup, file.getTitle()); - ThreadGroup tg = new AppThreadGroup(Launcher.mainGroup, - this.documentURL.toString()); - handler = new Thread(tg, this); + handler = new Thread(getThreadGroup(), this); handler.start(); } @@ -174,4 +208,19 @@ public class NetxPanel extends AppletViewerPanel { public boolean isAlive() { return handler != null && handler.isAlive() && this.appletAlive; } + + public ThreadGroup getThreadGroup() { + return uKeyToTG.get(uKey); + } + + public void createNewAppContext() { + if (Thread.currentThread().getThreadGroup() != getThreadGroup()) { + throw new RuntimeException("createNewAppContext called from the wrong thread."); + } + // only create a new context if one hasn't already been created for the + // applets with this unique key. + if (null == appContextCreated.putIfAbsent(uKey, Boolean.TRUE)) { + SunToolkit.createNewAppContext(); + } + } } diff --git a/netx/net/sourceforge/jnlp/PluginBridge.java b/netx/net/sourceforge/jnlp/PluginBridge.java index cbb6be1..f4cfa1e 100644 --- a/netx/net/sourceforge/jnlp/PluginBridge.java +++ b/netx/net/sourceforge/jnlp/PluginBridge.java @@ -44,7 +44,8 @@ public class PluginBridge extends JNLPFile { private boolean codeBaseLookup; public PluginBridge(URL codebase, URL documentBase, String jar, String main, - int width, int height, Hashtable<String, String> atts) + int width, int height, Hashtable<String, String> atts, + String uKey) throws Exception { specVersion = new Version("1.0"); fileVersion = new Version("1.1"); @@ -132,34 +133,7 @@ public class PluginBridge extends JNLPFile { else security = null; - /* According to http://download.oracle.com/javase/6/docs/technotes/guides/deployment/deployment-guide/applet-compatibility.html, - * classloaders are shared iff these properties match: - * codebase, cache_archive, java_archive, archive - * - * To achieve this, we create the uniquekey based on those 4 values, - * always in the same order. The initial "<NAME>=" parts ensure a - * bad tag cannot trick the loader into getting shared with another. - */ - - // Firefox sometimes skips the codebase if it is default -- ".", - // so set it that way if absent - String codebaseAttr = atts.get("codebase") != null ? - atts.get("codebase") : "."; - - String cache_archiveAttr = atts.get("cache_archive") != null ? - atts.get("cache_archive") : ""; - - String java_archiveAttr = atts.get("java_archive") != null ? - atts.get("java_archive") : ""; - - String archiveAttr = atts.get("archive") != null ? - atts.get("archive") : ""; - - this.uniqueKey = "codebase=" + codebaseAttr + - "cache_archive=" + cache_archiveAttr + - "java_archive=" + java_archiveAttr + - "archive=" + archiveAttr; - + this.uniqueKey = uKey; usePack = false; useVersion = false; String jargs = atts.get("java_arguments"); diff --git a/netx/net/sourceforge/jnlp/runtime/AppThreadGroup.java b/netx/net/sourceforge/jnlp/runtime/AppThreadGroup.java deleted file mode 100644 index f09bf36..0000000 --- a/netx/net/sourceforge/jnlp/runtime/AppThreadGroup.java +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2001-2003 Jon A. Maxwell (JAM) -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -package net.sourceforge.jnlp.runtime; - -/** - * Thread group for a JNLP application. - * - * @author <a href="mailto:[email protected]">Jon A. Maxwell (JAM)</a> - initial author - * @version $Revision: 1.5 $ - */ -public class AppThreadGroup extends ThreadGroup { - - /** the app */ - private ApplicationInstance app = null; - - /** - * Creates new JavaAppThreadGroup - * - * @param name of the App - */ - public AppThreadGroup(ThreadGroup parent, String name) { - super(parent, name); - } - - /** - * Sets the JNLP app this group is for; can only be called once. - */ - public void setApplication(ApplicationInstance app) { - if (this.app != null) - throw new IllegalStateException("Application can only be set once"); - - this.app = app; - } - - /** - * Returns the JNLP app for this thread group. - */ - public ApplicationInstance getApplication() { - return app; - } - - /** - * Handle uncaught exceptions for the app. - */ - public void uncaughtException(Thread t, Throwable e) { - super.uncaughtException(t, e); - } - -} |