diff options
Diffstat (limited to 'plugin/icedteanp')
13 files changed, 1707 insertions, 25 deletions
diff --git a/plugin/icedteanp/java/sun/applet/PluginAppletPanelFactory.java b/plugin/icedteanp/java-awt/sun/applet/PluginAppletPanelFactory.java index 429cb62..429cb62 100644 --- a/plugin/icedteanp/java/sun/applet/PluginAppletPanelFactory.java +++ b/plugin/icedteanp/java-awt/sun/applet/PluginAppletPanelFactory.java diff --git a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java b/plugin/icedteanp/java-awt/sun/applet/PluginAppletViewer.java index 8d1630d..8d1630d 100644 --- a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java +++ b/plugin/icedteanp/java-awt/sun/applet/PluginAppletViewer.java diff --git a/plugin/icedteanp/java/jogamp/plugin/applet/PluginApplet3PanelFactory.java b/plugin/icedteanp/java/jogamp/plugin/applet/PluginApplet3PanelFactory.java new file mode 100644 index 0000000..2c9040c --- /dev/null +++ b/plugin/icedteanp/java/jogamp/plugin/applet/PluginApplet3PanelFactory.java @@ -0,0 +1,229 @@ +/* Copyright (C) 2012 Red Hat + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +IcedTea 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +/* + * Copyright 1995-2004 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package jogamp.plugin.applet; + +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import jogamp.applet.Applet3Panel; +import jogamp.plugin.jnlp.NetxApplet3Panel; +import net.sourceforge.jnlp.PluginParameters; +import net.sourceforge.jnlp.util.logging.OutputController; +import sun.applet.AppletPanel; +import sun.applet.AppletSecurityContextManager; +import sun.applet.PluginDebug; +import sun.applet.PluginStreamHandler; + +import com.jogamp.plugin.applet.Applet3; + +/** + * Lets us construct one using unix-style one shot behaviors + */ + +public class PluginApplet3PanelFactory { + + public Applet3Panel createPanel(PluginStreamHandler streamhandler, + final int identifier, + final long nativeWindowHandle, + final URL doc, + final PluginParameters params) { + final int width = params.getWidth(); + final int height = params.getHeight(); + PluginDebug.debug("NativeWindow (Browser) Handle: 0x" + Long.toHexString(nativeWindowHandle)); + PluginDebug.debug("NativeWindow (Browser) Size: " + width + " x " + height); + final NetxApplet3Panel panel = AccessController.doPrivileged(new PrivilegedAction<NetxApplet3Panel>() { + @Override + public NetxApplet3Panel run() { + NetxApplet3Panel panel = new NetxApplet3Panel(nativeWindowHandle, width, height, doc, params); + NetxApplet3Panel.debug("Using NetX panel"); + PluginDebug.debug(params.toString()); + return panel; + } + }); + + // Framing the panel needs to happen in a thread whose thread group + // is the same as the threadgroup of the applet thread. If this + // isn't the case, the awt eventqueue thread's context classloader + // won't be set to a JNLPClassLoader, and when an applet class needs + // to be loaded from the awt eventqueue, it won't be found. + Thread panelInit = new Thread(panel.getThreadGroup(), new Runnable() { + @Override public void run() { + panel.createNewAppContext(); + // create the frame. + final PluginApplet3Viewer pav = PluginApplet3Viewer.framePanel(identifier, panel); + panel.setAppletViewerFrame(pav); + panel.setAppletContext(pav); + + panel.init(); + // Start the applet + initEventQueue(panel); + } + }, "NetXPanel initializer"); + + panelInit.start(); + try { + panelInit.join(); + } catch (InterruptedException e) { + OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e); + } + + setAppletViewerSize(panel, params.getWidth(), params.getHeight()); + + // Wait for the panel to initialize + PluginApplet3Viewer.waitForAppletInit(panel); + + Applet3 a = panel.getApplet(); + + // Still null? + if (a == null) { + streamhandler.write("instance " + identifier + " reference " + -1 + " fatalError: " + "Initialization timed out"); + return null; + } + + PluginDebug.debug("Applet ", a.getClass(), " initialized"); + streamhandler.write("instance " + identifier + " reference 0 initialized"); + + panel.removeSplash(); + + AppletSecurityContextManager.getSecurityContext(0).associateSrc(panel.getAppletClassLoader(), doc); + AppletSecurityContextManager.getSecurityContext(0).associateInstance(identifier, panel.getAppletClassLoader()); + + return panel; + } + + /* AppletViewerPanel sometimes doesn't set size right initially. This + * causes the parent frame to be the default (10x10) size. + * + * Normally it goes unnoticed since browsers like Firefox make a resize + * call after init. However some browsers (e.g. Midori) don't. + * + * We therefore manually set the parent to the right size. + */ + static private void setAppletViewerSize(final Applet3Panel panel, + final int width, final int height) { + try { + panel.resize(width, height); + } catch (Exception e) { + // Not being able to resize is non-fatal + PluginDebug.debug("Unable to resize panel: "); + OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e); + } + } + /** + * Send the initial set of events to the appletviewer event queue. + * On start-up the current behaviour is to load the applet and call + * Applet.init() and Applet.start(). + */ + private void initEventQueue(Applet3Panel panel) { + // appletviewer.send.event is an undocumented and unsupported system + // property which is used exclusively for testing purposes. + PrivilegedAction<String> pa = new PrivilegedAction<String>() { + @Override + public String run() { + return System.getProperty("appletviewer.send.event"); + } + }; + String eventList = AccessController.doPrivileged(pa); + + if (eventList == null) { + // Add the standard events onto the event queue. + panel.sendEvent(AppletPanel.APPLET_LOAD); + panel.sendEvent(AppletPanel.APPLET_INIT); + panel.sendEvent(AppletPanel.APPLET_START); + } else { + // We're testing AppletViewer. Force the specified set of events + // onto the event queue, wait for the events to be processed, and + // exit. + + // The list of events that will be executed is provided as a + // ","-separated list. No error-checking will be done on the list. + String[] events = eventList.split(","); + + for (String event : events) { + PluginDebug.debug("Adding event to queue: ", event); + if ("dispose".equals(event)) + panel.sendEvent(AppletPanel.APPLET_DISPOSE); + else if ("load".equals(event)) + panel.sendEvent(AppletPanel.APPLET_LOAD); + else if ("init".equals(event)) + panel.sendEvent(AppletPanel.APPLET_INIT); + else if ("start".equals(event)) + panel.sendEvent(AppletPanel.APPLET_START); + else if ("stop".equals(event)) + panel.sendEvent(AppletPanel.APPLET_STOP); + else if ("destroy".equals(event)) + panel.sendEvent(AppletPanel.APPLET_DESTROY); + else if ("quit".equals(event)) + panel.sendEvent(AppletPanel.APPLET_QUIT); + else if ("error".equals(event)) + panel.sendEvent(AppletPanel.APPLET_ERROR); + else + // non-fatal error if we get an unrecognized event + PluginDebug.debug("Unrecognized event name: ", event); + } + + while (!panel.emptyEventQueue()) + ; + } + } +}
\ No newline at end of file diff --git a/plugin/icedteanp/java/jogamp/plugin/applet/PluginApplet3Viewer.java b/plugin/icedteanp/java/jogamp/plugin/applet/PluginApplet3Viewer.java new file mode 100644 index 0000000..338ce42 --- /dev/null +++ b/plugin/icedteanp/java/jogamp/plugin/applet/PluginApplet3Viewer.java @@ -0,0 +1,1423 @@ +/* PluginAppletViewer -- Handles embedding of the applet panel + Copyright (C) 2008 Red Hat + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +IcedTea 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +/* + * Copyright 1995-2004 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package jogamp.plugin.applet; + +import static net.sourceforge.jnlp.runtime.Translator.R; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.SocketPermission; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.security.AccessController; +import java.security.AllPermission; +import java.security.PrivilegedAction; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +import jogamp.applet.App3Context; +import jogamp.applet.Applet3Panel; +import jogamp.plugin.jnlp.NetxApplet3Panel; +import net.sourceforge.jnlp.LaunchException; +import net.sourceforge.jnlp.PluginParameters; +import net.sourceforge.jnlp.runtime.JNLPClassLoader; +import net.sourceforge.jnlp.security.appletextendedsecurity.AppletSecurityLevel; +import net.sourceforge.jnlp.security.appletextendedsecurity.AppletStartupSecuritySettings; +import net.sourceforge.jnlp.splashscreen.SplashController; +import net.sourceforge.jnlp.splashscreen.SplashPanel; +import net.sourceforge.jnlp.splashscreen.SplashUtils; +import net.sourceforge.jnlp.util.logging.OutputController; +import sun.applet.Applet3MessageHandler; +import sun.applet.AppletEvent; +import sun.applet.AppletListener; +import sun.applet.AppletPanel; +import sun.applet.AppletSecurityContextManager; +import sun.applet.PluginAppletSecurityContext; +import sun.applet.PluginCallRequest; +import sun.applet.PluginCallRequestFactory; +import sun.applet.PluginDebug; +import sun.applet.PluginMessageConsumer; +import sun.applet.PluginParameterParser; +import sun.applet.PluginStreamHandler; + +import com.jogamp.plugin.applet.Applet3; +import com.jogamp.plugin.applet.Applet3Context; +import com.sun.jndi.toolkit.url.UrlUtil; + +/* + */ +// FIXME: declare JSProxy implementation +public class PluginApplet3Viewer implements Applet3Context, SplashController { + + /** + * Enumerates the current status of an applet + * + * PRE_INIT -> Parsing and initialization phase + * INIT_COMPLETE -> Initialization complete, reframe pending + * REFRAME_COMPLETE -> Reframe complete, applet is initialized and usable by the user + * INACTIVE -> Browser has directed that the applet be destroyed (this state is non-overridable except by DESTROYED) + * DESTROYED -> Applet has been destroyed + */ + private static enum PAV_INIT_STATUS { + PRE_INIT, INIT_COMPLETE, REFRAME_COMPLETE, INACTIVE, DESTROYED + }; + + /** + * The panel in which the applet is being displayed. + */ + private final NetxApplet3Panel panel; + static final ReentrantLock panelLock = new ReentrantLock(); + // CONDITION PREDICATE: panel.isAlive() + static final Condition panelLive = panelLock.newCondition(); + private int identifier; + + // Instance identifier -> PluginAppletViewer object. + private static ConcurrentMap<Integer, PluginApplet3Viewer> applets = + new ConcurrentHashMap<Integer, PluginApplet3Viewer>(); + private static final ReentrantLock appletsLock = new ReentrantLock(); + // CONDITION PREDICATE: !applets.containsKey(identifier) + private static final Condition appletAdded = appletsLock.newCondition(); + + private static PluginStreamHandler streamhandler; + + private static PluginCallRequestFactory requestFactory; + + private static ConcurrentMap<Integer, PAV_INIT_STATUS> status = + new ConcurrentHashMap<Integer, PAV_INIT_STATUS>(); + private static final ReentrantLock statusLock = new ReentrantLock(); + // CONDITION PREDICATE: !status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE) + private static final Condition initComplete = statusLock.newCondition(); + + private AppletEventListener appletEventListener = null; + + public static final long APPLET_TIMEOUT = 180000000000L; // 180s in ns + + private static final Object requestMutex = new Object(); + private static long requestIdentityCounter = 0L; + + private SplashPanel splashPanel; + + private static long REQUEST_TIMEOUT=60000;//60s + + private static void waitForRequestCompletion(PluginCallRequest request) { + try { + if (!request.isDone()) { + request.wait(REQUEST_TIMEOUT); + } + if (!request.isDone()) { + // Do not wait indefinitely to avoid the potential of deadlock + throw new RuntimeException("Possible deadlock, releasing"); + } + } catch (InterruptedException ex) { + throw new RuntimeException("Interrupted waiting for call request.", ex); + } + } + + /** + * Null constructor to allow instantiation via newInstance() + */ + public PluginApplet3Viewer() { + panel = null; + } + + public static PluginApplet3Viewer framePanel(int identifier, NetxApplet3Panel panel) { + + PluginDebug.debug("Framing ", panel); + + // SecurityManager MUST be set, and only privileged code may call framePanel() + System.getSecurityManager().checkPermission(new AllPermission()); + + PluginApplet3Viewer appletFrame = new PluginApplet3Viewer(identifier, panel); + + appletFrame.appletEventListener = new AppletEventListener(appletFrame); + panel.addAppletListener(appletFrame.appletEventListener); + // Clear references, if any + if (applets.containsKey(identifier)) { + PluginApplet3Viewer oldFrame = applets.get(identifier); + // FIXME oldFrame.remove(panel); + panel.removeAppletListener(oldFrame.appletEventListener); + } + + appletsLock.lock(); + applets.put(identifier, appletFrame); + appletAdded.signalAll(); + appletsLock.unlock(); + + PluginDebug.debug(panel, " framed"); + return appletFrame; + } + + /** + * Create new plugin appletviewer frame + */ + private PluginApplet3Viewer(final int identifier, NetxApplet3Panel appletPanel) { + this.identifier = identifier; + this.panel = appletPanel; + + synchronized(appletPanels) { + if (!appletPanels.contains(panel)) + appletPanels.addElement(panel); + } + + /** FIXME + windowEventListener = new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent evt) { + destroyApplet(identifier); + } + + @Override + public void windowIconified(WindowEvent evt) { + appletStop(); + } + + @Override + public void windowDeiconified(WindowEvent evt) { + appletStart(); + } + }; + addWindowListener(windowEventListener); + */ + new SplashCreator(panel); + } + + /** Called by {@link SplashCreator#run()} */ + private void initializeViewAndSlash(final Applet3Panel fPanel) { + } + + @Override + public void replaceSplash(final SplashPanel newSplash) { + } + + @Override + public void removeSplash() { + } + + @Override + public int getSplashWidth() { + if (splashPanel != null) { + return splashPanel.getSplashWidth(); + } else { + return -1; + } + } + + @Override + public int getSplashHeigth() { + if (splashPanel != null) { + return splashPanel.getSplashHeight(); + } else { + return -1; + } + } + + private static class AppletEventListener implements AppletListener { + final PluginApplet3Viewer appletViewer; + + public AppletEventListener(PluginApplet3Viewer appletViewer) { + this.appletViewer = appletViewer; + } + + @Override + public void appletStateChanged(AppletEvent evt) { + Applet3Panel src = (Applet3Panel) evt.getSource(); + + panelLock.lock(); + panelLive.signalAll(); + panelLock.unlock(); + switch (evt.getID()) { + case AppletPanel.APPLET_RESIZE: { + if (src != null) { + // FIXME ? appletViewer.setSize(appletViewer.getPreferredSize()); + // We already resized .. + } + break; + } + case AppletPanel.APPLET_LOADING_COMPLETED: { + /** + Applet3 a = src.getApplet(); // sun.applet.AppletPanel + // Fixed #4754451: Applet can have methods running on main + // thread event queue. + // + // The cause of this bug is that the frame of the applet + // is created in main thread group. Thus, when certain + // AWT/Swing events are generated, the events will be + // dispatched through the wrong event dispatch thread. + // + // To fix this, we rearrange the AppContext with the frame, + // so the proper event queue will be looked up. + // + // Swing also maintains a Frame list for the AppContext, + // so we will have to rearrange it as well. + // + if (a != null) { + Applet3Panel.changeFrameAppContext(src.appletWindow, SunToolkit.targetToAppContext(a)); + } + else */ { + Applet3Panel.changeFrameAppContext(src.getAppletWindow(), App3Context.getAppContext()); + } + + updateStatus(appletViewer.identifier, PAV_INIT_STATUS.INIT_COMPLETE); + + break; + } + case AppletPanel.APPLET_START: { + final int src_status = src.getStatus(); + if (src_status != AppletPanel.APPLET_INIT && src_status != AppletPanel.APPLET_STOP) { + String s="Applet started, but but reached invalid state"; + PluginDebug.debug(s); + SplashPanel sp=SplashUtils.getErrorSplashScreen(appletViewer.panel.getWidth(), appletViewer.panel.getHeight(), new Exception(s)); + appletViewer.replaceSplash(sp); + } + + break; + } + case AppletPanel.APPLET_ERROR: { + String s="Undefined error causing applet not to staart appeared"; + PluginDebug.debug(s); + SplashPanel sp=SplashUtils.getErrorSplashScreen(appletViewer.panel.getWidth(), appletViewer.panel.getHeight(), new Exception(s)); + appletViewer.replaceSplash(sp); + break; + } + } + } + } + + public static void setStreamhandler(PluginStreamHandler sh) { + streamhandler = sh; + } + + public static void setPluginCallRequestFactory(PluginCallRequestFactory rf) { + requestFactory = rf; + } + + private static void handleInitializationMessage(int identifier, String message) throws IOException, LaunchException { + + /* The user has specified via a global setting that applets should not be run.*/ + if (AppletStartupSecuritySettings.getInstance().getSecurityLevel() == AppletSecurityLevel.DENY_ALL) { + throw new LaunchException(null, null, R("LSFatal"), R("LCClient"), R("LUnsignedApplet"), R("LUnsignedAppletPolicyDenied")); + } + + // If there is a key for this status, it means it + // was either initialized before, or destroy has been + // processed. Stop moving further. + if (updateStatus(identifier, PAV_INIT_STATUS.PRE_INIT) != null) { + return; + } + + // Extract the information from the message + String[] msgParts = new String[4]; + for (int i = 0; i < 3; i++) { + int spaceLocation = message.indexOf(' '); + int nextSpaceLocation = message.indexOf(' ', spaceLocation + 1); + msgParts[i] = message.substring(spaceLocation + 1, nextSpaceLocation); + message = message.substring(nextSpaceLocation + 1); + } + + final long nativeWindowHandle = Long.parseLong(msgParts[0]); + String width = msgParts[1]; + String height = msgParts[2]; + + int spaceLocation = message.indexOf(' ', "tag".length() + 1); + String documentBase = message.substring("tag".length() + 1, spaceLocation); + String paramString = message.substring(spaceLocation + 1); + + PluginDebug.debug("Handle = 0x", Long.toHexString(nativeWindowHandle), "\n", + "Width = ", width, "\n", + "Height = ", height, "\n", + "DocumentBase = ", documentBase, "\n", + "Params = ", paramString); + + PluginApplet3PanelFactory factory = new PluginApplet3PanelFactory(); + Applet3MessageHandler amh = new Applet3MessageHandler("appletviewer"); + URL url = new URL(documentBase); + URLConnection conn = url.openConnection(); + /* The original URL may have been redirected - this + * sets it to whatever URL/codebase we ended up getting + */ + url = conn.getURL(); + + PluginParameters params = new PluginParameterParser().parse(width, height, paramString); + + // Let user know we are starting up + streamhandler.write("instance " + identifier + " status " + amh.getMessage("status.start")); + factory.createPanel(streamhandler, identifier, nativeWindowHandle, url, params); + + long maxTimeToSleep = APPLET_TIMEOUT; + appletsLock.lock(); + try { + while (!applets.containsKey(identifier) && + maxTimeToSleep > 0) { // Map is populated only by reFrame + maxTimeToSleep -= waitTillTimeout(appletsLock, appletAdded, + maxTimeToSleep); + } + } + finally { + appletsLock.unlock(); + } + + // If wait exceeded maxWait, we timed out. Throw an exception + if (maxTimeToSleep <= 0) { + // Caught in handleMessage + throw new RuntimeException("Applet initialization timeout"); + } + + // We should not try to destroy an applet during + // initialization. It may cause an inconsistent state, + // which would bad if it's a trusted applet that + // read/writes to files + waitForAppletInit(applets.get(identifier).panel); + + // Should we proceed with reframing? + PluginDebug.debug("Init complete"); + + if (updateStatus(identifier, PAV_INIT_STATUS.REFRAME_COMPLETE).equals(PAV_INIT_STATUS.INACTIVE)) { + destroyApplet(identifier); + return; + } + } + + /** + * Handle an incoming message from the plugin. + */ + public static void handleMessage(int identifier, int reference, String message) { + + PluginDebug.debug("PAV handling: ", message); + + try { + if (message.startsWith("handle")) { + handleInitializationMessage(identifier, message); + } else if (message.startsWith("destroy")) { + + // Set it inactive, and try to do cleanup is applicable + PAV_INIT_STATUS previousStatus = updateStatus(identifier, PAV_INIT_STATUS.INACTIVE); + PluginDebug.debug("Destroy status set for ", identifier); + + if (previousStatus != null && + previousStatus.equals(PAV_INIT_STATUS.REFRAME_COMPLETE)) { + destroyApplet(identifier); + } + + } else { + PluginDebug.debug("Handling message: ", message, " instance ", identifier, " ", Thread.currentThread()); + + // Wait till initialization finishes + while (!applets.containsKey(identifier) && + ( + !status.containsKey(identifier) || + status.get(identifier).equals(PAV_INIT_STATUS.PRE_INIT) + )) + ; + + // don't bother processing further for inactive applets + if (status.get(identifier).equals(PAV_INIT_STATUS.INACTIVE)) { + return; + } + + applets.get(identifier).handleMessage(reference, message); + } + } catch (Exception e) { + OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e); + + // If an exception happened during pre-init, we need to update status + updateStatus(identifier, PAV_INIT_STATUS.INACTIVE); + + e.printStackTrace(); // FIXME + + throw new RuntimeException("Failed to handle message: " + message + " for instance " + identifier, e); + } + } + + /** + * Sets the status unless an overriding status is set (e.g. if + * status is DESTROYED, it may not be overridden). + * + * @param identifier The identifier for which the status is to be set + * @param status The status to switch to + * @return The previous status + */ + private static synchronized PAV_INIT_STATUS updateStatus(int identifier, PAV_INIT_STATUS newStatus) { + + PAV_INIT_STATUS prev = status.get(identifier); + + // If the status is set + if (status.containsKey(identifier)) { + + // Nothing may override destroyed status + if (status.get(identifier).equals(PAV_INIT_STATUS.DESTROYED)) { + return prev; + } + + // If status is inactive, only DESTROYED may override it + if (status.get(identifier).equals(PAV_INIT_STATUS.INACTIVE)) { + if (!newStatus.equals(PAV_INIT_STATUS.DESTROYED)) { + return prev; + } + } + } + + // Else set to given status + + statusLock.lock(); + status.put(identifier, newStatus); + initComplete.signalAll(); + statusLock.unlock(); + + return prev; + } + + /** + * Destroys the given applet instance. + * + * This function may be called multiple times without problems. + * It does a synchronized check on the status and will only + * attempt to destroy the applet if not previously destroyed. + * + * @param identifier The instance which is to be destroyed + */ + + private static synchronized void destroyApplet(int identifier) { + final PluginApplet3Viewer pav = applets.get(identifier); + + if( null != pav ) { + // We should not try to destroy an applet during + // initialization. It may cause an inconsistent state. + waitForAppletInit( pav.panel ); + } + + PluginDebug.debug("DestroyApplet called for ", identifier); + + PAV_INIT_STATUS prev = updateStatus(identifier, PAV_INIT_STATUS.DESTROYED); + + // If already destroyed, return + if (prev.equals(PAV_INIT_STATUS.DESTROYED)) { + PluginDebug.debug(identifier, " already destroyed. Returning."); + return; + } + + PluginDebug.debug("Attempting to destroy frame ", identifier); + + // Try to dispose the panel right away + if (pav != null) { + // If panel is already disposed, return + if (pav.panel.getApplet() == null) { + PluginDebug.debug(identifier, " panel inactive. Returning."); + return; + } + + PluginDebug.debug("Attempting to destroy panel ", identifier); + + pav.appletClose(); + } + + PluginDebug.debug(identifier, " destroyed"); + } + + /** + * Function to block until applet initialization is complete. + * + * This function will return if the wait is longer than {@link #APPLET_TIMEOUT} + * + * @param panel the instance to wait for. + */ + public static void waitForAppletInit(NetxApplet3Panel panel) { + + PluginDebug.debug("Waiting for applet init"); + + // Wait till initialization finishes + long maxTimeToSleep = APPLET_TIMEOUT; + + panelLock.lock(); + try { + while (!panel.isInitialized() && + maxTimeToSleep > 0) { + PluginDebug.debug("Waiting for applet panel ", panel, " to initialize..."); + maxTimeToSleep -= waitTillTimeout(panelLock, panelLive, maxTimeToSleep); + } + } + finally { + panelLock.unlock(); + } + + PluginDebug.debug("Applet panel ", panel, " initialized"); + } + + public void handleMessage(int reference, String message) { + if (message.startsWith("width")) { + + // 0 => width, 1=> width_value, 2 => height, 3=> height_value + String[] dimMsg = message.split(" "); + + final int width = Integer.parseInt(dimMsg[1]); + final int height = Integer.parseInt(dimMsg[3]); + + /* Resize the applet asynchronously, to avoid the chance of + * deadlock while waiting for the applet to initialize. + * + * In general, worker threads should spawn new threads for any blocking operations. */ + Thread resizeAppletThread = new Thread("resizeAppletThread") { + @Override + public void run() { + resize(width, height); + } + }; + + /* Let it eventually complete */ + resizeAppletThread.start(); + + } else if (message.startsWith("GetJavaObject")) { + + // FIXME: how do we determine what security context this + // object should belong to? + Object o; + + // Wait for the panel to initialize + // (happens in a separate thread) + waitForAppletInit(panel); + + PluginDebug.debug(panel, " -- ", panel.getApplet(), " -- initialized: ", panel.isInitialized()); + + // Still null? + if (panel.getApplet() == null) { + streamhandler.write("instance " + identifier + " reference " + -1 + " fatalError: " + "Initialization failed"); + streamhandler.write("context 0 reference " + reference + " Error"); + return; + } + + o = panel.getApplet(); + PluginDebug.debug("Looking for object ", o, " panel is ", panel); + AppletSecurityContextManager.getSecurityContext(0).store(o); + PluginDebug.debug("WRITING 1: ", "context 0 reference ", reference, " GetJavaObject " + , AppletSecurityContextManager.getSecurityContext(0).getIdentifier(o)); + streamhandler.write("context 0 reference " + reference + " GetJavaObject " + + AppletSecurityContextManager.getSecurityContext(0).getIdentifier(o)); + PluginDebug.debug("WRITING 1 DONE"); + } + } + + private static Vector<NetxApplet3Panel> appletPanels = new Vector<NetxApplet3Panel>(); + + /** + * Get an applet by name. + */ + @Override + public Applet3Context getAppletContext(String name) { + name = name.toLowerCase(); + SocketPermission panelSp = + new SocketPermission(panel.getCodeBase().getHost(), "connect"); + synchronized(appletPanels) { + for (Enumeration<NetxApplet3Panel> e = appletPanels.elements(); e.hasMoreElements();) { + Applet3Panel p = e.nextElement(); + String param = p.getParameter("name"); + if (param != null) { + param = param.toLowerCase(); + } + if (name.equals(param) && + p.getDocumentBase().equals(panel.getDocumentBase())) { + + SocketPermission sp = + new SocketPermission(p.getCodeBase().getHost(), "connect"); + + if (panelSp.implies(sp)) { + return p; + } + } + } + } + return null; + } + + @Override + public Applet3 getApplet() { + return panel.getApplet(); + } + + @Override + public String getAppletName() { + return panel.getAppletName(); + } + + @Override + public boolean isActive() { + return panel.isActive(); + } + + @Override + public URL getDocumentBase() { + return panel.getDocumentBase(); + } + + @Override + public URL getCodeBase() { + return panel.getCodeBase(); + } + + @Override + public String getParameter(String name) { + return panel.getParameter(name); + } + + @Override + public Enumeration<Applet3Context> getAllAppletContexts() { + Vector<Applet3Context> v = new Vector<Applet3Context>(); + SocketPermission panelSp = + new SocketPermission(panel.getCodeBase().getHost(), "connect"); + + synchronized(appletPanels) { + for (Enumeration<NetxApplet3Panel> e = appletPanels.elements(); e.hasMoreElements();) { + Applet3Panel p = e.nextElement(); + if (p.getDocumentBase().equals(panel.getDocumentBase())) { + + SocketPermission sp = + new SocketPermission(p.getCodeBase().getHost(), "connect"); + if (panelSp.implies(sp)) { + v.addElement(p); + } + } + } + } + return v.elements(); + } + + /* Resizes an applet panel, waiting for the applet to initialze. + * Should be done asynchronously to avoid the chance of deadlock. */ + @Override + public void resize(final int width, final int height) { + /** FIXME: Resize native browser window ! + if (appEvtQ != null){ + appEvtQ.postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(), + new Runnable(){ + public void run(){ + if(ap != null) + { + ap.dispatchAppletEvent(APPLET_RESIZE, currentSize); + } + } + })); + } + */ + appletResize(width, height); + } + + /** + * Called when the applet wants to be resized. + * + * @param width the new requested width for the applet. + * @param height the new requested height for the applet. + */ + public void appletResize(int width, int height) { + // Wait for panel to come alive + waitForAppletInit(panel); + panel.appletResize(width, height); + } + + @Override + public void showDocument(URL url) { + PluginDebug.debug("Showing document..."); + showDocument(url, "_self"); + } + + @Override + public void showDocument(URL url, String target) { + // If it is a javascript document, eval on current page. + if ("javascript".equals(url.getProtocol())) { + // Snip protocol off string + String evalString = url.toString().substring("javascript:".length()); + eval(getWindow(), evalString); + return; + } + try { + Long reference = getRequestIdentifier(); + write("reference " + reference + " LoadURL " + UrlUtil.encode(url.toString(), "UTF-8") + " " + target); + } catch (IOException exception) { + // Deliberately ignore IOException. showDocument may be + // called from threads other than the main thread after + // streamhandler.pluginOutputStream has been closed. + } + } + + /** + * Show status. + */ + @Override + public void showStatus(String status) { + try { + // FIXME: change to postCallRequest + // For statuses, we cannot have a newline + status = status.replace("\n", " "); + write("status " + status); + } catch (IOException exception) { + // Deliberately ignore IOException. showStatus may be + // called from threads other than the main thread after + // streamhandler.pluginOutputStream has been closed. + } + } + + /** + * Returns an incremental number (unique identifier) for a message. + * If identifier hits Long.MAX_VALUE it loops back starting at 0. + * + * @return A unique Long identifier for the request + */ + private static long getRequestIdentifier() { + synchronized(requestMutex) { + if (requestIdentityCounter == Long.MAX_VALUE) { + requestIdentityCounter = 0L; + } + + return requestIdentityCounter++; + } + } + + public long getWindow() { + PluginDebug.debug("STARTING getWindow"); + Long reference = getRequestIdentifier(); + + PluginCallRequest request = requestFactory.getPluginCallRequest("window", + "instance " + identifier + " reference " + + +reference + " " + "GetWindow", reference); + + PluginDebug.debug("STARTING postCallRequest"); + streamhandler.postCallRequest(request); + PluginDebug.debug("STARTING postCallRequest done"); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait request 1"); + synchronized (request) { + PluginDebug.debug("wait request 2"); + while ((Long) request.getObject() == 0) + request.wait(); + PluginDebug.debug("wait request 3"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for call request.", + e); + } + + PluginDebug.debug("STARTING getWindow DONE"); + return (Long) request.getObject(); + } + + // FIXME: make private, access via reflection. + public static Object getMember(long internal, String name) { + AppletSecurityContextManager.getSecurityContext(0).store(name); + int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name); + Long reference = getRequestIdentifier(); + + // Prefix with dummy instance for convenience. + PluginCallRequest request = requestFactory.getPluginCallRequest("member", + "instance " + 0 + " reference " + reference + " GetMember " + + internal + " " + nameID, reference); + + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait getMEM request 1"); + synchronized (request) { + PluginDebug.debug("wait getMEM request 2"); + while (request.isDone() == false) + request.wait(); + PluginDebug.debug("wait getMEM request 3 GOT: ", request.getObject().getClass()); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for call request.", + e); + } + PluginDebug.debug(" getMember DONE"); + return request.getObject(); + } + + public static void setMember(long internal, String name, Object value) { + PluginDebug.debug("Setting to class " + value.getClass() + ":" + value.getClass().isPrimitive()); + PluginAppletSecurityContext securityContext = AppletSecurityContextManager.getSecurityContext(0); + securityContext.store(name); + int nameID = securityContext.getIdentifier(name); + Long reference = getRequestIdentifier(); + + // work on a copy of value, as we don't want to be manipulating + // complex objects + String objIDStr = securityContext.toObjectIDString(value, + value.getClass(), true /* unbox primitives */); + + // Prefix with dummy instance for convenience. + PluginCallRequest request = requestFactory.getPluginCallRequest("void", + "instance " + 0 + " reference " + reference + " SetMember " + + internal + " " + nameID + " " + objIDStr, reference); + + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait setMem request: ", request.getMessage()); + PluginDebug.debug("wait setMem request 1"); + synchronized (request) { + PluginDebug.debug("wait setMem request 2"); + while (request.isDone() == false) + request.wait(); + PluginDebug.debug("wait setMem request 3"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for call request.", + e); + } + PluginDebug.debug(" setMember DONE"); + } + + // FIXME: handle long index as well. + public static void setSlot(long internal, int index, Object value) { + PluginAppletSecurityContext securityContext = AppletSecurityContextManager.getSecurityContext(0); + securityContext.store(value); + Long reference = getRequestIdentifier(); + + String objIDStr = securityContext.toObjectIDString(value, + value.getClass(), true /* unbox primitives */); + + // Prefix with dummy instance for convenience. + PluginCallRequest request = requestFactory.getPluginCallRequest("void", + "instance " + 0 + " reference " + reference + " SetSlot " + + internal + " " + index + " " + objIDStr, reference); + + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait setSlot request 1"); + synchronized (request) { + PluginDebug.debug("wait setSlot request 2"); + while (request.isDone() == false) + request.wait(); + PluginDebug.debug("wait setSlot request 3"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for call request.", + e); + } + PluginDebug.debug(" setSlot DONE"); + } + + public static Object getSlot(long internal, int index) { + Long reference = getRequestIdentifier(); + + // Prefix with dummy instance for convenience. + PluginCallRequest request = requestFactory.getPluginCallRequest("member", + "instance " + 0 + " reference " + reference + " GetSlot " + + internal + " " + index, reference); + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait getSlot request 1"); + synchronized (request) { + PluginDebug.debug("wait getSlot request 2"); + while (request.isDone() == false) + request.wait(); + PluginDebug.debug("wait getSlot request 3"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for call request.", + e); + } + PluginDebug.debug(" getSlot DONE"); + return request.getObject(); + } + + public static Object eval(long internal, String s) { + AppletSecurityContextManager.getSecurityContext(0).store(s); + int stringID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(s); + Long reference = getRequestIdentifier(); + + // Prefix with dummy instance for convenience. + // FIXME: rename GetMemberPluginCallRequest ObjectPluginCallRequest. + PluginCallRequest request = requestFactory.getPluginCallRequest("member", + "instance " + 0 + " reference " + reference + " Eval " + + internal + " " + stringID, reference); + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait eval request 1"); + synchronized (request) { + PluginDebug.debug("wait eval request 2"); + while (request.isDone() == false) { + request.wait(); + } + PluginDebug.debug("wait eval request 3"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for call request.", + e); + } + PluginDebug.debug(" getSlot DONE"); + return request.getObject(); + } + + public static void removeMember(long internal, String name) { + AppletSecurityContextManager.getSecurityContext(0).store(name); + int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name); + Long reference = getRequestIdentifier(); + + // Prefix with dummy instance for convenience. + PluginCallRequest request = requestFactory.getPluginCallRequest("void", + "instance " + 0 + " reference " + reference + " RemoveMember " + + internal + " " + nameID, reference); + + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait removeMember request 1"); + synchronized (request) { + PluginDebug.debug("wait removeMember request 2"); + while (request.isDone() == false) + request.wait(); + PluginDebug.debug("wait removeMember request 3"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for call request.", + e); + } + PluginDebug.debug(" RemoveMember DONE"); + } + + public static Object call(long internal, String name, Object args[]) { + // FIXME: when is this removed from the object store? + // FIXME: reference should return the ID. + // FIXME: convenience method for this long line. + AppletSecurityContextManager.getSecurityContext(0).store(name); + int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name); + Long reference = getRequestIdentifier(); + + String argIDs = ""; + for (Object arg : args) { + AppletSecurityContextManager.getSecurityContext(0).store(arg); + argIDs += AppletSecurityContextManager.getSecurityContext(0).getIdentifier(arg) + " "; + } + argIDs = argIDs.trim(); + + // Prefix with dummy instance for convenience. + PluginCallRequest request = requestFactory.getPluginCallRequest("member", + "instance " + 0 + " reference " + reference + " Call " + + internal + " " + nameID + " " + argIDs, reference); + + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait call request 1"); + synchronized (request) { + PluginDebug.debug("wait call request 2"); + while (request.isDone() == false) { + request.wait(); + } + PluginDebug.debug("wait call request 3"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for call request.", + e); + } + PluginDebug.debug(" Call DONE"); + return request.getObject(); + } + + public static Object requestPluginCookieInfo(URI uri) { + + PluginCallRequest request; + Long reference = getRequestIdentifier(); + + try { + String encodedURI = UrlUtil.encode(uri.toString(), "UTF-8"); + request = requestFactory.getPluginCallRequest("cookieinfo", + "plugin PluginCookieInfo " + "reference " + reference + + " " + encodedURI, reference); + + } catch (UnsupportedEncodingException e) { + OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e); + return null; + } + + PluginMessageConsumer.registerPriorityWait(reference); + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait cookieinfo request 1"); + synchronized (request) { + PluginDebug.debug("wait cookieinfo request 2"); + while (request.isDone() == false) { + request.wait(); + } + PluginDebug.debug("wait cookieinfo request 3"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for cookieinfo request.", + e); + } + PluginDebug.debug(" Cookieinfo DONE"); + return request.getObject(); + } + + /** + * Obtain information about the proxy from the browser. + * + * @param uri a String in url-encoded form + * @return a {@link URI} that indicates a proxy. + */ + public static Object requestPluginProxyInfo(String uri) { + Long reference = getRequestIdentifier(); + + PluginCallRequest request = requestFactory.getPluginCallRequest("proxyinfo", + "plugin PluginProxyInfo reference " + reference + " " + + uri, reference); + + PluginMessageConsumer.registerPriorityWait(reference); + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait call request 1"); + synchronized (request) { + PluginDebug.debug("wait call request 2"); + while (request.isDone() == false) { + request.wait(); + } + PluginDebug.debug("wait call request 3"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for call request.", + e); + } + PluginDebug.debug(" Call DONE"); + return request.getObject(); + } + + public static void JavaScriptFinalize(long internal) { + Long reference = getRequestIdentifier(); + + // Prefix with dummy instance for convenience. + PluginCallRequest request = requestFactory.getPluginCallRequest("void", + "instance " + 0 + " reference " + reference + " Finalize " + + internal, reference); + + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + try { + PluginDebug.debug("wait finalize request 1"); + synchronized (request) { + PluginDebug.debug("wait finalize request 2"); + while (request.isDone() == false) { + request.wait(); + } + PluginDebug.debug("wait finalize request 3"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for call request.", + e); + } + PluginDebug.debug(" finalize DONE"); + } + + public static String javascriptToString(long internal) { + Long reference = getRequestIdentifier(); + + // Prefix with dummy instance for convenience. + PluginCallRequest request = requestFactory.getPluginCallRequest("member", + "instance " + 0 + " reference " + reference + " ToString " + + internal, reference); + + streamhandler.postCallRequest(request); + streamhandler.write(request.getMessage()); + PluginDebug.debug("wait ToString request 1"); + synchronized (request) { + PluginDebug.debug("wait ToString request 2"); + waitForRequestCompletion(request); + PluginDebug.debug("wait ToString request 3"); + } + + PluginDebug.debug(" ToString DONE"); + return (String) request.getObject(); + } + + // FIXME: make this private and access it from JSObject using + // reflection. + private void write(String message) throws IOException { + PluginDebug.debug("WRITING 2: ", "instance ", identifier, " " + message); + streamhandler.write("instance " + identifier + " " + message); + PluginDebug.debug("WRITING 2 DONE"); + } + + @Override + public void setStream(String key, InputStream stream) throws IOException { + // We do nothing. + } + + @Override + public InputStream getStream(String key) { + // We do nothing. + return null; + } + + @Override + public Iterator<String> getStreamKeys() { + // We do nothing. + return null; + } + + /** + * System parameters. + */ + static Hashtable<String, String> systemParam = new Hashtable<String, String>(); + + static { + systemParam.put("codebase", "codebase"); + systemParam.put("code", "code"); + systemParam.put("alt", "alt"); + systemParam.put("width", "width"); + systemParam.put("height", "height"); + systemParam.put("align", "align"); + systemParam.put("vspace", "vspace"); + systemParam.put("hspace", "hspace"); + } + + /** + * Restart the applet. + */ + void appletRestart() { + panel.sendEvent(AppletPanel.APPLET_STOP); + panel.sendEvent(AppletPanel.APPLET_DESTROY); + panel.sendEvent(AppletPanel.APPLET_INIT); + panel.sendEvent(AppletPanel.APPLET_START); + } + + /** + * Reload the applet. + */ + void appletReload() { + panel.sendEvent(AppletPanel.APPLET_STOP); + panel.sendEvent(AppletPanel.APPLET_DESTROY); + panel.sendEvent(AppletPanel.APPLET_DISPOSE); + + /** + * Fixed #4501142: Classlaoder sharing policy doesn't + * take "archive" into account. This will be overridden + * by Java Plug-in. [stanleyh] + */ + AppletPanel.flushClassLoader(panel.getClassLoaderCacheKey()); + + /* + * Make sure we don't have two threads running through the event queue + * at the same time. + */ + try { + ((Applet3Panel)panel).joinAppletThread(); + ((Applet3Panel)panel).release(); + } catch (InterruptedException e) { + return; // abort the reload + } + + AccessController.doPrivileged(new PrivilegedAction<Void>() { + @Override + public Void run() { + ((Applet3Panel)panel).createAppletThread(); + return null; + } + }); + + panel.sendEvent(AppletPanel.APPLET_LOAD); + panel.sendEvent(AppletPanel.APPLET_INIT); + panel.sendEvent(AppletPanel.APPLET_START); + } + + /** + * Start the applet. + */ + void appletStart() { + panel.sendEvent(AppletPanel.APPLET_START); + } + + /** + * Stop the applet. + */ + void appletStop() { + panel.sendEvent(AppletPanel.APPLET_STOP); + } + + /** + * Shutdown a viewer. + * Stop, Destroy, Dispose and Quit a viewer + */ + private void appletShutdown(Applet3Panel p) { + p.sendEvent(AppletPanel.APPLET_STOP); + p.sendEvent(AppletPanel.APPLET_DESTROY); + p.sendEvent(AppletPanel.APPLET_DISPOSE); + p.sendEvent(AppletPanel.APPLET_QUIT); + } + + /** + * Close this viewer. + * Stop, Destroy, Dispose and Quit an AppletView, then + * reclaim resources and exit the program if this is + * the last applet. + */ + void appletClose() { + + // The caller thread is event dispatch thread, so + // spawn a new thread to avoid blocking the event queue + // when calling appletShutdown. + // + final Applet3Panel p = panel; + + new Thread(new Runnable() { + @Override + public void run() { + ClassLoader cl = p.getApplet().getClass().getClassLoader(); + + // Since we want to deal with JNLPClassLoader, extract it if this + // is a codebase loader + if (cl instanceof JNLPClassLoader.CodeBaseClassLoader) { + cl = ((JNLPClassLoader.CodeBaseClassLoader) cl).getParentJNLPClassLoader(); + } + + appletShutdown(p); + appletPanels.removeElement(p); + + // Mark classloader unusable + ((JNLPClassLoader) cl).decrementLoaderUseCount(); + + if (countApplets() == 0) { + appletSystemExit(); + } + + updateStatus(identifier, PAV_INIT_STATUS.DESTROYED); + } + }).start(); + } + + /** + * Exit the program. + * Exit from the program (if not stand alone) - do no clean-up + */ + private void appletSystemExit() { + // Do nothing. Exit is handled by another + // block of code, called when _all_ applets are gone + } + + /** + * How many applets are running? + */ + + public static int countApplets() { + return appletPanels.size(); + } + + + /** + * Waits on a given condition queue until timeout. + * + * <b>This function assumes that the monitor lock has already been + * acquired by the caller.</b> + * + * If the given lock is null, this function returns immediately. + * + * @param lock the lock that must be held when this method is called. + * @param cond the condition queue on which to wait for notifications. + * @param timeout The maximum time to wait (nanoseconds) + * @return Approximate time spent sleeping (not guaranteed to be perfect) + */ + public static long waitTillTimeout(ReentrantLock lock, Condition cond, + long timeout) { + + // Can't wait on null. Return 0 indicating no wait happened. + if (lock == null) { + return 0; + } + + assert lock.isHeldByCurrentThread(); + + // Record when we started sleeping + long sleepStart = 0L; + + try { + sleepStart = System.nanoTime(); + cond.await(timeout, TimeUnit.NANOSECONDS); + } catch (InterruptedException ie) {} // Discarded, time to return + + // Return the difference + return System.nanoTime() - sleepStart; + } + + private class SplashCreator implements Runnable { + + private final Applet3Panel fPanel; + + public SplashCreator(Applet3Panel fPanel) { + this.fPanel = fPanel; + } + + @Override + public void run() { + initializeViewAndSlash(fPanel); + } + } +} diff --git a/plugin/icedteanp/java/netscape/javascript/JSObject.java b/plugin/icedteanp/java/netscape/javascript/JSObject.java index 489efa6..d3eec67 100644 --- a/plugin/icedteanp/java/netscape/javascript/JSObject.java +++ b/plugin/icedteanp/java/netscape/javascript/JSObject.java @@ -50,7 +50,7 @@ import java.applet.Applet; import java.security.AccessControlException; import java.security.AccessController; -import sun.applet.PluginAppletViewer; +import jogamp.plugin.applet.PluginApplet3Viewer; import sun.applet.PluginDebug; /** @@ -162,7 +162,7 @@ public final class JSObject { public Object getMember(String name) { PluginDebug.debug("JSObject.getMember ", name); - Object o = PluginAppletViewer.getMember(internal, name); + Object o = PluginApplet3Viewer.getMember(internal, name); PluginDebug.debug("JSObject.getMember GOT ", o); return o; } @@ -175,7 +175,7 @@ public final class JSObject { public Object getSlot(int index) { PluginDebug.debug("JSObject.getSlot ", index); - return PluginAppletViewer.getSlot(internal, index); + return PluginApplet3Viewer.getSlot(internal, index); } /** @@ -185,7 +185,7 @@ public final class JSObject { public void setMember(String name, Object value) { PluginDebug.debug("JSObject.setMember ", name, " ", value); - PluginAppletViewer.setMember(internal, name, value); + PluginApplet3Viewer.setMember(internal, name, value); } /** @@ -198,7 +198,7 @@ public final class JSObject { public void setSlot(int index, Object value) { PluginDebug.debug("JSObject.setSlot ", index, " ", value); - PluginAppletViewer.setSlot(internal, index, value); + PluginApplet3Viewer.setSlot(internal, index, value); } /** @@ -207,7 +207,7 @@ public final class JSObject { public void removeMember(String name) { PluginDebug.debug("JSObject.removeMember ", name); - PluginAppletViewer.removeMember(internal, name); + PluginApplet3Viewer.removeMember(internal, name); } /** @@ -223,7 +223,7 @@ public final class JSObject { PluginDebug.debug(" ", arg); } PluginDebug.debug(""); - return PluginAppletViewer.call(internal, methodName, args); + return PluginApplet3Viewer.call(internal, methodName, args); } /** @@ -233,7 +233,7 @@ public final class JSObject { */ public Object eval(String s) { PluginDebug.debug("JSObject.eval ", s); - return PluginAppletViewer.eval(internal, s); + return PluginApplet3Viewer.eval(internal, s); } /** @@ -241,7 +241,7 @@ public final class JSObject { */ public String toString() { PluginDebug.debug("JSObject.toString"); - return PluginAppletViewer.javascriptToString(internal); + return PluginApplet3Viewer.javascriptToString(internal); } // should use some sort of identifier rather than String @@ -255,8 +255,7 @@ public final class JSObject { PluginDebug.debug("JSObject.getWindow"); // FIXME: handle long case as well. long internal = 0; - internal = ((PluginAppletViewer) - applet.getAppletContext()).getWindow(); + internal = ((PluginApplet3Viewer)applet.getAppletContext()).getWindow(); PluginDebug.debug("GOT IT: ", internal); return new JSObject(internal); } @@ -272,6 +271,6 @@ public final class JSObject { return; PluginDebug.debug("JSObject.finalize "); - PluginAppletViewer.JavaScriptFinalize(internal); + PluginApplet3Viewer.JavaScriptFinalize(internal); } } diff --git a/plugin/icedteanp/java/sun/applet/Applet3MessageHandler.java b/plugin/icedteanp/java/sun/applet/Applet3MessageHandler.java new file mode 100644 index 0000000..140e5eb --- /dev/null +++ b/plugin/icedteanp/java/sun/applet/Applet3MessageHandler.java @@ -0,0 +1,21 @@ +package sun.applet; + +import sun.applet.AppletMessageHandler; + +public class Applet3MessageHandler extends AppletMessageHandler { + + public Applet3MessageHandler(String baseKey) { + super(baseKey); + } + + public String getMessage(String key) { + return super.getMessage(key); + } + public String getMessage(String key, Object arg){ + return super.getMessage(key, arg); + } + public String getMessage(String key, Object arg1, Object arg2){ + return super.getMessage(key, arg1, arg2); + } + +} diff --git a/plugin/icedteanp/java/sun/applet/PluginCookieManager.java b/plugin/icedteanp/java/sun/applet/PluginCookieManager.java index 21bdbc0..de58d07 100644 --- a/plugin/icedteanp/java/sun/applet/PluginCookieManager.java +++ b/plugin/icedteanp/java/sun/applet/PluginCookieManager.java @@ -45,6 +45,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import jogamp.plugin.applet.PluginApplet3Viewer; + import com.sun.jndi.toolkit.url.UrlUtil; public class PluginCookieManager extends CookieManager { @@ -64,8 +66,7 @@ public class PluginCookieManager extends CookieManager { Map<String, List<String>> cookieMap = new java.util.HashMap<String, List<String>>(); - String cookies = (String) PluginAppletViewer - .requestPluginCookieInfo(uri); + String cookies = (String) PluginApplet3Viewer.requestPluginCookieInfo(uri); List<String> cookieHeader = new java.util.ArrayList<String>(); if (cookies != null && cookies.length() > 0) diff --git a/plugin/icedteanp/java/sun/applet/PluginMain.java b/plugin/icedteanp/java/sun/applet/PluginMain.java index 421edb5..32b8ab6 100644 --- a/plugin/icedteanp/java/sun/applet/PluginMain.java +++ b/plugin/icedteanp/java/sun/applet/PluginMain.java @@ -77,14 +77,13 @@ import java.util.Enumeration; import java.util.Hashtable; import java.util.Map; import java.util.Properties; -import sun.awt.AppContext; -import sun.awt.SunToolkit; +import jogamp.applet.App3Context; +import jogamp.plugin.applet.PluginApplet3Viewer; import net.sourceforge.jnlp.config.DeploymentConfiguration; import net.sourceforge.jnlp.runtime.JNLPRuntime; import net.sourceforge.jnlp.security.JNLPAuthenticator; import net.sourceforge.jnlp.util.logging.JavaConsole; -import net.sourceforge.jnlp.util.logging.LogConfig; import net.sourceforge.jnlp.util.logging.OutputController; /** @@ -127,8 +126,12 @@ public class PluginMain { OutputController.getLogger().log(i + ": "+string); } + /** if (AppContext.getAppContext() == null) { SunToolkit.createNewAppContext(); + } */ + if (App3Context.getAppContext() == null) { + App3Context.createAppContext(); } installDummyJavascriptProtocolHandler(); @@ -152,8 +155,10 @@ public class PluginMain { PluginAppletSecurityContext.setStreamhandler(streamHandler); AppletSecurityContextManager.addContext(0, sc); - PluginAppletViewer.setStreamhandler(streamHandler); - PluginAppletViewer.setPluginCallRequestFactory(new PluginCallRequestFactory()); + // FIXME PluginAppletViewer.setStreamhandler(streamHandler); + // FIXME PluginAppletViewer.setPluginCallRequestFactory(new PluginCallRequestFactory()); + PluginApplet3Viewer.setStreamhandler(streamHandler); // FIXME + PluginApplet3Viewer.setPluginCallRequestFactory(new PluginCallRequestFactory()); // FIXME init(); diff --git a/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java b/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java index 1de8bd7..1975cba 100644 --- a/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java +++ b/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java @@ -41,7 +41,7 @@ import java.util.ArrayList; import java.util.LinkedList; import net.sourceforge.jnlp.util.logging.OutputController; -class PluginMessageConsumer { +public class PluginMessageConsumer { private static final int MAX_PARALLEL_INITS = 1; diff --git a/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java b/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java index 79d925d..c945b8e 100644 --- a/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java +++ b/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java @@ -39,7 +39,7 @@ package sun.applet; import net.sourceforge.jnlp.util.logging.OutputController; -class PluginMessageHandlerWorker extends Thread { +public class PluginMessageHandlerWorker extends Thread { private boolean free = true; private final boolean isPriorityWorker; diff --git a/plugin/icedteanp/java/sun/applet/PluginParameterParser.java b/plugin/icedteanp/java/sun/applet/PluginParameterParser.java index 1db6034..56dabc9 100644 --- a/plugin/icedteanp/java/sun/applet/PluginParameterParser.java +++ b/plugin/icedteanp/java/sun/applet/PluginParameterParser.java @@ -6,7 +6,7 @@ import java.util.Map; import net.sourceforge.jnlp.PluginParameters; -class PluginParameterParser { +public class PluginParameterParser { static private final char DELIMITER_ESCAPE = ':'; static private final String KEY_VALUE_DELIMITER = ";"; diff --git a/plugin/icedteanp/java/sun/applet/PluginProxySelector.java b/plugin/icedteanp/java/sun/applet/PluginProxySelector.java index 25689f5..7355ab9 100644 --- a/plugin/icedteanp/java/sun/applet/PluginProxySelector.java +++ b/plugin/icedteanp/java/sun/applet/PluginProxySelector.java @@ -45,6 +45,8 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; +import jogamp.plugin.applet.PluginApplet3Viewer; + import com.sun.jndi.toolkit.url.UrlUtil; import net.sourceforge.jnlp.config.DeploymentConfiguration; @@ -135,7 +137,7 @@ public class PluginProxySelector extends JNLPProxySelector { /** For tests to override */ protected Object getProxyFromRemoteCallToBrowser(String uri) { - return PluginAppletViewer.requestPluginProxyInfo(uri); + return PluginApplet3Viewer.requestPluginProxyInfo(uri); } /** diff --git a/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java b/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java index 990a903..d45cdc4 100644 --- a/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java +++ b/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java @@ -46,7 +46,7 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.Charset; -import javax.swing.SwingUtilities; +import jogamp.plugin.applet.PluginApplet3Viewer; import net.sourceforge.jnlp.runtime.JNLPRuntime; import net.sourceforge.jnlp.runtime.Translator; import net.sourceforge.jnlp.util.logging.JavaConsole; @@ -230,12 +230,14 @@ public class PluginStreamHandler { final String frest = rest; if (type.equals("instance")) { - PluginAppletViewer.handleMessage(identifier, freference, frest); + PluginApplet3Viewer.handleMessage(identifier, freference, frest); // FIXME + // FIXME PluginAppletViewer.handleMessage(identifier, freference, frest); } else if (type.equals("context")) { PluginDebug.debug("Sending to PASC: ", identifier, "/", reference, " and ", rest); AppletSecurityContextManager.handleMessage(identifier, reference, src, privileges, rest); } } catch (Exception e) { + e.printStackTrace(); // FIXME throw new PluginException(this, identifier, reference, e); } } |