diff options
author | Adam Domurad <[email protected]> | 2012-12-04 10:54:14 -0500 |
---|---|---|
committer | Adam Domurad <[email protected]> | 2012-12-04 10:54:14 -0500 |
commit | 3d2bf421439fc11bbc1c1aa33705d67efa879606 (patch) | |
tree | 18086c4b56d5de6d31f9d29b5865b94f1f82c2e3 | |
parent | 1f595aba1e38b1a0113f45492288e22d3fa90799 (diff) |
PluginAppletViewer refactoring
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | plugin/icedteanp/java/sun/applet/PluginAppletPanelFactory.java | 228 | ||||
-rw-r--r-- | plugin/icedteanp/java/sun/applet/PluginAppletViewer.java | 334 |
3 files changed, 326 insertions, 245 deletions
@@ -1,5 +1,14 @@ 2012-12-04 Adam Domurad <[email protected]> + PluginAppletViewer refactoring. + * plugin/icedteanp/java/sun/applet/PluginAppletViewer.java + (handleInitializationMessage): New, extracts initialization logic + from PluginAppletViewer.handleMessage. + * plugin/icedteanp/java/sun/applet/PluginAppletPanelFactory.java: Moved + into own file. + +2012-12-04 Adam Domurad <[email protected]> + Remove the applet/embed/object tag parser from ITW. Send the applet parameters directly from the C++. * Makefile.am: Allow unit-testing for classes in plugin.jar. diff --git a/plugin/icedteanp/java/sun/applet/PluginAppletPanelFactory.java b/plugin/icedteanp/java/sun/applet/PluginAppletPanelFactory.java new file mode 100644 index 0000000..122313e --- /dev/null +++ b/plugin/icedteanp/java/sun/applet/PluginAppletPanelFactory.java @@ -0,0 +1,228 @@ +/* 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 sun.applet; + +import java.applet.Applet; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.swing.SwingUtilities; + +import net.sourceforge.jnlp.NetxPanel; +import net.sourceforge.jnlp.PluginParameters; + +/** + * Lets us construct one using unix-style one shot behaviors + */ + +class PluginAppletPanelFactory { + + public AppletPanel createPanel(PluginStreamHandler streamhandler, + final int identifier, + final long handle, + final URL doc, + final PluginParameters params) { + final NetxPanel panel = AccessController.doPrivileged(new PrivilegedAction<NetxPanel>() { + public NetxPanel run() { + NetxPanel panel = new NetxPanel(doc, params, false); + NetxPanel.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. + PluginDebug.debug("X and Y are: " + params.getWidth() + " " + params.getHeight()); + panel.setAppletViewerFrame(PluginAppletViewer.framePanel(identifier, handle, + params.getWidth(), params.getHeight(), panel)); + + panel.init(); + // Start the applet + initEventQueue(panel); + } + }, "NetXPanel initializer"); + + panelInit.start(); + while(panelInit.isAlive()) { + try { + panelInit.join(); + } catch (InterruptedException e) { + } + } + + // Wait for the panel to initialize + PluginAppletViewer.waitForAppletInit(panel); + + Applet 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"); + + /* 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. + */ + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + panel.getParent().setSize(params.getWidth(), params.getHeight()); + } + }); + } catch (InvocationTargetException ite) { + // Not being able to resize is non-fatal + PluginDebug.debug("Unable to resize panel: "); + ite.printStackTrace(); + } catch (InterruptedException ie) { + // Not being able to resize is non-fatal + PluginDebug.debug("Unable to resize panel: "); + ie.printStackTrace(); + } + + panel.removeSplash(); + + AppletSecurityContextManager.getSecurityContext(0).associateSrc(panel.getAppletClassLoader(), doc); + AppletSecurityContextManager.getSecurityContext(0).associateInstance(identifier, panel.getAppletClassLoader()); + + return panel; + } + + public boolean isStandalone() { + return false; + } + + /** + * 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(AppletPanel panel) { + // appletviewer.send.event is an undocumented and unsupported system + // property which is used exclusively for testing purposes. + PrivilegedAction<String> pa = new PrivilegedAction<String>() { + 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/sun/applet/PluginAppletViewer.java b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java index 611ed56..c98899a 100644 --- a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java +++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java @@ -65,6 +65,8 @@ package sun.applet; import java.applet.Applet; import java.applet.AppletContext; import java.applet.AudioClip; +import java.awt.BorderLayout; +import java.awt.Component; import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; @@ -75,14 +77,11 @@ import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.print.PageFormat; import java.awt.print.Printable; -import java.awt.Component; import java.io.IOException; import java.io.InputStream; -import java.io.PrintStream; -import java.io.Reader; -import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; import java.net.SocketPermission; import java.net.URI; import java.net.URL; @@ -90,17 +89,15 @@ import java.net.URLConnection; import java.security.AccessController; import java.security.AllPermission; import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.util.Enumeration; import java.util.HashMap; +import java.util.Hashtable; import java.util.Iterator; import java.util.Map; - +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; @@ -109,173 +106,15 @@ import javax.swing.SwingUtilities; import net.sourceforge.jnlp.NetxPanel; import net.sourceforge.jnlp.PluginParameters; import net.sourceforge.jnlp.runtime.JNLPClassLoader; +import net.sourceforge.jnlp.splashscreen.SplashController; +import net.sourceforge.jnlp.splashscreen.SplashPanel; +import net.sourceforge.jnlp.splashscreen.SplashUtils; import sun.awt.AppContext; import sun.awt.SunToolkit; import sun.awt.X11.XEmbeddedFrame; import sun.misc.Ref; import com.sun.jndi.toolkit.url.UrlUtil; -import java.awt.BorderLayout; -import java.util.Hashtable; -import java.util.Vector; -import net.sourceforge.jnlp.splashscreen.SplashController; -import net.sourceforge.jnlp.splashscreen.SplashPanel; -import net.sourceforge.jnlp.splashscreen.SplashUtils; - -/** - * Lets us construct one using unix-style one shot behaviors - */ - -class PluginAppletPanelFactory { - - public AppletPanel createPanel(PluginStreamHandler streamhandler, - final int identifier, - final long handle, - final URL doc, - final PluginParameters params) { - final NetxPanel panel = AccessController.doPrivileged(new PrivilegedAction<NetxPanel>() { - public NetxPanel run() { - NetxPanel panel = new NetxPanel(doc, params, false); - NetxPanel.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. - PluginDebug.debug("X and Y are: " + params.getWidth() + " " + params.getHeight()); - panel.setAppletViewerFrame(PluginAppletViewer.framePanel(identifier, handle, - params.getWidth(), params.getHeight(), panel)); - - panel.init(); - // Start the applet - initEventQueue(panel); - } - }, "NetXPanel initializer"); - - panelInit.start(); - while(panelInit.isAlive()) { - try { - panelInit.join(); - } catch (InterruptedException e) { - } - } - - // Wait for the panel to initialize - PluginAppletViewer.waitForAppletInit(panel); - - Applet 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"); - - /* 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. - */ - try { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - panel.getParent().setSize(params.getWidth(), params.getHeight()); - } - }); - } catch (InvocationTargetException ite) { - // Not being able to resize is non-fatal - PluginDebug.debug("Unable to resize panel: "); - ite.printStackTrace(); - } catch (InterruptedException ie) { - // Not being able to resize is non-fatal - PluginDebug.debug("Unable to resize panel: "); - ie.printStackTrace(); - } - - panel.removeSplash(); - - AppletSecurityContextManager.getSecurityContext(0).associateSrc(panel.getAppletClassLoader(), doc); - AppletSecurityContextManager.getSecurityContext(0).associateInstance(identifier, panel.getAppletClassLoader()); - - return panel; - } - - public boolean isStandalone() { - return false; - } - - /** - * 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(AppletPanel panel) { - // appletviewer.send.event is an undocumented and unsupported system - // property which is used exclusively for testing purposes. - PrivilegedAction<String> pa = new PrivilegedAction<String>() { - 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()) - ; - } - } -} /* */ @@ -567,92 +406,97 @@ public class PluginAppletViewer extends XEmbeddedFrame requestFactory = rf; } - /** - * Handle an incoming message from the plugin. - */ - public static void handleMessage(int identifier, int reference, String message) { + private static void handleInitializationMessage(int identifier, String message) throws IOException { - PluginDebug.debug("PAV handling: ", message); + // 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; - try { - if (message.startsWith("handle")) { + // 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); + } - // 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; + long handle = Long.parseLong(msgParts[0]); + String width = msgParts[1]; + String height = msgParts[2]; + + int spaceLocation = message.indexOf(' ', "tag".length() + 1); + String documentBase = + UrlUtil.decode(message.substring("tag".length() + 1, spaceLocation)); + String paramString = message.substring(spaceLocation + 1); + + PluginDebug.debug("Handle = ", handle, "\n", + "Width = ", width, "\n", + "Height = ", height, "\n", + "DocumentBase = ", documentBase, "\n", + "Params = ", paramString); + + PluginAppletPanelFactory factory = new PluginAppletPanelFactory(); + AppletMessageHandler amh = new AppletMessageHandler("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(); - // 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); - } + PluginParameters params = new PluginParameterParser().parse(width, height, paramString); - long handle = Long.parseLong(msgParts[0]); - String width = msgParts[1]; - String height = msgParts[2]; - - int spaceLocation = message.indexOf(' ', "tag".length() + 1); - String documentBase = - UrlUtil.decode(message.substring("tag".length() + 1, spaceLocation)); - String paramString = message.substring(spaceLocation + 1); - - PluginDebug.debug("Handle = ", handle, "\n", - "Width = ", width, "\n", - "Height = ", height, "\n", - "DocumentBase = ", documentBase, "\n", - "Params = ", paramString); - - PluginAppletPanelFactory factory = new PluginAppletPanelFactory(); - AppletMessageHandler amh = new AppletMessageHandler("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, handle, 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(); - } + // Let user know we are starting up + streamhandler.write("instance " + identifier + " status " + amh.getMessage("status.start")); + factory.createPanel(streamhandler, identifier, handle, url, params); - // If wait exceeded maxWait, we timed out. Throw an exception - if (maxTimeToSleep <= 0) - throw new Exception("Applet initialization timeout"); + 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(); + } - // 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); + // If wait exceeded maxWait, we timed out. Throw an exception + if (maxTimeToSleep <= 0) { + // Caught in handleMessage + throw new RuntimeException("Applet initialization timeout"); + } - // Should we proceed with reframing? - PluginDebug.debug("Init complete"); + // 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); - if (updateStatus(identifier, PAV_INIT_STATUS.REFRAME_COMPLETE).equals(PAV_INIT_STATUS.INACTIVE)) { - destroyApplet(identifier); - return; - } + // 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 |