changeset 1046:3e5d21f2b7a4

Moved IcedTeaPlugin related classes into a separate jar, so that it can be run in a sandbox. Removed new files out of the IcedTeaPlugin patch, and moved them into a directory, so that history can be tracked properly.
author Deepak Bhole <dbhole@redhat.com>
date Thu, 18 Sep 2008 15:49:10 -0400
parents 8e3089767a4a
children 30b1dbd707d5
files Makefile.am patches/icedtea-liveconnect.patch patches/icedtea-plugin.patch plugin/gcj/java/src/main/sun/applet/PluginAppletViewer.java plugin/gcj/java/src/main/sun/applet/PluginMain.java plugin/icedtea/java/src/main/sun/applet/GetMemberPluginCallRequest.java plugin/icedtea/java/src/main/sun/applet/GetWindowPluginCallRequest.java plugin/icedtea/java/src/main/sun/applet/PluginAppletSecurityContext.java plugin/icedtea/java/src/main/sun/applet/PluginAppletViewer.java plugin/icedtea/java/src/main/sun/applet/PluginCallRequest.java plugin/icedtea/java/src/main/sun/applet/PluginDebug.java plugin/icedtea/java/src/main/sun/applet/PluginException.java plugin/icedtea/java/src/main/sun/applet/PluginMain.java plugin/icedtea/java/src/main/sun/applet/PluginMessageConsumer.java plugin/icedtea/java/src/main/sun/applet/PluginMessageHandlerWorker.java plugin/icedtea/java/src/main/sun/applet/PluginObjectStore.java plugin/icedtea/java/src/main/sun/applet/TestEnv.java plugin/icedtea/java/src/main/sun/applet/VoidPluginCallRequest.java
diffstat 18 files changed, 4811 insertions(+), 4850 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.am	Thu Sep 18 11:31:59 2008 -0400
+++ b/Makefile.am	Thu Sep 18 15:49:10 2008 -0400
@@ -12,12 +12,14 @@
 if ENABLE_LIVECONNECT
 ICEDTEAPLUGIN_CLEAN = clean-IcedTeaPlugin
 ICEDTEAPLUGIN_TARGET = IcedTeaPlugin.so
+ICEDTEAPLUGIN_JAR = IcedTeaPlugin.jar
 PLUGIN_PATCH = patches/icedtea-liveconnect.patch
 EXCLUDE_LIVECONNECT =
 LIVECONNECT_DIR = -C lib/rt netscape
 else
 ICEDTEAPLUGIN_CLEAN =
 ICEDTEAPLUGIN_TARGET =
+ICEDTEAPLUGIN_JAR =
 PLUGIN_PATCH = patches/icedtea-plugin.patch
 EXCLUDE_LIVECONNECT = | grep -v 'netscape/javascript'
 LIVECONNECT_DIR =
@@ -894,7 +896,7 @@
 stamps/icedtea.stamp: stamps/bootstrap-directory-symlink.stamp \
 	stamps/hotspot-tools.stamp stamps/plugs.stamp \
 	stamps/ports.stamp stamps/patch.stamp stamps/overlay.stamp \
-	$(GCJWEBPLUGIN_TARGET) $(ICEDTEAPLUGIN_TARGET) \
+	$(GCJWEBPLUGIN_TARGET) $(ICEDTEAPLUGIN_TARGET) $(ICEDTEAPLUGIN_JAR) \
 	extra-lib/about.jar stamps/cacao.stamp stamps/visualvm.stamp
 	$(MAKE) \
 	  $(ICEDTEA_ENV) \
@@ -905,6 +907,10 @@
 	  $(BUILD_OUTPUT_DIR)/j2sdk-image/jre/lib/$(INSTALL_ARCH_DIR)
 	cp -pPRf IcedTeaPlugin.so \
 	  $(BUILD_OUTPUT_DIR)/j2re-image/lib/$(INSTALL_ARCH_DIR)
+	cp -pPRf IcedTeaPlugin.jar \
+	  $(BUILD_OUTPUT_DIR)/j2sdk-image/jre/lib/
+	cp -pPRf IcedTeaPlugin.jar \
+	  $(BUILD_OUTPUT_DIR)/j2re-image/lib/
 else
 if ENABLE_PLUGIN
 	cp -pPRf gcjwebplugin.so \
@@ -945,7 +951,7 @@
 stamps/icedtea-debug.stamp: stamps/bootstrap-directory-symlink.stamp \
 	stamps/hotspot-tools.stamp stamps/plugs.stamp \
 	stamps/ports.stamp stamps/patch.stamp stamps/overlay.stamp \
-	$(GCJWEBPLUGIN_TARGET) $(ICEDTEAPLUGIN_TARGET) \
+	$(GCJWEBPLUGIN_TARGET) $(ICEDTEAPLUGIN_TARGET) $(ICEDTEAPLUGIN_JAR) \
 	extra-lib/about.jar stamps/cacao.stamp
 	$(MAKE) \
 	  $(ICEDTEA_ENV) \
@@ -956,6 +962,10 @@
 	  $(BUILD_OUTPUT_DIR)-debug/j2sdk-image/jre/lib/$(INSTALL_ARCH_DIR)
 	cp -pPRf IcedTeaPlugin.so \
 	  $(BUILD_OUTPUT_DIR)-debug/j2re-image/lib/$(INSTALL_ARCH_DIR)
+	cp -pPRf IcedTeaPlugin.jar \
+	  $(BUILD_OUTPUT_DIR)-debug/j2sdk-image/jre/lib/
+	cp -pPRf IcedTeaPlugin.jar \
+	  $(BUILD_OUTPUT_DIR)-debug/j2re-image/lib/
 else
 if ENABLE_PLUGIN
 	cp -pPRf gcjwebplugin.so \
@@ -1309,6 +1319,17 @@
 	  $(XULRUNNER_LIBS) \
 	  -shared -o $@
 
+# icedtea plugin jar for java-side classes
+IcedTeaPlugin.jar:
+	mkdir -p $(BUILD_OUTPUT_DIR)/plugin/icedtea/classes
+	(cd plugin/icedtea/java/src/main/; \
+	  $(ICEDTEA_BOOT_DIR)/bin/javac -g \
+	  -d $(BUILD_OUTPUT_DIR)/plugin/icedtea/classes \
+	  -bootclasspath $(ICEDTEA_BOOT_DIR)/jre/lib/rt.jar \
+	  sun/applet/*.java \
+	)
+	$(JAR) cf $@ -C $(BUILD_OUTPUT_DIR)/plugin/icedtea/classes sun
+
 clean-IcedTeaPlugin:
 	rm -f IcedTeaPlugin.o
 	rm -f IcedTeaPlugin.so
--- a/patches/icedtea-liveconnect.patch	Thu Sep 18 11:31:59 2008 -0400
+++ b/patches/icedtea-liveconnect.patch	Thu Sep 18 15:49:10 2008 -0400
@@ -1,6 +1,6 @@
 diff -urN openjdk.orig/jdk/make/sun/Makefile openjdk/jdk/make/sun/Makefile
 --- openjdk.orig/jdk/make/sun/Makefile	2008-07-10 15:54:44.000000000 -0400
-+++ openjdk/jdk/make/sun/Makefile	2008-09-15 16:21:47.000000000 -0400
++++ openjdk/jdk/make/sun/Makefile	2008-09-18 14:28:41.000000000 -0400
 @@ -66,6 +66,7 @@
            $(HEADLESS_SUBDIR) $(DGA_SUBDIR) \
  	  font jpeg cmm applet rmi beans $(JDBC_SUBDIR) \
@@ -11,7 +11,7 @@
  all build clean clobber::
 diff -urN openjdk.orig/jdk/make/sun/Makefile.orig openjdk/jdk/make/sun/Makefile.orig
 --- openjdk.orig/jdk/make/sun/Makefile.orig	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/make/sun/Makefile.orig	2008-09-15 16:21:47.000000000 -0400
++++ openjdk/jdk/make/sun/Makefile.orig	2008-09-18 14:28:41.000000000 -0400
 @@ -0,0 +1,73 @@
 +#
 +# Copyright 1995-2007 Sun Microsystems, Inc.  All Rights Reserved.
@@ -88,7 +88,7 @@
 +
 diff -urN openjdk.orig/jdk/make/sun/plugin/Makefile openjdk/jdk/make/sun/plugin/Makefile
 --- openjdk.orig/jdk/make/sun/plugin/Makefile	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/make/sun/plugin/Makefile	2008-09-15 16:21:47.000000000 -0400
++++ openjdk/jdk/make/sun/plugin/Makefile	2008-09-18 14:28:41.000000000 -0400
 @@ -0,0 +1,53 @@
 +#
 +# Copyright 1995-2005 Sun Microsystems, Inc.  All Rights Reserved.
@@ -143,3556 +143,3 @@
 +JAVA_ARGS = "{ \"sun.applet.PluginMain\" }"
 +include $(BUILDDIR)/common/Program.gmk
 +
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/GetMemberPluginCallRequest.java openjdk/jdk/src/share/classes/sun/applet/GetMemberPluginCallRequest.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/GetMemberPluginCallRequest.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/GetMemberPluginCallRequest.java	2008-09-15 16:22:06.000000000 -0400
-@@ -0,0 +1,72 @@
-+/* GetMemberPluginCallRequest -- represent Java-to-JavaScript requests
-+   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. */
-+
-+package sun.applet;
-+
-+class GetMemberPluginCallRequest extends PluginCallRequest {
-+    Object object = null;
-+
-+    public GetMemberPluginCallRequest(String message, String returnString) {
-+        super(message, returnString);
-+        System.out.println ("GetMEMBerPLUGINCAlL " + message + " " + returnString);
-+    }
-+
-+    public void parseReturn(String message) {
-+        System.out.println ("GetMEMBerparseReturn GOT: " + message);
-+        String[] args = message.split(" ");
-+        // FIXME: add thread ID to messages to support multiple
-+        // threads using the netscape.javascript package.
-+        object = PluginAppletSecurityContext.contexts.get(
-+            0).store.getObject(Integer.parseInt(args[1]));
-+        done = true;
-+    }
-+    
-+    /**
-+     * Returns whether the given message is serviceable by this object
-+     * 
-+     * @param message The message to service
-+     * @return boolean indicating if message is serviceable
-+     */
-+    public boolean serviceable(String message) {
-+    	return message.contains("JavaScriptCall") ||
-+    			message.contains("JavaScriptEval") ||
-+    			message.contains("JavaScriptGetMember") ||
-+    			message.contains("JavaScriptGetSlot") ||
-+    			message.contains("JavaScriptToString");
-+    }
-+}
-+
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/GetWindowPluginCallRequest.java openjdk/jdk/src/share/classes/sun/applet/GetWindowPluginCallRequest.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/GetWindowPluginCallRequest.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/GetWindowPluginCallRequest.java	2008-09-15 16:22:06.000000000 -0400
-@@ -0,0 +1,66 @@
-+/* GetWindowPluginCallRequest -- represent Java-to-JavaScript requests
-+   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. */
-+
-+package sun.applet;
-+
-+class GetWindowPluginCallRequest extends PluginCallRequest {
-+    // FIXME: look into int vs long JavaScript internal values.
-+    int internal;
-+
-+    public GetWindowPluginCallRequest(String message, String returnString) {
-+        super(message, returnString);
-+    }
-+
-+    public void parseReturn(String message) {
-+        System.out.println ("GetWINDOWparseReturn GOT: " + message);
-+        String[] args = message.split(" ");
-+        // FIXME: add thread ID to messages to support multiple
-+        // threads using the netscape.javascript package.
-+        internal = Integer.parseInt(args[1]);
-+        done = true;
-+    }
-+    
-+    /**
-+     * Returns whether the given message is serviceable by this object
-+     * 
-+     * @param message The message to service
-+     * @return boolean indicating if message is serviceable
-+     */
-+    public boolean serviceable(String message) {
-+    	return message.contains("JavaScriptGetWindow");
-+    }
-+}
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginAppletSecurityContext.java openjdk/jdk/src/share/classes/sun/applet/PluginAppletSecurityContext.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginAppletSecurityContext.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginAppletSecurityContext.java	2008-09-15 16:22:07.000000000 -0400
-@@ -0,0 +1,847 @@
-+/* PluginAppletSecurityContext -- execute plugin JNI messages
-+   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. */
-+
-+package sun.applet;
-+
-+import java.lang.reflect.Array;
-+import java.lang.reflect.Constructor;
-+import java.lang.reflect.Field;
-+import java.lang.reflect.Method;
-+import java.util.ArrayList;
-+import java.util.HashMap;
-+import java.util.List;
-+import java.util.StringTokenizer;
-+
-+class Signature {
-+	private String signature;
-+	private int currentIndex;
-+	private List<Class> typeList;
-+	private static final char ARRAY = '[';
-+	private static final char OBJECT = 'L';
-+	private static final char SIGNATURE_ENDCLASS = ';';
-+	private static final char SIGNATURE_FUNC = '(';
-+	private static final char SIGNATURE_ENDFUNC = ')';
-+	private static final char VOID = 'V';
-+	private static final char BOOLEAN = 'Z';
-+	private static final char BYTE = 'B';
-+	private static final char CHARACTER = 'C';
-+	private static final char SHORT = 'S';
-+	private static final char INTEGER = 'I';
-+	private static final char LONG = 'J';
-+	private static final char FLOAT = 'F';
-+	private static final char DOUBLE = 'D';
-+
-+	private String nextTypeName() {
-+		char key = signature.charAt(currentIndex++);
-+
-+		switch (key) {
-+		case ARRAY:
-+			return nextTypeName() + "[]";
-+
-+		case OBJECT:
-+			int endClass = signature.indexOf(SIGNATURE_ENDCLASS, currentIndex);
-+			String retVal = signature.substring(currentIndex, endClass);
-+			retVal = retVal.replace('/', '.');
-+			currentIndex = endClass + 1;
-+			return retVal;
-+
-+			// FIXME: generated bytecode with classes named after
-+			// primitives will not work in this scheme -- those
-+			// classes will be incorrectly treated as primitive
-+			// types.
-+		case VOID:
-+			return "void";
-+		case BOOLEAN:
-+			return "boolean";
-+		case BYTE:
-+			return "byte";
-+		case CHARACTER:
-+			return "char";
-+		case SHORT:
-+			return "short";
-+		case INTEGER:
-+			return "int";
-+		case LONG:
-+			return "long";
-+		case FLOAT:
-+			return "float";
-+		case DOUBLE:
-+			return "double";
-+
-+		case SIGNATURE_ENDFUNC:
-+		case SIGNATURE_FUNC:
-+			return nextTypeName();
-+
-+		default:
-+			throw new IllegalArgumentException(
-+					"Invalid JNI signature character '" + key + "'");
-+		}
-+	}
-+
-+	public Signature(String signature, String src) {
-+		this.signature = signature;
-+		currentIndex = 0;
-+		typeList = new ArrayList<Class>(10);
-+
-+		String elem;
-+		while (currentIndex < signature.length()) {
-+			elem = nextTypeName();
-+			// System.out.println ("NEXT TYPE: " + elem);
-+			Class primitive = primitiveNameToType(elem);
-+			if (primitive != null)
-+				typeList.add(primitive);
-+			else {
-+				// System.out.println ("HERE1");
-+				int dimsize = 0;
-+				int n = elem.indexOf('[');
-+				if (n != -1) {
-+					// System.out.println ("HERE2");
-+					String arrayType = elem.substring(0, n);
-+					dimsize++;
-+					n = elem.indexOf('[', n + 1);
-+					// System.out.println ("HERE2.5");
-+					while (n != -1) {
-+						dimsize++;
-+						n = elem.indexOf('[', n + 1);
-+						// System.out.println ("HERE2.8");
-+					}
-+					int[] dims = new int[dimsize];
-+					primitive = primitiveNameToType(arrayType);
-+					// System.out.println ("HERE3");
-+					if (primitive != null) {
-+						typeList.add(Array.newInstance(primitive, dims)
-+								.getClass());
-+						// System.out.println ("HERE4");
-+					} else
-+						typeList.add(Array.newInstance(
-+								getClass(arrayType, src), dims).getClass());
-+				} else {
-+					typeList.add(getClass(elem, src));
-+				}
-+			}
-+		}
-+		if (typeList.size() == 0) {
-+			throw new IllegalArgumentException("Invalid JNI signature '"
-+					+ signature + "'");
-+		}
-+	}
-+
-+	public static Class getClass(String name, String src) {
-+
-+		Class c = null;
-+		
-+		try {
-+			c = Class.forName(name);
-+		} catch (ClassNotFoundException cnfe) {
-+
-+			StringTokenizer st = new StringTokenizer(src, ",");
-+
-+			while (st.hasMoreTokens()) {
-+
-+				String tok = st.nextToken();
-+				System.err.println("Searching for " + name  + " at key " + tok);
-+
-+				try {
-+					c = PluginAppletSecurityContext.classLoaders.get(tok).loadClass(name);
-+				} catch (ClassNotFoundException e) {
-+					// do nothing .. thrown below
-+				}
-+				
-+				if (c != null)
-+					break;
-+			}
-+		}
-+
-+		if (c == null) {
-+			throw (new RuntimeException(new ClassNotFoundException("Unable to find class " + name)));
-+		}
-+
-+		return c;
-+	}
-+	
-+	public static Class primitiveNameToType(String name) {
-+		if (name.equals("void"))
-+			return Void.TYPE;
-+		else if (name.equals("boolean"))
-+			return Boolean.TYPE;
-+		else if (name.equals("byte"))
-+			return Byte.TYPE;
-+		else if (name.equals("char"))
-+			return Character.TYPE;
-+		else if (name.equals("short"))
-+			return Short.TYPE;
-+		else if (name.equals("int"))
-+			return Integer.TYPE;
-+		else if (name.equals("long"))
-+			return Long.TYPE;
-+		else if (name.equals("float"))
-+			return Float.TYPE;
-+		else if (name.equals("double"))
-+			return Double.TYPE;
-+		else
-+			return null;
-+	}
-+
-+	public Class[] getClassArray() {
-+		return typeList.subList(0, typeList.size() - 1).toArray(new Class[] {});
-+	}
-+}
-+
-+public class PluginAppletSecurityContext {
-+	// Context identifier -> PluginAppletSecurityContext object.
-+	// FIXME: make private
-+	public static HashMap<Integer, PluginAppletSecurityContext> contexts = new HashMap();
-+	
-+	public static HashMap<String, ClassLoader> classLoaders = new HashMap<String, ClassLoader>();
-+
-+	// FIXME: make private
-+	public PluginObjectStore store = new PluginObjectStore();
-+	private Throwable throwable = null;
-+	private ClassLoader liveconnectLoader = ClassLoader.getSystemClassLoader();
-+	int identifier = 0;
-+
-+	static {
-+		// FIXME: when should we add each new security context? but how would 
-+		// we be able to know which context applies to which request from nspr? 
-+		// the nspr jni functions do not know what applet they are being called
-+		// in reference to
-+		contexts.put(0, new PluginAppletSecurityContext(0));
-+	}
-+
-+	public PluginAppletSecurityContext(int identifier) {
-+		this.identifier = identifier;
-+	}
-+
-+	public static <V> V parseCall(String s, String src, Class<V> c) {
-+		if (c == Integer.class)
-+			return (V) new Integer(s);
-+		else if (c == String.class)
-+			return (V) new String(s);
-+		else if (c == Signature.class)
-+			return (V) new Signature(s, src);
-+		else
-+			throw new RuntimeException("Unexpected call value.");
-+	}
-+
-+	public Object parseArgs(String s, Class c) {
-+		if (c == Boolean.TYPE || c == Boolean.class)
-+			return new Boolean(s);
-+		else if (c == Byte.TYPE || c == Byte.class)
-+			return new Byte(s);
-+		else if (c == Character.TYPE || c == Character.class) {
-+			String[] bytes = s.split("_");
-+			int low = Integer.parseInt(bytes[0]);
-+			int high = Integer.parseInt(bytes[1]);
-+			int full = ((high << 8) & 0x0ff00) | (low & 0x0ff);
-+			return new Character((char) full);
-+		} else if (c == Short.TYPE || c == Short.class)
-+			return new Short(s);
-+		else if (c == Integer.TYPE || c == Integer.class)
-+			return new Integer(s);
-+		else if (c == Long.TYPE || c == Long.class)
-+			return new Long(s);
-+		else if (c == Float.TYPE || c == Float.class)
-+			return new Float(s);
-+		else if (c == Double.TYPE || c == Double.class)
-+			return new Double(s);
-+		else
-+			return store.getObject(new Integer(s));
-+	}
-+
-+	public static void handleMessage(int identifier, String src, int reference,
-+			String message) {
-+		contexts.get(identifier).handleMessage(reference, src, message);
-+	}
-+
-+	public void handleMessage(int reference, String src, String message) {
-+
-+		try {
-+			if (message.startsWith("FindClass")) {
-+				ClassLoader cl = null;
-+				Class c = null;
-+				cl = liveconnectLoader;
-+				String className = message.substring("FindClass".length() + 1)
-+						.replace('/', '.');
-+
-+				try {
-+					c = cl.loadClass(className);
-+					store.reference(c);
-+					write(reference, "FindClass " + store.getIdentifier(c));
-+				} catch (ClassNotFoundException cnfe) {
-+					write(reference, "FindClass 0");
-+				}
-+
-+			} else if (message.startsWith("GetStaticMethodID")
-+					|| message.startsWith("GetMethodID")) {
-+				String[] args = message.split(" ");
-+				Integer classID = parseCall(args[1], src, Integer.class);
-+				String methodName = parseCall(args[2], src, String.class);
-+				Signature signature = parseCall(args[3], src, Signature.class);
-+				Object[] a = signature.getClassArray();
-+
-+				Class c = (Class) store.getObject(classID);
-+				Method m = null;
-+				Constructor cs = null;
-+				Object o = null;
-+				if (methodName.equals("<init>")
-+						|| methodName.equals("<clinit>")) {
-+					o = cs = c.getConstructor(signature.getClassArray());
-+					store.reference(cs);
-+				} else {
-+					o = m = c.getMethod(methodName, signature.getClassArray());
-+					store.reference(m);
-+				}
-+				PluginDebug.debug(o + " has id " + store.getIdentifier(o));
-+				write(reference, args[0] + " " + store.getIdentifier(o));
-+			} else if (message.startsWith("GetStaticFieldID")
-+					|| message.startsWith("GetFieldID")) {
-+				String[] args = message.split(" ");
-+				Integer classID = parseCall(args[1], src, Integer.class);
-+				String fieldName = parseCall(args[2], src, String.class);
-+				Signature signature = parseCall(args[3], src, Signature.class);
-+
-+				Class c = (Class) store.getObject(classID);
-+				Field f = null;
-+				f = c.getField(fieldName);
-+
-+				store.reference(f);
-+
-+				write(reference, "GetStaticFieldID " + store.getIdentifier(f));
-+			} else if (message.startsWith("GetStaticField")) {
-+				String[] args = message.split(" ");
-+				String type = parseCall(args[1], src, String.class);
-+				Integer classID = parseCall(args[1], src, Integer.class);
-+				Integer fieldID = parseCall(args[2], src, Integer.class);
-+
-+				Class c = (Class) store.getObject(classID);
-+				Field f = (Field) store.getObject(fieldID);
-+
-+				Object ret = null;
-+				ret = f.get(c);
-+
-+				// System.out.println ("FIELD VALUE: " + ret);
-+				if (ret == null) {
-+					write(reference, "GetStaticField 0");
-+				} else if (f.getType() == Boolean.TYPE
-+						|| f.getType() == Byte.TYPE
-+						|| f.getType() == Character.TYPE
-+						|| f.getType() == Short.TYPE
-+						|| f.getType() == Integer.TYPE
-+						|| f.getType() == Long.TYPE
-+						|| f.getType() == Float.TYPE
-+						|| f.getType() == Double.TYPE) {
-+					write(reference, "GetStaticField " + ret);
-+				} else {
-+					// Track returned object.
-+					store.reference(ret);
-+					write(reference, "GetStaticField "
-+							+ store.getIdentifier(ret));
-+				}
-+			} else if (message.startsWith("SetStaticField")) {
-+				String[] args = message.split(" ");
-+				String type = parseCall(args[1], src, String.class);
-+				Integer classID = parseCall(args[2], src, Integer.class);
-+				Integer fieldID = parseCall(args[3], src, Integer.class);
-+
-+				Object value = null;
-+				if (Signature.primitiveNameToType(type) != null) {
-+					value = parseArgs(args[4], Signature
-+							.primitiveNameToType(type));
-+					// System.out.println ("HERE1: " + value);
-+				} else {
-+					value = parseArgs(args[3], Object.class);
-+					// System.out.println ("HERE2: " + value);
-+				}
-+
-+				Class c = (Class) store.getObject(classID);
-+				Field f = (Field) store.getObject(fieldID);
-+
-+				f.set(c, value);
-+
-+				write(reference, "SetStaticField");
-+			} else if (message.startsWith("SetField")) {
-+				String[] args = message.split(" ");
-+				String type = parseCall(args[1], src, String.class);
-+				Integer objectID = parseCall(args[2], src, Integer.class);
-+				Integer fieldID = parseCall(args[3], src, Integer.class);
-+
-+				Object value = null;
-+				if (Signature.primitiveNameToType(type) != null) {
-+					value = parseArgs(args[4], Signature
-+							.primitiveNameToType(type));
-+					// System.out.println ("HERE1: " + value);
-+				} else {
-+					value = parseArgs(args[3], Object.class);
-+					// System.out.println ("HERE2: " + value);
-+				}
-+
-+				Object o = (Object) store.getObject(objectID);
-+				Field f = (Field) store.getObject(fieldID);
-+
-+				f.set(o, value);
-+
-+				write(reference, "SetField");
-+			} else if (message.startsWith("GetObjectArrayElement")) {
-+				String[] args = message.split(" ");
-+				Integer arrayID = parseCall(args[1], src, Integer.class);
-+				Integer index = parseCall(args[2], src, Integer.class);
-+
-+				Object[] o = (Object[]) store.getObject(arrayID);
-+				Object ret = null;
-+
-+				ret = o[index];
-+
-+				// Track returned object.
-+				store.reference(ret);
-+				// System.out.println ("array element: " + index + " " + ret);
-+				write(reference, "GetObjectArrayElement "
-+						+ store.getIdentifier(ret));
-+			} else if (message.startsWith("SetObjectArrayElement")) {
-+				String[] args = message.split(" ");
-+				Integer arrayID = parseCall(args[1], src, Integer.class);
-+				Integer index = parseCall(args[2], src, Integer.class);
-+				Integer objectID = parseCall(args[3], src, Integer.class);
-+
-+				Object[] o = (Object[]) store.getObject(arrayID);
-+				Object toSet = (Object) store.getObject(objectID);
-+
-+				o[index] = toSet;
-+
-+				write(reference, "SetObjectArrayElement");
-+			} else if (message.startsWith("GetArrayLength")) {
-+				String[] args = message.split(" ");
-+				Integer arrayID = parseCall(args[1], src, Integer.class);
-+
-+				System.out.println("ARRAYID: " + arrayID);
-+				Object o = (Object) store.getObject(arrayID);
-+				int len = 0;
-+				len = Array.getLength(o);
-+				// System.out.println ("Returning array length: " + len);
-+
-+				// System.out.println ("array length: " + o + " " + len);
-+				write(reference, "GetArrayLength " + Array.getLength(o));
-+			} else if (message.startsWith("GetField")) {
-+				String[] args = message.split(" ");
-+				String type = parseCall(args[1], src, String.class);
-+				Integer objectID = parseCall(args[1], src, Integer.class);
-+				Integer fieldID = parseCall(args[2], src, Integer.class);
-+
-+				Object o = (Object) store.getObject(objectID);
-+				Field f = (Field) store.getObject(fieldID);
-+
-+				Object ret = null;
-+				ret = f.get(o);
-+
-+				// System.out.println ("FIELD VALUE: " + ret);
-+				if (ret == null) {
-+					write(reference, "GetField 0");
-+				} else if (f.getType() == Boolean.TYPE
-+						|| f.getType() == Byte.TYPE
-+						|| f.getType() == Character.TYPE
-+						|| f.getType() == Short.TYPE
-+						|| f.getType() == Integer.TYPE
-+						|| f.getType() == Long.TYPE
-+						|| f.getType() == Float.TYPE
-+						|| f.getType() == Double.TYPE) {
-+					write(reference, "GetField " + ret);
-+				} else {
-+					// Track returned object.
-+					store.reference(ret);
-+					write(reference, "GetField " + store.getIdentifier(ret));
-+				}
-+			} else if (message.startsWith("GetObjectClass")) {
-+				int oid = Integer.parseInt(message.substring("GetObjectClass"
-+						.length() + 1));
-+				// System.out.println ("GETTING CLASS FOR: " + oid);
-+				Class c = store.getObject(oid).getClass();
-+				// System.out.println (" OBJ: " + store.getObject(oid));
-+				// System.out.println (" CLS: " + c);
-+				store.reference(c);
-+
-+				write(reference, "GetObjectClass " + store.getIdentifier(c));
-+			} else if (message.startsWith("CallStaticMethod")) {
-+				String[] args = message.split(" ");
-+				Integer classID = parseCall(args[1], src, Integer.class);
-+				Integer methodID = parseCall(args[2], src, Integer.class);
-+
-+				System.out.println("GETTING: " + methodID);
-+				Method m = (Method) store.getObject(methodID);
-+				System.out.println("GOT: " + m);
-+				Class[] argTypes = m.getParameterTypes();
-+
-+				Object[] arguments = new Object[argTypes.length];
-+				for (int i = 0; i < argTypes.length; i++) {
-+					arguments[i] = parseArgs(args[3 + i], argTypes[i]);
-+					// System.out.println ("GOT ARG: " + argTypes[i] + " " +
-+					// arguments[i]);
-+				}
-+
-+				// System.out.println ("Calling " + m);
-+				Object ret = null;
-+				ret = m.invoke(null, arguments);
-+
-+				// if (ret != null)
-+				// System.out.println ("RETURN VALUE: " + ret + " " +
-+				// ret.getClass());
-+				// else
-+				// System.out.println ("RETURN VALUE: " + ret);
-+				if (ret == null) {
-+					write(reference, "CallStaticMethod void");
-+				} else if (m.getReturnType() == Boolean.TYPE
-+						|| m.getReturnType() == Byte.TYPE
-+						|| m.getReturnType() == Short.TYPE
-+						|| m.getReturnType() == Integer.TYPE
-+						|| m.getReturnType() == Long.TYPE
-+						|| m.getReturnType() == Float.TYPE
-+						|| m.getReturnType() == Double.TYPE) {
-+					write(reference, "CallStaticMethod " + ret);
-+				} else if (m.getReturnType() == Character.TYPE) {
-+					char ch = (Character) ret;
-+					int high = (((int) ch) >> 8) & 0x0ff;
-+					int low = ((int) ch) & 0x0ff;
-+					write(reference, "CallStaticMethod " + low + "_" + high);
-+				} else {
-+					// Track returned object.
-+					store.reference(ret);
-+					write(reference, "CallStaticMethod "
-+							+ store.getIdentifier(ret));
-+				}
-+			} else if (message.startsWith("CallMethod")) {
-+				String[] args = message.split(" ");
-+				Integer objectID = parseCall(args[1], src, Integer.class);
-+				Integer methodID = parseCall(args[2], src, Integer.class);
-+
-+				Object o = (Object) store.getObject(objectID);
-+				Method m = (Method) store.getObject(methodID);
-+				Class[] argTypes = m.getParameterTypes();
-+
-+				Object[] arguments = new Object[argTypes.length];
-+				for (int i = 0; i < argTypes.length; i++) {
-+					arguments[i] = parseArgs(args[3 + i], argTypes[i]);
-+					PluginDebug.debug("GOT ARG: " + argTypes[i] + " "
-+							+ arguments[i]);
-+				}
-+
-+				String collapsedArgs = "";
-+				for (String s : args) {
-+					collapsedArgs += " " + s;
-+				}
-+
-+				PluginDebug.debug("Calling method " + m + " on object " + o
-+						+ " with " + arguments);
-+				Object ret = null;
-+				ret = m.invoke(o, arguments);
-+
-+				String retO;
-+				if (ret == null) {
-+					retO = "null";
-+				} else {
-+					retO = ret.getClass().toString();
-+				}
-+
-+				PluginDebug.debug("Calling " + m + " on " + o + " with "
-+						+ collapsedArgs + " and that returned: " + ret
-+						+ " of type " + retO);
-+
-+				if (ret == null) {
-+					write(reference, "CallMethod void");
-+				} else if (m.getReturnType() == Boolean.TYPE
-+						|| m.getReturnType() == Byte.TYPE
-+						|| m.getReturnType() == Short.TYPE
-+						|| m.getReturnType() == Integer.TYPE
-+						|| m.getReturnType() == Long.TYPE
-+						|| m.getReturnType() == Float.TYPE
-+						|| m.getReturnType() == Double.TYPE) {
-+					write(reference, "CallMethod " + ret);
-+				} else if (m.getReturnType() == Character.TYPE) {
-+					char ch = (Character) ret;
-+					int high = (((int) ch) >> 8) & 0x0ff;
-+					int low = ((int) ch) & 0x0ff;
-+					write(reference, "CallMethod " + low + "_" + high);
-+				} else {
-+					// Track returned object.
-+					store.reference(ret);
-+					write(reference, "CallMethod " + store.getIdentifier(ret));
-+				}
-+			} else if (message.startsWith("GetSuperclass")) {
-+				String[] args = message.split(" ");
-+				Integer classID = parseCall(args[1], src, Integer.class);
-+				Class c = null;
-+				Class ret = null;
-+
-+				c = (Class) store.getObject(classID);
-+				ret = c.getSuperclass();
-+				store.reference(ret);
-+
-+				write(reference, "GetSuperclass " + store.getIdentifier(ret));
-+			} else if (message.startsWith("IsAssignableFrom")) {
-+				String[] args = message.split(" ");
-+				Integer classID = parseCall(args[1], src, Integer.class);
-+				Integer superclassID = parseCall(args[2], src, Integer.class);
-+
-+				boolean result = false;
-+				Class clz = (Class) store.getObject(classID);
-+				Class sup = (Class) store.getObject(superclassID);
-+
-+				result = sup.isAssignableFrom(clz);
-+
-+				write(reference, "IsAssignableFrom " + (result ? "1" : "0"));
-+			} else if (message.startsWith("IsInstanceOf")) {
-+				String[] args = message.split(" ");
-+				Integer objectID = parseCall(args[1], src, Integer.class);
-+				Integer classID = parseCall(args[2], src, Integer.class);
-+
-+				boolean result = false;
-+				Object o = (Object) store.getObject(objectID);
-+				Class c = (Class) store.getObject(classID);
-+
-+				result = c.isInstance(o);
-+
-+				write(reference, "IsInstanceOf " + (result ? "1" : "0"));
-+			} else if (message.startsWith("GetStringUTFLength")) {
-+				String[] args = message.split(" ");
-+				Integer stringID = parseCall(args[1], src, Integer.class);
-+
-+				String o = null;
-+				byte[] b = null;
-+				o = (String) store.getObject(stringID);
-+				b = o.getBytes("UTF-8");
-+				// System.out.println ("STRING UTF-8 LENGTH: " + o + " " +
-+				// b.length);
-+
-+				write(reference, "GetStringUTFLength " + o.length());
-+			} else if (message.startsWith("GetStringLength")) {
-+				String[] args = message.split(" ");
-+				Integer stringID = parseCall(args[1], src, Integer.class);
-+
-+				String o = null;
-+				byte[] b = null;
-+				o = (String) store.getObject(stringID);
-+				b = o.getBytes("UTF-16LE");
-+				// System.out.println ("STRING UTF-16 LENGTH: " + o + " " +
-+				// b.length);
-+
-+				// System.out.println ("Java: GetStringLength " + b.length);
-+				write(reference, "GetStringLength " + o.length());
-+			} else if (message.startsWith("GetStringUTFChars")) {
-+				String[] args = message.split(" ");
-+				Integer stringID = parseCall(args[1], src, Integer.class);
-+
-+				String o = null;
-+				byte[] b = null;
-+				StringBuffer buf = null;
-+				o = (String) store.getObject(stringID);
-+				b = o.getBytes("UTF-8");
-+				buf = new StringBuffer(b.length * 2);
-+				buf.append(b.length);
-+				for (int i = 0; i < b.length; i++)
-+					buf
-+							.append(" "
-+									+ Integer
-+											.toString(((int) b[i]) & 0x0ff, 16));
-+
-+				// System.out.println ("Java: GetStringUTFChars: " + o);
-+				// //System.out.println ("String UTF BYTES: " + buf);
-+				write(reference, "GetStringUTFChars " + buf);
-+			} else if (message.startsWith("GetStringChars")) {
-+				String[] args = message.split(" ");
-+				Integer stringID = parseCall(args[1], src, Integer.class);
-+
-+				String o = null;
-+				byte[] b = null;
-+				StringBuffer buf = null;
-+				o = (String) store.getObject(stringID);
-+				// FIXME: LiveConnect uses UCS-2.
-+				b = o.getBytes("UTF-16LE");
-+				buf = new StringBuffer(b.length * 2);
-+				buf.append(b.length);
-+				for (int i = 0; i < b.length; i++)
-+					buf
-+							.append(" "
-+									+ Integer
-+											.toString(((int) b[i]) & 0x0ff, 16));
-+
-+				System.out.println("Java: GetStringChars: " + o);
-+				System.out.println("  String BYTES: " + buf);
-+				write(reference, "GetStringChars " + buf);
-+			} else if (message.startsWith("NewArray")) {
-+				String[] args = message.split(" ");
-+				String type = parseCall(args[1], src, String.class);
-+				Integer length = parseCall(args[2], src, Integer.class);
-+
-+				// System.out.println ("CALLING: NewArray: " + type + " " +
-+				// length + " "
-+				// + Signature.primitiveNameToType(type));
-+
-+				Object newArray = null;
-+				newArray = Array.newInstance(Signature
-+						.primitiveNameToType(type), length);
-+
-+				store.reference(newArray);
-+				write(reference, "NewArray " + store.getIdentifier(newArray));
-+			} else if (message.startsWith("NewObjectArray")) {
-+				String[] args = message.split(" ");
-+				Integer length = parseCall(args[1], src, Integer.class);
-+				Integer classID = parseCall(args[2], src, Integer.class);
-+				Integer objectID = parseCall(args[3], src, Integer.class);
-+
-+				// System.out.println ("CALLING: NewObjectArray: " +
-+				// classID + " " + length + " "
-+				// + objectID);
-+
-+				Object newArray = null;
-+				newArray = Array.newInstance((Class) store.getObject(classID),
-+						length);
-+
-+				Object[] array = (Object[]) newArray;
-+				for (int i = 0; i < array.length; i++)
-+					array[i] = store.getObject(objectID);
-+				store.reference(newArray);
-+				write(reference, "NewObjectArray "
-+						+ store.getIdentifier(newArray));
-+			} else if (message.startsWith("NewObject")) {
-+				String[] args = message.split(" ");
-+				Integer classID = parseCall(args[1], src, Integer.class);
-+				Integer methodID = parseCall(args[2], src, Integer.class);
-+
-+				Constructor m = (Constructor) store.getObject(methodID);
-+				Class[] argTypes = m.getParameterTypes();
-+
-+				// System.out.println ("NEWOBJ: HERE1");
-+				Object[] arguments = new Object[argTypes.length];
-+				// System.out.println ("NEWOBJ: HERE2");
-+				for (int i = 0; i < argTypes.length; i++) {
-+					arguments[i] = parseArgs(args[3 + i], argTypes[i]);
-+					// System.out.println ("NEWOBJ: GOT ARG: " + arguments[i]);
-+				}
-+
-+				// System.out.println ("NEWOBJ: Calling " + m);
-+				Object ret = null;
-+				ret = m.newInstance(arguments);
-+
-+				// System.out.println ("NEWOBJ: CALLED: " + ret);
-+				// System.out.println ("NEWOBJ: CALLED: " +
-+				// store.getObject(ret));
-+				store.reference(ret);
-+				write(reference, "NewObject " + store.getIdentifier(ret));
-+			} else if (message.startsWith("NewString")) {
-+				System.out.println("MESSAGE: " + message);
-+				String[] args = message.split(" ");
-+				Integer strlength = parseCall(args[1], src, Integer.class);
-+				int bytelength = 2 * strlength;
-+				byte[] byteArray = new byte[bytelength];
-+				String ret = null;
-+				for (int i = 0; i < strlength; i++) {
-+					int c = parseCall(args[2 + i], src, Integer.class);
-+					System.out.println("char " + i + " " + c);
-+					// Low.
-+					byteArray[2 * i] = (byte) (c & 0x0ff);
-+					// High.
-+					byteArray[2 * i + 1] = (byte) ((c >> 8) & 0x0ff);
-+				}
-+				ret = new String(byteArray, 0, bytelength, "UTF-16LE");
-+				System.out.println("NEWSTRING: " + ret);
-+
-+				// System.out.println ("NEWOBJ: CALLED: " + ret);
-+				// System.out.println ("NEWOBJ: CALLED: " +
-+				// store.getObject(ret));
-+				store.reference(ret);
-+				write(reference, "NewString " + store.getIdentifier(ret));
-+			} else if (message.startsWith("NewStringUTF")) {
-+				System.out.println("MESSAGE: " + message);
-+				String[] args = message.split(" ");
-+				byte[] byteArray = new byte[60];
-+				String ret = null;
-+				int i = 0;
-+				int c = 0;
-+				while (((byte) c) != 0) {
-+					c = parseCall(args[1 + i], src, Integer.class);
-+					byteArray[i] = (byte) c;
-+					i++;
-+					if (i == byteArray.length) {
-+						byte[] newByteArray = new byte[2 * byteArray.length];
-+						System.arraycopy(byteArray, 0, newByteArray, 0,
-+								byteArray.length);
-+						byteArray = newByteArray;
-+					}
-+				}
-+				byteArray[i] = (byte) 0;
-+				ret = new String(byteArray, "UTF-8");
-+				System.out.println("NEWSTRINGUTF: " + ret);
-+
-+				store.reference(ret);
-+				write(reference, "NewStringUTF " + store.getIdentifier(ret));
-+			} else if (message.startsWith("ExceptionOccurred")) {
-+				System.out.println("EXCEPTION: " + throwable);
-+				if (throwable != null)
-+					store.reference(throwable);
-+				write(reference, "ExceptionOccurred "
-+						+ store.getIdentifier(throwable));
-+			} else if (message.startsWith("ExceptionClear")) {
-+				if (throwable != null)
-+					store.unreference(store.getIdentifier(throwable));
-+				throwable = null;
-+				write(reference, "ExceptionClear");
-+			} else if (message.startsWith("DeleteGlobalRef")) {
-+				String[] args = message.split(" ");
-+				Integer id = parseCall(args[1], src, Integer.class);
-+				store.unreference(id);
-+				write(reference, "DeleteGlobalRef");
-+			} else if (message.startsWith("DeleteLocalRef")) {
-+				String[] args = message.split(" ");
-+				Integer id = parseCall(args[1], src, Integer.class);
-+				store.unreference(id);
-+				write(reference, "DeleteLocalRef");
-+			} else if (message.startsWith("NewGlobalRef")) {
-+				String[] args = message.split(" ");
-+				Integer id = parseCall(args[1], src, Integer.class);
-+				store.reference(store.getObject(id));
-+				write(reference, "NewGlobalRef " + id);
-+			}
-+		} catch (Throwable t) {
-+			t.printStackTrace();
-+			throwable = t;
-+			PluginException p = new PluginException(identifier, reference, t);
-+		}
-+	}
-+
-+	public void write(int reference, String message) {
-+		PluginDebug.debug("appletviewer writing " + message);
-+		PluginMain.write("context " + identifier + " reference " + reference
-+				+ " " + message);
-+	}
-+}
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginAppletViewer.java openjdk/jdk/src/share/classes/sun/applet/PluginAppletViewer.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginAppletViewer.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginAppletViewer.java	2008-09-15 16:22:07.000000000 -0400
-@@ -0,0 +1,1439 @@
-+ /*
-+  * 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.util.*;
-+ import java.io.*;
-+ import java.awt.*;
-+ import java.awt.event.*;
-+ import java.awt.print.*;
-+ import javax.print.attribute.*;
-+ import java.applet.*;
-+ import java.net.URL;
-+ import java.net.MalformedURLException;
-+ import java.net.SocketPermission;
-+ import sun.misc.Ref;
-+ import java.security.AccessController;
-+ import java.security.PrivilegedAction;
-+ import java.lang.reflect.InvocationTargetException;
-+ import java.lang.reflect.Method;
-+ import sun.awt.SunToolkit;
-+ import sun.awt.AppContext;
-+ import sun.awt.X11.*;
-+ import java.lang.ref.WeakReference;
-+ import net.sourceforge.jnlp.NetxPanel;
-+ 
-+ /**
-+  * Lets us construct one using unix-style one shot behaviors
-+  */
-+ 
-+ class PluginAppletViewerFactory
-+ {
-+     public PluginAppletViewer createAppletViewer(int identifier,
-+                                                  long handle, int x, int y,
-+ 						 URL doc, Hashtable atts) {
-+         PluginAppletViewer pluginappletviewer = new PluginAppletViewer(identifier, handle, x, y, doc, atts, System.out, this);
-+         return pluginappletviewer;
-+     }
-+ 
-+     public boolean isStandalone()
-+     {
-+         return false;
-+     }
-+ }
-+ 
-+ class PluginParseRequest
-+ {
-+     long handle;
-+     String tag;
-+     String documentbase;
-+ }
-+ 
-+ /*
-+  */
-+ // FIXME: declare JSProxy implementation
-+ public class PluginAppletViewer extends XEmbeddedFrame
-+     implements AppletContext, Printable {
-+     /**
-+      * Some constants...
-+      */
-+     private static String defaultSaveFile = "Applet.ser";
-+ 
-+     /**
-+      * The panel in which the applet is being displayed.
-+      */
-+     AppletViewerPanel panel;
-+ 
-+     /**
-+      * The status line.
-+      */
-+     Label label;
-+ 
-+     /**
-+      * output status messages to this stream
-+      */
-+ 
-+     PrintStream statusMsgStream;
-+ 
-+     /**
-+      * For cloning
-+      */
-+     PluginAppletViewerFactory factory;
-+ 
-+     int identifier;
-+ 
-+     private static HashMap<Integer, PluginParseRequest> requests = new HashMap();
-+ 
-+     // Instance identifier -> PluginAppletViewer object.
-+     private static HashMap<Integer, PluginAppletViewer> applets = new HashMap();
-+ 
-+     /**
-+      * Create the applet viewer
-+      */
-+     public PluginAppletViewer(int identifier, long handle, int x, int y, final URL doc,
-+                               final Hashtable atts, PrintStream statusMsgStream,
-+                               PluginAppletViewerFactory factory) {
-+         super(handle, true);
-+     	this.factory = factory;
-+ 	this.statusMsgStream = statusMsgStream;
-+         this.identifier = identifier;
-+         // FIXME: when/where do we remove this?
-+         PluginDebug.debug ("PARSING: PUTTING " + identifier + " " + this);
-+         applets.put(identifier, this);
-+ 
-+ 	try {
-+ 		panel = new NetxPanel(doc, atts);
-+ 		AppletViewerPanel.debug("Using NetX panel");
-+ 	} catch (Exception ex) {
-+ 		AppletViewerPanel.debug("Unable to start NetX applet - defaulting to Sun applet", ex);
-+ 		panel = new AppletViewerPanel(doc, atts);
-+ 	}
-+
-+ 	add("Center", panel);
-+ 	panel.init();
-+ 	appletPanels.addElement(panel);
-+ 
-+ 	pack();
-+ 	setVisible(true);
-+ 
-+ 	WindowListener windowEventListener = new WindowAdapter() {
-+ 
-+ 	    public void windowClosing(WindowEvent evt) {
-+ 		appletClose();
-+ 	    }
-+ 
-+ 	    public void windowIconified(WindowEvent evt) {
-+ 		appletStop();
-+ 	    }
-+ 
-+ 	    public void windowDeiconified(WindowEvent evt) {
-+ 		appletStart();
-+ 	    }
-+ 	};
-+ 
-+ 	class AppletEventListener implements AppletListener  
-+ 	{
-+ 	    final Frame frame;
-+ 
-+ 	    public AppletEventListener(Frame frame)
-+ 	    {
-+ 		this.frame = frame;
-+ 	    }
-+ 
-+ 	    public void appletStateChanged(AppletEvent evt) 
-+ 	    {
-+ 		AppletPanel src = (AppletPanel)evt.getSource();
-+ 
-+ 		switch (evt.getID()) {
-+                     case AppletPanel.APPLET_RESIZE: {
-+ 			if(src != null) {
-+ 			    resize(preferredSize());
-+ 			    validate();
-+                         }
-+ 			break;
-+ 		    }
-+ 		    case AppletPanel.APPLET_LOADING_COMPLETED: {
-+ 			Applet 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)
-+ 			    AppletPanel.changeFrameAppContext(frame, SunToolkit.targetToAppContext(a));
-+ 			else
-+ 			    AppletPanel.changeFrameAppContext(frame, AppContext.getAppContext());
-+ 
-+ 			break;
-+ 		    }
-+ 		}
-+ 	    }
-+ 	};
-+ 
-+ 	addWindowListener(windowEventListener);
-+ 	panel.addAppletListener(new AppletEventListener(this));
-+ 
-+ 	// Start the applet
-+    showStatus(amh.getMessage("status.start"));
-+ 	initEventQueue();
-+ 	
-+ 	try {
-+ 	    write("initialized");
-+ 	} catch (IOException ioe) {
-+ 		ioe.printStackTrace();
-+ 	}
-+ 	
-+    // Wait for a maximum of 10 seconds for the panel to initialize
-+    // (happens in a separate thread)
-+ 	Applet a;
-+    int maxSleepTime = 10000;
-+    int sleepTime = 0;
-+    while ((a = panel.getApplet()) == null && sleepTime < maxSleepTime) {
-+   	 try {
-+   		 Thread.sleep(100);
-+   		 sleepTime += 100;
-+   		 PluginDebug.debug("Waiting for applet to initialize... ");
-+   	 } catch (InterruptedException ie) {
-+   		 // ignore
-+   	 }
-+    }
-+
-+    // Applet initialized. Find out it's classloader and add it to the list
-+    PluginAppletSecurityContext.classLoaders.put(Integer.toString(identifier), a.getClass().getClassLoader());
-+    
-+     }
-+ 
-+     /**
-+      * 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("tag")) {
-+        		 
-+        		 // tag and handle must both be set before parsing, so we need
-+        		 // synchronization here, as the setting of these variables
-+        		 // may happen in independent threads
-+        		 
-+        		 synchronized(requests) {
-+        			 PluginParseRequest request = requests.get(identifier);
-+        			 if (request == null) {
-+        				 request = new PluginParseRequest();
-+        				 requests.put(identifier, request);
-+        			 }
-+        			 int index = message.indexOf(' ', "tag".length() + 1);
-+        			 request.documentbase =
-+        				 message.substring("tag".length() + 1, index);
-+        			 request.tag = message.substring(index + 1);
-+        			 PluginDebug.debug ("REQUEST TAG: " + request.tag + " " +
-+        					 Thread.currentThread());
-+
-+        			 if (request.handle != 0) {
-+        				 PluginDebug.debug ("REQUEST TAG, PARSING " +
-+        						 Thread.currentThread());
-+        				 PluginAppletViewer.parse
-+        				 (identifier, request.handle,
-+        						 new StringReader(request.tag),
-+        						 new URL(request.documentbase));
-+        				 requests.remove(identifier);
-+        			 } else {
-+        				 PluginDebug.debug ("REQUEST HANDLE NOT SET: " + request.handle + ". BYPASSING");
-+        			 }
-+        		 }
-+             } else if (message.startsWith("handle")) {
-+            	 synchronized(requests) {
-+            		 PluginParseRequest request = requests.get(identifier);
-+            		 if (request == null) {
-+            			 request = new PluginParseRequest();
-+            			 requests.put(identifier, request);
-+            		 }
-+            		 request.handle = Long.parseLong
-+            		 (message.substring("handle".length() + 1));
-+            		 PluginDebug.debug ("REQUEST HANDLE: " + request.handle);
-+            		 if (request.tag != null) {
-+            			 PluginDebug.debug ("REQUEST HANDLE, PARSING " +
-+            					 Thread.currentThread());
-+            			 PluginAppletViewer.parse
-+            			 (identifier, request.handle,
-+            					 new StringReader(request.tag),
-+            					 new URL(request.documentbase));
-+            			 requests.remove(identifier);
-+            			 PluginDebug.debug ("REQUEST HANDLE, DONE PARSING " +
-+            					 Thread.currentThread());
-+            		 } else {
-+            			 PluginDebug.debug ("REQUEST HANDLE NOT SET: " + request.tag + ". BYPASSING");
-+            		 }
-+            	 }
-+             } else {
-+                 PluginDebug.debug ("HANDLING MESSAGE " + message + " instance " + identifier + " " + Thread.currentThread());
-+                 applets.get(identifier).handleMessage(reference, message);
-+             }
-+         } catch (Exception e) {
-+             throw new RuntimeException("Failed to handle message: " + message + " " +
-+                                         Thread.currentThread(), e);
-+         }
-+     }
-+ 
-+     public void handleMessage(int reference, String message)
-+     {
-+         if (message.startsWith("width")) {
-+        	 int width =
-+        		 Integer.parseInt(message.substring("width".length() + 1));
-+             panel.setAppletSizeIfNeeded(width, -1);
-+             setSize(width, getHeight());
-+         } else if (message.startsWith("height")) {
-+             int height = 
-+            	 Integer.parseInt(message.substring("height".length() + 1));
-+             panel.setAppletSizeIfNeeded(-1, height);
-+             setSize(getWidth(), height);
-+         } else if (message.startsWith("destroy")) {
-+             dispose();
-+         } else if (message.startsWith("GetJavaObject")) {
-+             // FIXME: how do we determine what security context this
-+             // object should belong to?
-+             Object o;
-+
-+             // Wait for a maximum of 10 seconds for the panel to initialize
-+             // (happens in a separate thread)
-+             int maxSleepTime = 10000;
-+             int sleepTime = 0;
-+             while ((o = panel.getApplet()) == null && sleepTime < maxSleepTime) {
-+            	 try {
-+            		 Thread.sleep(100);
-+            		 sleepTime += 100;
-+            		 PluginDebug.debug("Waiting for applet to initialize...");
-+            	 } catch (InterruptedException ie) {
-+            		 // ignore
-+            	 }
-+             }
-+
-+             System.err.println ("Looking for object " + o + " panel is " + panel.getClass());
-+             PluginAppletSecurityContext.contexts.get(0).store.reference(o);
-+             System.err.println ("WRITING 1: " + "context 0 reference " + reference + " GetJavaObject "
-+                                 + PluginAppletSecurityContext.contexts.get(0).store.getIdentifier(o));
-+             PluginMain.write("context 0 reference " + reference + " GetJavaObject "
-+                              + PluginAppletSecurityContext.contexts.get(0).store.getIdentifier(o));
-+             System.err.println ("WRITING 1 DONE");
-+         }
-+     }
-+ 
-+     /**
-+      * 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() {
-+ 	// appletviewer.send.event is an undocumented and unsupported system
-+ 	// property which is used exclusively for testing purposes.
-+ 	String eventList = System.getProperty("appletviewer.send.event");
-+ 
-+ 	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 = splitSeparator(",", eventList);
-+ 
-+  	    for (int i = 0; i < events.length; i++) {
-+  		System.out.println("Adding event to queue: " + events[i]);
-+  		if (events[i].equals("dispose"))
-+  		    panel.sendEvent(AppletPanel.APPLET_DISPOSE);
-+  		else if (events[i].equals("load"))
-+  		    panel.sendEvent(AppletPanel.APPLET_LOAD);
-+  		else if (events[i].equals("init"))
-+  		    panel.sendEvent(AppletPanel.APPLET_INIT);
-+  		else if (events[i].equals("start"))
-+  		    panel.sendEvent(AppletPanel.APPLET_START);
-+  		else if (events[i].equals("stop"))
-+  		    panel.sendEvent(AppletPanel.APPLET_STOP);
-+  		else if (events[i].equals("destroy"))
-+  		    panel.sendEvent(AppletPanel.APPLET_DESTROY);
-+  		else if (events[i].equals("quit"))
-+  		    panel.sendEvent(AppletPanel.APPLET_QUIT);
-+  		else if (events[i].equals("error"))
-+  		    panel.sendEvent(AppletPanel.APPLET_ERROR);
-+  		else
-+ 		    // non-fatal error if we get an unrecognized event
-+  		    System.out.println("Unrecognized event name: " + events[i]);
-+  	    }
-+ 
-+   	    while (!panel.emptyEventQueue()) ;
-+  	    appletSystemExit();
-+ 	}
-+     }
-+ 
-+     /**
-+      * Split a string based on the presence of a specified separator.  Returns
-+      * an array of arbitrary length.  The end of each element in the array is
-+      * indicated by the separator of the end of the string.  If there is a
-+      * separator immediately before the end of the string, the final element
-+      * will be empty.  None of the strings will contain the separator.  Useful
-+      * when separating strings such as "foo/bar/bas" using separator "/".
-+      *
-+      * @param sep  The separator.
-+      * @param s    The string to split.
-+      * @return     An array of strings.  Each string in the array is determined
-+      *             by the location of the provided sep in the original string,
-+      *             s.  Whitespace not stripped.
-+      */
-+     private String [] splitSeparator(String sep, String s) {
-+  	Vector v = new Vector();
-+ 	int tokenStart = 0;
-+ 	int tokenEnd   = 0;
-+ 
-+ 	while ((tokenEnd = s.indexOf(sep, tokenStart)) != -1) {
-+ 	    v.addElement(s.substring(tokenStart, tokenEnd));
-+ 	    tokenStart = tokenEnd+1;
-+ 	}
-+ 	// Add the final element.
-+ 	v.addElement(s.substring(tokenStart));
-+ 
-+ 	String [] retVal = new String[v.size()];
-+ 	v.copyInto(retVal);
-+  	return retVal;
-+     }
-+ 
-+     /*
-+      * Methods for java.applet.AppletContext
-+      */
-+ 
-+     private static Map audioClips = new HashMap();
-+ 
-+     /**
-+      * Get an audio clip.
-+      */
-+     public AudioClip getAudioClip(URL url) {
-+ 	checkConnect(url);
-+ 	synchronized (audioClips) {
-+ 	    AudioClip clip = (AudioClip)audioClips.get(url);
-+ 	    if (clip == null) {
-+ 		audioClips.put(url, clip = new AppletAudioClip(url));
-+ 	    }
-+ 	    return clip;
-+ 	}
-+     }
-+ 
-+     private static Map imageRefs = new HashMap();
-+ 
-+     /**
-+      * Get an image.
-+      */
-+     public Image getImage(URL url) {
-+ 	return getCachedImage(url);
-+     }
-+ 
-+     static Image getCachedImage(URL url) {
-+ 	// System.getSecurityManager().checkConnection(url.getHost(), url.getPort());
-+ 	return (Image)getCachedImageRef(url).get();
-+     }
-+ 
-+     /**
-+      * Get an image ref.
-+      */
-+     static Ref getCachedImageRef(URL url) {
-+ 	synchronized (imageRefs) {
-+ 	    AppletImageRef ref = (AppletImageRef)imageRefs.get(url);
-+ 	    if (ref == null) {
-+ 		ref = new AppletImageRef(url);
-+ 		imageRefs.put(url, ref);
-+ 	    }
-+ 	    return ref;
-+ 	}
-+     }
-+ 
-+     /**
-+      * Flush the image cache.
-+      */
-+     static void flushImageCache() {
-+ 	imageRefs.clear();
-+     }
-+ 
-+     static Vector appletPanels = new Vector();
-+ 
-+     /**
-+      * Get an applet by name.
-+      */
-+     public Applet getApplet(String name) {
-+ 	AppletSecurity security = (AppletSecurity)System.getSecurityManager();
-+ 	name = name.toLowerCase();
-+ 	SocketPermission panelSp =
-+ 	    new SocketPermission(panel.getCodeBase().getHost(), "connect");
-+ 	for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
-+ 	    AppletPanel p = (AppletPanel)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.applet;
-+ 		}
-+ 	    }
-+ 	}
-+ 	return null;
-+     }
-+ 
-+     /**
-+      * Return an enumeration of all the accessible
-+      * applets on this page.
-+      */
-+     public Enumeration getApplets() {
-+ 	AppletSecurity security = (AppletSecurity)System.getSecurityManager();
-+ 	Vector v = new Vector();
-+ 	SocketPermission panelSp =
-+ 	    new SocketPermission(panel.getCodeBase().getHost(), "connect");
-+ 
-+ 	for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
-+ 	    AppletPanel p = (AppletPanel)e.nextElement();
-+ 	    if (p.getDocumentBase().equals(panel.getDocumentBase())) {
-+ 
-+ 		SocketPermission sp =
-+ 		    new SocketPermission(p.getCodeBase().getHost(), "connect");
-+ 		if (panelSp.implies(sp)) {
-+ 		    v.addElement(p.applet);
-+ 		}
-+ 	    }
-+ 	}
-+ 	return v.elements();
-+     }
-+ 
-+     /**
-+      * Ignore.
-+      */
-+     public void showDocument(URL url) {
-+    	 PluginDebug.debug("Showing document...");
-+ 	showDocument(url, "_self");
-+     }
-+ 
-+     /**
-+      * Ignore.
-+      */
-+     public void showDocument(URL url, String target) {
-+ 	try {
-+             // FIXME: change to postCallRequest
-+ 	    write("url " + url + " " + target);
-+ 	} catch (IOException exception) {
-+ 	    // Deliberately ignore IOException.  showDocument may be
-+ 	    // called from threads other than the main thread after
-+ 	    // PluginMain.pluginOutputStream has been closed.
-+ 	}
-+     }
-+ 
-+     /**
-+      * Show status.
-+      */
-+     public void showStatus(String status) {
-+ 	try {
-+             // FIXME: change to postCallRequest
-+ 	    write("status " + status);
-+ 	} catch (IOException exception) {
-+ 	    // Deliberately ignore IOException.  showStatus may be
-+ 	    // called from threads other than the main thread after
-+ 	    // PluginMain.pluginOutputStream has been closed.
-+ 	}
-+     }
-+ 
-+     public int getWindow() {
-+    	 System.out.println ("STARTING getWindow");
-+    	 GetWindowPluginCallRequest request =
-+    		 new GetWindowPluginCallRequest("instance " + identifier + " " +
-+    				 "GetWindow", "JavaScriptGetWindow");
-+    	 System.out.println ("STARTING postCallRequest");
-+    	 PluginMain.postCallRequest(request);
-+    	 System.out.println ("STARTING postCallRequest done");
-+    	 PluginMain.write(request.message);
-+    	 try {
-+    		 System.out.println ("wait request 1");
-+    		 synchronized(request) {
-+    			 System.out.println ("wait request 2");
-+    			 while (request.internal == 0)
-+    				 request.wait();
-+    			 System.out.println ("wait request 3");
-+    		 }
-+    	 } catch (InterruptedException e) {
-+    		 throw new RuntimeException("Interrupted waiting for call request.",
-+    				 e);
-+    	 }
-+
-+    	 System.out.println ("STARTING getWindow DONE");
-+    	 return request.internal;
-+     }
-+ 
-+     // FIXME: make private, access via reflection.
-+     public static Object getMember(int internal, String name)
-+     {
-+         PluginAppletSecurityContext.contexts.get(0).store.reference(name);
-+         int nameID = PluginAppletSecurityContext.contexts.get(
-+             0).store.getIdentifier(name);
-+ 
-+         // Prefix with dummy instance for convenience.
-+         GetMemberPluginCallRequest request =
-+             new GetMemberPluginCallRequest("instance " + 0 +
-+                                            " GetMember " + internal +
-+                                            " " + nameID, "JavaScriptGetMember");
-+         PluginMain.postCallRequest(request);
-+         PluginMain.write(request.message);
-+         try {
-+             System.out.println ("wait getMEM request 1");
-+             synchronized(request) {
-+                 System.out.println ("wait getMEM request 2");
-+                 while (request.done == false)
-+                     request.wait();
-+                 System.out.println ("wait getMEM request 3");
-+             }
-+         } catch (InterruptedException e) {
-+             throw new RuntimeException("Interrupted waiting for call request.",
-+                                        e);
-+         }
-+         System.out.println (" getMember DONE");
-+         return request.object;
-+     }
-+ 
-+     public static void setMember(int internal, String name, Object value) {
-+         PluginAppletSecurityContext.contexts.get(0).store.reference(name);
-+         int nameID = PluginAppletSecurityContext.contexts.get(
-+             0).store.getIdentifier(name);
-+         PluginAppletSecurityContext.contexts.get(0).store.reference(value);
-+         int valueID = PluginAppletSecurityContext.contexts.get(
-+             0).store.getIdentifier(value);
-+ 
-+         // Prefix with dummy instance for convenience.
-+         VoidPluginCallRequest request =
-+             new VoidPluginCallRequest("instance " + 0 +
-+                                            " SetMember " + internal +
-+                                            " " + nameID + " " + valueID, "JavaScriptSetMember");
-+         PluginMain.postCallRequest(request);
-+         PluginMain.write(request.message);
-+         try {
-+             System.out.println ("wait setMem request: " + request.message);
-+             System.out.println ("wait setMem request 1");
-+             synchronized(request) {
-+                 System.out.println ("wait setMem request 2");
-+                 while (request.done == false)
-+                     request.wait();
-+                 System.out.println ("wait setMem request 3");
-+             }
-+         } catch (InterruptedException e) {
-+             throw new RuntimeException("Interrupted waiting for call request.",
-+                                        e);
-+         }
-+         System.out.println (" setMember DONE");
-+     }
-+ 
-+     // FIXME: handle long index as well.
-+     public static void setSlot(int internal, int index, Object value) {
-+         PluginAppletSecurityContext.contexts.get(0).store.reference(value);
-+         int valueID = PluginAppletSecurityContext.contexts.get(
-+             0).store.getIdentifier(value);
-+ 
-+         // Prefix with dummy instance for convenience.
-+         VoidPluginCallRequest request =
-+             new VoidPluginCallRequest("instance " + 0 +
-+                                       " SetSlot " + internal +
-+                                       " " + index + " " + valueID, "JavaScriptSetSlot");
-+         PluginMain.postCallRequest(request);
-+         PluginMain.write(request.message);
-+         try {
-+             System.out.println ("wait setSlot request 1");
-+             synchronized(request) {
-+                 System.out.println ("wait setSlot request 2");
-+                 while (request.done == false)
-+                     request.wait();
-+                 System.out.println ("wait setSlot request 3");
-+             }
-+         } catch (InterruptedException e) {
-+             throw new RuntimeException("Interrupted waiting for call request.",
-+                                        e);
-+         }
-+         System.out.println (" setSlot DONE");
-+     }
-+ 
-+     public static Object getSlot(int internal, int index)
-+     {
-+         // Prefix with dummy instance for convenience.
-+         GetMemberPluginCallRequest request =
-+             new GetMemberPluginCallRequest("instance " + 0 +
-+                                            " GetSlot " + internal +
-+                                            " " + index, "JavaScriptGetSlot");
-+         PluginMain.postCallRequest(request);
-+         PluginMain.write(request.message);
-+         try {
-+             System.out.println ("wait getSlot request 1");
-+             synchronized(request) {
-+                 System.out.println ("wait getSlot request 2");
-+                 while (request.done == false)
-+                     request.wait();
-+                 System.out.println ("wait getSlot request 3");
-+             }
-+         } catch (InterruptedException e) {
-+             throw new RuntimeException("Interrupted waiting for call request.",
-+                                        e);
-+         }
-+         System.out.println (" getSlot DONE");
-+         return request.object;
-+     }
-+ 
-+     public static Object eval(int internal, String s)
-+     {
-+         PluginAppletSecurityContext.contexts.get(0).store.reference(s);
-+         int stringID = PluginAppletSecurityContext.contexts.get(
-+             0).store.getIdentifier(s);
-+         // Prefix with dummy instance for convenience.
-+         // FIXME: rename GetMemberPluginCallRequest ObjectPluginCallRequest.
-+         GetMemberPluginCallRequest request =
-+             new GetMemberPluginCallRequest("instance " + 0 +
-+                                            " Eval " + internal +
-+                                            " " + stringID, "JavaScriptEval");
-+         PluginMain.postCallRequest(request);
-+         PluginMain.write(request.message);
-+         try {
-+             System.out.println ("wait eval request 1");
-+             synchronized(request) {
-+                 System.out.println ("wait eval request 2");
-+                 while (request.done == false)
-+                     request.wait();
-+                 System.out.println ("wait eval request 3");
-+             }
-+         } catch (InterruptedException e) {
-+             throw new RuntimeException("Interrupted waiting for call request.",
-+                                        e);
-+         }
-+         System.out.println (" getSlot DONE");
-+         return request.object;
-+     }
-+ 
-+     public static void removeMember (int internal, String name) {
-+         PluginAppletSecurityContext.contexts.get(0).store.reference(name);
-+         int nameID = PluginAppletSecurityContext.contexts.get(
-+             0).store.getIdentifier(name);
-+ 
-+         // Prefix with dummy instance for convenience.
-+         VoidPluginCallRequest request =
-+             new VoidPluginCallRequest("instance " + 0 +
-+                                         " RemoveMember " + internal +
-+                                         " " + nameID, "JavaScriptRemoveMember");
-+         PluginMain.postCallRequest(request);
-+         PluginMain.write(request.message);
-+         try {
-+             System.out.println ("wait removeMember request 1");
-+             synchronized(request) {
-+                 System.out.println ("wait removeMember request 2");
-+                 while (request.done == false)
-+                     request.wait();
-+                 System.out.println ("wait removeMember request 3");
-+             }
-+         } catch (InterruptedException e) {
-+             throw new RuntimeException("Interrupted waiting for call request.",
-+                                        e);
-+         }
-+         System.out.println (" RemoveMember DONE");
-+     }
-+ 
-+     public static Object call(int 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.
-+         PluginAppletSecurityContext.contexts.get(0).store.reference(name);
-+         int nameID = PluginAppletSecurityContext.contexts.get(
-+             0).store.getIdentifier(name);
-+         PluginAppletSecurityContext.contexts.get(0).store.reference(args);
-+         int argsID = PluginAppletSecurityContext.contexts.get(
-+             0).store.getIdentifier(args);
-+ 
-+         // Prefix with dummy instance for convenience.
-+         GetMemberPluginCallRequest request =
-+             new GetMemberPluginCallRequest("instance " + 0 +
-+                                            " Call " + internal +
-+                                            " " + nameID + " " + argsID, "JavaScriptCall");
-+         PluginMain.postCallRequest(request);
-+         PluginMain.write(request.message);
-+         try {
-+             System.out.println ("wait call request 1");
-+             synchronized(request) {
-+                 System.out.println ("wait call request 2");
-+                 while (request.done == false)
-+                     request.wait();
-+                 System.out.println ("wait call request 3");
-+             }
-+         } catch (InterruptedException e) {
-+             throw new RuntimeException("Interrupted waiting for call request.",
-+                                        e);
-+         }
-+         System.out.println (" Call DONE");
-+         return request.object;
-+     }
-+ 
-+     public static void JavaScriptFinalize(int internal)
-+     {
-+         // Prefix with dummy instance for convenience.
-+         VoidPluginCallRequest request =
-+             new VoidPluginCallRequest("instance " + 0 +
-+                                            " Finalize " + internal, "JavaScriptFinalize");
-+         PluginMain.postCallRequest(request);
-+         PluginMain.write(request.message);
-+         try {
-+             System.out.println ("wait finalize request 1");
-+             synchronized(request) {
-+                 System.out.println ("wait finalize request 2");
-+                 while (request.done == false)
-+                     request.wait();
-+                 System.out.println ("wait finalize request 3");
-+             }
-+         } catch (InterruptedException e) {
-+             throw new RuntimeException("Interrupted waiting for call request.",
-+                                        e);
-+         }
-+         System.out.println (" finalize DONE");
-+     }
-+ 
-+     public static String javascriptToString(int internal)
-+     {
-+         // Prefix with dummy instance for convenience.
-+         GetMemberPluginCallRequest request =
-+             new GetMemberPluginCallRequest("instance " + 0 +
-+                                       " ToString " + internal, "JavaScriptToString");
-+         PluginMain.postCallRequest(request);
-+         PluginMain.write(request.message);
-+         try {
-+             System.out.println ("wait ToString request 1");
-+             synchronized(request) {
-+                 System.out.println ("wait ToString request 2");
-+                 while (request.done == false)
-+                     request.wait();
-+                 System.out.println ("wait ToString request 3");
-+             }
-+         } catch (InterruptedException e) {
-+             throw new RuntimeException("Interrupted waiting for call request.",
-+                                        e);
-+         }
-+         System.out.println (" ToString DONE");
-+         return (String) request.object;
-+     }
-+ 
-+     // FIXME: make this private and access it from JSObject using
-+     // reflection.
-+     private void write(String message) throws IOException {
-+         System.err.println ("WRITING 2: " + "instance " + identifier + " " + message);
-+         PluginMain.write("instance " + identifier + " " + message);
-+         System.err.println ("WRITING 2 DONE");
-+     }
-+ 
-+     // FIXME: make this private and access it from JSObject using
-+     // reflection.
-+     private String read() throws IOException {
-+         System.out.println ("READING 1");
-+         String ret = PluginMain.read();
-+         System.out.println ("READING 1 DONE");
-+         return ret;
-+     }
-+ 
-+     public void setStream(String key, InputStream stream)throws IOException{
-+ 	// We do nothing.
-+     }
-+ 
-+     public InputStream getStream(String key){
-+ 	// We do nothing.
-+ 	return null;
-+     }
-+ 
-+     public Iterator getStreamKeys(){
-+ 	// We do nothing.
-+ 	return null;
-+     }
-+ 
-+     /**
-+      * System parameters.
-+      */
-+     static Hashtable systemParam = new Hashtable();
-+ 
-+     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");
-+     }
-+ 
-+     /**
-+      * Print the HTML tag.
-+      */
-+     public static void printTag(PrintStream out, Hashtable atts) {
-+ 	out.print("<applet");
-+ 
-+ 	String v = (String)atts.get("codebase");
-+ 	if (v != null) {
-+ 	    out.print(" codebase=\"" + v + "\"");
-+ 	}
-+ 
-+ 	v = (String)atts.get("code");
-+ 	if (v == null) {
-+ 	    v = "applet.class";
-+ 	}
-+ 	out.print(" code=\"" + v + "\"");
-+ 	v = (String)atts.get("width");
-+ 	if (v == null) {
-+ 	    v = "150";
-+ 	}
-+ 	out.print(" width=" + v);
-+ 
-+ 	v = (String)atts.get("height");
-+ 	if (v == null) {
-+ 	    v = "100";
-+ 	}
-+ 	out.print(" height=" + v);
-+ 
-+ 	v = (String)atts.get("name");
-+ 	if (v != null) {
-+ 	    out.print(" name=\"" + v + "\"");
-+ 	}
-+ 	out.println(">");
-+ 
-+ 	// A very slow sorting algorithm
-+ 	int len = atts.size();
-+ 	String params[] = new String[len];
-+ 	len = 0;
-+ 	for (Enumeration e = atts.keys() ; e.hasMoreElements() ;) {
-+ 	    String param = (String)e.nextElement();
-+ 	    int i = 0;
-+ 	    for (; i < len ; i++) {
-+ 		if (params[i].compareTo(param) >= 0) {
-+ 		    break;
-+ 		}
-+ 	    }
-+ 	    System.arraycopy(params, i, params, i + 1, len - i);
-+ 	    params[i] = param;
-+ 	    len++;
-+ 	}
-+ 
-+ 	for (int i = 0 ; i < len ; i++) {
-+ 	    String param = params[i];
-+ 	    if (systemParam.get(param) == null) {
-+ 		out.println("<param name=" + param +
-+ 			    " value=\"" + atts.get(param) + "\">");
-+ 	    }
-+ 	}
-+ 	out.println("</applet>");
-+     }
-+ 
-+     /**
-+      * Make sure the atrributes are uptodate.
-+      */
-+     public void updateAtts() {
-+ 	Dimension d = panel.size();
-+ 	Insets in = panel.insets();
-+ 	panel.atts.put("width",
-+ 		       new Integer(d.width - (in.left + in.right)).toString());
-+ 	panel.atts.put("height",
-+ 		       new Integer(d.height - (in.top + in.bottom)).toString());
-+     }
-+ 
-+     /**
-+      * 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 {
-+             panel.joinAppletThread();
-+ 	    panel.release();
-+         } catch (InterruptedException e) {
-+             return;   // abort the reload
-+         }
-+ 
-+         panel.createAppletThread();
-+ 	panel.sendEvent(AppletPanel.APPLET_LOAD);
-+ 	panel.sendEvent(AppletPanel.APPLET_INIT);
-+ 	panel.sendEvent(AppletPanel.APPLET_START);
-+     }
-+ 
-+     public int print(Graphics graphics, PageFormat pf, int pageIndex) {
-+         return Printable.NO_SUCH_PAGE;
-+     }
-+ 
-+     /**
-+      * 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(AppletPanel 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 AppletPanel p = panel;
-+ 
-+ 	new Thread(new Runnable()
-+ 	{
-+ 	    public void run()
-+ 	    {
-+     		appletShutdown(p);
-+ 		appletPanels.removeElement(p);
-+ 		dispose();
-+ 
-+ 		if (countApplets() == 0) {
-+ 		    appletSystemExit();
-+ 		}
-+ 	    }
-+ 	}).start();
-+     }
-+ 
-+     /**
-+      * Exit the program.
-+      * Exit from the program (if not stand alone) - do no clean-up
-+      */
-+     private void appletSystemExit() {
-+ 	if (factory.isStandalone())
-+ 	    System.exit(0);
-+     }
-+ 
-+     /**
-+      * How many applets are running?
-+      */
-+ 
-+     public static int countApplets() {
-+ 	return appletPanels.size();
-+     }
-+ 
-+ 
-+     /**
-+      * The current character.
-+      */
-+     static int c;
-+ 
-+     /**
-+      * Scan spaces.
-+      */
-+     public static void skipSpace(Reader in) throws IOException {
-+         while ((c >= 0) &&
-+ 	       ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))) {
-+ 	    c = in.read();
-+ 	}
-+     }
-+ 
-+     /**
-+      * Scan identifier
-+      */
-+     public static String scanIdentifier(Reader in) throws IOException {
-+ 	StringBuffer buf = new StringBuffer();
-+ 	while (true) {
-+ 	    if (((c >= 'a') && (c <= 'z')) ||
-+ 		((c >= 'A') && (c <= 'Z')) ||
-+ 		((c >= '0') && (c <= '9')) || (c == '_')) {
-+ 		buf.append((char)c);
-+ 		c = in.read();
-+ 	    } else {
-+ 		return buf.toString();
-+ 	    }
-+ 	}
-+     }
-+ 
-+     /**
-+      * Scan tag
-+      */
-+     public static Hashtable scanTag(Reader in) throws IOException {
-+ 	Hashtable atts = new Hashtable();
-+ 	skipSpace(in);
-+         while (c >= 0 && c != '>') {
-+ 	    String att = scanIdentifier(in);
-+ 	    String val = "";
-+ 	    skipSpace(in);
-+ 	    if (c == '=') {
-+ 		int quote = -1;
-+ 		c = in.read();
-+ 		skipSpace(in);
-+ 		if ((c == '\'') || (c == '\"')) {
-+ 		    quote = c;
-+ 		    c = in.read();
-+ 		}
-+ 		StringBuffer buf = new StringBuffer();
-+                 while ((c > 0) &&
-+ 		       (((quote < 0) && (c != ' ') && (c != '\t') &&
-+                          (c != '\n') && (c != '\r') && (c != '>'))
-+ 			|| ((quote >= 0) && (c != quote)))) {
-+ 		    buf.append((char)c);
-+ 		    c = in.read();
-+ 		}
-+ 		if (c == quote) {
-+ 		    c = in.read();
-+ 		}
-+ 		skipSpace(in);
-+ 		val = buf.toString();
-+ 	    }
-+ 	    System.err.println("PUT " + att + " = '" + val + "'");
-+ 	    if (! val.equals("")) {
-+ 		atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val);
-+ 	    }
-+             while (true) {
-+                 if ((c == '>') || (c < 0) ||
-+                     ((c >= 'a') && (c <= 'z')) ||
-+                     ((c >= 'A') && (c <= 'Z')) ||
-+                     ((c >= '0') && (c <= '9')) || (c == '_'))
-+                     break;
-+                 c = in.read();
-+             }
-+             //skipSpace(in);
-+ 	}
-+ 	return atts;
-+     }
-+ 
-+     /* values used for placement of AppletViewer's frames */
-+     private static int x = 0;
-+     private static int y = 0;
-+     private static final int XDELTA = 30;
-+     private static final int YDELTA = XDELTA;
-+ 
-+     static String encoding = null;
-+ 
-+     static private Reader makeReader(InputStream is) {
-+ 	if (encoding != null) {
-+ 	    try {
-+ 		return new BufferedReader(new InputStreamReader(is, encoding));
-+ 	    } catch (IOException x) { }
-+ 	}
-+ 	InputStreamReader r = new InputStreamReader(is);
-+ 	encoding = r.getEncoding();
-+ 	return new BufferedReader(r);
-+     }
-+ 
-+     /**
-+      * Scan an html file for <applet> tags
-+      */
-+     public static void parse(int identifier, long handle, Reader in, URL url, String enc)
-+         throws IOException {
-+         encoding = enc;
-+         parse(identifier, handle, in, url, System.out, new PluginAppletViewerFactory());
-+     }
-+ 
-+     public static void parse(int identifier, long handle, Reader in, URL url)
-+         throws IOException {
-+         parse(identifier, handle, in, url, System.out, new PluginAppletViewerFactory());
-+     }
-+ 
-+     public static void parse(int identifier, long handle, Reader in, URL url,
-+                              PrintStream statusMsgStream,
-+                              PluginAppletViewerFactory factory)
-+         throws IOException
-+     {
-+    	 // <OBJECT> <EMBED> tag flags
-+    	 boolean isAppletTag = false;
-+    	 boolean isObjectTag = false;
-+    	 boolean isEmbedTag = false;
-+
-+    	 // warning messages
-+    	 String requiresNameWarning = amh.getMessage("parse.warning.requiresname");
-+    	 String paramOutsideWarning = amh.getMessage("parse.warning.paramoutside");
-+    	 String appletRequiresCodeWarning = amh.getMessage("parse.warning.applet.requirescode");
-+    	 String appletRequiresHeightWarning = amh.getMessage("parse.warning.applet.requiresheight");
-+    	 String appletRequiresWidthWarning = amh.getMessage("parse.warning.applet.requireswidth");
-+    	 String objectRequiresCodeWarning = amh.getMessage("parse.warning.object.requirescode");
-+    	 String objectRequiresHeightWarning = amh.getMessage("parse.warning.object.requiresheight");
-+    	 String objectRequiresWidthWarning = amh.getMessage("parse.warning.object.requireswidth");
-+    	 String embedRequiresCodeWarning = amh.getMessage("parse.warning.embed.requirescode");
-+    	 String embedRequiresHeightWarning = amh.getMessage("parse.warning.embed.requiresheight");
-+    	 String embedRequiresWidthWarning = amh.getMessage("parse.warning.embed.requireswidth");
-+    	 String appNotLongerSupportedWarning = amh.getMessage("parse.warning.appnotLongersupported");
-+
-+    	 java.net.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();
-+
-+    	 int ydisp = 1;
-+    	 Hashtable atts = null;
-+
-+    	 while(true) {
-+    		 c = in.read();
-+    		 if (c == -1)
-+    			 break;
-+
-+    		 if (c == '<') {
-+    			 c = in.read();
-+    			 if (c == '/') {
-+    				 c = in.read();
-+    				 String nm = scanIdentifier(in);
-+    				 if (nm.equalsIgnoreCase("applet") ||
-+    						 nm.equalsIgnoreCase("object") ||
-+    						 nm.equalsIgnoreCase("embed")) {
-+
-+    					 // We can't test for a code tag until </OBJECT>
-+    					 // because it is a parameter, not an attribute.
-+    					 if(isObjectTag) {
-+    						 if (atts.get("code") == null && atts.get("object") == null) {
-+    							 statusMsgStream.println(objectRequiresCodeWarning);
-+    							 atts = null;
-+    						 }
-+    					 }
-+
-+    					 if (atts != null) {
-+    						 // XXX 5/18 In general this code just simply
-+    						 // shouldn't be part of parsing.  It's presence
-+    						 // causes things to be a little too much of a
-+    						 // hack.
-+    						 factory.createAppletViewer(identifier, handle, x, y, url, atts);
-+    						 x += XDELTA;
-+    						 y += YDELTA;
-+    						 // make sure we don't go too far!
-+    						 Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
-+    						 if ((x > d.width - 300) || (y > d.height - 300)) {
-+    							 x = 0;
-+    							 y = 2 * ydisp * YDELTA;
-+    							 ydisp++;
-+    						 }
-+    					 }
-+    					 atts = null;
-+    					 isAppletTag = false;
-+    					 isObjectTag = false;
-+    					 isEmbedTag = false;
-+    				 }
-+    			 }
-+    			 else {
-+    				 String nm = scanIdentifier(in);
-+    				 if (nm.equalsIgnoreCase("param")) {
-+    					 Hashtable t = scanTag(in);
-+    					 String att = (String)t.get("name");
-+    					 if (att == null) {
-+    						 statusMsgStream.println(requiresNameWarning);
-+    					 } else {
-+    						 String val = (String)t.get("value");
-+    						 if (val == null) {
-+    							 statusMsgStream.println(requiresNameWarning);
-+    						 } else if (atts != null) {
-+    							 atts.put(att.toLowerCase(), val);
-+    						 } else {
-+    							 statusMsgStream.println(paramOutsideWarning);
-+    						 }
-+    					 }
-+    				 }
-+    				 else if (nm.equalsIgnoreCase("applet")) {
-+    					 isAppletTag = true;
-+    					 atts = scanTag(in);
-+
-+    					 // If there is a classid present, transform it to code tag
-+    					 if (atts.get("code") == null && atts.get("classid") != null && 
-+    							 ((String) atts.get("classid")).startsWith("java:")) {
-+    						 //skip "java:"
-+    						 atts.put("code", ((String) atts.get("classid")).substring(5));
-+    					 }
-+
-+    					 if (atts.get("code") == null && atts.get("object") == null) {
-+    						 statusMsgStream.println(appletRequiresCodeWarning);
-+    						 atts = null;
-+    					 }
-+
-+    					 if (atts.get("width") == null) {
-+    						 atts.put("width", "100%");
-+    					 } 
-+
-+    					 if (atts.get("height") == null) {
-+    						 atts.put("height", "100%");
-+    					 }
-+    				 }
-+    				 else if (nm.equalsIgnoreCase("object")) {
-+    					 isObjectTag = true;
-+    					 atts = scanTag(in);
-+
-+    					 // If there is a classid present, transform it to code tag
-+    					 if (atts.get("code") == null && atts.get("classid") != null && 
-+    							 ((String) atts.get("classid")).startsWith("java:")) {
-+    						 //skip "java:"
-+    						 atts.put("code", ((String) atts.get("classid")).substring(5));
-+    					 }
-+
-+    					 // The <OBJECT> attribute codebase isn't what
-+    					 // we want when not dealing with jars. If its 
-+    					 // defined, remove it in that case.
-+    					 if(atts.get("archive") == null && atts.get("codebase") != null) {
-+    						 atts.remove("codebase");
-+    					 }
-+
-+    					 if (atts.get("width") == null) {
-+    						 atts.put("width", "100%");
-+    					 } 
-+
-+    					 if (atts.get("height") == null) {
-+    						 atts.put("height", "100%");
-+    					 }
-+    				 }
-+    				 else if (nm.equalsIgnoreCase("embed")) {
-+    					 isEmbedTag = true;
-+    					 atts = scanTag(in);
-+
-+    					 // If there is a classid present, transform it to code tag
-+    					 if (atts.get("code") == null && atts.get("classid") != null && 
-+    							 ((String) atts.get("classid")).startsWith("java:")) {
-+    						 //skip "java:"
-+    						 atts.put("code", ((String) atts.get("classid")).substring(5));
-+    					 }
-+
-+    					 if (atts.get("code") == null && atts.get("object") == null) {
-+    						 statusMsgStream.println(embedRequiresCodeWarning);
-+    						 atts = null;
-+    					 }
-+    					 
-+    					 if (atts.get("width") == null) {
-+    						 atts.put("width", "100%");
-+    					 } 
-+
-+    					 if (atts.get("height") == null) {
-+    						 atts.put("height", "100%");
-+    					 }
-+    				 }
-+    				 else if (nm.equalsIgnoreCase("app")) {
-+    					 statusMsgStream.println(appNotLongerSupportedWarning);
-+    					 Hashtable atts2 = scanTag(in);
-+    					 nm = (String)atts2.get("class");
-+    					 if (nm != null) {
-+    						 atts2.remove("class");
-+    						 atts2.put("code", nm + ".class");
-+    					 }
-+    					 nm = (String)atts2.get("src");
-+    					 if (nm != null) {
-+    						 atts2.remove("src");
-+    						 atts2.put("codebase", nm);
-+    					 }
-+    					 if (atts2.get("width") == null) {
-+    						 atts2.put("width", "100%");
-+    					 }
-+    					 if (atts2.get("height") == null) {
-+    						 atts2.put("height", "100%");
-+    					 }
-+    					 printTag(statusMsgStream, atts2);
-+    					 statusMsgStream.println();
-+    				 }
-+    			 }
-+    		 }
-+    	 }
-+    	 in.close();
-+     }
-+ 
-+     /**
-+      * Old main entry point.
-+      *
-+      * @deprecated
-+      */
-+     @Deprecated
-+     public static void main(String args[]) throws IOException {
-+         PluginMain.main(args);
-+     }
-+ 
-+     private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer");
-+ 
-+     private static void checkConnect(URL url)
-+     {
-+ 	SecurityManager security = System.getSecurityManager();
-+ 	if (security != null) {
-+ 	    try {
-+ 		java.security.Permission perm =
-+ 		    url.openConnection().getPermission();
-+ 		if (perm != null)
-+ 		    security.checkPermission(perm);
-+ 		else
-+ 		    security.checkConnect(url.getHost(), url.getPort());
-+ 	    } catch (java.io.IOException ioe) {
-+ 		    security.checkConnect(url.getHost(), url.getPort());
-+ 	    }
-+ 	}
-+     }
-+ }
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginCallRequest.java openjdk/jdk/src/share/classes/sun/applet/PluginCallRequest.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginCallRequest.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginCallRequest.java	2008-09-15 16:22:07.000000000 -0400
-@@ -0,0 +1,56 @@
-+/* PluginCallRequest -- represent Java-to-JavaScript requests
-+   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. */
-+
-+package sun.applet;
-+
-+// FIXME: for each type of request extend a new (anonymous?)
-+// PluginCallRequest.
-+abstract class PluginCallRequest {
-+    String message;
-+    String returnString;
-+    PluginCallRequest next;
-+    boolean done = false;
-+
-+    public PluginCallRequest(String message, String returnString) {
-+        this.message = message;
-+        this.returnString = returnString;
-+    }
-+
-+    public abstract void parseReturn(String message);
-+    
-+    public abstract boolean serviceable(String message);
-+}
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginDebug.java openjdk/jdk/src/share/classes/sun/applet/PluginDebug.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginDebug.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginDebug.java	2008-09-15 16:21:47.000000000 -0400
-@@ -0,0 +1,13 @@
-+package sun.applet;
-+
-+import java.io.*;
-+
-+public class PluginDebug {
-+	
-+	static final boolean DEBUG = true; 
-+
-+    public static void debug(String message) {
-+    	if (DEBUG)
-+    		System.err.println(message);
-+	}
-+}
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginException.java openjdk/jdk/src/share/classes/sun/applet/PluginException.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginException.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginException.java	2008-09-15 16:22:08.000000000 -0400
-@@ -0,0 +1,14 @@
-+package sun.applet;
-+
-+public class PluginException extends Exception {
-+
-+	public PluginException (int instance, int reference, Throwable t) {
-+		t.printStackTrace();
-+		this.setStackTrace(t.getStackTrace());
-+		
-+		PluginAppletSecurityContext.contexts.get(0).store.dump();
-+
-+		String message = "instance " + instance + " reference " + reference + " Error " + t.getMessage();
-+		PluginMain.write(message);
-+	}
-+}
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginMain.java openjdk/jdk/src/share/classes/sun/applet/PluginMain.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginMain.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginMain.java	2008-09-15 16:22:08.000000000 -0400
-@@ -0,0 +1,533 @@
-+/*
-+ * Copyright 1999-2006 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.io.*;
-+import java.lang.reflect.*;
-+import java.net.*;
-+import java.nio.charset.Charset;
-+import java.util.*;
-+
-+import sun.net.www.ParseUtil;
-+
-+class RequestQueue {
-+    PluginCallRequest head = null;
-+    PluginCallRequest tail = null;
-+    private int size = 0;
-+
-+    void post(PluginCallRequest request) {
-+        if (head == null) {
-+            head = tail = request;
-+            tail.next = null;
-+        } else {
-+            tail.next = request;
-+            tail = request;
-+            tail.next = null;
-+        }
-+        
-+        size++;
-+    }
-+
-+    PluginCallRequest pop() {
-+        if (head == null)
-+            return null;
-+
-+        PluginCallRequest ret = head;
-+        head = head.next;
-+        ret.next = null;
-+        
-+        size--;
-+        
-+        return ret;
-+    }
-+    
-+    int size() {
-+    	return size;
-+    }
-+}
-+
-+/**
-+ * The main entry point into PluginAppletViewer.
-+ */
-+public class PluginMain
-+{
-+    private static BufferedReader pluginInputReader;
-+    private static StreamTokenizer pluginInputTokenizer;
-+    private static BufferedWriter pluginOutputWriter;
-+    // This is used in init().	Getting rid of this is desirable but depends
-+    // on whether the property that uses it is necessary/standard.
-+    public static final String theVersion = System.getProperty("java.version");
-+
-+    private static RequestQueue queue = new RequestQueue();
-+
-+	static LinkedList<String> readQueue = new LinkedList<String>();
-+	static LinkedList<String> writeQueue = new LinkedList<String>();
-+
-+	static PluginMessageConsumer consumer;
-+	static Boolean shuttingDown = false;
-+	
-+	static final boolean redirectStreams = false;
-+
-+    /**
-+     * The main entry point into AppletViewer.
-+     */
-+    public static void main(String args[])
-+	throws IOException
-+    {
-+
-+    	if (args.length != 1) {
-+    		// Indicate to plugin that appletviewer is installed correctly.
-+    		System.exit(0);
-+    	}
-+
-+    	int port = 0;
-+    	try {
-+    		port = Integer.parseInt(args[0]);
-+    	} catch (NumberFormatException e) {
-+    		System.err.println("Failed to parse port number: " + e);
-+    		System.exit(1);
-+    	}
-+
-+    	if (redirectStreams) {
-+    		try {
-+    			File errFile = new File("/tmp/java.stderr");
-+    			File outFile = new File("/tmp/java.stdout");
-+
-+    			System.setErr(new PrintStream(new FileOutputStream(errFile)));
-+    			System.setOut(new PrintStream(new FileOutputStream(outFile)));
-+
-+    		} catch (Exception e) {
-+    			System.err.println("Unable to redirect streams");
-+    			e.printStackTrace();
-+    		}
-+    	}
-+
-+    	// INSTALL THE SECURITY MANAGER
-+    	init();
-+
-+    	System.err.println("Creating consumer...");
-+    	consumer = new PluginMessageConsumer();
-+
-+    	beginListening(50007);
-+    }
-+
-+    public PluginMain() {
-+    	
-+    	try {
-+    	    File errFile = new File("/tmp/java.stderr");
-+    	    File outFile = new File("/tmp/java.stdout");
-+
-+    	    System.setErr(new PrintStream(new FileOutputStream(errFile)));
-+    	    System.setOut(new PrintStream(new FileOutputStream(outFile)));
-+
-+    	} catch (Exception e) {
-+    	    System.err.println("Unable to redirect streams");
-+    	    e.printStackTrace();
-+    	}
-+
-+    	// INSTALL THE SECURITY MANAGER
-+    	init();
-+
-+    	System.err.println("Creating consumer...");
-+    	consumer = new PluginMessageConsumer();
-+
-+		beginListening(50007);
-+
-+    }
-+
-+	private static void beginListening(int port) {
-+    	/*
-+    	 * Code for TCP/IP communication
-+    	 */ 
-+    	Socket socket = null;
-+
-+    	try {
-+    		socket = new Socket("localhost", port);
-+    	} catch (Exception e) {
-+    		e.printStackTrace();
-+    	}
-+    	
-+    	System.err.println("Socket initialized. Proceeding with start()");
-+
-+		try {
-+	    	start(socket.getInputStream(), socket.getOutputStream());
-+	    	System.err.println("Streams initialized");
-+		} catch (IOException ioe) {
-+			ioe.printStackTrace();
-+		}
-+	}
-+    
-+    public static void postMessage(String s) {
-+
-+    	if (s == null || s.equals("shutdown")) {
-+    	    try {
-+    		// Close input/output channels to plugin.
-+    		pluginInputReader.close();
-+    		pluginOutputWriter.close();
-+    	    } catch (IOException exception) {
-+    		// Deliberately ignore IOException caused by broken
-+    		// pipe since plugin may have already detached.
-+    	    }
-+                PluginAppletSecurityContext.contexts.get(0).store.dump();
-+    	    System.err.println("APPLETVIEWER: exiting appletviewer");
-+    	    System.exit(0);
-+    	}
-+
-+   		//PluginAppletSecurityContext.contexts.get(0).store.dump();
-+   		PluginDebug.debug("Plugin posted: " + s);
-+
-+		System.err.println("Consuming " + s);
-+		consumer.consume(s);
-+
-+   		PluginDebug.debug("Added to queue");
-+    }
-+
-+    private static void init() {
-+	Properties avProps = new Properties();
-+
-+	// ADD OTHER RANDOM PROPERTIES
-+	// XXX 5/18 need to revisit why these are here, is there some
-+	// standard for what is available?
-+
-+	// Standard browser properties
-+	avProps.put("browser", "sun.applet.AppletViewer");
-+	avProps.put("browser.version", "1.06");
-+	avProps.put("browser.vendor", "Sun Microsystems Inc.");
-+	avProps.put("http.agent", "Java(tm) 2 SDK, Standard Edition v" + theVersion);
-+
-+	// Define which packages can be extended by applets
-+	// XXX 5/19 probably not needed, not checked in AppletSecurity
-+	avProps.put("package.restrict.definition.java", "true");
-+	avProps.put("package.restrict.definition.sun", "true");
-+
-+	// Define which properties can be read by applets.
-+	// A property named by "key" can be read only when its twin
-+	// property "key.applet" is true.  The following ten properties
-+	// are open by default.	 Any other property can be explicitly
-+	// opened up by the browser user by calling appletviewer with
-+	// -J-Dkey.applet=true
-+	avProps.put("java.version.applet", "true");
-+	avProps.put("java.vendor.applet", "true");
-+	avProps.put("java.vendor.url.applet", "true");
-+	avProps.put("java.class.version.applet", "true");
-+	avProps.put("os.name.applet", "true");
-+	avProps.put("os.version.applet", "true");
-+	avProps.put("os.arch.applet", "true");
-+	avProps.put("file.separator.applet", "true");
-+	avProps.put("path.separator.applet", "true");
-+	avProps.put("line.separator.applet", "true");
-+
-+	// Read in the System properties.  If something is going to be
-+	// over-written, warn about it.
-+	Properties sysProps = System.getProperties();
-+	for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements(); ) {
-+	    String key = (String) e.nextElement();
-+	    String val = (String) sysProps.getProperty(key);
-+	    avProps.setProperty(key, val);
-+	}
-+
-+	// INSTALL THE PROPERTY LIST
-+	System.setProperties(avProps);
-+
-+	// Create and install the security manager
-+	System.setSecurityManager(new AppletSecurity());
-+
-+	// REMIND: Create and install a socket factory!
-+    }
-+
-+    public static void handleMessage(String message) throws PluginException{
-+
-+    	StringTokenizer st = new StringTokenizer(message, " ");
-+
-+    	String type = st.nextToken();
-+    	int identifier = Integer.parseInt(st.nextToken());
-+
-+    	String rest = "";
-+    	int reference = -1;
-+    	String src = null;
-+
-+    	String potentialReference = st.hasMoreTokens() ? st.nextToken() : "";
-+
-+    	// if the next token is reference, read it, else reset "rest"
-+    	if (potentialReference.equals("reference")) {
-+    		reference = Integer.parseInt(st.nextToken());
-+    	} else {
-+    		rest += potentialReference + " ";
-+    	}
-+
-+    	String potentialSrc = st.hasMoreTokens() ? st.nextToken() : "";
-+
-+    	if (potentialSrc.equals("src")) {
-+    		src = st.nextToken();
-+    	} else {
-+    		rest += potentialSrc + " ";
-+    	}
-+
-+    	while (st.hasMoreElements()) {
-+    		rest += st.nextToken();
-+    		rest += " ";
-+    	}
-+
-+    	rest = rest.trim();
-+
-+    	try {
-+
-+    		System.err.println("Breakdown -- type: " + type + " identifier: " + identifier + " reference: " + reference + " src: " + src + " rest: " + rest);
-+
-+    		if (rest.contains("JavaScriptGetWindow")
-+    				|| rest.contains("JavaScriptGetMember")
-+    				|| rest.contains("JavaScriptSetMember")
-+    				|| rest.contains("JavaScriptGetSlot")
-+    				|| rest.contains("JavaScriptSetSlot")
-+    				|| rest.contains("JavaScriptEval")
-+    				|| rest.contains("JavaScriptRemoveMember")
-+    				|| rest.contains("JavaScriptCall")
-+    				|| rest.contains("JavaScriptFinalize")
-+    				|| rest.contains("JavaScriptToString")) {
-+    			finishCallRequest(rest);
-+    			return;
-+    		}
-+
-+    		if (type.equals("instance"))
-+    			PluginAppletViewer.handleMessage(identifier, reference, rest);
-+    		else if (type.equals("context")) {
-+    			PluginDebug.debug("Sending to PASC: " + identifier + "/" + reference + " and " + rest);
-+    			PluginAppletSecurityContext.handleMessage(identifier, src, reference, rest);
-+    		}
-+    	} catch (Exception e) {
-+    		throw new PluginException(identifier, reference, e);
-+    	}
-+    }
-+
-+    static void start(InputStream inputstream, OutputStream outputstream)
-+	throws MalformedURLException, IOException
-+    {
-+	// Set up input and output pipes.  Use UTF-8 encoding.
-+	pluginInputReader =
-+	    new BufferedReader(new InputStreamReader(inputstream,
-+						     Charset.forName("UTF-8")));
-+        pluginInputTokenizer = new StreamTokenizer(pluginInputReader);
-+        pluginInputTokenizer.resetSyntax();
-+        pluginInputTokenizer.whitespaceChars('\u0000', '\u0000');
-+        pluginInputTokenizer.wordChars('\u0001', '\u00FF');
-+	pluginOutputWriter =
-+	    new BufferedWriter(new OutputStreamWriter
-+			       (outputstream, Charset.forName("UTF-8")));
-+
-+	
-+	Thread listenerThread = new Thread() {
-+
-+		public void run() {
-+			while (true) {
-+
-+				System.err.println("Waiting for data...");
-+
-+				int readChar = -1;
-+				// blocking read, discard first character
-+				try {
-+					readChar = pluginInputReader.read();
-+				} catch (IOException ioe) {
-+					// plugin may have detached
-+				}
-+
-+				// if not disconnected
-+				if (readChar != -1) {
-+					String s = read();
-+					System.err.println("Got data, consuming " + s);
-+					consumer.consume(s);
-+				} else {
-+					try {
-+						// Close input/output channels to plugin.
-+						pluginInputReader.close();
-+						pluginOutputWriter.close();
-+					} catch (IOException exception) {
-+						// Deliberately ignore IOException caused by broken
-+						// pipe since plugin may have already detached.
-+					}
-+					PluginAppletSecurityContext.contexts.get(0).store.dump();
-+					System.err.println("APPLETVIEWER: exiting appletviewer");
-+					System.exit(0);
-+				}
-+			}
-+		}
-+	};
-+	
-+	listenerThread.start();
-+	
-+/*
-+	while(true) {
-+            String message = read();
-+            PluginDebug.debug(message);
-+            handleMessage(message);
-+            // TODO:
-+            // write(queue.peek());
-+	}
-+*/
-+    }
-+
-+    public static void postCallRequest(PluginCallRequest request) {
-+        synchronized(queue) {
-+            queue.post(request);
-+        }
-+    }
-+
-+    private static void finishCallRequest(String message) {
-+        PluginDebug.debug ("DISPATCHCALLREQUESTS 1");
-+        synchronized(queue) {
-+        PluginDebug.debug ("DISPATCHCALLREQUESTS 2");
-+            PluginCallRequest request = queue.pop();
-+            
-+            // make sure we give the message to the right request 
-+            // in the queue.. for the love of God, MAKE SURE!
-+            
-+            // first let's be efficient.. if there was only one 
-+            // request in queue, we're already set
-+            if (queue.size() != 0) {
-+
-+            	int size = queue.size();
-+            	int count = 0;
-+
-+            	while (!request.serviceable(message)) {
-+            		
-+            		// something is very wrong.. we have a message to 
-+            		// process, but no one to service it
-+            		if (count >= size) {
-+            			throw new RuntimeException("Unable to find processor for message " + message);
-+            		}
-+            		
-+        			// post request at the end of the queue
-+        			queue.post(request);
-+
-+        			// Look at the next request
-+        			request = queue.pop();
-+        			
-+        			count++;
-+            	}
-+            	
-+            }
-+            
-+        PluginDebug.debug ("DISPATCHCALLREQUESTS 3");
-+            if (request != null) {
-+                PluginDebug.debug ("DISPATCHCALLREQUESTS 5");
-+                synchronized(request) {
-+                    request.parseReturn(message);
-+                    request.notifyAll();
-+                }
-+        PluginDebug.debug ("DISPATCHCALLREQUESTS 6");
-+        PluginDebug.debug ("DISPATCHCALLREQUESTS 7");
-+            }
-+        }
-+        PluginDebug.debug ("DISPATCHCALLREQUESTS 8");
-+    }
-+
-+    /**
-+     * Write string to plugin.
-+     * 
-+     * @param message the message to write
-+     *
-+     * @exception IOException if an error occurs
-+     */
-+    static void write(String message)
-+    {
-+
-+    	System.err.println("  PIPE: appletviewer wrote: " + message);
-+        synchronized(pluginOutputWriter) {
-+        	try {
-+        		pluginOutputWriter.write(message, 0, message.length());
-+        		pluginOutputWriter.write(0);
-+        		pluginOutputWriter.flush();
-+        	} catch (IOException e) {
-+        		// if we are shutting down, ignore write failures as 
-+        		// pipe may have closed
-+        		synchronized(shuttingDown) {
-+        			if (!shuttingDown) {
-+        				e.printStackTrace();
-+        			}
-+        		}
-+
-+        		// either ways, if the pipe is broken, there is nothing 
-+        		// we can do anymore. Don't hang around.
-+        		System.err.println("Unable to write to PIPE. APPLETVIEWER exiting");        		
-+        		System.exit(1);
-+        	}
-+		}
-+
-+		return;
-+    /*	
-+    	synchronized(writeQueue) {
-+            writeQueue.add(message);
-+            System.err.println("  PIPE: appletviewer wrote: " + message);
-+    	}
-+	*/
-+
-+    }
-+
-+    static boolean messageAvailable() {
-+    	return writeQueue.size() != 0;
-+    }
-+
-+    static String getMessage() {
-+    	synchronized(writeQueue) {
-+			String ret = writeQueue.size() > 0 ? writeQueue.poll() : "";
-+    		return ret;
-+    	}
-+    }
-+
-+    /**
-+     * Read string from plugin.
-+     *
-+     * @return the read string
-+     *
-+     * @exception IOException if an error occurs
-+     */
-+    static String read()
-+    {
-+    	try {
-+    		pluginInputTokenizer.nextToken();
-+    	} catch (IOException e) {
-+    		throw new RuntimeException(e);
-+    	}
-+    	String message = pluginInputTokenizer.sval;
-+    	PluginDebug.debug("  PIPE: appletviewer read: " + message);
-+    	if (message == null || message.equals("shutdown")) {
-+    		synchronized(shuttingDown) {
-+    			shuttingDown = true;
-+    		}
-+    		try {
-+    			// Close input/output channels to plugin.
-+    			pluginInputReader.close();
-+    			pluginOutputWriter.close();
-+    		} catch (IOException exception) {
-+    			// Deliberately ignore IOException caused by broken
-+    			// pipe since plugin may have already detached.
-+    		}
-+    		PluginAppletSecurityContext.contexts.get(0).store.dump();
-+    		System.err.println("APPLETVIEWER: exiting appletviewer");
-+    		System.exit(0);
-+    	}
-+    	return message;
-+    }
-+}
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginMessageConsumer.java openjdk/jdk/src/share/classes/sun/applet/PluginMessageConsumer.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginMessageConsumer.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginMessageConsumer.java	2008-09-15 16:21:47.000000000 -0400
-@@ -0,0 +1,49 @@
-+package sun.applet;
-+
-+import java.util.ArrayList;
-+
-+class PluginMessageConsumer {
-+
-+	int MAX_WORKERS = 3;
-+	ArrayList<PluginMessageHandlerWorker> workers = new ArrayList<PluginMessageHandlerWorker>();
-+
-+	public PluginMessageConsumer() {
-+		for (int i=0; i < MAX_WORKERS; i++) {
-+			System.err.println("Creating worker " + i);
-+			PluginMessageHandlerWorker worker = new PluginMessageHandlerWorker(i);
-+			worker.start();
-+			workers.add(worker);
-+		}
-+	}
-+
-+	public void consume(String message) {
-+		
-+		PluginDebug.debug("Consumer received message " + message);
-+		
-+		synchronized(PluginMain.readQueue) {
-+			PluginMain.readQueue.add(message);
-+		}
-+
-+		PluginDebug.debug("Message " + message + " added to queue. Looking for free worker...");
-+		PluginMessageHandlerWorker worker = getFreeWorker();
-+		worker.interrupt();
-+	}
-+
-+	private PluginMessageHandlerWorker getFreeWorker() {
-+		
-+		// FIXME: Can be made more efficient by having an idle worker pool
-+		
-+		while (true) {
-+			for (PluginMessageHandlerWorker worker: workers) {
-+				if (worker.isFree()) {
-+					PluginDebug.debug("Found free worker with id " + worker.getWorkerId());
-+					return worker;
-+				}
-+			}
-+			Thread.yield();
-+		}
-+
-+		//throw new RuntimeException("Out of message handler workers");
-+	}
-+	
-+}
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginMessageHandlerWorker.java openjdk/jdk/src/share/classes/sun/applet/PluginMessageHandlerWorker.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginMessageHandlerWorker.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginMessageHandlerWorker.java	2008-09-15 16:21:47.000000000 -0400
-@@ -0,0 +1,59 @@
-+package sun.applet;
-+
-+class PluginMessageHandlerWorker extends Thread {
-+
-+	private boolean free = true;
-+	private int id;
-+	
-+	public PluginMessageHandlerWorker(int id) {
-+		this.id = id;
-+	}
-+	
-+	public void run() {
-+		while (true) {
-+
-+			String msg = null;
-+			synchronized(PluginMain.readQueue) {
-+				if (PluginMain.readQueue.size() > 0) {
-+					msg = PluginMain.readQueue.poll();
-+				}
-+			}
-+			
-+			if (msg != null) {
-+				free = false;
-+				System.err.println("Thread " + id + " picking up " + msg + " from queue...");
-+
-+				try {
-+					PluginMain.handleMessage(msg);
-+				} catch (PluginException pe) {
-+					/*
-+					   catch the exception and DO NOTHING. The plugin should take over after 
-+					   this error and let the user know. We don't quit because otherwise the 
-+					   exception will spread to the rest of the applets which is a no-no
-+					 */ 
-+				}
-+
-+				free = true;
-+			} else {
-+
-+				// Sleep when there is nothing to do
-+				try {
-+					Thread.sleep(Integer.MAX_VALUE);
-+					System.err.println("Consumer thread " + id + " sleeping...");
-+				} catch (InterruptedException ie) {
-+					System.err.println("Consumer thread " + id + " woken...");
-+					// nothing.. someone woke us up, see if there 
-+					// is work to do
-+				}
-+			}
-+		}
-+	}
-+	
-+	public int getWorkerId() {
-+		return id;
-+	}
-+	
-+	public boolean isFree() {
-+		return free;
-+	}
-+}
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginObjectStore.java openjdk/jdk/src/share/classes/sun/applet/PluginObjectStore.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginObjectStore.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginObjectStore.java	2008-09-15 16:21:47.000000000 -0400
-@@ -0,0 +1,119 @@
-+/* PluginObjectStore -- manage identifier-to-object mapping
-+   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. */
-+
-+package sun.applet;
-+
-+import java.util.*;
-+import java.lang.reflect.*;
-+import java.io.*;
-+
-+public class PluginObjectStore
-+{
-+    private static HashMap<Integer, Object> objects = new HashMap();
-+    private static HashMap<Integer, Integer> counts = new HashMap();
-+    private static HashMap<Object, Integer> identifiers = new HashMap();
-+    // FIXME:
-+    //
-+    // IF uniqueID == MAX_LONG, uniqueID =
-+    // 0 && wrapped = true
-+    //
-+    // if (wrapped), check if
-+    // objects.get(uniqueID) returns null
-+    //
-+    // if yes, use uniqueID, if no,
-+    // uniqueID++ and keep checking
-+    // or:
-+    // stack of available ids:
-+    // derefed id -> derefed id -> nextUniqueIdentifier
-+    private static int nextUniqueIdentifier = 1;
-+
-+    public Object getObject(Integer identifier) {
-+        return objects.get(identifier);
-+    }
-+
-+    public Integer getIdentifier(Object object) {
-+        if (object == null)
-+            return 0;
-+        return identifiers.get(object);
-+    }
-+
-+    public void reference(Object object) {
-+        Integer identifier = identifiers.get(object);
-+        if (identifier == null) {
-+            objects.put(nextUniqueIdentifier, object);
-+            counts.put(nextUniqueIdentifier, 1);
-+            identifiers.put(object, nextUniqueIdentifier);
-+            System.out.println("JAVA ADDED: " + nextUniqueIdentifier);
-+            System.out.println("JAVA REFERENCED: " + nextUniqueIdentifier
-+                               + " to: 1");
-+            nextUniqueIdentifier++;
-+        } else {
-+            counts.put(identifier, counts.get(identifier) + 1);
-+            System.out.println("JAVA REFERENCED: " + identifier +
-+                               " to: " + counts.get(identifier));
-+        }
-+    }
-+
-+    public void unreference(int identifier) {
-+        Integer currentCount = counts.get(identifier);
-+        if (currentCount == null)
-+            System.out.println("ERROR UNREFERENCING: " + identifier);
-+        if (currentCount == 1) {
-+            System.out.println("JAVA DEREFERENCED: " + identifier
-+                               + " to: 0");
-+            Object object = objects.get(identifier);
-+            objects.remove(identifier);
-+            counts.remove(identifier);
-+            identifiers.remove(object);
-+            System.out.println("JAVA REMOVED: " + identifier);
-+        } else {
-+            counts.put(identifier, currentCount - 1);
-+            System.out.println("JAVA DEREFERENCED: " +
-+                               identifier + " to: " +
-+                               counts.get(identifier));
-+        }
-+    }
-+
-+    public void dump() {
-+   		Iterator i = objects.keySet().iterator();
-+   		while (i.hasNext()) {
-+   			Object key = i.next();
-+   			System.err.println(key + "::" +  objects.get(key));
-+   		}
-+    }
-+}
-+
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/TestEnv.java openjdk/jdk/src/share/classes/sun/applet/TestEnv.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/TestEnv.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/TestEnv.java	2008-09-15 16:21:47.000000000 -0400
-@@ -0,0 +1,172 @@
-+/* TestEnv -- test JavaScript-to-Java calls
-+   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. */
-+
-+package sun.applet;
-+
-+public class TestEnv
-+{
-+    public static int intField = 103;
-+    public int intInstanceField = 7822;
-+    public String stringField = "hello";
-+    // z <musical G clef> <chinese water>
-+    public String complexStringField = "z\uD834\uDD1E\u6C34";
-+
-+    public static void TestIt() {
-+        System.out.println("TestIt");
-+    }
-+
-+    public static void TestItBool(boolean arg) {
-+        System.out.println("TestItBool: " + arg);
-+    }
-+
-+    public static void TestItByte(byte arg) {
-+        System.out.println("TestItByte: " + arg);
-+    }
-+
-+    public static void TestItChar(char arg) {
-+        System.out.println("TestItChar: " + arg);
-+    }
-+
-+    public static void TestItShort(short arg) {
-+        System.out.println("TestItShort: " + arg);
-+    }
-+
-+    public static void TestItInt(int arg) {
-+        System.out.println("TestItInt: " + arg);
-+    }
-+
-+    public static void TestItLong(long arg) {
-+        System.out.println("TestItLong: " + arg);
-+    }
-+
-+    public static void TestItFloat(float arg) {
-+        System.out.println("TestItFloat: " + arg);
-+    }
-+
-+    public static void TestItDouble(double arg) {
-+        System.out.println("TestItDouble: " + arg);
-+    }
-+
-+    public static void TestItObject(TestEnv arg) {
-+        System.out.println("TestItObject: " + arg);
-+    }
-+
-+    public static void TestItObjectString(String arg) {
-+        System.out.println("TestItObjectString: " + arg);
-+    }
-+
-+    public static void TestItIntArray(int[] arg) {
-+        System.out.println("TestItIntArray: " + arg);
-+        for (int i = 0; i < arg.length; i++)
-+            System.out.println ("ELEMENT: " + i + " " + arg[i]);
-+    }
-+
-+    public static void TestItObjectArray(String[] arg) {
-+        System.out.println("TestItObjectArray: " + arg);
-+        for (int i = 0; i < arg.length; i++)
-+            System.out.println ("ELEMENT: " + i + " " + arg[i]);
-+    }
-+
-+    public static void TestItObjectArrayMulti(String[][] arg) {
-+        System.out.println("TestItObjectArrayMulti: " + arg);
-+        for (int i = 0; i < arg.length; i++)
-+            for (int j = 0; j < arg[i].length; j++)
-+                System.out.println ("ELEMENT: " + i + " " + j + " " + arg[i][j]);
-+    }
-+
-+    public static boolean TestItBoolReturnTrue() {
-+        return true;
-+    }
-+
-+    public static boolean TestItBoolReturnFalse() {
-+        return false;
-+    }
-+
-+    public static byte TestItByteReturn() {
-+        return (byte) 0xfe;
-+    }
-+
-+    public static char TestItCharReturn() {
-+        return 'K';
-+    }
-+
-+    public static char TestItCharUnicodeReturn() {
-+        return '\u6C34';
-+    }
-+
-+    public static short TestItShortReturn() {
-+        return 23;
-+    }
-+
-+    public static int TestItIntReturn() {
-+        return 3445;
-+    }
-+
-+    public static long TestItLongReturn() {
-+        return 3242883;
-+    }
-+
-+    public static float TestItFloatReturn() {
-+        return 9.21E4f;
-+    }
-+
-+    public static double TestItDoubleReturn() {
-+        return 8.33E88;
-+    }
-+
-+    public static Object TestItObjectReturn() {
-+        return new String("Thomas");
-+    }
-+
-+    public static int[] TestItIntArrayReturn() {
-+        return new int[] { 6, 7, 8 };
-+    }
-+
-+    public static String[] TestItObjectArrayReturn() {
-+        return new String[] { "Thomas", "Brigitte" };
-+    }
-+
-+    public static String[][] TestItObjectArrayMultiReturn() {
-+        return new String[][] { {"Thomas", "Brigitte"},
-+                                {"Lindsay", "Michael"} };
-+    }
-+
-+    public int TestItIntInstance(int arg) {
-+        System.out.println("TestItIntInstance: " + this + " " + arg);
-+        return 899;
-+    }
-+}
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/VoidPluginCallRequest.java openjdk/jdk/src/share/classes/sun/applet/VoidPluginCallRequest.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/VoidPluginCallRequest.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/VoidPluginCallRequest.java	2008-09-15 16:22:09.000000000 -0400
-@@ -0,0 +1,62 @@
-+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
-+   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. */
-+
-+package sun.applet;
-+
-+class VoidPluginCallRequest extends PluginCallRequest {
-+    public VoidPluginCallRequest(String message, String returnString) {
-+        super(message, returnString);
-+        System.out.println ("VoidPLUGINCAlL " + message + " " + returnString);
-+    }
-+
-+    public void parseReturn(String message) {
-+        done = true;
-+    }
-+    
-+    /**
-+     * Returns whether the given message is serviceable by this object
-+     * 
-+     * @param message The message to service
-+     * @return boolean indicating if message is serviceable
-+     */
-+    public boolean serviceable(String message) {
-+    	return message.contains("JavaScriptFinalize") ||
-+    			message.contains("JavaScriptRemoveMember") ||
-+    			message.contains("JavaScriptSetMember") ||
-+    			message.contains("JavaScriptSetSlot");
-+    }
-+}
--- a/patches/icedtea-plugin.patch	Thu Sep 18 11:31:59 2008 -0400
+++ b/patches/icedtea-plugin.patch	Thu Sep 18 15:49:10 2008 -0400
@@ -1,6 +1,6 @@
 diff -urN openjdk.orig/jdk/make/launchers/Makefile openjdk/jdk/make/launchers/Makefile
---- openjdk.orig/jdk/make/launchers/Makefile	2008-06-29 09:40:07.000000000 -0400
-+++ openjdk/jdk/make/launchers/Makefile	2008-06-29 09:40:16.000000000 -0400
+--- openjdk.orig/jdk/make/launchers/Makefile	2008-07-10 15:54:41.000000000 -0400
++++ openjdk/jdk/make/launchers/Makefile	2008-09-18 14:21:46.000000000 -0400
 @@ -92,6 +92,7 @@
    -J-Dcom.sun.CORBA.activation.Port=1049 \
    -J-Dcom.sun.CORBA.POA.ORBServerId=1, )
@@ -9,1293 +9,3 @@
  $(call make-launcher, policytool, sun.security.tools.PolicyTool, , )
  $(call make-launcher, rmic, sun.rmi.rmic.Main, , )
  $(call make-launcher, rmid, sun.rmi.server.Activation, , )
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginMain.java openjdk/jdk/src/share/classes/sun/applet/PluginMain.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginMain.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginMain.java	2008-01-14 14:18:53.000000000 -0500
-@@ -0,0 +1,274 @@
-+/*
-+ * Copyright 1999-2006 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.io.*;
-+import java.lang.reflect.Method;
-+import java.lang.reflect.InvocationTargetException;
-+import java.net.*;
-+import java.nio.charset.Charset;
-+import java.util.*;
-+import sun.net.www.ParseUtil;
-+
-+class PluginParseRequest
-+{
-+  long handle;
-+  String tag;
-+  String documentbase;
-+  boolean alreadySent;
-+}
-+
-+/**
-+ * The main entry point into PluginAppletViewer.
-+ */
-+public class PluginMain
-+{
-+    // A mapping of instance IDs to PluginAppletViewers.
-+    private static HashMap appletWindows = new HashMap();
-+    private static HashMap parseRequests = new HashMap();
-+    private static String currentKey;
-+    private static PluginAppletViewer currentWindow;
-+    private static PluginParseRequest currentRequest;
-+    private static BufferedReader pluginInputStream;
-+    private static BufferedWriter pluginOutputStream;
-+    // This is used in init().	Getting rid of this is desirable but depends
-+    // on whether the property that uses it is necessary/standard.
-+    public static final String theVersion = System.getProperty("java.version");
-+
-+    /**
-+     * The main entry point into AppletViewer.
-+     */
-+    public static void main(String args[])
-+	throws IOException
-+    {
-+	if(args.length != 2) {
-+	    // Indicate to plugin that appletviewer is installed correctly.
-+	    System.exit(0);
-+	}
-+	// INSTALL THE SECURITY MANAGER
-+	init();
-+	start(new FileInputStream(args[0]), new FileOutputStream(args[1]));
-+	System.exit(0);
-+    }
-+
-+    private static void init() {
-+	Properties avProps = new Properties();
-+
-+	// ADD OTHER RANDOM PROPERTIES
-+	// XXX 5/18 need to revisit why these are here, is there some
-+	// standard for what is available?
-+
-+	// Standard browser properties
-+	avProps.put("browser", "sun.applet.AppletViewer");
-+	avProps.put("browser.version", "1.06");
-+	avProps.put("browser.vendor", "Sun Microsystems Inc.");
-+	avProps.put("http.agent", "Java(tm) 2 SDK, Standard Edition v" + theVersion);
-+
-+	// Define which packages can be extended by applets
-+	// XXX 5/19 probably not needed, not checked in AppletSecurity
-+	avProps.put("package.restrict.definition.java", "true");
-+	avProps.put("package.restrict.definition.sun", "true");
-+
-+	// Define which properties can be read by applets.
-+	// A property named by "key" can be read only when its twin
-+	// property "key.applet" is true.  The following ten properties
-+	// are open by default.	 Any other property can be explicitly
-+	// opened up by the browser user by calling appletviewer with
-+	// -J-Dkey.applet=true
-+	avProps.put("java.version.applet", "true");
-+	avProps.put("java.vendor.applet", "true");
-+	avProps.put("java.vendor.url.applet", "true");
-+	avProps.put("java.class.version.applet", "true");
-+	avProps.put("os.name.applet", "true");
-+	avProps.put("os.version.applet", "true");
-+	avProps.put("os.arch.applet", "true");
-+	avProps.put("file.separator.applet", "true");
-+	avProps.put("path.separator.applet", "true");
-+	avProps.put("line.separator.applet", "true");
-+
-+	// Read in the System properties.  If something is going to be
-+	// over-written, warn about it.
-+	Properties sysProps = System.getProperties();
-+	for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements(); ) {
-+	    String key = (String) e.nextElement();
-+	    String val = (String) sysProps.getProperty(key);
-+	    avProps.setProperty(key, val);
-+	}
-+
-+	// INSTALL THE PROPERTY LIST
-+	System.setProperties(avProps);
-+
-+	// Create and install the security manager
-+	System.setSecurityManager(new AppletSecurity());
-+
-+	// REMIND: Create and install a socket factory!
-+    }
-+
-+    static void registerWindow(PluginAppletViewer pluginappletviewer)
-+    {
-+	appletWindows.put(currentKey, pluginappletviewer);
-+	currentWindow = (PluginAppletViewer)appletWindows.get(currentKey);
-+    }
-+
-+    private static void deregisterWindow(PluginAppletViewer pluginappletviewer)
-+    {
-+	appletWindows.remove(currentWindow);
-+	currentWindow.dispose();
-+	currentWindow = null;
-+    }
-+
-+    static void start(InputStream inputstream, OutputStream outputstream)
-+	throws MalformedURLException, IOException
-+    {
-+	// Set up input and output pipes.  Use UTF-8 encoding.
-+	pluginInputStream =
-+	    new BufferedReader(new InputStreamReader(inputstream,
-+						     Charset.forName("UTF-8")));
-+	pluginOutputStream =
-+	    new BufferedWriter(new OutputStreamWriter
-+			       (outputstream, Charset.forName("UTF-8")));
-+
-+	write("running");
-+
-+	// Read first message.
-+	String message = read();
-+
-+	while(true) {
-+	    if (message.startsWith("instance")) {
-+		// Read applet instance identifier.
-+		currentKey = message.substring("instance".length() + 1);
-+		currentWindow =
-+		    (PluginAppletViewer)appletWindows.get(currentKey);
-+		currentRequest = null;
-+		if (currentWindow == null) {
-+		    if (!parseRequests.containsKey(currentKey))
-+			parseRequests.put(currentKey, new PluginParseRequest());
-+		    currentRequest =
-+			(PluginParseRequest)parseRequests.get(currentKey);
-+		}
-+	    } else if (message.startsWith("tag")) {
-+		if (currentRequest != null) {
-+		    int index = message.indexOf(' ', "tag".length() + 1);
-+		    currentRequest.documentbase =
-+			message.substring("tag".length() + 1, index);
-+		    currentRequest.tag = message.substring(index + 1);
-+		    if (currentRequest.handle != 0
-+			&& !currentRequest.alreadySent) {
-+			PluginAppletViewer.parse
-+			    (currentRequest.handle, 1, 1,
-+			     new StringReader(currentRequest.tag),
-+			     new URL(currentRequest.documentbase));
-+			parseRequests.remove(currentKey);
-+		    }
-+		}
-+	    } else if (message.startsWith("handle")) {
-+		if (currentRequest != null) {
-+		    currentRequest.handle = Long.parseLong
-+			(message.substring("handle".length() + 1, 
-+						message.indexOf("width") - 1));
-+		    int width = Integer.parseInt(message.substring
-+					(message.indexOf("width") + 
-+					"width".length() + 1, 
-+					message.indexOf("height") - 1));
-+		    int height = Integer.parseInt(message.substring(
-+					message.indexOf("height") + 
-+					"height".length() + 1));
-+		    if (currentRequest.tag != null
-+		       && !currentRequest.alreadySent) {
-+			PluginAppletViewer.parse
-+			    (currentRequest.handle, width, height,
-+			     new StringReader(currentRequest.tag),
-+			     new URL(currentRequest.documentbase));
-+			parseRequests.remove(currentKey);
-+		    }
-+		}
-+	    } else if (message.startsWith("width")) {
-+		int width =
-+		    Integer.parseInt(message.substring("width".length() + 1));
-+		int height = currentWindow.getHeight();
-+		currentWindow.updateAtts(width, height);
-+	 	currentWindow.setSize(width, height);
-+	    } else if (message.startsWith("height")) {
-+		int height =
-+		    Integer.parseInt(message.substring("height".length() + 1));
-+		int width = currentWindow.getWidth();
-+		currentWindow.updateAtts(width, height);
-+	        currentWindow.setSize(width, height);
-+	    } else if (message.startsWith("destroy")
-+		       && currentWindow != null) {
-+		deregisterWindow(currentWindow);
-+	    }
-+
-+	    // Read next message.
-+	    message = read();
-+	}
-+    }
-+
-+    /**
-+     * Write string to plugin.
-+     * 
-+     * @param message the message to write
-+     *
-+     * @exception IOException if an error occurs
-+     */
-+    static void write(String message)
-+	throws IOException
-+    {
-+	pluginOutputStream.write(message, 0, message.length());
-+	pluginOutputStream.newLine();
-+	pluginOutputStream.flush();
-+
-+	System.err.println("  PIPE: appletviewer wrote: " + message);
-+    }
-+
-+    /**
-+     * Read string from plugin.
-+     *
-+     * @return the read string
-+     *
-+     * @exception IOException if an error occurs
-+     */
-+    static String read()
-+	throws IOException
-+    {
-+	String message = pluginInputStream.readLine();
-+	System.err.println("  PIPE: appletviewer read: " + message);
-+	if (message == null || message.equals("shutdown")) {
-+	    try {
-+		// Close input/output channels to plugin.
-+		pluginInputStream.close();
-+		pluginOutputStream.close();
-+	    } catch (IOException exception) {
-+		// Deliberately ignore IOException caused by broken
-+		// pipe since plugin may have already detached.
-+	    }
-+
-+	    System.err.println("APPLETVIEWER: exiting appletviewer");
-+	    System.exit(0);
-+	}
-+	return message;
-+    }
-+}
-diff -urN openjdk.orig/jdk/src/share/classes/sun/applet/PluginAppletViewer.java openjdk/jdk/src/share/classes/sun/applet/PluginAppletViewer.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginAppletViewer.java	2008-06-24 22:55:57.286013713 -0400
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginAppletViewer.java	2008-06-29 10:34:07.000000000 -0400
-@@ -0,0 +1,1008 @@
-+/*
-+ * 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.util.*;
-+import java.io.*;
-+import java.awt.*;
-+import java.awt.event.*;
-+import java.awt.print.*;
-+import javax.print.attribute.*;
-+import java.applet.*;
-+import java.net.URL;
-+import java.net.MalformedURLException;
-+import java.net.SocketPermission;
-+import sun.misc.Ref;
-+import java.security.AccessController;
-+import java.security.PrivilegedAction;
-+import java.lang.reflect.InvocationTargetException;
-+import java.lang.reflect.Method;
-+import sun.awt.SunToolkit;
-+import sun.awt.AppContext;
-+import sun.awt.X11.*;
-+import java.lang.ref.WeakReference;
-+import net.sourceforge.jnlp.NetxPanel;
-+
-+/**
-+ * Lets us construct one using unix-style one shot behaviors
-+ */
-+
-+class PluginAppletViewerFactory
-+{
-+    public PluginAppletViewer createAppletViewer(long handle, int x, int y,
-+						 URL doc, Hashtable atts) {
-+        PluginAppletViewer pluginappletviewer = new PluginAppletViewer(handle, x, y, doc, atts, System.out, this);
-+        PluginMain.registerWindow(pluginappletviewer);
-+        return pluginappletviewer;
-+    }
-+
-+    public boolean isStandalone()
-+    {
-+        return false;
-+    }
-+}
-+
-+/*
-+ */
-+public class PluginAppletViewer extends XEmbeddedFrame
-+    implements AppletContext, Printable {
-+    /**
-+     * Some constants...
-+     */
-+    private static String defaultSaveFile = "Applet.ser";
-+
-+    /**
-+     * The panel in which the applet is being displayed.
-+     */
-+    AppletViewerPanel panel;
-+
-+    /**
-+     * The status line.
-+     */
-+    Label label;
-+
-+    /**
-+     * output status messages to this stream
-+     */
-+
-+    PrintStream statusMsgStream;
-+
-+    /**
-+     * For cloning
-+     */
-+    PluginAppletViewerFactory factory;
-+
-+    /**
-+     * Create the applet viewer
-+     */
-+    public PluginAppletViewer(long handle, int x, int y, final URL doc,
-+                              final Hashtable atts, PrintStream statusMsgStream,
-+                              PluginAppletViewerFactory factory) {
-+        super(handle, true);
-+    	this.factory = factory;
-+	this.statusMsgStream = statusMsgStream;
-+
-+	try {
-+		panel = new NetxPanel(doc, atts);
-+		AppletViewerPanel.debug("Using NetX panel");
-+	} catch (Exception ex) {
-+		AppletViewerPanel.debug("Unable to start NetX applet - defaulting to Sun applet", ex);
-+		panel = new AppletViewerPanel(doc, atts);
-+	}
-+	add("Center", panel);
-+	panel.init();
-+	appletPanels.addElement(panel);
-+
-+	pack();
-+	setVisible(true);
-+
-+	WindowListener windowEventListener = new WindowAdapter() {
-+
-+	    public void windowClosing(WindowEvent evt) {
-+		appletClose();
-+	    }
-+
-+	    public void windowIconified(WindowEvent evt) {
-+		appletStop();
-+	    }
-+
-+	    public void windowDeiconified(WindowEvent evt) {
-+		appletStart();
-+	    }
-+	};
-+
-+	class AppletEventListener implements AppletListener  
-+	{
-+	    final Frame frame;
-+
-+	    public AppletEventListener(Frame frame)
-+	    {
-+		this.frame = frame;
-+	    }
-+
-+	    public void appletStateChanged(AppletEvent evt) 
-+	    {
-+		AppletPanel src = (AppletPanel)evt.getSource();
-+
-+		switch (evt.getID()) {
-+                    case AppletPanel.APPLET_RESIZE: {
-+			if(src != null) {
-+			    resize(preferredSize());
-+			    validate();
-+                        }
-+			break;
-+		    }
-+		    case AppletPanel.APPLET_LOADING_COMPLETED: {
-+			Applet 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)
-+			    AppletPanel.changeFrameAppContext(frame, SunToolkit.targetToAppContext(a));
-+			else
-+			    AppletPanel.changeFrameAppContext(frame, AppContext.getAppContext());
-+
-+			break;
-+		    }
-+		}
-+	    }
-+	};
-+
-+	ComponentListener componentListener = new ComponentAdapter() {
-+		public void componentResized(ComponentEvent event)
-+  		{
-+		    if (panel != null)
-+		      {
-+		        ComponentListener[] l = panel.getComponentListeners();
-+		        for (int i = 0; i < l.length; i++)
-+		          l[i].componentResized(event);
-+			panel.validate();
-+		      }
-+		  }
-+
-+		public void componentMoved(ComponentEvent event)
-+		  {
-+		    if (panel != null)
-+		      {
-+		        ComponentListener[] l = panel.getComponentListeners();
-+		        for (int i = 0; i < l.length; i++)
-+		          l[i].componentMoved(event);
-+			panel.validate();
-+		      }
-+		  }
-+        };
-+
-+	HierarchyBoundsListener hierarchyBoundsListener = new HierarchyBoundsAdapter() {
-+		public void ancestorMoved(HierarchyEvent e)
-+		  {
-+		     if (panel != null)
-+                      {
-+		        HierarchyBoundsListener[] l = panel.getHierarchyBoundsListeners();
-+		        for (int i = 0; i < l.length; i++)
-+		          l[i].ancestorMoved(e);
-+			panel.validate();
-+		      }
-+		  }
-+
-+		public void ancestorResized(HierarchyEvent e)
-+		  {
-+		    if (panel != null)
-+		      {
-+		        HierarchyBoundsListener[] l = panel.getHierarchyBoundsListeners();
-+		        for (int i = 0; i < l.length; i++)
-+		          l[i].ancestorResized(e);
-+			panel.validate();
-+		      }
-+		  }
-+	};
-+
-+	addWindowListener(windowEventListener);
-+        addComponentListener(componentListener);
-+        addHierarchyBoundsListener(hierarchyBoundsListener);
-+	panel.addAppletListener(new AppletEventListener(this));
-+
-+	// Start the applet
-+        showStatus(amh.getMessage("status.start"));
-+	initEventQueue();
-+    }
-+
-+    /**
-+     * 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() {
-+	// appletviewer.send.event is an undocumented and unsupported system
-+	// property which is used exclusively for testing purposes.
-+	String eventList = System.getProperty("appletviewer.send.event");
-+
-+	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 = splitSeparator(",", eventList);
-+
-+ 	    for (int i = 0; i < events.length; i++) {
-+ 		System.out.println("Adding event to queue: " + events[i]);
-+ 		if (events[i].equals("dispose"))
-+ 		    panel.sendEvent(AppletPanel.APPLET_DISPOSE);
-+ 		else if (events[i].equals("load"))
-+ 		    panel.sendEvent(AppletPanel.APPLET_LOAD);
-+ 		else if (events[i].equals("init"))
-+ 		    panel.sendEvent(AppletPanel.APPLET_INIT);
-+ 		else if (events[i].equals("start"))
-+ 		    panel.sendEvent(AppletPanel.APPLET_START);
-+ 		else if (events[i].equals("stop"))
-+ 		    panel.sendEvent(AppletPanel.APPLET_STOP);
-+ 		else if (events[i].equals("destroy"))
-+ 		    panel.sendEvent(AppletPanel.APPLET_DESTROY);
-+ 		else if (events[i].equals("quit"))
-+ 		    panel.sendEvent(AppletPanel.APPLET_QUIT);
-+ 		else if (events[i].equals("error"))
-+ 		    panel.sendEvent(AppletPanel.APPLET_ERROR);
-+ 		else
-+		    // non-fatal error if we get an unrecognized event
-+ 		    System.out.println("Unrecognized event name: " + events[i]);
-+ 	    }
-+
-+  	    while (!panel.emptyEventQueue()) ;
-+ 	    appletSystemExit();
-+	}
-+    }
-+
-+    /**
-+     * Split a string based on the presence of a specified separator.  Returns
-+     * an array of arbitrary length.  The end of each element in the array is
-+     * indicated by the separator of the end of the string.  If there is a
-+     * separator immediately before the end of the string, the final element
-+     * will be empty.  None of the strings will contain the separator.  Useful
-+     * when separating strings such as "foo/bar/bas" using separator "/".
-+     *
-+     * @param sep  The separator.
-+     * @param s    The string to split.
-+     * @return     An array of strings.  Each string in the array is determined
-+     *             by the location of the provided sep in the original string,
-+     *             s.  Whitespace not stripped.
-+     */
-+    private String [] splitSeparator(String sep, String s) {
-+ 	Vector v = new Vector();
-+	int tokenStart = 0;
-+	int tokenEnd   = 0;
-+
-+	while ((tokenEnd = s.indexOf(sep, tokenStart)) != -1) {
-+	    v.addElement(s.substring(tokenStart, tokenEnd));
-+	    tokenStart = tokenEnd+1;
-+	}
-+	// Add the final element.
-+	v.addElement(s.substring(tokenStart));
-+
-+	String [] retVal = new String[v.size()];
-+	v.copyInto(retVal);
-+ 	return retVal;
-+    }
-+
-+    /*
-+     * Methods for java.applet.AppletContext
-+     */
-+
-+    private static Map audioClips = new HashMap();
-+
-+    /**
-+     * Get an audio clip.
-+     */
-+    public AudioClip getAudioClip(URL url) {
-+	checkConnect(url);
-+	synchronized (audioClips) {
-+	    AudioClip clip = (AudioClip)audioClips.get(url);
-+	    if (clip == null) {
-+		audioClips.put(url, clip = new AppletAudioClip(url));
-+	    }
-+	    return clip;
-+	}
-+    }
-+
-+    private static Map imageRefs = new HashMap();
-+
-+    /**
-+     * Get an image.
-+     */
-+    public Image getImage(URL url) {
-+	return getCachedImage(url);
-+    }
-+
-+    static Image getCachedImage(URL url) {
-+	// System.getSecurityManager().checkConnection(url.getHost(), url.getPort());
-+	return (Image)getCachedImageRef(url).get();
-+    }
-+
-+    /**
-+     * Get an image ref.
-+     */
-+    static Ref getCachedImageRef(URL url) {
-+	synchronized (imageRefs) {
-+	    AppletImageRef ref = (AppletImageRef)imageRefs.get(url);
-+	    if (ref == null) {
-+		ref = new AppletImageRef(url);
-+		imageRefs.put(url, ref);
-+	    }
-+	    return ref;
-+	}
-+    }
-+
-+    /**
-+     * Flush the image cache.
-+     */
-+    static void flushImageCache() {
-+	imageRefs.clear();
-+    }
-+
-+    static Vector appletPanels = new Vector();
-+
-+    /**
-+     * Get an applet by name.
-+     */
-+    public Applet getApplet(String name) {
-+	AppletSecurity security = (AppletSecurity)System.getSecurityManager();
-+	name = name.toLowerCase();
-+	SocketPermission panelSp =
-+	    new SocketPermission(panel.getCodeBase().getHost(), "connect");
-+	for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
-+	    AppletPanel p = (AppletPanel)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.applet;
-+		}
-+	    }
-+	}
-+	return null;
-+    }
-+
-+    /**
-+     * Return an enumeration of all the accessible
-+     * applets on this page.
-+     */
-+    public Enumeration getApplets() {
-+	AppletSecurity security = (AppletSecurity)System.getSecurityManager();
-+	Vector v = new Vector();
-+	SocketPermission panelSp =
-+	    new SocketPermission(panel.getCodeBase().getHost(), "connect");
-+
-+	for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
-+	    AppletPanel p = (AppletPanel)e.nextElement();
-+	    if (p.getDocumentBase().equals(panel.getDocumentBase())) {
-+
-+		SocketPermission sp =
-+		    new SocketPermission(p.getCodeBase().getHost(), "connect");
-+		if (panelSp.implies(sp)) {
-+		    v.addElement(p.applet);
-+		}
-+	    }
-+	}
-+	return v.elements();
-+    }
-+
-+    /**
-+     * Ignore.
-+     */
-+    public void showDocument(URL url) {
-+	showDocument(url, "_self");
-+    }
-+
-+    /**
-+     * Ignore.
-+     */
-+    public void showDocument(URL url, String target) {
-+	try {
-+	    PluginMain.write("url " + url + " " + target);
-+	} catch (IOException exception) {
-+	    // Deliberately ignore IOException.  showDocument may be
-+	    // called from threads other than the main thread after
-+	    // PluginMain.pluginOutputStream has been closed.
-+	}
-+    }
-+
-+    /**
-+     * Show status.
-+     */
-+    public void showStatus(String status) {
-+	try {
-+	    PluginMain.write("status " + status);
-+	} catch (IOException exception) {
-+	    // Deliberately ignore IOException.  showStatus may be
-+	    // called from threads other than the main thread after
-+	    // PluginMain.pluginOutputStream has been closed.
-+	}
-+    }
-+
-+    public void setStream(String key, InputStream stream)throws IOException{
-+	// We do nothing.
-+    }
-+
-+    public InputStream getStream(String key){
-+	// We do nothing.
-+	return null;
-+    }
-+
-+    public Iterator getStreamKeys(){
-+	// We do nothing.
-+	return null;
-+    }
-+
-+    /**
-+     * System parameters.
-+     */
-+    static Hashtable systemParam = new Hashtable();
-+
-+    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");
-+    }
-+
-+    /**
-+     * Print the HTML tag.
-+     */
-+    public static void printTag(PrintStream out, Hashtable atts) {
-+	out.print("<applet");
-+
-+	String v = (String)atts.get("codebase");
-+	if (v != null) {
-+	    out.print(" codebase=\"" + v + "\"");
-+	}
-+
-+	v = (String)atts.get("code");
-+	if (v == null) {
-+	    v = "applet.class";
-+	}
-+	out.print(" code=\"" + v + "\"");
-+	v = (String)atts.get("width");
-+	if (v == null) {
-+	    v = "150";
-+	}
-+	out.print(" width=" + v);
-+
-+	v = (String)atts.get("height");
-+	if (v == null) {
-+	    v = "100";
-+	}
-+	out.print(" height=" + v);
-+
-+	v = (String)atts.get("name");
-+	if (v != null) {
-+	    out.print(" name=\"" + v + "\"");
-+	}
-+	out.println(">");
-+
-+	// A very slow sorting algorithm
-+	int len = atts.size();
-+	String params[] = new String[len];
-+	len = 0;
-+	for (Enumeration e = atts.keys() ; e.hasMoreElements() ;) {
-+	    String param = (String)e.nextElement();
-+	    int i = 0;
-+	    for (; i < len ; i++) {
-+		if (params[i].compareTo(param) >= 0) {
-+		    break;
-+		}
-+	    }
-+	    System.arraycopy(params, i, params, i + 1, len - i);
-+	    params[i] = param;
-+	    len++;
-+	}
-+
-+	for (int i = 0 ; i < len ; i++) {
-+	    String param = params[i];
-+	    if (systemParam.get(param) == null) {
-+		out.println("<param name=" + param +
-+			    " value=\"" + atts.get(param) + "\">");
-+	    }
-+	}
-+	out.println("</applet>");
-+    }
-+
-+    /**
-+     * Make sure the attributes are up-to-date.
-+     */
-+    public void updateAtts(int width, int height) {
-+	panel.atts.remove("width");
-+	panel.atts.remove("height");
-+	panel.atts.put("width", new Integer(width).toString());
-+	panel.atts.put("height", new Integer(height).toString());
-+    }
-+
-+    /**
-+     * 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 {
-+            panel.joinAppletThread();
-+	    panel.release();
-+        } catch (InterruptedException e) {
-+            return;   // abort the reload
-+        }
-+
-+        panel.createAppletThread();
-+	panel.sendEvent(AppletPanel.APPLET_LOAD);
-+	panel.sendEvent(AppletPanel.APPLET_INIT);
-+	panel.sendEvent(AppletPanel.APPLET_START);
-+    }
-+
-+    public int print(Graphics graphics, PageFormat pf, int pageIndex) {
-+        return Printable.NO_SUCH_PAGE;
-+    }
-+
-+    /**
-+     * 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(AppletPanel 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 AppletPanel p = panel;
-+
-+	new Thread(new Runnable()
-+	{
-+	    public void run()
-+	    {
-+    		appletShutdown(p);
-+		appletPanels.removeElement(p);
-+		dispose();
-+
-+		if (countApplets() == 0) {
-+		    appletSystemExit();
-+		}
-+	    }
-+	}).start();
-+    }
-+
-+    /**
-+     * Exit the program.
-+     * Exit from the program (if not stand alone) - do no clean-up
-+     */
-+    private void appletSystemExit() {
-+	if (factory.isStandalone())
-+	    System.exit(0);
-+    }
-+
-+    /**
-+     * How many applets are running?
-+     */
-+
-+    public static int countApplets() {
-+	return appletPanels.size();
-+    }
-+
-+
-+    /**
-+     * The current character.
-+     */
-+    static int c;
-+
-+    /**
-+     * Scan spaces.
-+     */
-+    public static void skipSpace(Reader in) throws IOException {
-+        while ((c >= 0) &&
-+	       ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))) {
-+	    c = in.read();
-+	}
-+    }
-+
-+    /**
-+     * Scan identifier
-+     */
-+    public static String scanIdentifier(Reader in) throws IOException {
-+	StringBuffer buf = new StringBuffer();
-+	while (true) {
-+	    if (((c >= 'a') && (c <= 'z')) ||
-+		((c >= 'A') && (c <= 'Z')) ||
-+		((c >= '0') && (c <= '9')) || (c == '_')) {
-+		buf.append((char)c);
-+		c = in.read();
-+	    } else {
-+		return buf.toString();
-+	    }
-+	}
-+    }
-+
-+    /**
-+     * Scan tag
-+     */
-+    public static Hashtable scanTag(Reader in) throws IOException {
-+	Hashtable atts = new Hashtable();
-+	skipSpace(in);
-+        while (c >= 0 && c != '>') {
-+	    String att = scanIdentifier(in);
-+	    String val = "";
-+	    skipSpace(in);
-+	    if (c == '=') {
-+		int quote = -1;
-+		c = in.read();
-+		skipSpace(in);
-+		if ((c == '\'') || (c == '\"')) {
-+		    quote = c;
-+		    c = in.read();
-+		}
-+		StringBuffer buf = new StringBuffer();
-+                while ((c > 0) &&
-+		       (((quote < 0) && (c != ' ') && (c != '\t') &&
-+                         (c != '\n') && (c != '\r') && (c != '>'))
-+			|| ((quote >= 0) && (c != quote)))) {
-+		    buf.append((char)c);
-+		    c = in.read();
-+		}
-+		if (c == quote) {
-+		    c = in.read();
-+		}
-+		skipSpace(in);
-+		val = buf.toString();
-+	    }
-+	    //statusMsgStream.println("PUT " + att + " = '" + val + "'");
-+	    if (! val.equals("")) {
-+		atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val);
-+	    }
-+            while (true) {
-+                if ((c == '>') || (c < 0) ||
-+                    ((c >= 'a') && (c <= 'z')) ||
-+                    ((c >= 'A') && (c <= 'Z')) ||
-+                    ((c >= '0') && (c <= '9')) || (c == '_'))
-+                    break;
-+                c = in.read();
-+            }
-+            //skipSpace(in);
-+	}
-+	return atts;
-+    }
-+
-+    /* values used for placement of AppletViewer's frames */
-+    private static int x = 0;
-+    private static int y = 0;
-+    private static final int XDELTA = 30;
-+    private static final int YDELTA = XDELTA;
-+
-+    static String encoding = null;
-+
-+    static private Reader makeReader(InputStream is) {
-+	if (encoding != null) {
-+	    try {
-+		return new BufferedReader(new InputStreamReader(is, encoding));
-+	    } catch (IOException x) { }
-+	}
-+	InputStreamReader r = new InputStreamReader(is);
-+	encoding = r.getEncoding();
-+	return new BufferedReader(r);
-+    }
-+
-+    /**
-+     * Scan an html file for <applet> tags
-+     */
-+    public static void parse(long handle, Reader in, URL url, String enc)
-+        throws IOException {
-+        encoding = enc;
-+        parse(handle, 1, 1, in, url, System.out, new PluginAppletViewerFactory());
-+    }
-+
-+    public static void parse(long handle, int width, int height, Reader in, URL url)
-+        throws IOException {
-+        parse(handle, width, height,
-+		in, url, System.out, new PluginAppletViewerFactory());
-+    }
-+
-+    public static void parse(long handle, int width, int height, Reader in, 
-+				URL url,
-+	                        PrintStream statusMsgStream,
-+        	                PluginAppletViewerFactory factory)
-+        throws IOException
-+    {
-+        // <OBJECT> <EMBED> tag flags
-+        boolean isAppletTag = false;
-+        boolean isObjectTag = false;
-+        boolean isEmbedTag = false;
-+
-+	// warning messages
-+        String requiresNameWarning = amh.getMessage("parse.warning.requiresname");
-+        String paramOutsideWarning = amh.getMessage("parse.warning.paramoutside");
-+        String appletRequiresCodeWarning = amh.getMessage("parse.warning.applet.requirescode");
-+        String appletRequiresHeightWarning = amh.getMessage("parse.warning.applet.requiresheight");
-+        String appletRequiresWidthWarning = amh.getMessage("parse.warning.applet.requireswidth");
-+        String objectRequiresCodeWarning = amh.getMessage("parse.warning.object.requirescode");
-+        String objectRequiresHeightWarning = amh.getMessage("parse.warning.object.requiresheight");
-+        String objectRequiresWidthWarning = amh.getMessage("parse.warning.object.requireswidth");
-+        String embedRequiresCodeWarning = amh.getMessage("parse.warning.embed.requirescode");
-+        String embedRequiresHeightWarning = amh.getMessage("parse.warning.embed.requiresheight");
-+        String embedRequiresWidthWarning = amh.getMessage("parse.warning.embed.requireswidth");
-+        String appNotLongerSupportedWarning = amh.getMessage("parse.warning.appnotLongersupported");
-+
-+	java.net.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();
-+
-+	int ydisp = 1;
-+	Hashtable atts = null;
-+
-+        while(true) {
-+	    c = in.read();
-+	    if (c == -1)
-+		break;
-+
-+	    if (c == '<') {
-+		c = in.read();
-+		if (c == '/') {
-+		    c = in.read();
-+		    String nm = scanIdentifier(in);
-+		    if (nm.equalsIgnoreCase("applet") ||
-+                        nm.equalsIgnoreCase("object") ||
-+                        nm.equalsIgnoreCase("embed")) {
-+
-+                        // We can't test for a code tag until </OBJECT>
-+                        // because it is a parameter, not an attribute.
-+                        if(isObjectTag) {
-+                            if (atts.get("code") == null && atts.get("object") == null) {
-+                                statusMsgStream.println(objectRequiresCodeWarning);
-+                                atts = null;
-+                            }
-+                        }
-+
-+			if (atts != null) {
-+			    atts.remove("width");
-+			    atts.remove("height");
-+			    atts.put("width", new Integer(width).toString());
-+			    atts.put("height", new Integer(height).toString());
-+
-+			    // XXX 5/18 In general this code just simply
-+			    // shouldn't be part of parsing.  It's presence
-+			    // causes things to be a little too much of a
-+			    // hack.
-+                            factory.createAppletViewer(handle, x, y, url, atts);
-+			    x += XDELTA;
-+			    y += YDELTA;
-+			    // make sure we don't go too far!
-+			    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
-+			    if ((x > d.width - 300) || (y > d.height - 300)) {
-+				x = 0;
-+				y = 2 * ydisp * YDELTA;
-+				ydisp++;
-+			    }
-+			}
-+			atts = null;
-+                        isAppletTag = false;
-+                        isObjectTag = false;
-+                        isEmbedTag = false;
-+		    }
-+		}
-+		else {
-+		    String nm = scanIdentifier(in);
-+		    if (nm.equalsIgnoreCase("param")) {
-+			Hashtable t = scanTag(in);
-+			String att = (String)t.get("name");
-+			if (att == null) {
-+			    statusMsgStream.println(requiresNameWarning);
-+			} else {
-+			    String val = (String)t.get("value");
-+			    if (val == null) {
-+				statusMsgStream.println(requiresNameWarning);
-+			    } else if (atts != null) {
-+				String name = att.toLowerCase();
-+				atts.put(name, val);
-+			    } else {
-+				statusMsgStream.println(paramOutsideWarning);
-+			    }
-+			}
-+		    }
-+		    else if (nm.equalsIgnoreCase("applet")) {
-+                        isAppletTag = true;
-+			atts = scanTag(in);
-+			if (atts.get("code") == null && atts.get("object") == null) {
-+			    statusMsgStream.println(appletRequiresCodeWarning);
-+			    atts = null;
-+			} else if (atts.get("width") == null) {
-+			    statusMsgStream.println(appletRequiresWidthWarning);
-+			    atts = null;
-+			} else if (atts.get("height") == null) {
-+			    statusMsgStream.println(appletRequiresHeightWarning);
-+			    atts = null;
-+			}
-+		    }
-+		    else if (nm.equalsIgnoreCase("object")) {
-+                        isObjectTag = true;
-+			atts = scanTag(in);
-+                        // The <OBJECT> attribute codebase isn't what
-+                        // we want. If its defined, remove it.
-+                        if(atts.get("codebase") != null) {
-+                            atts.remove("codebase");
-+                        }
-+
-+                        if (atts.get("width") == null) {
-+			    statusMsgStream.println(objectRequiresWidthWarning);
-+			    atts = null;
-+			} else if (atts.get("height") == null) {
-+			    statusMsgStream.println(objectRequiresHeightWarning);
-+			    atts = null;
-+			}
-+		    }
-+		    else if (nm.equalsIgnoreCase("embed")) {
-+                        isEmbedTag = true;
-+			atts = scanTag(in);
-+
-+			if (atts.get("code") == null && atts.get("object") == null) {
-+			    statusMsgStream.println(embedRequiresCodeWarning);
-+			    atts = null;
-+			} else if (atts.get("width") == null) {
-+			    statusMsgStream.println(embedRequiresWidthWarning);
-+			    atts = null;
-+			} else if (atts.get("height") == null) {
-+			    statusMsgStream.println(embedRequiresHeightWarning);
-+			    atts = null;
-+			}
-+		    }
-+		    else if (nm.equalsIgnoreCase("app")) {
-+			statusMsgStream.println(appNotLongerSupportedWarning);
-+			Hashtable atts2 = scanTag(in);
-+			nm = (String)atts2.get("class");
-+			if (nm != null) {
-+			    atts2.remove("class");
-+			    atts2.put("code", nm + ".class");
-+			}
-+			nm = (String)atts2.get("src");
-+			if (nm != null) {
-+			    atts2.remove("src");
-+			    atts2.put("codebase", nm);
-+			}
-+			if (atts2.get("width") == null) {
-+			    atts2.put("width", "100");
-+			}
-+			if (atts2.get("height") == null) {
-+			    atts2.put("height", "100");
-+			}
-+			printTag(statusMsgStream, atts2);
-+			statusMsgStream.println();
-+		    }
-+		}
-+	    }
-+	}
-+	in.close();
-+    }
-+
-+    /**
-+     * Old main entry point.
-+     *
-+     * @deprecated
-+     */
-+    @Deprecated
-+    public static void main(String args[]) throws IOException {
-+        PluginMain.main(args);
-+    }
-+
-+    private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer");
-+
-+    private static void checkConnect(URL url)
-+    {
-+	SecurityManager security = System.getSecurityManager();
-+	if (security != null) {
-+	    try {
-+		java.security.Permission perm =
-+		    url.openConnection().getPermission();
-+		if (perm != null)
-+		    security.checkPermission(perm);
-+		else
-+		    security.checkConnect(url.getHost(), url.getPort());
-+	    } catch (java.io.IOException ioe) {
-+		    security.checkConnect(url.getHost(), url.getPort());
-+	    }
-+	}
-+    }
-+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/gcj/java/src/main/sun/applet/PluginAppletViewer.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,1008 @@
+/*
+ * 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.util.*;
+import java.io.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.print.*;
+import javax.print.attribute.*;
+import java.applet.*;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.net.SocketPermission;
+import sun.misc.Ref;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import sun.awt.SunToolkit;
+import sun.awt.AppContext;
+import sun.awt.X11.*;
+import java.lang.ref.WeakReference;
+import net.sourceforge.jnlp.NetxPanel;
+
+/**
+ * Lets us construct one using unix-style one shot behaviors
+ */
+
+class PluginAppletViewerFactory
+{
+    public PluginAppletViewer createAppletViewer(long handle, int x, int y,
+						 URL doc, Hashtable atts) {
+        PluginAppletViewer pluginappletviewer = new PluginAppletViewer(handle, x, y, doc, atts, System.out, this);
+        PluginMain.registerWindow(pluginappletviewer);
+        return pluginappletviewer;
+    }
+
+    public boolean isStandalone()
+    {
+        return false;
+    }
+}
+
+/*
+ */
+public class PluginAppletViewer extends XEmbeddedFrame
+    implements AppletContext, Printable {
+    /**
+     * Some constants...
+     */
+    private static String defaultSaveFile = "Applet.ser";
+
+    /**
+     * The panel in which the applet is being displayed.
+     */
+    AppletViewerPanel panel;
+
+    /**
+     * The status line.
+     */
+    Label label;
+
+    /**
+     * output status messages to this stream
+     */
+
+    PrintStream statusMsgStream;
+
+    /**
+     * For cloning
+     */
+    PluginAppletViewerFactory factory;
+
+    /**
+     * Create the applet viewer
+     */
+    public PluginAppletViewer(long handle, int x, int y, final URL doc,
+                              final Hashtable atts, PrintStream statusMsgStream,
+                              PluginAppletViewerFactory factory) {
+        super(handle, true);
+    	this.factory = factory;
+	this.statusMsgStream = statusMsgStream;
+
+	try {
+		panel = new NetxPanel(doc, atts);
+		AppletViewerPanel.debug("Using NetX panel");
+	} catch (Exception ex) {
+		AppletViewerPanel.debug("Unable to start NetX applet - defaulting to Sun applet", ex);
+		panel = new AppletViewerPanel(doc, atts);
+	}
+	add("Center", panel);
+	panel.init();
+	appletPanels.addElement(panel);
+
+	pack();
+	setVisible(true);
+
+	WindowListener windowEventListener = new WindowAdapter() {
+
+	    public void windowClosing(WindowEvent evt) {
+		appletClose();
+	    }
+
+	    public void windowIconified(WindowEvent evt) {
+		appletStop();
+	    }
+
+	    public void windowDeiconified(WindowEvent evt) {
+		appletStart();
+	    }
+	};
+
+	class AppletEventListener implements AppletListener  
+	{
+	    final Frame frame;
+
+	    public AppletEventListener(Frame frame)
+	    {
+		this.frame = frame;
+	    }
+
+	    public void appletStateChanged(AppletEvent evt) 
+	    {
+		AppletPanel src = (AppletPanel)evt.getSource();
+
+		switch (evt.getID()) {
+                    case AppletPanel.APPLET_RESIZE: {
+			if(src != null) {
+			    resize(preferredSize());
+			    validate();
+                        }
+			break;
+		    }
+		    case AppletPanel.APPLET_LOADING_COMPLETED: {
+			Applet 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)
+			    AppletPanel.changeFrameAppContext(frame, SunToolkit.targetToAppContext(a));
+			else
+			    AppletPanel.changeFrameAppContext(frame, AppContext.getAppContext());
+
+			break;
+		    }
+		}
+	    }
+	};
+
+	ComponentListener componentListener = new ComponentAdapter() {
+		public void componentResized(ComponentEvent event)
+  		{
+		    if (panel != null)
+		      {
+		        ComponentListener[] l = panel.getComponentListeners();
+		        for (int i = 0; i < l.length; i++)
+		          l[i].componentResized(event);
+			panel.validate();
+		      }
+		  }
+
+		public void componentMoved(ComponentEvent event)
+		  {
+		    if (panel != null)
+		      {
+		        ComponentListener[] l = panel.getComponentListeners();
+		        for (int i = 0; i < l.length; i++)
+		          l[i].componentMoved(event);
+			panel.validate();
+		      }
+		  }
+        };
+
+	HierarchyBoundsListener hierarchyBoundsListener = new HierarchyBoundsAdapter() {
+		public void ancestorMoved(HierarchyEvent e)
+		  {
+		     if (panel != null)
+                      {
+		        HierarchyBoundsListener[] l = panel.getHierarchyBoundsListeners();
+		        for (int i = 0; i < l.length; i++)
+		          l[i].ancestorMoved(e);
+			panel.validate();
+		      }
+		  }
+
+		public void ancestorResized(HierarchyEvent e)
+		  {
+		    if (panel != null)
+		      {
+		        HierarchyBoundsListener[] l = panel.getHierarchyBoundsListeners();
+		        for (int i = 0; i < l.length; i++)
+		          l[i].ancestorResized(e);
+			panel.validate();
+		      }
+		  }
+	};
+
+	addWindowListener(windowEventListener);
+        addComponentListener(componentListener);
+        addHierarchyBoundsListener(hierarchyBoundsListener);
+	panel.addAppletListener(new AppletEventListener(this));
+
+	// Start the applet
+        showStatus(amh.getMessage("status.start"));
+	initEventQueue();
+    }
+
+    /**
+     * 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() {
+	// appletviewer.send.event is an undocumented and unsupported system
+	// property which is used exclusively for testing purposes.
+	String eventList = System.getProperty("appletviewer.send.event");
+
+	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 = splitSeparator(",", eventList);
+
+ 	    for (int i = 0; i < events.length; i++) {
+ 		System.out.println("Adding event to queue: " + events[i]);
+ 		if (events[i].equals("dispose"))
+ 		    panel.sendEvent(AppletPanel.APPLET_DISPOSE);
+ 		else if (events[i].equals("load"))
+ 		    panel.sendEvent(AppletPanel.APPLET_LOAD);
+ 		else if (events[i].equals("init"))
+ 		    panel.sendEvent(AppletPanel.APPLET_INIT);
+ 		else if (events[i].equals("start"))
+ 		    panel.sendEvent(AppletPanel.APPLET_START);
+ 		else if (events[i].equals("stop"))
+ 		    panel.sendEvent(AppletPanel.APPLET_STOP);
+ 		else if (events[i].equals("destroy"))
+ 		    panel.sendEvent(AppletPanel.APPLET_DESTROY);
+ 		else if (events[i].equals("quit"))
+ 		    panel.sendEvent(AppletPanel.APPLET_QUIT);
+ 		else if (events[i].equals("error"))
+ 		    panel.sendEvent(AppletPanel.APPLET_ERROR);
+ 		else
+		    // non-fatal error if we get an unrecognized event
+ 		    System.out.println("Unrecognized event name: " + events[i]);
+ 	    }
+
+  	    while (!panel.emptyEventQueue()) ;
+ 	    appletSystemExit();
+	}
+    }
+
+    /**
+     * Split a string based on the presence of a specified separator.  Returns
+     * an array of arbitrary length.  The end of each element in the array is
+     * indicated by the separator of the end of the string.  If there is a
+     * separator immediately before the end of the string, the final element
+     * will be empty.  None of the strings will contain the separator.  Useful
+     * when separating strings such as "foo/bar/bas" using separator "/".
+     *
+     * @param sep  The separator.
+     * @param s    The string to split.
+     * @return     An array of strings.  Each string in the array is determined
+     *             by the location of the provided sep in the original string,
+     *             s.  Whitespace not stripped.
+     */
+    private String [] splitSeparator(String sep, String s) {
+ 	Vector v = new Vector();
+	int tokenStart = 0;
+	int tokenEnd   = 0;
+
+	while ((tokenEnd = s.indexOf(sep, tokenStart)) != -1) {
+	    v.addElement(s.substring(tokenStart, tokenEnd));
+	    tokenStart = tokenEnd+1;
+	}
+	// Add the final element.
+	v.addElement(s.substring(tokenStart));
+
+	String [] retVal = new String[v.size()];
+	v.copyInto(retVal);
+ 	return retVal;
+    }
+
+    /*
+     * Methods for java.applet.AppletContext
+     */
+
+    private static Map audioClips = new HashMap();
+
+    /**
+     * Get an audio clip.
+     */
+    public AudioClip getAudioClip(URL url) {
+	checkConnect(url);
+	synchronized (audioClips) {
+	    AudioClip clip = (AudioClip)audioClips.get(url);
+	    if (clip == null) {
+		audioClips.put(url, clip = new AppletAudioClip(url));
+	    }
+	    return clip;
+	}
+    }
+
+    private static Map imageRefs = new HashMap();
+
+    /**
+     * Get an image.
+     */
+    public Image getImage(URL url) {
+	return getCachedImage(url);
+    }
+
+    static Image getCachedImage(URL url) {
+	// System.getSecurityManager().checkConnection(url.getHost(), url.getPort());
+	return (Image)getCachedImageRef(url).get();
+    }
+
+    /**
+     * Get an image ref.
+     */
+    static Ref getCachedImageRef(URL url) {
+	synchronized (imageRefs) {
+	    AppletImageRef ref = (AppletImageRef)imageRefs.get(url);
+	    if (ref == null) {
+		ref = new AppletImageRef(url);
+		imageRefs.put(url, ref);
+	    }
+	    return ref;
+	}
+    }
+
+    /**
+     * Flush the image cache.
+     */
+    static void flushImageCache() {
+	imageRefs.clear();
+    }
+
+    static Vector appletPanels = new Vector();
+
+    /**
+     * Get an applet by name.
+     */
+    public Applet getApplet(String name) {
+	AppletSecurity security = (AppletSecurity)System.getSecurityManager();
+	name = name.toLowerCase();
+	SocketPermission panelSp =
+	    new SocketPermission(panel.getCodeBase().getHost(), "connect");
+	for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
+	    AppletPanel p = (AppletPanel)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.applet;
+		}
+	    }
+	}
+	return null;
+    }
+
+    /**
+     * Return an enumeration of all the accessible
+     * applets on this page.
+     */
+    public Enumeration getApplets() {
+	AppletSecurity security = (AppletSecurity)System.getSecurityManager();
+	Vector v = new Vector();
+	SocketPermission panelSp =
+	    new SocketPermission(panel.getCodeBase().getHost(), "connect");
+
+	for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
+	    AppletPanel p = (AppletPanel)e.nextElement();
+	    if (p.getDocumentBase().equals(panel.getDocumentBase())) {
+
+		SocketPermission sp =
+		    new SocketPermission(p.getCodeBase().getHost(), "connect");
+		if (panelSp.implies(sp)) {
+		    v.addElement(p.applet);
+		}
+	    }
+	}
+	return v.elements();
+    }
+
+    /**
+     * Ignore.
+     */
+    public void showDocument(URL url) {
+	showDocument(url, "_self");
+    }
+
+    /**
+     * Ignore.
+     */
+    public void showDocument(URL url, String target) {
+	try {
+	    PluginMain.write("url " + url + " " + target);
+	} catch (IOException exception) {
+	    // Deliberately ignore IOException.  showDocument may be
+	    // called from threads other than the main thread after
+	    // PluginMain.pluginOutputStream has been closed.
+	}
+    }
+
+    /**
+     * Show status.
+     */
+    public void showStatus(String status) {
+	try {
+	    PluginMain.write("status " + status);
+	} catch (IOException exception) {
+	    // Deliberately ignore IOException.  showStatus may be
+	    // called from threads other than the main thread after
+	    // PluginMain.pluginOutputStream has been closed.
+	}
+    }
+
+    public void setStream(String key, InputStream stream)throws IOException{
+	// We do nothing.
+    }
+
+    public InputStream getStream(String key){
+	// We do nothing.
+	return null;
+    }
+
+    public Iterator getStreamKeys(){
+	// We do nothing.
+	return null;
+    }
+
+    /**
+     * System parameters.
+     */
+    static Hashtable systemParam = new Hashtable();
+
+    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");
+    }
+
+    /**
+     * Print the HTML tag.
+     */
+    public static void printTag(PrintStream out, Hashtable atts) {
+	out.print("<applet");
+
+	String v = (String)atts.get("codebase");
+	if (v != null) {
+	    out.print(" codebase=\"" + v + "\"");
+	}
+
+	v = (String)atts.get("code");
+	if (v == null) {
+	    v = "applet.class";
+	}
+	out.print(" code=\"" + v + "\"");
+	v = (String)atts.get("width");
+	if (v == null) {
+	    v = "150";
+	}
+	out.print(" width=" + v);
+
+	v = (String)atts.get("height");
+	if (v == null) {
+	    v = "100";
+	}
+	out.print(" height=" + v);
+
+	v = (String)atts.get("name");
+	if (v != null) {
+	    out.print(" name=\"" + v + "\"");
+	}
+	out.println(">");
+
+	// A very slow sorting algorithm
+	int len = atts.size();
+	String params[] = new String[len];
+	len = 0;
+	for (Enumeration e = atts.keys() ; e.hasMoreElements() ;) {
+	    String param = (String)e.nextElement();
+	    int i = 0;
+	    for (; i < len ; i++) {
+		if (params[i].compareTo(param) >= 0) {
+		    break;
+		}
+	    }
+	    System.arraycopy(params, i, params, i + 1, len - i);
+	    params[i] = param;
+	    len++;
+	}
+
+	for (int i = 0 ; i < len ; i++) {
+	    String param = params[i];
+	    if (systemParam.get(param) == null) {
+		out.println("<param name=" + param +
+			    " value=\"" + atts.get(param) + "\">");
+	    }
+	}
+	out.println("</applet>");
+    }
+
+    /**
+     * Make sure the attributes are up-to-date.
+     */
+    public void updateAtts(int width, int height) {
+	panel.atts.remove("width");
+	panel.atts.remove("height");
+	panel.atts.put("width", new Integer(width).toString());
+	panel.atts.put("height", new Integer(height).toString());
+    }
+
+    /**
+     * 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 {
+            panel.joinAppletThread();
+	    panel.release();
+        } catch (InterruptedException e) {
+            return;   // abort the reload
+        }
+
+        panel.createAppletThread();
+	panel.sendEvent(AppletPanel.APPLET_LOAD);
+	panel.sendEvent(AppletPanel.APPLET_INIT);
+	panel.sendEvent(AppletPanel.APPLET_START);
+    }
+
+    public int print(Graphics graphics, PageFormat pf, int pageIndex) {
+        return Printable.NO_SUCH_PAGE;
+    }
+
+    /**
+     * 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(AppletPanel 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 AppletPanel p = panel;
+
+	new Thread(new Runnable()
+	{
+	    public void run()
+	    {
+    		appletShutdown(p);
+		appletPanels.removeElement(p);
+		dispose();
+
+		if (countApplets() == 0) {
+		    appletSystemExit();
+		}
+	    }
+	}).start();
+    }
+
+    /**
+     * Exit the program.
+     * Exit from the program (if not stand alone) - do no clean-up
+     */
+    private void appletSystemExit() {
+	if (factory.isStandalone())
+	    System.exit(0);
+    }
+
+    /**
+     * How many applets are running?
+     */
+
+    public static int countApplets() {
+	return appletPanels.size();
+    }
+
+
+    /**
+     * The current character.
+     */
+    static int c;
+
+    /**
+     * Scan spaces.
+     */
+    public static void skipSpace(Reader in) throws IOException {
+        while ((c >= 0) &&
+	       ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))) {
+	    c = in.read();
+	}
+    }
+
+    /**
+     * Scan identifier
+     */
+    public static String scanIdentifier(Reader in) throws IOException {
+	StringBuffer buf = new StringBuffer();
+	while (true) {
+	    if (((c >= 'a') && (c <= 'z')) ||
+		((c >= 'A') && (c <= 'Z')) ||
+		((c >= '0') && (c <= '9')) || (c == '_')) {
+		buf.append((char)c);
+		c = in.read();
+	    } else {
+		return buf.toString();
+	    }
+	}
+    }
+
+    /**
+     * Scan tag
+     */
+    public static Hashtable scanTag(Reader in) throws IOException {
+	Hashtable atts = new Hashtable();
+	skipSpace(in);
+        while (c >= 0 && c != '>') {
+	    String att = scanIdentifier(in);
+	    String val = "";
+	    skipSpace(in);
+	    if (c == '=') {
+		int quote = -1;
+		c = in.read();
+		skipSpace(in);
+		if ((c == '\'') || (c == '\"')) {
+		    quote = c;
+		    c = in.read();
+		}
+		StringBuffer buf = new StringBuffer();
+                while ((c > 0) &&
+		       (((quote < 0) && (c != ' ') && (c != '\t') &&
+                         (c != '\n') && (c != '\r') && (c != '>'))
+			|| ((quote >= 0) && (c != quote)))) {
+		    buf.append((char)c);
+		    c = in.read();
+		}
+		if (c == quote) {
+		    c = in.read();
+		}
+		skipSpace(in);
+		val = buf.toString();
+	    }
+	    //statusMsgStream.println("PUT " + att + " = '" + val + "'");
+	    if (! val.equals("")) {
+		atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val);
+	    }
+            while (true) {
+                if ((c == '>') || (c < 0) ||
+                    ((c >= 'a') && (c <= 'z')) ||
+                    ((c >= 'A') && (c <= 'Z')) ||
+                    ((c >= '0') && (c <= '9')) || (c == '_'))
+                    break;
+                c = in.read();
+            }
+            //skipSpace(in);
+	}
+	return atts;
+    }
+
+    /* values used for placement of AppletViewer's frames */
+    private static int x = 0;
+    private static int y = 0;
+    private static final int XDELTA = 30;
+    private static final int YDELTA = XDELTA;
+
+    static String encoding = null;
+
+    static private Reader makeReader(InputStream is) {
+	if (encoding != null) {
+	    try {
+		return new BufferedReader(new InputStreamReader(is, encoding));
+	    } catch (IOException x) { }
+	}
+	InputStreamReader r = new InputStreamReader(is);
+	encoding = r.getEncoding();
+	return new BufferedReader(r);
+    }
+
+    /**
+     * Scan an html file for <applet> tags
+     */
+    public static void parse(long handle, Reader in, URL url, String enc)
+        throws IOException {
+        encoding = enc;
+        parse(handle, 1, 1, in, url, System.out, new PluginAppletViewerFactory());
+    }
+
+    public static void parse(long handle, int width, int height, Reader in, URL url)
+        throws IOException {
+        parse(handle, width, height,
+		in, url, System.out, new PluginAppletViewerFactory());
+    }
+
+    public static void parse(long handle, int width, int height, Reader in, 
+				URL url,
+	                        PrintStream statusMsgStream,
+        	                PluginAppletViewerFactory factory)
+        throws IOException
+    {
+        // <OBJECT> <EMBED> tag flags
+        boolean isAppletTag = false;
+        boolean isObjectTag = false;
+        boolean isEmbedTag = false;
+
+	// warning messages
+        String requiresNameWarning = amh.getMessage("parse.warning.requiresname");
+        String paramOutsideWarning = amh.getMessage("parse.warning.paramoutside");
+        String appletRequiresCodeWarning = amh.getMessage("parse.warning.applet.requirescode");
+        String appletRequiresHeightWarning = amh.getMessage("parse.warning.applet.requiresheight");
+        String appletRequiresWidthWarning = amh.getMessage("parse.warning.applet.requireswidth");
+        String objectRequiresCodeWarning = amh.getMessage("parse.warning.object.requirescode");
+        String objectRequiresHeightWarning = amh.getMessage("parse.warning.object.requiresheight");
+        String objectRequiresWidthWarning = amh.getMessage("parse.warning.object.requireswidth");
+        String embedRequiresCodeWarning = amh.getMessage("parse.warning.embed.requirescode");
+        String embedRequiresHeightWarning = amh.getMessage("parse.warning.embed.requiresheight");
+        String embedRequiresWidthWarning = amh.getMessage("parse.warning.embed.requireswidth");
+        String appNotLongerSupportedWarning = amh.getMessage("parse.warning.appnotLongersupported");
+
+	java.net.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();
+
+	int ydisp = 1;
+	Hashtable atts = null;
+
+        while(true) {
+	    c = in.read();
+	    if (c == -1)
+		break;
+
+	    if (c == '<') {
+		c = in.read();
+		if (c == '/') {
+		    c = in.read();
+		    String nm = scanIdentifier(in);
+		    if (nm.equalsIgnoreCase("applet") ||
+                        nm.equalsIgnoreCase("object") ||
+                        nm.equalsIgnoreCase("embed")) {
+
+                        // We can't test for a code tag until </OBJECT>
+                        // because it is a parameter, not an attribute.
+                        if(isObjectTag) {
+                            if (atts.get("code") == null && atts.get("object") == null) {
+                                statusMsgStream.println(objectRequiresCodeWarning);
+                                atts = null;
+                            }
+                        }
+
+			if (atts != null) {
+			    atts.remove("width");
+			    atts.remove("height");
+			    atts.put("width", new Integer(width).toString());
+			    atts.put("height", new Integer(height).toString());
+
+			    // XXX 5/18 In general this code just simply
+			    // shouldn't be part of parsing.  It's presence
+			    // causes things to be a little too much of a
+			    // hack.
+                            factory.createAppletViewer(handle, x, y, url, atts);
+			    x += XDELTA;
+			    y += YDELTA;
+			    // make sure we don't go too far!
+			    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+			    if ((x > d.width - 300) || (y > d.height - 300)) {
+				x = 0;
+				y = 2 * ydisp * YDELTA;
+				ydisp++;
+			    }
+			}
+			atts = null;
+                        isAppletTag = false;
+                        isObjectTag = false;
+                        isEmbedTag = false;
+		    }
+		}
+		else {
+		    String nm = scanIdentifier(in);
+		    if (nm.equalsIgnoreCase("param")) {
+			Hashtable t = scanTag(in);
+			String att = (String)t.get("name");
+			if (att == null) {
+			    statusMsgStream.println(requiresNameWarning);
+			} else {
+			    String val = (String)t.get("value");
+			    if (val == null) {
+				statusMsgStream.println(requiresNameWarning);
+			    } else if (atts != null) {
+				String name = att.toLowerCase();
+				atts.put(name, val);
+			    } else {
+				statusMsgStream.println(paramOutsideWarning);
+			    }
+			}
+		    }
+		    else if (nm.equalsIgnoreCase("applet")) {
+                        isAppletTag = true;
+			atts = scanTag(in);
+			if (atts.get("code") == null && atts.get("object") == null) {
+			    statusMsgStream.println(appletRequiresCodeWarning);
+			    atts = null;
+			} else if (atts.get("width") == null) {
+			    statusMsgStream.println(appletRequiresWidthWarning);
+			    atts = null;
+			} else if (atts.get("height") == null) {
+			    statusMsgStream.println(appletRequiresHeightWarning);
+			    atts = null;
+			}
+		    }
+		    else if (nm.equalsIgnoreCase("object")) {
+                        isObjectTag = true;
+			atts = scanTag(in);
+                        // The <OBJECT> attribute codebase isn't what
+                        // we want. If its defined, remove it.
+                        if(atts.get("codebase") != null) {
+                            atts.remove("codebase");
+                        }
+
+                        if (atts.get("width") == null) {
+			    statusMsgStream.println(objectRequiresWidthWarning);
+			    atts = null;
+			} else if (atts.get("height") == null) {
+			    statusMsgStream.println(objectRequiresHeightWarning);
+			    atts = null;
+			}
+		    }
+		    else if (nm.equalsIgnoreCase("embed")) {
+                        isEmbedTag = true;
+			atts = scanTag(in);
+
+			if (atts.get("code") == null && atts.get("object") == null) {
+			    statusMsgStream.println(embedRequiresCodeWarning);
+			    atts = null;
+			} else if (atts.get("width") == null) {
+			    statusMsgStream.println(embedRequiresWidthWarning);
+			    atts = null;
+			} else if (atts.get("height") == null) {
+			    statusMsgStream.println(embedRequiresHeightWarning);
+			    atts = null;
+			}
+		    }
+		    else if (nm.equalsIgnoreCase("app")) {
+			statusMsgStream.println(appNotLongerSupportedWarning);
+			Hashtable atts2 = scanTag(in);
+			nm = (String)atts2.get("class");
+			if (nm != null) {
+			    atts2.remove("class");
+			    atts2.put("code", nm + ".class");
+			}
+			nm = (String)atts2.get("src");
+			if (nm != null) {
+			    atts2.remove("src");
+			    atts2.put("codebase", nm);
+			}
+			if (atts2.get("width") == null) {
+			    atts2.put("width", "100");
+			}
+			if (atts2.get("height") == null) {
+			    atts2.put("height", "100");
+			}
+			printTag(statusMsgStream, atts2);
+			statusMsgStream.println();
+		    }
+		}
+	    }
+	}
+	in.close();
+    }
+
+    /**
+     * Old main entry point.
+     *
+     * @deprecated
+     */
+    @Deprecated
+    public static void main(String args[]) throws IOException {
+        PluginMain.main(args);
+    }
+
+    private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer");
+
+    private static void checkConnect(URL url)
+    {
+	SecurityManager security = System.getSecurityManager();
+	if (security != null) {
+	    try {
+		java.security.Permission perm =
+		    url.openConnection().getPermission();
+		if (perm != null)
+		    security.checkPermission(perm);
+		else
+		    security.checkConnect(url.getHost(), url.getPort());
+	    } catch (java.io.IOException ioe) {
+		    security.checkConnect(url.getHost(), url.getPort());
+	    }
+	}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/gcj/java/src/main/sun/applet/PluginMain.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,274 @@
+/*
+ * Copyright 1999-2006 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.io.*;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.net.*;
+import java.nio.charset.Charset;
+import java.util.*;
+import sun.net.www.ParseUtil;
+
+class PluginParseRequest
+{
+  long handle;
+  String tag;
+  String documentbase;
+  boolean alreadySent;
+}
+
+/**
+ * The main entry point into PluginAppletViewer.
+ */
+public class PluginMain
+{
+    // A mapping of instance IDs to PluginAppletViewers.
+    private static HashMap appletWindows = new HashMap();
+    private static HashMap parseRequests = new HashMap();
+    private static String currentKey;
+    private static PluginAppletViewer currentWindow;
+    private static PluginParseRequest currentRequest;
+    private static BufferedReader pluginInputStream;
+    private static BufferedWriter pluginOutputStream;
+    // This is used in init().	Getting rid of this is desirable but depends
+    // on whether the property that uses it is necessary/standard.
+    public static final String theVersion = System.getProperty("java.version");
+
+    /**
+     * The main entry point into AppletViewer.
+     */
+    public static void main(String args[])
+	throws IOException
+    {
+	if(args.length != 2) {
+	    // Indicate to plugin that appletviewer is installed correctly.
+	    System.exit(0);
+	}
+	// INSTALL THE SECURITY MANAGER
+	init();
+	start(new FileInputStream(args[0]), new FileOutputStream(args[1]));
+	System.exit(0);
+    }
+
+    private static void init() {
+	Properties avProps = new Properties();
+
+	// ADD OTHER RANDOM PROPERTIES
+	// XXX 5/18 need to revisit why these are here, is there some
+	// standard for what is available?
+
+	// Standard browser properties
+	avProps.put("browser", "sun.applet.AppletViewer");
+	avProps.put("browser.version", "1.06");
+	avProps.put("browser.vendor", "Sun Microsystems Inc.");
+	avProps.put("http.agent", "Java(tm) 2 SDK, Standard Edition v" + theVersion);
+
+	// Define which packages can be extended by applets
+	// XXX 5/19 probably not needed, not checked in AppletSecurity
+	avProps.put("package.restrict.definition.java", "true");
+	avProps.put("package.restrict.definition.sun", "true");
+
+	// Define which properties can be read by applets.
+	// A property named by "key" can be read only when its twin
+	// property "key.applet" is true.  The following ten properties
+	// are open by default.	 Any other property can be explicitly
+	// opened up by the browser user by calling appletviewer with
+	// -J-Dkey.applet=true
+	avProps.put("java.version.applet", "true");
+	avProps.put("java.vendor.applet", "true");
+	avProps.put("java.vendor.url.applet", "true");
+	avProps.put("java.class.version.applet", "true");
+	avProps.put("os.name.applet", "true");
+	avProps.put("os.version.applet", "true");
+	avProps.put("os.arch.applet", "true");
+	avProps.put("file.separator.applet", "true");
+	avProps.put("path.separator.applet", "true");
+	avProps.put("line.separator.applet", "true");
+
+	// Read in the System properties.  If something is going to be
+	// over-written, warn about it.
+	Properties sysProps = System.getProperties();
+	for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements(); ) {
+	    String key = (String) e.nextElement();
+	    String val = (String) sysProps.getProperty(key);
+	    avProps.setProperty(key, val);
+	}
+
+	// INSTALL THE PROPERTY LIST
+	System.setProperties(avProps);
+
+	// Create and install the security manager
+	System.setSecurityManager(new AppletSecurity());
+
+	// REMIND: Create and install a socket factory!
+    }
+
+    static void registerWindow(PluginAppletViewer pluginappletviewer)
+    {
+	appletWindows.put(currentKey, pluginappletviewer);
+	currentWindow = (PluginAppletViewer)appletWindows.get(currentKey);
+    }
+
+    private static void deregisterWindow(PluginAppletViewer pluginappletviewer)
+    {
+	appletWindows.remove(currentWindow);
+	currentWindow.dispose();
+	currentWindow = null;
+    }
+
+    static void start(InputStream inputstream, OutputStream outputstream)
+	throws MalformedURLException, IOException
+    {
+	// Set up input and output pipes.  Use UTF-8 encoding.
+	pluginInputStream =
+	    new BufferedReader(new InputStreamReader(inputstream,
+						     Charset.forName("UTF-8")));
+	pluginOutputStream =
+	    new BufferedWriter(new OutputStreamWriter
+			       (outputstream, Charset.forName("UTF-8")));
+
+	write("running");
+
+	// Read first message.
+	String message = read();
+
+	while(true) {
+	    if (message.startsWith("instance")) {
+		// Read applet instance identifier.
+		currentKey = message.substring("instance".length() + 1);
+		currentWindow =
+		    (PluginAppletViewer)appletWindows.get(currentKey);
+		currentRequest = null;
+		if (currentWindow == null) {
+		    if (!parseRequests.containsKey(currentKey))
+			parseRequests.put(currentKey, new PluginParseRequest());
+		    currentRequest =
+			(PluginParseRequest)parseRequests.get(currentKey);
+		}
+	    } else if (message.startsWith("tag")) {
+		if (currentRequest != null) {
+		    int index = message.indexOf(' ', "tag".length() + 1);
+		    currentRequest.documentbase =
+			message.substring("tag".length() + 1, index);
+		    currentRequest.tag = message.substring(index + 1);
+		    if (currentRequest.handle != 0
+			&& !currentRequest.alreadySent) {
+			PluginAppletViewer.parse
+			    (currentRequest.handle, 1, 1,
+			     new StringReader(currentRequest.tag),
+			     new URL(currentRequest.documentbase));
+			parseRequests.remove(currentKey);
+		    }
+		}
+	    } else if (message.startsWith("handle")) {
+		if (currentRequest != null) {
+		    currentRequest.handle = Long.parseLong
+			(message.substring("handle".length() + 1, 
+						message.indexOf("width") - 1));
+		    int width = Integer.parseInt(message.substring
+					(message.indexOf("width") + 
+					"width".length() + 1, 
+					message.indexOf("height") - 1));
+		    int height = Integer.parseInt(message.substring(
+					message.indexOf("height") + 
+					"height".length() + 1));
+		    if (currentRequest.tag != null
+		       && !currentRequest.alreadySent) {
+			PluginAppletViewer.parse
+			    (currentRequest.handle, width, height,
+			     new StringReader(currentRequest.tag),
+			     new URL(currentRequest.documentbase));
+			parseRequests.remove(currentKey);
+		    }
+		}
+	    } else if (message.startsWith("width")) {
+		int width =
+		    Integer.parseInt(message.substring("width".length() + 1));
+		int height = currentWindow.getHeight();
+		currentWindow.updateAtts(width, height);
+	 	currentWindow.setSize(width, height);
+	    } else if (message.startsWith("height")) {
+		int height =
+		    Integer.parseInt(message.substring("height".length() + 1));
+		int width = currentWindow.getWidth();
+		currentWindow.updateAtts(width, height);
+	        currentWindow.setSize(width, height);
+	    } else if (message.startsWith("destroy")
+		       && currentWindow != null) {
+		deregisterWindow(currentWindow);
+	    }
+
+	    // Read next message.
+	    message = read();
+	}
+    }
+
+    /**
+     * Write string to plugin.
+     * 
+     * @param message the message to write
+     *
+     * @exception IOException if an error occurs
+     */
+    static void write(String message)
+	throws IOException
+    {
+	pluginOutputStream.write(message, 0, message.length());
+	pluginOutputStream.newLine();
+	pluginOutputStream.flush();
+
+	System.err.println("  PIPE: appletviewer wrote: " + message);
+    }
+
+    /**
+     * Read string from plugin.
+     *
+     * @return the read string
+     *
+     * @exception IOException if an error occurs
+     */
+    static String read()
+	throws IOException
+    {
+	String message = pluginInputStream.readLine();
+	System.err.println("  PIPE: appletviewer read: " + message);
+	if (message == null || message.equals("shutdown")) {
+	    try {
+		// Close input/output channels to plugin.
+		pluginInputStream.close();
+		pluginOutputStream.close();
+	    } catch (IOException exception) {
+		// Deliberately ignore IOException caused by broken
+		// pipe since plugin may have already detached.
+	    }
+
+	    System.err.println("APPLETVIEWER: exiting appletviewer");
+	    System.exit(0);
+	}
+	return message;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/GetMemberPluginCallRequest.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,72 @@
+/* GetMemberPluginCallRequest -- represent Java-to-JavaScript requests
+   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. */
+
+package sun.applet;
+
+class GetMemberPluginCallRequest extends PluginCallRequest {
+    Object object = null;
+
+    public GetMemberPluginCallRequest(String message, String returnString) {
+        super(message, returnString);
+        System.out.println ("GetMEMBerPLUGINCAlL " + message + " " + returnString);
+    }
+
+    public void parseReturn(String message) {
+        System.out.println ("GetMEMBerparseReturn GOT: " + message);
+        String[] args = message.split(" ");
+        // FIXME: add thread ID to messages to support multiple
+        // threads using the netscape.javascript package.
+        object = PluginAppletSecurityContext.contexts.get(
+            0).store.getObject(Integer.parseInt(args[1]));
+        done = true;
+    }
+    
+    /**
+     * Returns whether the given message is serviceable by this object
+     * 
+     * @param message The message to service
+     * @return boolean indicating if message is serviceable
+     */
+    public boolean serviceable(String message) {
+    	return message.contains("JavaScriptCall") ||
+    			message.contains("JavaScriptEval") ||
+    			message.contains("JavaScriptGetMember") ||
+    			message.contains("JavaScriptGetSlot") ||
+    			message.contains("JavaScriptToString");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/GetWindowPluginCallRequest.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,66 @@
+/* GetWindowPluginCallRequest -- represent Java-to-JavaScript requests
+   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. */
+
+package sun.applet;
+
+class GetWindowPluginCallRequest extends PluginCallRequest {
+    // FIXME: look into int vs long JavaScript internal values.
+    int internal;
+
+    public GetWindowPluginCallRequest(String message, String returnString) {
+        super(message, returnString);
+    }
+
+    public void parseReturn(String message) {
+        System.out.println ("GetWINDOWparseReturn GOT: " + message);
+        String[] args = message.split(" ");
+        // FIXME: add thread ID to messages to support multiple
+        // threads using the netscape.javascript package.
+        internal = Integer.parseInt(args[1]);
+        done = true;
+    }
+    
+    /**
+     * Returns whether the given message is serviceable by this object
+     * 
+     * @param message The message to service
+     * @return boolean indicating if message is serviceable
+     */
+    public boolean serviceable(String message) {
+    	return message.contains("JavaScriptGetWindow");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/PluginAppletSecurityContext.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,847 @@
+/* PluginAppletSecurityContext -- execute plugin JNI messages
+   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. */
+
+package sun.applet;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.StringTokenizer;
+
+class Signature {
+	private String signature;
+	private int currentIndex;
+	private List<Class> typeList;
+	private static final char ARRAY = '[';
+	private static final char OBJECT = 'L';
+	private static final char SIGNATURE_ENDCLASS = ';';
+	private static final char SIGNATURE_FUNC = '(';
+	private static final char SIGNATURE_ENDFUNC = ')';
+	private static final char VOID = 'V';
+	private static final char BOOLEAN = 'Z';
+	private static final char BYTE = 'B';
+	private static final char CHARACTER = 'C';
+	private static final char SHORT = 'S';
+	private static final char INTEGER = 'I';
+	private static final char LONG = 'J';
+	private static final char FLOAT = 'F';
+	private static final char DOUBLE = 'D';
+
+	private String nextTypeName() {
+		char key = signature.charAt(currentIndex++);
+
+		switch (key) {
+		case ARRAY:
+			return nextTypeName() + "[]";
+
+		case OBJECT:
+			int endClass = signature.indexOf(SIGNATURE_ENDCLASS, currentIndex);
+			String retVal = signature.substring(currentIndex, endClass);
+			retVal = retVal.replace('/', '.');
+			currentIndex = endClass + 1;
+			return retVal;
+
+			// FIXME: generated bytecode with classes named after
+			// primitives will not work in this scheme -- those
+			// classes will be incorrectly treated as primitive
+			// types.
+		case VOID:
+			return "void";
+		case BOOLEAN:
+			return "boolean";
+		case BYTE:
+			return "byte";
+		case CHARACTER:
+			return "char";
+		case SHORT:
+			return "short";
+		case INTEGER:
+			return "int";
+		case LONG:
+			return "long";
+		case FLOAT:
+			return "float";
+		case DOUBLE:
+			return "double";
+
+		case SIGNATURE_ENDFUNC:
+		case SIGNATURE_FUNC:
+			return nextTypeName();
+
+		default:
+			throw new IllegalArgumentException(
+					"Invalid JNI signature character '" + key + "'");
+		}
+	}
+
+	public Signature(String signature, String src) {
+		this.signature = signature;
+		currentIndex = 0;
+		typeList = new ArrayList<Class>(10);
+
+		String elem;
+		while (currentIndex < signature.length()) {
+			elem = nextTypeName();
+			// System.out.println ("NEXT TYPE: " + elem);
+			Class primitive = primitiveNameToType(elem);
+			if (primitive != null)
+				typeList.add(primitive);
+			else {
+				// System.out.println ("HERE1");
+				int dimsize = 0;
+				int n = elem.indexOf('[');
+				if (n != -1) {
+					// System.out.println ("HERE2");
+					String arrayType = elem.substring(0, n);
+					dimsize++;
+					n = elem.indexOf('[', n + 1);
+					// System.out.println ("HERE2.5");
+					while (n != -1) {
+						dimsize++;
+						n = elem.indexOf('[', n + 1);
+						// System.out.println ("HERE2.8");
+					}
+					int[] dims = new int[dimsize];
+					primitive = primitiveNameToType(arrayType);
+					// System.out.println ("HERE3");
+					if (primitive != null) {
+						typeList.add(Array.newInstance(primitive, dims)
+								.getClass());
+						// System.out.println ("HERE4");
+					} else
+						typeList.add(Array.newInstance(
+								getClass(arrayType, src), dims).getClass());
+				} else {
+					typeList.add(getClass(elem, src));
+				}
+			}
+		}
+		if (typeList.size() == 0) {
+			throw new IllegalArgumentException("Invalid JNI signature '"
+					+ signature + "'");
+		}
+	}
+
+	public static Class getClass(String name, String src) {
+
+		Class c = null;
+		
+		try {
+			c = Class.forName(name);
+		} catch (ClassNotFoundException cnfe) {
+
+			StringTokenizer st = new StringTokenizer(src, ",");
+
+			while (st.hasMoreTokens()) {
+
+				String tok = st.nextToken();
+				System.err.println("Searching for " + name  + " at key " + tok);
+
+				try {
+					c = PluginAppletSecurityContext.classLoaders.get(tok).loadClass(name);
+				} catch (ClassNotFoundException e) {
+					// do nothing .. thrown below
+				}
+				
+				if (c != null)
+					break;
+			}
+		}
+
+		if (c == null) {
+			throw (new RuntimeException(new ClassNotFoundException("Unable to find class " + name)));
+		}
+
+		return c;
+	}
+	
+	public static Class primitiveNameToType(String name) {
+		if (name.equals("void"))
+			return Void.TYPE;
+		else if (name.equals("boolean"))
+			return Boolean.TYPE;
+		else if (name.equals("byte"))
+			return Byte.TYPE;
+		else if (name.equals("char"))
+			return Character.TYPE;
+		else if (name.equals("short"))
+			return Short.TYPE;
+		else if (name.equals("int"))
+			return Integer.TYPE;
+		else if (name.equals("long"))
+			return Long.TYPE;
+		else if (name.equals("float"))
+			return Float.TYPE;
+		else if (name.equals("double"))
+			return Double.TYPE;
+		else
+			return null;
+	}
+
+	public Class[] getClassArray() {
+		return typeList.subList(0, typeList.size() - 1).toArray(new Class[] {});
+	}
+}
+
+public class PluginAppletSecurityContext {
+	// Context identifier -> PluginAppletSecurityContext object.
+	// FIXME: make private
+	public static HashMap<Integer, PluginAppletSecurityContext> contexts = new HashMap();
+	
+	public static HashMap<String, ClassLoader> classLoaders = new HashMap<String, ClassLoader>();
+
+	// FIXME: make private
+	public PluginObjectStore store = new PluginObjectStore();
+	private Throwable throwable = null;
+	private ClassLoader liveconnectLoader = ClassLoader.getSystemClassLoader();
+	int identifier = 0;
+
+	static {
+		// FIXME: when should we add each new security context? but how would 
+		// we be able to know which context applies to which request from nspr? 
+		// the nspr jni functions do not know what applet they are being called
+		// in reference to
+		contexts.put(0, new PluginAppletSecurityContext(0));
+	}
+
+	public PluginAppletSecurityContext(int identifier) {
+		this.identifier = identifier;
+	}
+
+	public static <V> V parseCall(String s, String src, Class<V> c) {
+		if (c == Integer.class)
+			return (V) new Integer(s);
+		else if (c == String.class)
+			return (V) new String(s);
+		else if (c == Signature.class)
+			return (V) new Signature(s, src);
+		else
+			throw new RuntimeException("Unexpected call value.");
+	}
+
+	public Object parseArgs(String s, Class c) {
+		if (c == Boolean.TYPE || c == Boolean.class)
+			return new Boolean(s);
+		else if (c == Byte.TYPE || c == Byte.class)
+			return new Byte(s);
+		else if (c == Character.TYPE || c == Character.class) {
+			String[] bytes = s.split("_");
+			int low = Integer.parseInt(bytes[0]);
+			int high = Integer.parseInt(bytes[1]);
+			int full = ((high << 8) & 0x0ff00) | (low & 0x0ff);
+			return new Character((char) full);
+		} else if (c == Short.TYPE || c == Short.class)
+			return new Short(s);
+		else if (c == Integer.TYPE || c == Integer.class)
+			return new Integer(s);
+		else if (c == Long.TYPE || c == Long.class)
+			return new Long(s);
+		else if (c == Float.TYPE || c == Float.class)
+			return new Float(s);
+		else if (c == Double.TYPE || c == Double.class)
+			return new Double(s);
+		else
+			return store.getObject(new Integer(s));
+	}
+
+	public static void handleMessage(int identifier, String src, int reference,
+			String message) {
+		contexts.get(identifier).handleMessage(reference, src, message);
+	}
+
+	public void handleMessage(int reference, String src, String message) {
+
+		try {
+			if (message.startsWith("FindClass")) {
+				ClassLoader cl = null;
+				Class c = null;
+				cl = liveconnectLoader;
+				String className = message.substring("FindClass".length() + 1)
+						.replace('/', '.');
+
+				try {
+					c = cl.loadClass(className);
+					store.reference(c);
+					write(reference, "FindClass " + store.getIdentifier(c));
+				} catch (ClassNotFoundException cnfe) {
+					write(reference, "FindClass 0");
+				}
+
+			} else if (message.startsWith("GetStaticMethodID")
+					|| message.startsWith("GetMethodID")) {
+				String[] args = message.split(" ");
+				Integer classID = parseCall(args[1], src, Integer.class);
+				String methodName = parseCall(args[2], src, String.class);
+				Signature signature = parseCall(args[3], src, Signature.class);
+				Object[] a = signature.getClassArray();
+
+				Class c = (Class) store.getObject(classID);
+				Method m = null;
+				Constructor cs = null;
+				Object o = null;
+				if (methodName.equals("<init>")
+						|| methodName.equals("<clinit>")) {
+					o = cs = c.getConstructor(signature.getClassArray());
+					store.reference(cs);
+				} else {
+					o = m = c.getMethod(methodName, signature.getClassArray());
+					store.reference(m);
+				}
+				PluginDebug.debug(o + " has id " + store.getIdentifier(o));
+				write(reference, args[0] + " " + store.getIdentifier(o));
+			} else if (message.startsWith("GetStaticFieldID")
+					|| message.startsWith("GetFieldID")) {
+				String[] args = message.split(" ");
+				Integer classID = parseCall(args[1], src, Integer.class);
+				String fieldName = parseCall(args[2], src, String.class);
+				Signature signature = parseCall(args[3], src, Signature.class);
+
+				Class c = (Class) store.getObject(classID);
+				Field f = null;
+				f = c.getField(fieldName);
+
+				store.reference(f);
+
+				write(reference, "GetStaticFieldID " + store.getIdentifier(f));
+			} else if (message.startsWith("GetStaticField")) {
+				String[] args = message.split(" ");
+				String type = parseCall(args[1], src, String.class);
+				Integer classID = parseCall(args[1], src, Integer.class);
+				Integer fieldID = parseCall(args[2], src, Integer.class);
+
+				Class c = (Class) store.getObject(classID);
+				Field f = (Field) store.getObject(fieldID);
+
+				Object ret = null;
+				ret = f.get(c);
+
+				// System.out.println ("FIELD VALUE: " + ret);
+				if (ret == null) {
+					write(reference, "GetStaticField 0");
+				} else if (f.getType() == Boolean.TYPE
+						|| f.getType() == Byte.TYPE
+						|| f.getType() == Character.TYPE
+						|| f.getType() == Short.TYPE
+						|| f.getType() == Integer.TYPE
+						|| f.getType() == Long.TYPE
+						|| f.getType() == Float.TYPE
+						|| f.getType() == Double.TYPE) {
+					write(reference, "GetStaticField " + ret);
+				} else {
+					// Track returned object.
+					store.reference(ret);
+					write(reference, "GetStaticField "
+							+ store.getIdentifier(ret));
+				}
+			} else if (message.startsWith("SetStaticField")) {
+				String[] args = message.split(" ");
+				String type = parseCall(args[1], src, String.class);
+				Integer classID = parseCall(args[2], src, Integer.class);
+				Integer fieldID = parseCall(args[3], src, Integer.class);
+
+				Object value = null;
+				if (Signature.primitiveNameToType(type) != null) {
+					value = parseArgs(args[4], Signature
+							.primitiveNameToType(type));
+					// System.out.println ("HERE1: " + value);
+				} else {
+					value = parseArgs(args[3], Object.class);
+					// System.out.println ("HERE2: " + value);
+				}
+
+				Class c = (Class) store.getObject(classID);
+				Field f = (Field) store.getObject(fieldID);
+
+				f.set(c, value);
+
+				write(reference, "SetStaticField");
+			} else if (message.startsWith("SetField")) {
+				String[] args = message.split(" ");
+				String type = parseCall(args[1], src, String.class);
+				Integer objectID = parseCall(args[2], src, Integer.class);
+				Integer fieldID = parseCall(args[3], src, Integer.class);
+
+				Object value = null;
+				if (Signature.primitiveNameToType(type) != null) {
+					value = parseArgs(args[4], Signature
+							.primitiveNameToType(type));
+					// System.out.println ("HERE1: " + value);
+				} else {
+					value = parseArgs(args[3], Object.class);
+					// System.out.println ("HERE2: " + value);
+				}
+
+				Object o = (Object) store.getObject(objectID);
+				Field f = (Field) store.getObject(fieldID);
+
+				f.set(o, value);
+
+				write(reference, "SetField");
+			} else if (message.startsWith("GetObjectArrayElement")) {
+				String[] args = message.split(" ");
+				Integer arrayID = parseCall(args[1], src, Integer.class);
+				Integer index = parseCall(args[2], src, Integer.class);
+
+				Object[] o = (Object[]) store.getObject(arrayID);
+				Object ret = null;
+
+				ret = o[index];
+
+				// Track returned object.
+				store.reference(ret);
+				// System.out.println ("array element: " + index + " " + ret);
+				write(reference, "GetObjectArrayElement "
+						+ store.getIdentifier(ret));
+			} else if (message.startsWith("SetObjectArrayElement")) {
+				String[] args = message.split(" ");
+				Integer arrayID = parseCall(args[1], src, Integer.class);
+				Integer index = parseCall(args[2], src, Integer.class);
+				Integer objectID = parseCall(args[3], src, Integer.class);
+
+				Object[] o = (Object[]) store.getObject(arrayID);
+				Object toSet = (Object) store.getObject(objectID);
+
+				o[index] = toSet;
+
+				write(reference, "SetObjectArrayElement");
+			} else if (message.startsWith("GetArrayLength")) {
+				String[] args = message.split(" ");
+				Integer arrayID = parseCall(args[1], src, Integer.class);
+
+				System.out.println("ARRAYID: " + arrayID);
+				Object o = (Object) store.getObject(arrayID);
+				int len = 0;
+				len = Array.getLength(o);
+				// System.out.println ("Returning array length: " + len);
+
+				// System.out.println ("array length: " + o + " " + len);
+				write(reference, "GetArrayLength " + Array.getLength(o));
+			} else if (message.startsWith("GetField")) {
+				String[] args = message.split(" ");
+				String type = parseCall(args[1], src, String.class);
+				Integer objectID = parseCall(args[1], src, Integer.class);
+				Integer fieldID = parseCall(args[2], src, Integer.class);
+
+				Object o = (Object) store.getObject(objectID);
+				Field f = (Field) store.getObject(fieldID);
+
+				Object ret = null;
+				ret = f.get(o);
+
+				// System.out.println ("FIELD VALUE: " + ret);
+				if (ret == null) {
+					write(reference, "GetField 0");
+				} else if (f.getType() == Boolean.TYPE
+						|| f.getType() == Byte.TYPE
+						|| f.getType() == Character.TYPE
+						|| f.getType() == Short.TYPE
+						|| f.getType() == Integer.TYPE
+						|| f.getType() == Long.TYPE
+						|| f.getType() == Float.TYPE
+						|| f.getType() == Double.TYPE) {
+					write(reference, "GetField " + ret);
+				} else {
+					// Track returned object.
+					store.reference(ret);
+					write(reference, "GetField " + store.getIdentifier(ret));
+				}
+			} else if (message.startsWith("GetObjectClass")) {
+				int oid = Integer.parseInt(message.substring("GetObjectClass"
+						.length() + 1));
+				// System.out.println ("GETTING CLASS FOR: " + oid);
+				Class c = store.getObject(oid).getClass();
+				// System.out.println (" OBJ: " + store.getObject(oid));
+				// System.out.println (" CLS: " + c);
+				store.reference(c);
+
+				write(reference, "GetObjectClass " + store.getIdentifier(c));
+			} else if (message.startsWith("CallStaticMethod")) {
+				String[] args = message.split(" ");
+				Integer classID = parseCall(args[1], src, Integer.class);
+				Integer methodID = parseCall(args[2], src, Integer.class);
+
+				System.out.println("GETTING: " + methodID);
+				Method m = (Method) store.getObject(methodID);
+				System.out.println("GOT: " + m);
+				Class[] argTypes = m.getParameterTypes();
+
+				Object[] arguments = new Object[argTypes.length];
+				for (int i = 0; i < argTypes.length; i++) {
+					arguments[i] = parseArgs(args[3 + i], argTypes[i]);
+					// System.out.println ("GOT ARG: " + argTypes[i] + " " +
+					// arguments[i]);
+				}
+
+				// System.out.println ("Calling " + m);
+				Object ret = null;
+				ret = m.invoke(null, arguments);
+
+				// if (ret != null)
+				// System.out.println ("RETURN VALUE: " + ret + " " +
+				// ret.getClass());
+				// else
+				// System.out.println ("RETURN VALUE: " + ret);
+				if (ret == null) {
+					write(reference, "CallStaticMethod void");
+				} else if (m.getReturnType() == Boolean.TYPE
+						|| m.getReturnType() == Byte.TYPE
+						|| m.getReturnType() == Short.TYPE
+						|| m.getReturnType() == Integer.TYPE
+						|| m.getReturnType() == Long.TYPE
+						|| m.getReturnType() == Float.TYPE
+						|| m.getReturnType() == Double.TYPE) {
+					write(reference, "CallStaticMethod " + ret);
+				} else if (m.getReturnType() == Character.TYPE) {
+					char ch = (Character) ret;
+					int high = (((int) ch) >> 8) & 0x0ff;
+					int low = ((int) ch) & 0x0ff;
+					write(reference, "CallStaticMethod " + low + "_" + high);
+				} else {
+					// Track returned object.
+					store.reference(ret);
+					write(reference, "CallStaticMethod "
+							+ store.getIdentifier(ret));
+				}
+			} else if (message.startsWith("CallMethod")) {
+				String[] args = message.split(" ");
+				Integer objectID = parseCall(args[1], src, Integer.class);
+				Integer methodID = parseCall(args[2], src, Integer.class);
+
+				Object o = (Object) store.getObject(objectID);
+				Method m = (Method) store.getObject(methodID);
+				Class[] argTypes = m.getParameterTypes();
+
+				Object[] arguments = new Object[argTypes.length];
+				for (int i = 0; i < argTypes.length; i++) {
+					arguments[i] = parseArgs(args[3 + i], argTypes[i]);
+					PluginDebug.debug("GOT ARG: " + argTypes[i] + " "
+							+ arguments[i]);
+				}
+
+				String collapsedArgs = "";
+				for (String s : args) {
+					collapsedArgs += " " + s;
+				}
+
+				PluginDebug.debug("Calling method " + m + " on object " + o
+						+ " with " + arguments);
+				Object ret = null;
+				ret = m.invoke(o, arguments);
+
+				String retO;
+				if (ret == null) {
+					retO = "null";
+				} else {
+					retO = ret.getClass().toString();
+				}
+
+				PluginDebug.debug("Calling " + m + " on " + o + " with "
+						+ collapsedArgs + " and that returned: " + ret
+						+ " of type " + retO);
+
+				if (ret == null) {
+					write(reference, "CallMethod void");
+				} else if (m.getReturnType() == Boolean.TYPE
+						|| m.getReturnType() == Byte.TYPE
+						|| m.getReturnType() == Short.TYPE
+						|| m.getReturnType() == Integer.TYPE
+						|| m.getReturnType() == Long.TYPE
+						|| m.getReturnType() == Float.TYPE
+						|| m.getReturnType() == Double.TYPE) {
+					write(reference, "CallMethod " + ret);
+				} else if (m.getReturnType() == Character.TYPE) {
+					char ch = (Character) ret;
+					int high = (((int) ch) >> 8) & 0x0ff;
+					int low = ((int) ch) & 0x0ff;
+					write(reference, "CallMethod " + low + "_" + high);
+				} else {
+					// Track returned object.
+					store.reference(ret);
+					write(reference, "CallMethod " + store.getIdentifier(ret));
+				}
+			} else if (message.startsWith("GetSuperclass")) {
+				String[] args = message.split(" ");
+				Integer classID = parseCall(args[1], src, Integer.class);
+				Class c = null;
+				Class ret = null;
+
+				c = (Class) store.getObject(classID);
+				ret = c.getSuperclass();
+				store.reference(ret);
+
+				write(reference, "GetSuperclass " + store.getIdentifier(ret));
+			} else if (message.startsWith("IsAssignableFrom")) {
+				String[] args = message.split(" ");
+				Integer classID = parseCall(args[1], src, Integer.class);
+				Integer superclassID = parseCall(args[2], src, Integer.class);
+
+				boolean result = false;
+				Class clz = (Class) store.getObject(classID);
+				Class sup = (Class) store.getObject(superclassID);
+
+				result = sup.isAssignableFrom(clz);
+
+				write(reference, "IsAssignableFrom " + (result ? "1" : "0"));
+			} else if (message.startsWith("IsInstanceOf")) {
+				String[] args = message.split(" ");
+				Integer objectID = parseCall(args[1], src, Integer.class);
+				Integer classID = parseCall(args[2], src, Integer.class);
+
+				boolean result = false;
+				Object o = (Object) store.getObject(objectID);
+				Class c = (Class) store.getObject(classID);
+
+				result = c.isInstance(o);
+
+				write(reference, "IsInstanceOf " + (result ? "1" : "0"));
+			} else if (message.startsWith("GetStringUTFLength")) {
+				String[] args = message.split(" ");
+				Integer stringID = parseCall(args[1], src, Integer.class);
+
+				String o = null;
+				byte[] b = null;
+				o = (String) store.getObject(stringID);
+				b = o.getBytes("UTF-8");
+				// System.out.println ("STRING UTF-8 LENGTH: " + o + " " +
+				// b.length);
+
+				write(reference, "GetStringUTFLength " + o.length());
+			} else if (message.startsWith("GetStringLength")) {
+				String[] args = message.split(" ");
+				Integer stringID = parseCall(args[1], src, Integer.class);
+
+				String o = null;
+				byte[] b = null;
+				o = (String) store.getObject(stringID);
+				b = o.getBytes("UTF-16LE");
+				// System.out.println ("STRING UTF-16 LENGTH: " + o + " " +
+				// b.length);
+
+				// System.out.println ("Java: GetStringLength " + b.length);
+				write(reference, "GetStringLength " + o.length());
+			} else if (message.startsWith("GetStringUTFChars")) {
+				String[] args = message.split(" ");
+				Integer stringID = parseCall(args[1], src, Integer.class);
+
+				String o = null;
+				byte[] b = null;
+				StringBuffer buf = null;
+				o = (String) store.getObject(stringID);
+				b = o.getBytes("UTF-8");
+				buf = new StringBuffer(b.length * 2);
+				buf.append(b.length);
+				for (int i = 0; i < b.length; i++)
+					buf
+							.append(" "
+									+ Integer
+											.toString(((int) b[i]) & 0x0ff, 16));
+
+				// System.out.println ("Java: GetStringUTFChars: " + o);
+				// //System.out.println ("String UTF BYTES: " + buf);
+				write(reference, "GetStringUTFChars " + buf);
+			} else if (message.startsWith("GetStringChars")) {
+				String[] args = message.split(" ");
+				Integer stringID = parseCall(args[1], src, Integer.class);
+
+				String o = null;
+				byte[] b = null;
+				StringBuffer buf = null;
+				o = (String) store.getObject(stringID);
+				// FIXME: LiveConnect uses UCS-2.
+				b = o.getBytes("UTF-16LE");
+				buf = new StringBuffer(b.length * 2);
+				buf.append(b.length);
+				for (int i = 0; i < b.length; i++)
+					buf
+							.append(" "
+									+ Integer
+											.toString(((int) b[i]) & 0x0ff, 16));
+
+				System.out.println("Java: GetStringChars: " + o);
+				System.out.println("  String BYTES: " + buf);
+				write(reference, "GetStringChars " + buf);
+			} else if (message.startsWith("NewArray")) {
+				String[] args = message.split(" ");
+				String type = parseCall(args[1], src, String.class);
+				Integer length = parseCall(args[2], src, Integer.class);
+
+				// System.out.println ("CALLING: NewArray: " + type + " " +
+				// length + " "
+				// + Signature.primitiveNameToType(type));
+
+				Object newArray = null;
+				newArray = Array.newInstance(Signature
+						.primitiveNameToType(type), length);
+
+				store.reference(newArray);
+				write(reference, "NewArray " + store.getIdentifier(newArray));
+			} else if (message.startsWith("NewObjectArray")) {
+				String[] args = message.split(" ");
+				Integer length = parseCall(args[1], src, Integer.class);
+				Integer classID = parseCall(args[2], src, Integer.class);
+				Integer objectID = parseCall(args[3], src, Integer.class);
+
+				// System.out.println ("CALLING: NewObjectArray: " +
+				// classID + " " + length + " "
+				// + objectID);
+
+				Object newArray = null;
+				newArray = Array.newInstance((Class) store.getObject(classID),
+						length);
+
+				Object[] array = (Object[]) newArray;
+				for (int i = 0; i < array.length; i++)
+					array[i] = store.getObject(objectID);
+				store.reference(newArray);
+				write(reference, "NewObjectArray "
+						+ store.getIdentifier(newArray));
+			} else if (message.startsWith("NewObject")) {
+				String[] args = message.split(" ");
+				Integer classID = parseCall(args[1], src, Integer.class);
+				Integer methodID = parseCall(args[2], src, Integer.class);
+
+				Constructor m = (Constructor) store.getObject(methodID);
+				Class[] argTypes = m.getParameterTypes();
+
+				// System.out.println ("NEWOBJ: HERE1");
+				Object[] arguments = new Object[argTypes.length];
+				// System.out.println ("NEWOBJ: HERE2");
+				for (int i = 0; i < argTypes.length; i++) {
+					arguments[i] = parseArgs(args[3 + i], argTypes[i]);
+					// System.out.println ("NEWOBJ: GOT ARG: " + arguments[i]);
+				}
+
+				// System.out.println ("NEWOBJ: Calling " + m);
+				Object ret = null;
+				ret = m.newInstance(arguments);
+
+				// System.out.println ("NEWOBJ: CALLED: " + ret);
+				// System.out.println ("NEWOBJ: CALLED: " +
+				// store.getObject(ret));
+				store.reference(ret);
+				write(reference, "NewObject " + store.getIdentifier(ret));
+			} else if (message.startsWith("NewString")) {
+				System.out.println("MESSAGE: " + message);
+				String[] args = message.split(" ");
+				Integer strlength = parseCall(args[1], src, Integer.class);
+				int bytelength = 2 * strlength;
+				byte[] byteArray = new byte[bytelength];
+				String ret = null;
+				for (int i = 0; i < strlength; i++) {
+					int c = parseCall(args[2 + i], src, Integer.class);
+					System.out.println("char " + i + " " + c);
+					// Low.
+					byteArray[2 * i] = (byte) (c & 0x0ff);
+					// High.
+					byteArray[2 * i + 1] = (byte) ((c >> 8) & 0x0ff);
+				}
+				ret = new String(byteArray, 0, bytelength, "UTF-16LE");
+				System.out.println("NEWSTRING: " + ret);
+
+				// System.out.println ("NEWOBJ: CALLED: " + ret);
+				// System.out.println ("NEWOBJ: CALLED: " +
+				// store.getObject(ret));
+				store.reference(ret);
+				write(reference, "NewString " + store.getIdentifier(ret));
+			} else if (message.startsWith("NewStringUTF")) {
+				System.out.println("MESSAGE: " + message);
+				String[] args = message.split(" ");
+				byte[] byteArray = new byte[60];
+				String ret = null;
+				int i = 0;
+				int c = 0;
+				while (((byte) c) != 0) {
+					c = parseCall(args[1 + i], src, Integer.class);
+					byteArray[i] = (byte) c;
+					i++;
+					if (i == byteArray.length) {
+						byte[] newByteArray = new byte[2 * byteArray.length];
+						System.arraycopy(byteArray, 0, newByteArray, 0,
+								byteArray.length);
+						byteArray = newByteArray;
+					}
+				}
+				byteArray[i] = (byte) 0;
+				ret = new String(byteArray, "UTF-8");
+				System.out.println("NEWSTRINGUTF: " + ret);
+
+				store.reference(ret);
+				write(reference, "NewStringUTF " + store.getIdentifier(ret));
+			} else if (message.startsWith("ExceptionOccurred")) {
+				System.out.println("EXCEPTION: " + throwable);
+				if (throwable != null)
+					store.reference(throwable);
+				write(reference, "ExceptionOccurred "
+						+ store.getIdentifier(throwable));
+			} else if (message.startsWith("ExceptionClear")) {
+				if (throwable != null)
+					store.unreference(store.getIdentifier(throwable));
+				throwable = null;
+				write(reference, "ExceptionClear");
+			} else if (message.startsWith("DeleteGlobalRef")) {
+				String[] args = message.split(" ");
+				Integer id = parseCall(args[1], src, Integer.class);
+				store.unreference(id);
+				write(reference, "DeleteGlobalRef");
+			} else if (message.startsWith("DeleteLocalRef")) {
+				String[] args = message.split(" ");
+				Integer id = parseCall(args[1], src, Integer.class);
+				store.unreference(id);
+				write(reference, "DeleteLocalRef");
+			} else if (message.startsWith("NewGlobalRef")) {
+				String[] args = message.split(" ");
+				Integer id = parseCall(args[1], src, Integer.class);
+				store.reference(store.getObject(id));
+				write(reference, "NewGlobalRef " + id);
+			}
+		} catch (Throwable t) {
+			t.printStackTrace();
+			throwable = t;
+			PluginException p = new PluginException(identifier, reference, t);
+		}
+	}
+
+	public void write(int reference, String message) {
+		PluginDebug.debug("appletviewer writing " + message);
+		PluginMain.write("context " + identifier + " reference " + reference
+				+ " " + message);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/PluginAppletViewer.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,1439 @@
+ /*
+  * 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.util.*;
+ import java.io.*;
+ import java.awt.*;
+ import java.awt.event.*;
+ import java.awt.print.*;
+ import javax.print.attribute.*;
+ import java.applet.*;
+ import java.net.URL;
+ import java.net.MalformedURLException;
+ import java.net.SocketPermission;
+ import sun.misc.Ref;
+ import java.security.AccessController;
+ import java.security.PrivilegedAction;
+ import java.lang.reflect.InvocationTargetException;
+ import java.lang.reflect.Method;
+ import sun.awt.SunToolkit;
+ import sun.awt.AppContext;
+ import sun.awt.X11.*;
+ import java.lang.ref.WeakReference;
+ import net.sourceforge.jnlp.NetxPanel;
+ 
+ /**
+  * Lets us construct one using unix-style one shot behaviors
+  */
+ 
+ class PluginAppletViewerFactory
+ {
+     public PluginAppletViewer createAppletViewer(int identifier,
+                                                  long handle, int x, int y,
+ 						 URL doc, Hashtable atts) {
+         PluginAppletViewer pluginappletviewer = new PluginAppletViewer(identifier, handle, x, y, doc, atts, System.out, this);
+         return pluginappletviewer;
+     }
+ 
+     public boolean isStandalone()
+     {
+         return false;
+     }
+ }
+ 
+ class PluginParseRequest
+ {
+     long handle;
+     String tag;
+     String documentbase;
+ }
+ 
+ /*
+  */
+ // FIXME: declare JSProxy implementation
+ public class PluginAppletViewer extends XEmbeddedFrame
+     implements AppletContext, Printable {
+     /**
+      * Some constants...
+      */
+     private static String defaultSaveFile = "Applet.ser";
+ 
+     /**
+      * The panel in which the applet is being displayed.
+      */
+     AppletViewerPanel panel;
+ 
+     /**
+      * The status line.
+      */
+     Label label;
+ 
+     /**
+      * output status messages to this stream
+      */
+ 
+     PrintStream statusMsgStream;
+ 
+     /**
+      * For cloning
+      */
+     PluginAppletViewerFactory factory;
+ 
+     int identifier;
+ 
+     private static HashMap<Integer, PluginParseRequest> requests = new HashMap();
+ 
+     // Instance identifier -> PluginAppletViewer object.
+     private static HashMap<Integer, PluginAppletViewer> applets = new HashMap();
+ 
+     /**
+      * Create the applet viewer
+      */
+     public PluginAppletViewer(int identifier, long handle, int x, int y, final URL doc,
+                               final Hashtable atts, PrintStream statusMsgStream,
+                               PluginAppletViewerFactory factory) {
+         super(handle, true);
+     	this.factory = factory;
+ 	this.statusMsgStream = statusMsgStream;
+         this.identifier = identifier;
+         // FIXME: when/where do we remove this?
+         PluginDebug.debug ("PARSING: PUTTING " + identifier + " " + this);
+         applets.put(identifier, this);
+ 
+ 	try {
+ 		panel = new NetxPanel(doc, atts);
+ 		AppletViewerPanel.debug("Using NetX panel");
+ 	} catch (Exception ex) {
+ 		AppletViewerPanel.debug("Unable to start NetX applet - defaulting to Sun applet", ex);
+ 		panel = new AppletViewerPanel(doc, atts);
+ 	}
+
+ 	add("Center", panel);
+ 	panel.init();
+ 	appletPanels.addElement(panel);
+ 
+ 	pack();
+ 	setVisible(true);
+ 
+ 	WindowListener windowEventListener = new WindowAdapter() {
+ 
+ 	    public void windowClosing(WindowEvent evt) {
+ 		appletClose();
+ 	    }
+ 
+ 	    public void windowIconified(WindowEvent evt) {
+ 		appletStop();
+ 	    }
+ 
+ 	    public void windowDeiconified(WindowEvent evt) {
+ 		appletStart();
+ 	    }
+ 	};
+ 
+ 	class AppletEventListener implements AppletListener  
+ 	{
+ 	    final Frame frame;
+ 
+ 	    public AppletEventListener(Frame frame)
+ 	    {
+ 		this.frame = frame;
+ 	    }
+ 
+ 	    public void appletStateChanged(AppletEvent evt) 
+ 	    {
+ 		AppletPanel src = (AppletPanel)evt.getSource();
+ 
+ 		switch (evt.getID()) {
+                     case AppletPanel.APPLET_RESIZE: {
+ 			if(src != null) {
+ 			    resize(preferredSize());
+ 			    validate();
+                         }
+ 			break;
+ 		    }
+ 		    case AppletPanel.APPLET_LOADING_COMPLETED: {
+ 			Applet 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)
+ 			    AppletPanel.changeFrameAppContext(frame, SunToolkit.targetToAppContext(a));
+ 			else
+ 			    AppletPanel.changeFrameAppContext(frame, AppContext.getAppContext());
+ 
+ 			break;
+ 		    }
+ 		}
+ 	    }
+ 	};
+ 
+ 	addWindowListener(windowEventListener);
+ 	panel.addAppletListener(new AppletEventListener(this));
+ 
+ 	// Start the applet
+    showStatus(amh.getMessage("status.start"));
+ 	initEventQueue();
+ 	
+ 	try {
+ 	    write("initialized");
+ 	} catch (IOException ioe) {
+ 		ioe.printStackTrace();
+ 	}
+ 	
+    // Wait for a maximum of 10 seconds for the panel to initialize
+    // (happens in a separate thread)
+ 	Applet a;
+    int maxSleepTime = 10000;
+    int sleepTime = 0;
+    while ((a = panel.getApplet()) == null && sleepTime < maxSleepTime) {
+   	 try {
+   		 Thread.sleep(100);
+   		 sleepTime += 100;
+   		 PluginDebug.debug("Waiting for applet to initialize... ");
+   	 } catch (InterruptedException ie) {
+   		 // ignore
+   	 }
+    }
+
+    // Applet initialized. Find out it's classloader and add it to the list
+    PluginAppletSecurityContext.classLoaders.put(Integer.toString(identifier), a.getClass().getClassLoader());
+    
+     }
+ 
+     /**
+      * 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("tag")) {
+        		 
+        		 // tag and handle must both be set before parsing, so we need
+        		 // synchronization here, as the setting of these variables
+        		 // may happen in independent threads
+        		 
+        		 synchronized(requests) {
+        			 PluginParseRequest request = requests.get(identifier);
+        			 if (request == null) {
+        				 request = new PluginParseRequest();
+        				 requests.put(identifier, request);
+        			 }
+        			 int index = message.indexOf(' ', "tag".length() + 1);
+        			 request.documentbase =
+        				 message.substring("tag".length() + 1, index);
+        			 request.tag = message.substring(index + 1);
+        			 PluginDebug.debug ("REQUEST TAG: " + request.tag + " " +
+        					 Thread.currentThread());
+
+        			 if (request.handle != 0) {
+        				 PluginDebug.debug ("REQUEST TAG, PARSING " +
+        						 Thread.currentThread());
+        				 PluginAppletViewer.parse
+        				 (identifier, request.handle,
+        						 new StringReader(request.tag),
+        						 new URL(request.documentbase));
+        				 requests.remove(identifier);
+        			 } else {
+        				 PluginDebug.debug ("REQUEST HANDLE NOT SET: " + request.handle + ". BYPASSING");
+        			 }
+        		 }
+             } else if (message.startsWith("handle")) {
+            	 synchronized(requests) {
+            		 PluginParseRequest request = requests.get(identifier);
+            		 if (request == null) {
+            			 request = new PluginParseRequest();
+            			 requests.put(identifier, request);
+            		 }
+            		 request.handle = Long.parseLong
+            		 (message.substring("handle".length() + 1));
+            		 PluginDebug.debug ("REQUEST HANDLE: " + request.handle);
+            		 if (request.tag != null) {
+            			 PluginDebug.debug ("REQUEST HANDLE, PARSING " +
+            					 Thread.currentThread());
+            			 PluginAppletViewer.parse
+            			 (identifier, request.handle,
+            					 new StringReader(request.tag),
+            					 new URL(request.documentbase));
+            			 requests.remove(identifier);
+            			 PluginDebug.debug ("REQUEST HANDLE, DONE PARSING " +
+            					 Thread.currentThread());
+            		 } else {
+            			 PluginDebug.debug ("REQUEST HANDLE NOT SET: " + request.tag + ". BYPASSING");
+            		 }
+            	 }
+             } else {
+                 PluginDebug.debug ("HANDLING MESSAGE " + message + " instance " + identifier + " " + Thread.currentThread());
+                 applets.get(identifier).handleMessage(reference, message);
+             }
+         } catch (Exception e) {
+             throw new RuntimeException("Failed to handle message: " + message + " " +
+                                         Thread.currentThread(), e);
+         }
+     }
+ 
+     public void handleMessage(int reference, String message)
+     {
+         if (message.startsWith("width")) {
+        	 int width =
+        		 Integer.parseInt(message.substring("width".length() + 1));
+             panel.setAppletSizeIfNeeded(width, -1);
+             setSize(width, getHeight());
+         } else if (message.startsWith("height")) {
+             int height = 
+            	 Integer.parseInt(message.substring("height".length() + 1));
+             panel.setAppletSizeIfNeeded(-1, height);
+             setSize(getWidth(), height);
+         } else if (message.startsWith("destroy")) {
+             dispose();
+         } else if (message.startsWith("GetJavaObject")) {
+             // FIXME: how do we determine what security context this
+             // object should belong to?
+             Object o;
+
+             // Wait for a maximum of 10 seconds for the panel to initialize
+             // (happens in a separate thread)
+             int maxSleepTime = 10000;
+             int sleepTime = 0;
+             while ((o = panel.getApplet()) == null && sleepTime < maxSleepTime) {
+            	 try {
+            		 Thread.sleep(100);
+            		 sleepTime += 100;
+            		 PluginDebug.debug("Waiting for applet to initialize...");
+            	 } catch (InterruptedException ie) {
+            		 // ignore
+            	 }
+             }
+
+             System.err.println ("Looking for object " + o + " panel is " + panel.getClass());
+             PluginAppletSecurityContext.contexts.get(0).store.reference(o);
+             System.err.println ("WRITING 1: " + "context 0 reference " + reference + " GetJavaObject "
+                                 + PluginAppletSecurityContext.contexts.get(0).store.getIdentifier(o));
+             PluginMain.write("context 0 reference " + reference + " GetJavaObject "
+                              + PluginAppletSecurityContext.contexts.get(0).store.getIdentifier(o));
+             System.err.println ("WRITING 1 DONE");
+         }
+     }
+ 
+     /**
+      * 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() {
+ 	// appletviewer.send.event is an undocumented and unsupported system
+ 	// property which is used exclusively for testing purposes.
+ 	String eventList = System.getProperty("appletviewer.send.event");
+ 
+ 	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 = splitSeparator(",", eventList);
+ 
+  	    for (int i = 0; i < events.length; i++) {
+  		System.out.println("Adding event to queue: " + events[i]);
+  		if (events[i].equals("dispose"))
+  		    panel.sendEvent(AppletPanel.APPLET_DISPOSE);
+  		else if (events[i].equals("load"))
+  		    panel.sendEvent(AppletPanel.APPLET_LOAD);
+  		else if (events[i].equals("init"))
+  		    panel.sendEvent(AppletPanel.APPLET_INIT);
+  		else if (events[i].equals("start"))
+  		    panel.sendEvent(AppletPanel.APPLET_START);
+  		else if (events[i].equals("stop"))
+  		    panel.sendEvent(AppletPanel.APPLET_STOP);
+  		else if (events[i].equals("destroy"))
+  		    panel.sendEvent(AppletPanel.APPLET_DESTROY);
+  		else if (events[i].equals("quit"))
+  		    panel.sendEvent(AppletPanel.APPLET_QUIT);
+  		else if (events[i].equals("error"))
+  		    panel.sendEvent(AppletPanel.APPLET_ERROR);
+  		else
+ 		    // non-fatal error if we get an unrecognized event
+  		    System.out.println("Unrecognized event name: " + events[i]);
+  	    }
+ 
+   	    while (!panel.emptyEventQueue()) ;
+  	    appletSystemExit();
+ 	}
+     }
+ 
+     /**
+      * Split a string based on the presence of a specified separator.  Returns
+      * an array of arbitrary length.  The end of each element in the array is
+      * indicated by the separator of the end of the string.  If there is a
+      * separator immediately before the end of the string, the final element
+      * will be empty.  None of the strings will contain the separator.  Useful
+      * when separating strings such as "foo/bar/bas" using separator "/".
+      *
+      * @param sep  The separator.
+      * @param s    The string to split.
+      * @return     An array of strings.  Each string in the array is determined
+      *             by the location of the provided sep in the original string,
+      *             s.  Whitespace not stripped.
+      */
+     private String [] splitSeparator(String sep, String s) {
+  	Vector v = new Vector();
+ 	int tokenStart = 0;
+ 	int tokenEnd   = 0;
+ 
+ 	while ((tokenEnd = s.indexOf(sep, tokenStart)) != -1) {
+ 	    v.addElement(s.substring(tokenStart, tokenEnd));
+ 	    tokenStart = tokenEnd+1;
+ 	}
+ 	// Add the final element.
+ 	v.addElement(s.substring(tokenStart));
+ 
+ 	String [] retVal = new String[v.size()];
+ 	v.copyInto(retVal);
+  	return retVal;
+     }
+ 
+     /*
+      * Methods for java.applet.AppletContext
+      */
+ 
+     private static Map audioClips = new HashMap();
+ 
+     /**
+      * Get an audio clip.
+      */
+     public AudioClip getAudioClip(URL url) {
+ 	checkConnect(url);
+ 	synchronized (audioClips) {
+ 	    AudioClip clip = (AudioClip)audioClips.get(url);
+ 	    if (clip == null) {
+ 		audioClips.put(url, clip = new AppletAudioClip(url));
+ 	    }
+ 	    return clip;
+ 	}
+     }
+ 
+     private static Map imageRefs = new HashMap();
+ 
+     /**
+      * Get an image.
+      */
+     public Image getImage(URL url) {
+ 	return getCachedImage(url);
+     }
+ 
+     static Image getCachedImage(URL url) {
+ 	// System.getSecurityManager().checkConnection(url.getHost(), url.getPort());
+ 	return (Image)getCachedImageRef(url).get();
+     }
+ 
+     /**
+      * Get an image ref.
+      */
+     static Ref getCachedImageRef(URL url) {
+ 	synchronized (imageRefs) {
+ 	    AppletImageRef ref = (AppletImageRef)imageRefs.get(url);
+ 	    if (ref == null) {
+ 		ref = new AppletImageRef(url);
+ 		imageRefs.put(url, ref);
+ 	    }
+ 	    return ref;
+ 	}
+     }
+ 
+     /**
+      * Flush the image cache.
+      */
+     static void flushImageCache() {
+ 	imageRefs.clear();
+     }
+ 
+     static Vector appletPanels = new Vector();
+ 
+     /**
+      * Get an applet by name.
+      */
+     public Applet getApplet(String name) {
+ 	AppletSecurity security = (AppletSecurity)System.getSecurityManager();
+ 	name = name.toLowerCase();
+ 	SocketPermission panelSp =
+ 	    new SocketPermission(panel.getCodeBase().getHost(), "connect");
+ 	for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
+ 	    AppletPanel p = (AppletPanel)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.applet;
+ 		}
+ 	    }
+ 	}
+ 	return null;
+     }
+ 
+     /**
+      * Return an enumeration of all the accessible
+      * applets on this page.
+      */
+     public Enumeration getApplets() {
+ 	AppletSecurity security = (AppletSecurity)System.getSecurityManager();
+ 	Vector v = new Vector();
+ 	SocketPermission panelSp =
+ 	    new SocketPermission(panel.getCodeBase().getHost(), "connect");
+ 
+ 	for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
+ 	    AppletPanel p = (AppletPanel)e.nextElement();
+ 	    if (p.getDocumentBase().equals(panel.getDocumentBase())) {
+ 
+ 		SocketPermission sp =
+ 		    new SocketPermission(p.getCodeBase().getHost(), "connect");
+ 		if (panelSp.implies(sp)) {
+ 		    v.addElement(p.applet);
+ 		}
+ 	    }
+ 	}
+ 	return v.elements();
+     }
+ 
+     /**
+      * Ignore.
+      */
+     public void showDocument(URL url) {
+    	 PluginDebug.debug("Showing document...");
+ 	showDocument(url, "_self");
+     }
+ 
+     /**
+      * Ignore.
+      */
+     public void showDocument(URL url, String target) {
+ 	try {
+             // FIXME: change to postCallRequest
+ 	    write("url " + url + " " + target);
+ 	} catch (IOException exception) {
+ 	    // Deliberately ignore IOException.  showDocument may be
+ 	    // called from threads other than the main thread after
+ 	    // PluginMain.pluginOutputStream has been closed.
+ 	}
+     }
+ 
+     /**
+      * Show status.
+      */
+     public void showStatus(String status) {
+ 	try {
+             // FIXME: change to postCallRequest
+ 	    write("status " + status);
+ 	} catch (IOException exception) {
+ 	    // Deliberately ignore IOException.  showStatus may be
+ 	    // called from threads other than the main thread after
+ 	    // PluginMain.pluginOutputStream has been closed.
+ 	}
+     }
+ 
+     public int getWindow() {
+    	 System.out.println ("STARTING getWindow");
+    	 GetWindowPluginCallRequest request =
+    		 new GetWindowPluginCallRequest("instance " + identifier + " " +
+    				 "GetWindow", "JavaScriptGetWindow");
+    	 System.out.println ("STARTING postCallRequest");
+    	 PluginMain.postCallRequest(request);
+    	 System.out.println ("STARTING postCallRequest done");
+    	 PluginMain.write(request.message);
+    	 try {
+    		 System.out.println ("wait request 1");
+    		 synchronized(request) {
+    			 System.out.println ("wait request 2");
+    			 while (request.internal == 0)
+    				 request.wait();
+    			 System.out.println ("wait request 3");
+    		 }
+    	 } catch (InterruptedException e) {
+    		 throw new RuntimeException("Interrupted waiting for call request.",
+    				 e);
+    	 }
+
+    	 System.out.println ("STARTING getWindow DONE");
+    	 return request.internal;
+     }
+ 
+     // FIXME: make private, access via reflection.
+     public static Object getMember(int internal, String name)
+     {
+         PluginAppletSecurityContext.contexts.get(0).store.reference(name);
+         int nameID = PluginAppletSecurityContext.contexts.get(
+             0).store.getIdentifier(name);
+ 
+         // Prefix with dummy instance for convenience.
+         GetMemberPluginCallRequest request =
+             new GetMemberPluginCallRequest("instance " + 0 +
+                                            " GetMember " + internal +
+                                            " " + nameID, "JavaScriptGetMember");
+         PluginMain.postCallRequest(request);
+         PluginMain.write(request.message);
+         try {
+             System.out.println ("wait getMEM request 1");
+             synchronized(request) {
+                 System.out.println ("wait getMEM request 2");
+                 while (request.done == false)
+                     request.wait();
+                 System.out.println ("wait getMEM request 3");
+             }
+         } catch (InterruptedException e) {
+             throw new RuntimeException("Interrupted waiting for call request.",
+                                        e);
+         }
+         System.out.println (" getMember DONE");
+         return request.object;
+     }
+ 
+     public static void setMember(int internal, String name, Object value) {
+         PluginAppletSecurityContext.contexts.get(0).store.reference(name);
+         int nameID = PluginAppletSecurityContext.contexts.get(
+             0).store.getIdentifier(name);
+         PluginAppletSecurityContext.contexts.get(0).store.reference(value);
+         int valueID = PluginAppletSecurityContext.contexts.get(
+             0).store.getIdentifier(value);
+ 
+         // Prefix with dummy instance for convenience.
+         VoidPluginCallRequest request =
+             new VoidPluginCallRequest("instance " + 0 +
+                                            " SetMember " + internal +
+                                            " " + nameID + " " + valueID, "JavaScriptSetMember");
+         PluginMain.postCallRequest(request);
+         PluginMain.write(request.message);
+         try {
+             System.out.println ("wait setMem request: " + request.message);
+             System.out.println ("wait setMem request 1");
+             synchronized(request) {
+                 System.out.println ("wait setMem request 2");
+                 while (request.done == false)
+                     request.wait();
+                 System.out.println ("wait setMem request 3");
+             }
+         } catch (InterruptedException e) {
+             throw new RuntimeException("Interrupted waiting for call request.",
+                                        e);
+         }
+         System.out.println (" setMember DONE");
+     }
+ 
+     // FIXME: handle long index as well.
+     public static void setSlot(int internal, int index, Object value) {
+         PluginAppletSecurityContext.contexts.get(0).store.reference(value);
+         int valueID = PluginAppletSecurityContext.contexts.get(
+             0).store.getIdentifier(value);
+ 
+         // Prefix with dummy instance for convenience.
+         VoidPluginCallRequest request =
+             new VoidPluginCallRequest("instance " + 0 +
+                                       " SetSlot " + internal +
+                                       " " + index + " " + valueID, "JavaScriptSetSlot");
+         PluginMain.postCallRequest(request);
+         PluginMain.write(request.message);
+         try {
+             System.out.println ("wait setSlot request 1");
+             synchronized(request) {
+                 System.out.println ("wait setSlot request 2");
+                 while (request.done == false)
+                     request.wait();
+                 System.out.println ("wait setSlot request 3");
+             }
+         } catch (InterruptedException e) {
+             throw new RuntimeException("Interrupted waiting for call request.",
+                                        e);
+         }
+         System.out.println (" setSlot DONE");
+     }
+ 
+     public static Object getSlot(int internal, int index)
+     {
+         // Prefix with dummy instance for convenience.
+         GetMemberPluginCallRequest request =
+             new GetMemberPluginCallRequest("instance " + 0 +
+                                            " GetSlot " + internal +
+                                            " " + index, "JavaScriptGetSlot");
+         PluginMain.postCallRequest(request);
+         PluginMain.write(request.message);
+         try {
+             System.out.println ("wait getSlot request 1");
+             synchronized(request) {
+                 System.out.println ("wait getSlot request 2");
+                 while (request.done == false)
+                     request.wait();
+                 System.out.println ("wait getSlot request 3");
+             }
+         } catch (InterruptedException e) {
+             throw new RuntimeException("Interrupted waiting for call request.",
+                                        e);
+         }
+         System.out.println (" getSlot DONE");
+         return request.object;
+     }
+ 
+     public static Object eval(int internal, String s)
+     {
+         PluginAppletSecurityContext.contexts.get(0).store.reference(s);
+         int stringID = PluginAppletSecurityContext.contexts.get(
+             0).store.getIdentifier(s);
+         // Prefix with dummy instance for convenience.
+         // FIXME: rename GetMemberPluginCallRequest ObjectPluginCallRequest.
+         GetMemberPluginCallRequest request =
+             new GetMemberPluginCallRequest("instance " + 0 +
+                                            " Eval " + internal +
+                                            " " + stringID, "JavaScriptEval");
+         PluginMain.postCallRequest(request);
+         PluginMain.write(request.message);
+         try {
+             System.out.println ("wait eval request 1");
+             synchronized(request) {
+                 System.out.println ("wait eval request 2");
+                 while (request.done == false)
+                     request.wait();
+                 System.out.println ("wait eval request 3");
+             }
+         } catch (InterruptedException e) {
+             throw new RuntimeException("Interrupted waiting for call request.",
+                                        e);
+         }
+         System.out.println (" getSlot DONE");
+         return request.object;
+     }
+ 
+     public static void removeMember (int internal, String name) {
+         PluginAppletSecurityContext.contexts.get(0).store.reference(name);
+         int nameID = PluginAppletSecurityContext.contexts.get(
+             0).store.getIdentifier(name);
+ 
+         // Prefix with dummy instance for convenience.
+         VoidPluginCallRequest request =
+             new VoidPluginCallRequest("instance " + 0 +
+                                         " RemoveMember " + internal +
+                                         " " + nameID, "JavaScriptRemoveMember");
+         PluginMain.postCallRequest(request);
+         PluginMain.write(request.message);
+         try {
+             System.out.println ("wait removeMember request 1");
+             synchronized(request) {
+                 System.out.println ("wait removeMember request 2");
+                 while (request.done == false)
+                     request.wait();
+                 System.out.println ("wait removeMember request 3");
+             }
+         } catch (InterruptedException e) {
+             throw new RuntimeException("Interrupted waiting for call request.",
+                                        e);
+         }
+         System.out.println (" RemoveMember DONE");
+     }
+ 
+     public static Object call(int 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.
+         PluginAppletSecurityContext.contexts.get(0).store.reference(name);
+         int nameID = PluginAppletSecurityContext.contexts.get(
+             0).store.getIdentifier(name);
+         PluginAppletSecurityContext.contexts.get(0).store.reference(args);
+         int argsID = PluginAppletSecurityContext.contexts.get(
+             0).store.getIdentifier(args);
+ 
+         // Prefix with dummy instance for convenience.
+         GetMemberPluginCallRequest request =
+             new GetMemberPluginCallRequest("instance " + 0 +
+                                            " Call " + internal +
+                                            " " + nameID + " " + argsID, "JavaScriptCall");
+         PluginMain.postCallRequest(request);
+         PluginMain.write(request.message);
+         try {
+             System.out.println ("wait call request 1");
+             synchronized(request) {
+                 System.out.println ("wait call request 2");
+                 while (request.done == false)
+                     request.wait();
+                 System.out.println ("wait call request 3");
+             }
+         } catch (InterruptedException e) {
+             throw new RuntimeException("Interrupted waiting for call request.",
+                                        e);
+         }
+         System.out.println (" Call DONE");
+         return request.object;
+     }
+ 
+     public static void JavaScriptFinalize(int internal)
+     {
+         // Prefix with dummy instance for convenience.
+         VoidPluginCallRequest request =
+             new VoidPluginCallRequest("instance " + 0 +
+                                            " Finalize " + internal, "JavaScriptFinalize");
+         PluginMain.postCallRequest(request);
+         PluginMain.write(request.message);
+         try {
+             System.out.println ("wait finalize request 1");
+             synchronized(request) {
+                 System.out.println ("wait finalize request 2");
+                 while (request.done == false)
+                     request.wait();
+                 System.out.println ("wait finalize request 3");
+             }
+         } catch (InterruptedException e) {
+             throw new RuntimeException("Interrupted waiting for call request.",
+                                        e);
+         }
+         System.out.println (" finalize DONE");
+     }
+ 
+     public static String javascriptToString(int internal)
+     {
+         // Prefix with dummy instance for convenience.
+         GetMemberPluginCallRequest request =
+             new GetMemberPluginCallRequest("instance " + 0 +
+                                       " ToString " + internal, "JavaScriptToString");
+         PluginMain.postCallRequest(request);
+         PluginMain.write(request.message);
+         try {
+             System.out.println ("wait ToString request 1");
+             synchronized(request) {
+                 System.out.println ("wait ToString request 2");
+                 while (request.done == false)
+                     request.wait();
+                 System.out.println ("wait ToString request 3");
+             }
+         } catch (InterruptedException e) {
+             throw new RuntimeException("Interrupted waiting for call request.",
+                                        e);
+         }
+         System.out.println (" ToString DONE");
+         return (String) request.object;
+     }
+ 
+     // FIXME: make this private and access it from JSObject using
+     // reflection.
+     private void write(String message) throws IOException {
+         System.err.println ("WRITING 2: " + "instance " + identifier + " " + message);
+         PluginMain.write("instance " + identifier + " " + message);
+         System.err.println ("WRITING 2 DONE");
+     }
+ 
+     // FIXME: make this private and access it from JSObject using
+     // reflection.
+     private String read() throws IOException {
+         System.out.println ("READING 1");
+         String ret = PluginMain.read();
+         System.out.println ("READING 1 DONE");
+         return ret;
+     }
+ 
+     public void setStream(String key, InputStream stream)throws IOException{
+ 	// We do nothing.
+     }
+ 
+     public InputStream getStream(String key){
+ 	// We do nothing.
+ 	return null;
+     }
+ 
+     public Iterator getStreamKeys(){
+ 	// We do nothing.
+ 	return null;
+     }
+ 
+     /**
+      * System parameters.
+      */
+     static Hashtable systemParam = new Hashtable();
+ 
+     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");
+     }
+ 
+     /**
+      * Print the HTML tag.
+      */
+     public static void printTag(PrintStream out, Hashtable atts) {
+ 	out.print("<applet");
+ 
+ 	String v = (String)atts.get("codebase");
+ 	if (v != null) {
+ 	    out.print(" codebase=\"" + v + "\"");
+ 	}
+ 
+ 	v = (String)atts.get("code");
+ 	if (v == null) {
+ 	    v = "applet.class";
+ 	}
+ 	out.print(" code=\"" + v + "\"");
+ 	v = (String)atts.get("width");
+ 	if (v == null) {
+ 	    v = "150";
+ 	}
+ 	out.print(" width=" + v);
+ 
+ 	v = (String)atts.get("height");
+ 	if (v == null) {
+ 	    v = "100";
+ 	}
+ 	out.print(" height=" + v);
+ 
+ 	v = (String)atts.get("name");
+ 	if (v != null) {
+ 	    out.print(" name=\"" + v + "\"");
+ 	}
+ 	out.println(">");
+ 
+ 	// A very slow sorting algorithm
+ 	int len = atts.size();
+ 	String params[] = new String[len];
+ 	len = 0;
+ 	for (Enumeration e = atts.keys() ; e.hasMoreElements() ;) {
+ 	    String param = (String)e.nextElement();
+ 	    int i = 0;
+ 	    for (; i < len ; i++) {
+ 		if (params[i].compareTo(param) >= 0) {
+ 		    break;
+ 		}
+ 	    }
+ 	    System.arraycopy(params, i, params, i + 1, len - i);
+ 	    params[i] = param;
+ 	    len++;
+ 	}
+ 
+ 	for (int i = 0 ; i < len ; i++) {
+ 	    String param = params[i];
+ 	    if (systemParam.get(param) == null) {
+ 		out.println("<param name=" + param +
+ 			    " value=\"" + atts.get(param) + "\">");
+ 	    }
+ 	}
+ 	out.println("</applet>");
+     }
+ 
+     /**
+      * Make sure the atrributes are uptodate.
+      */
+     public void updateAtts() {
+ 	Dimension d = panel.size();
+ 	Insets in = panel.insets();
+ 	panel.atts.put("width",
+ 		       new Integer(d.width - (in.left + in.right)).toString());
+ 	panel.atts.put("height",
+ 		       new Integer(d.height - (in.top + in.bottom)).toString());
+     }
+ 
+     /**
+      * 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 {
+             panel.joinAppletThread();
+ 	    panel.release();
+         } catch (InterruptedException e) {
+             return;   // abort the reload
+         }
+ 
+         panel.createAppletThread();
+ 	panel.sendEvent(AppletPanel.APPLET_LOAD);
+ 	panel.sendEvent(AppletPanel.APPLET_INIT);
+ 	panel.sendEvent(AppletPanel.APPLET_START);
+     }
+ 
+     public int print(Graphics graphics, PageFormat pf, int pageIndex) {
+         return Printable.NO_SUCH_PAGE;
+     }
+ 
+     /**
+      * 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(AppletPanel 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 AppletPanel p = panel;
+ 
+ 	new Thread(new Runnable()
+ 	{
+ 	    public void run()
+ 	    {
+     		appletShutdown(p);
+ 		appletPanels.removeElement(p);
+ 		dispose();
+ 
+ 		if (countApplets() == 0) {
+ 		    appletSystemExit();
+ 		}
+ 	    }
+ 	}).start();
+     }
+ 
+     /**
+      * Exit the program.
+      * Exit from the program (if not stand alone) - do no clean-up
+      */
+     private void appletSystemExit() {
+ 	if (factory.isStandalone())
+ 	    System.exit(0);
+     }
+ 
+     /**
+      * How many applets are running?
+      */
+ 
+     public static int countApplets() {
+ 	return appletPanels.size();
+     }
+ 
+ 
+     /**
+      * The current character.
+      */
+     static int c;
+ 
+     /**
+      * Scan spaces.
+      */
+     public static void skipSpace(Reader in) throws IOException {
+         while ((c >= 0) &&
+ 	       ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))) {
+ 	    c = in.read();
+ 	}
+     }
+ 
+     /**
+      * Scan identifier
+      */
+     public static String scanIdentifier(Reader in) throws IOException {
+ 	StringBuffer buf = new StringBuffer();
+ 	while (true) {
+ 	    if (((c >= 'a') && (c <= 'z')) ||
+ 		((c >= 'A') && (c <= 'Z')) ||
+ 		((c >= '0') && (c <= '9')) || (c == '_')) {
+ 		buf.append((char)c);
+ 		c = in.read();
+ 	    } else {
+ 		return buf.toString();
+ 	    }
+ 	}
+     }
+ 
+     /**
+      * Scan tag
+      */
+     public static Hashtable scanTag(Reader in) throws IOException {
+ 	Hashtable atts = new Hashtable();
+ 	skipSpace(in);
+         while (c >= 0 && c != '>') {
+ 	    String att = scanIdentifier(in);
+ 	    String val = "";
+ 	    skipSpace(in);
+ 	    if (c == '=') {
+ 		int quote = -1;
+ 		c = in.read();
+ 		skipSpace(in);
+ 		if ((c == '\'') || (c == '\"')) {
+ 		    quote = c;
+ 		    c = in.read();
+ 		}
+ 		StringBuffer buf = new StringBuffer();
+                 while ((c > 0) &&
+ 		       (((quote < 0) && (c != ' ') && (c != '\t') &&
+                          (c != '\n') && (c != '\r') && (c != '>'))
+ 			|| ((quote >= 0) && (c != quote)))) {
+ 		    buf.append((char)c);
+ 		    c = in.read();
+ 		}
+ 		if (c == quote) {
+ 		    c = in.read();
+ 		}
+ 		skipSpace(in);
+ 		val = buf.toString();
+ 	    }
+ 	    System.err.println("PUT " + att + " = '" + val + "'");
+ 	    if (! val.equals("")) {
+ 		atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val);
+ 	    }
+             while (true) {
+                 if ((c == '>') || (c < 0) ||
+                     ((c >= 'a') && (c <= 'z')) ||
+                     ((c >= 'A') && (c <= 'Z')) ||
+                     ((c >= '0') && (c <= '9')) || (c == '_'))
+                     break;
+                 c = in.read();
+             }
+             //skipSpace(in);
+ 	}
+ 	return atts;
+     }
+ 
+     /* values used for placement of AppletViewer's frames */
+     private static int x = 0;
+     private static int y = 0;
+     private static final int XDELTA = 30;
+     private static final int YDELTA = XDELTA;
+ 
+     static String encoding = null;
+ 
+     static private Reader makeReader(InputStream is) {
+ 	if (encoding != null) {
+ 	    try {
+ 		return new BufferedReader(new InputStreamReader(is, encoding));
+ 	    } catch (IOException x) { }
+ 	}
+ 	InputStreamReader r = new InputStreamReader(is);
+ 	encoding = r.getEncoding();
+ 	return new BufferedReader(r);
+     }
+ 
+     /**
+      * Scan an html file for <applet> tags
+      */
+     public static void parse(int identifier, long handle, Reader in, URL url, String enc)
+         throws IOException {
+         encoding = enc;
+         parse(identifier, handle, in, url, System.out, new PluginAppletViewerFactory());
+     }
+ 
+     public static void parse(int identifier, long handle, Reader in, URL url)
+         throws IOException {
+         parse(identifier, handle, in, url, System.out, new PluginAppletViewerFactory());
+     }
+ 
+     public static void parse(int identifier, long handle, Reader in, URL url,
+                              PrintStream statusMsgStream,
+                              PluginAppletViewerFactory factory)
+         throws IOException
+     {
+    	 // <OBJECT> <EMBED> tag flags
+    	 boolean isAppletTag = false;
+    	 boolean isObjectTag = false;
+    	 boolean isEmbedTag = false;
+
+    	 // warning messages
+    	 String requiresNameWarning = amh.getMessage("parse.warning.requiresname");
+    	 String paramOutsideWarning = amh.getMessage("parse.warning.paramoutside");
+    	 String appletRequiresCodeWarning = amh.getMessage("parse.warning.applet.requirescode");
+    	 String appletRequiresHeightWarning = amh.getMessage("parse.warning.applet.requiresheight");
+    	 String appletRequiresWidthWarning = amh.getMessage("parse.warning.applet.requireswidth");
+    	 String objectRequiresCodeWarning = amh.getMessage("parse.warning.object.requirescode");
+    	 String objectRequiresHeightWarning = amh.getMessage("parse.warning.object.requiresheight");
+    	 String objectRequiresWidthWarning = amh.getMessage("parse.warning.object.requireswidth");
+    	 String embedRequiresCodeWarning = amh.getMessage("parse.warning.embed.requirescode");
+    	 String embedRequiresHeightWarning = amh.getMessage("parse.warning.embed.requiresheight");
+    	 String embedRequiresWidthWarning = amh.getMessage("parse.warning.embed.requireswidth");
+    	 String appNotLongerSupportedWarning = amh.getMessage("parse.warning.appnotLongersupported");
+
+    	 java.net.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();
+
+    	 int ydisp = 1;
+    	 Hashtable atts = null;
+
+    	 while(true) {
+    		 c = in.read();
+    		 if (c == -1)
+    			 break;
+
+    		 if (c == '<') {
+    			 c = in.read();
+    			 if (c == '/') {
+    				 c = in.read();
+    				 String nm = scanIdentifier(in);
+    				 if (nm.equalsIgnoreCase("applet") ||
+    						 nm.equalsIgnoreCase("object") ||
+    						 nm.equalsIgnoreCase("embed")) {
+
+    					 // We can't test for a code tag until </OBJECT>
+    					 // because it is a parameter, not an attribute.
+    					 if(isObjectTag) {
+    						 if (atts.get("code") == null && atts.get("object") == null) {
+    							 statusMsgStream.println(objectRequiresCodeWarning);
+    							 atts = null;
+    						 }
+    					 }
+
+    					 if (atts != null) {
+    						 // XXX 5/18 In general this code just simply
+    						 // shouldn't be part of parsing.  It's presence
+    						 // causes things to be a little too much of a
+    						 // hack.
+    						 factory.createAppletViewer(identifier, handle, x, y, url, atts);
+    						 x += XDELTA;
+    						 y += YDELTA;
+    						 // make sure we don't go too far!
+    						 Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+    						 if ((x > d.width - 300) || (y > d.height - 300)) {
+    							 x = 0;
+    							 y = 2 * ydisp * YDELTA;
+    							 ydisp++;
+    						 }
+    					 }
+    					 atts = null;
+    					 isAppletTag = false;
+    					 isObjectTag = false;
+    					 isEmbedTag = false;
+    				 }
+    			 }
+    			 else {
+    				 String nm = scanIdentifier(in);
+    				 if (nm.equalsIgnoreCase("param")) {
+    					 Hashtable t = scanTag(in);
+    					 String att = (String)t.get("name");
+    					 if (att == null) {
+    						 statusMsgStream.println(requiresNameWarning);
+    					 } else {
+    						 String val = (String)t.get("value");
+    						 if (val == null) {
+    							 statusMsgStream.println(requiresNameWarning);
+    						 } else if (atts != null) {
+    							 atts.put(att.toLowerCase(), val);
+    						 } else {
+    							 statusMsgStream.println(paramOutsideWarning);
+    						 }
+    					 }
+    				 }
+    				 else if (nm.equalsIgnoreCase("applet")) {
+    					 isAppletTag = true;
+    					 atts = scanTag(in);
+
+    					 // If there is a classid present, transform it to code tag
+    					 if (atts.get("code") == null && atts.get("classid") != null && 
+    							 ((String) atts.get("classid")).startsWith("java:")) {
+    						 //skip "java:"
+    						 atts.put("code", ((String) atts.get("classid")).substring(5));
+    					 }
+
+    					 if (atts.get("code") == null && atts.get("object") == null) {
+    						 statusMsgStream.println(appletRequiresCodeWarning);
+    						 atts = null;
+    					 }
+
+    					 if (atts.get("width") == null) {
+    						 atts.put("width", "100%");
+    					 } 
+
+    					 if (atts.get("height") == null) {
+    						 atts.put("height", "100%");
+    					 }
+    				 }
+    				 else if (nm.equalsIgnoreCase("object")) {
+    					 isObjectTag = true;
+    					 atts = scanTag(in);
+
+    					 // If there is a classid present, transform it to code tag
+    					 if (atts.get("code") == null && atts.get("classid") != null && 
+    							 ((String) atts.get("classid")).startsWith("java:")) {
+    						 //skip "java:"
+    						 atts.put("code", ((String) atts.get("classid")).substring(5));
+    					 }
+
+    					 // The <OBJECT> attribute codebase isn't what
+    					 // we want when not dealing with jars. If its 
+    					 // defined, remove it in that case.
+    					 if(atts.get("archive") == null && atts.get("codebase") != null) {
+    						 atts.remove("codebase");
+    					 }
+
+    					 if (atts.get("width") == null) {
+    						 atts.put("width", "100%");
+    					 } 
+
+    					 if (atts.get("height") == null) {
+    						 atts.put("height", "100%");
+    					 }
+    				 }
+    				 else if (nm.equalsIgnoreCase("embed")) {
+    					 isEmbedTag = true;
+    					 atts = scanTag(in);
+
+    					 // If there is a classid present, transform it to code tag
+    					 if (atts.get("code") == null && atts.get("classid") != null && 
+    							 ((String) atts.get("classid")).startsWith("java:")) {
+    						 //skip "java:"
+    						 atts.put("code", ((String) atts.get("classid")).substring(5));
+    					 }
+
+    					 if (atts.get("code") == null && atts.get("object") == null) {
+    						 statusMsgStream.println(embedRequiresCodeWarning);
+    						 atts = null;
+    					 }
+    					 
+    					 if (atts.get("width") == null) {
+    						 atts.put("width", "100%");
+    					 } 
+
+    					 if (atts.get("height") == null) {
+    						 atts.put("height", "100%");
+    					 }
+    				 }
+    				 else if (nm.equalsIgnoreCase("app")) {
+    					 statusMsgStream.println(appNotLongerSupportedWarning);
+    					 Hashtable atts2 = scanTag(in);
+    					 nm = (String)atts2.get("class");
+    					 if (nm != null) {
+    						 atts2.remove("class");
+    						 atts2.put("code", nm + ".class");
+    					 }
+    					 nm = (String)atts2.get("src");
+    					 if (nm != null) {
+    						 atts2.remove("src");
+    						 atts2.put("codebase", nm);
+    					 }
+    					 if (atts2.get("width") == null) {
+    						 atts2.put("width", "100%");
+    					 }
+    					 if (atts2.get("height") == null) {
+    						 atts2.put("height", "100%");
+    					 }
+    					 printTag(statusMsgStream, atts2);
+    					 statusMsgStream.println();
+    				 }
+    			 }
+    		 }
+    	 }
+    	 in.close();
+     }
+ 
+     /**
+      * Old main entry point.
+      *
+      * @deprecated
+      */
+     @Deprecated
+     public static void main(String args[]) throws IOException {
+         PluginMain.main(args);
+     }
+ 
+     private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer");
+ 
+     private static void checkConnect(URL url)
+     {
+ 	SecurityManager security = System.getSecurityManager();
+ 	if (security != null) {
+ 	    try {
+ 		java.security.Permission perm =
+ 		    url.openConnection().getPermission();
+ 		if (perm != null)
+ 		    security.checkPermission(perm);
+ 		else
+ 		    security.checkConnect(url.getHost(), url.getPort());
+ 	    } catch (java.io.IOException ioe) {
+ 		    security.checkConnect(url.getHost(), url.getPort());
+ 	    }
+ 	}
+     }
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/PluginCallRequest.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,56 @@
+/* PluginCallRequest -- represent Java-to-JavaScript requests
+   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. */
+
+package sun.applet;
+
+// FIXME: for each type of request extend a new (anonymous?)
+// PluginCallRequest.
+abstract class PluginCallRequest {
+    String message;
+    String returnString;
+    PluginCallRequest next;
+    boolean done = false;
+
+    public PluginCallRequest(String message, String returnString) {
+        this.message = message;
+        this.returnString = returnString;
+    }
+
+    public abstract void parseReturn(String message);
+    
+    public abstract boolean serviceable(String message);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/PluginDebug.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,13 @@
+package sun.applet;
+
+import java.io.*;
+
+public class PluginDebug {
+	
+	static final boolean DEBUG = true; 
+
+    public static void debug(String message) {
+    	if (DEBUG)
+    		System.err.println(message);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/PluginException.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,14 @@
+package sun.applet;
+
+public class PluginException extends Exception {
+
+	public PluginException (int instance, int reference, Throwable t) {
+		t.printStackTrace();
+		this.setStackTrace(t.getStackTrace());
+		
+		PluginAppletSecurityContext.contexts.get(0).store.dump();
+
+		String message = "instance " + instance + " reference " + reference + " Error " + t.getMessage();
+		PluginMain.write(message);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/PluginMain.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,533 @@
+/*
+ * Copyright 1999-2006 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.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.nio.charset.Charset;
+import java.util.*;
+
+import sun.net.www.ParseUtil;
+
+class RequestQueue {
+    PluginCallRequest head = null;
+    PluginCallRequest tail = null;
+    private int size = 0;
+
+    void post(PluginCallRequest request) {
+        if (head == null) {
+            head = tail = request;
+            tail.next = null;
+        } else {
+            tail.next = request;
+            tail = request;
+            tail.next = null;
+        }
+        
+        size++;
+    }
+
+    PluginCallRequest pop() {
+        if (head == null)
+            return null;
+
+        PluginCallRequest ret = head;
+        head = head.next;
+        ret.next = null;
+        
+        size--;
+        
+        return ret;
+    }
+    
+    int size() {
+    	return size;
+    }
+}
+
+/**
+ * The main entry point into PluginAppletViewer.
+ */
+public class PluginMain
+{
+    private static BufferedReader pluginInputReader;
+    private static StreamTokenizer pluginInputTokenizer;
+    private static BufferedWriter pluginOutputWriter;
+    // This is used in init().	Getting rid of this is desirable but depends
+    // on whether the property that uses it is necessary/standard.
+    public static final String theVersion = System.getProperty("java.version");
+
+    private static RequestQueue queue = new RequestQueue();
+
+	static LinkedList<String> readQueue = new LinkedList<String>();
+	static LinkedList<String> writeQueue = new LinkedList<String>();
+
+	static PluginMessageConsumer consumer;
+	static Boolean shuttingDown = false;
+	
+	static final boolean redirectStreams = false;
+
+    /**
+     * The main entry point into AppletViewer.
+     */
+    public static void main(String args[])
+	throws IOException
+    {
+
+    	if (args.length != 1) {
+    		// Indicate to plugin that appletviewer is installed correctly.
+    		System.exit(0);
+    	}
+
+    	int port = 0;
+    	try {
+    		port = Integer.parseInt(args[0]);
+    	} catch (NumberFormatException e) {
+    		System.err.println("Failed to parse port number: " + e);
+    		System.exit(1);
+    	}
+
+    	if (redirectStreams) {
+    		try {
+    			File errFile = new File("/tmp/java.stderr");
+    			File outFile = new File("/tmp/java.stdout");
+
+    			System.setErr(new PrintStream(new FileOutputStream(errFile)));
+    			System.setOut(new PrintStream(new FileOutputStream(outFile)));
+
+    		} catch (Exception e) {
+    			System.err.println("Unable to redirect streams");
+    			e.printStackTrace();
+    		}
+    	}
+
+    	// INSTALL THE SECURITY MANAGER
+    	init();
+
+    	System.err.println("Creating consumer...");
+    	consumer = new PluginMessageConsumer();
+
+    	beginListening(50007);
+    }
+
+    public PluginMain() {
+    	
+    	try {
+    	    File errFile = new File("/tmp/java.stderr");
+    	    File outFile = new File("/tmp/java.stdout");
+
+    	    System.setErr(new PrintStream(new FileOutputStream(errFile)));
+    	    System.setOut(new PrintStream(new FileOutputStream(outFile)));
+
+    	} catch (Exception e) {
+    	    System.err.println("Unable to redirect streams");
+    	    e.printStackTrace();
+    	}
+
+    	// INSTALL THE SECURITY MANAGER
+    	init();
+
+    	System.err.println("Creating consumer...");
+    	consumer = new PluginMessageConsumer();
+
+		beginListening(50007);
+
+    }
+
+	private static void beginListening(int port) {
+    	/*
+    	 * Code for TCP/IP communication
+    	 */ 
+    	Socket socket = null;
+
+    	try {
+    		socket = new Socket("localhost", port);
+    	} catch (Exception e) {
+    		e.printStackTrace();
+    	}
+    	
+    	System.err.println("Socket initialized. Proceeding with start()");
+
+		try {
+	    	start(socket.getInputStream(), socket.getOutputStream());
+	    	System.err.println("Streams initialized");
+		} catch (IOException ioe) {
+			ioe.printStackTrace();
+		}
+	}
+    
+    public static void postMessage(String s) {
+
+    	if (s == null || s.equals("shutdown")) {
+    	    try {
+    		// Close input/output channels to plugin.
+    		pluginInputReader.close();
+    		pluginOutputWriter.close();
+    	    } catch (IOException exception) {
+    		// Deliberately ignore IOException caused by broken
+    		// pipe since plugin may have already detached.
+    	    }
+                PluginAppletSecurityContext.contexts.get(0).store.dump();
+    	    System.err.println("APPLETVIEWER: exiting appletviewer");
+    	    System.exit(0);
+    	}
+
+   		//PluginAppletSecurityContext.contexts.get(0).store.dump();
+   		PluginDebug.debug("Plugin posted: " + s);
+
+		System.err.println("Consuming " + s);
+		consumer.consume(s);
+
+   		PluginDebug.debug("Added to queue");
+    }
+
+    private static void init() {
+	Properties avProps = new Properties();
+
+	// ADD OTHER RANDOM PROPERTIES
+	// XXX 5/18 need to revisit why these are here, is there some
+	// standard for what is available?
+
+	// Standard browser properties
+	avProps.put("browser", "sun.applet.AppletViewer");
+	avProps.put("browser.version", "1.06");
+	avProps.put("browser.vendor", "Sun Microsystems Inc.");
+	avProps.put("http.agent", "Java(tm) 2 SDK, Standard Edition v" + theVersion);
+
+	// Define which packages can be extended by applets
+	// XXX 5/19 probably not needed, not checked in AppletSecurity
+	avProps.put("package.restrict.definition.java", "true");
+	avProps.put("package.restrict.definition.sun", "true");
+
+	// Define which properties can be read by applets.
+	// A property named by "key" can be read only when its twin
+	// property "key.applet" is true.  The following ten properties
+	// are open by default.	 Any other property can be explicitly
+	// opened up by the browser user by calling appletviewer with
+	// -J-Dkey.applet=true
+	avProps.put("java.version.applet", "true");
+	avProps.put("java.vendor.applet", "true");
+	avProps.put("java.vendor.url.applet", "true");
+	avProps.put("java.class.version.applet", "true");
+	avProps.put("os.name.applet", "true");
+	avProps.put("os.version.applet", "true");
+	avProps.put("os.arch.applet", "true");
+	avProps.put("file.separator.applet", "true");
+	avProps.put("path.separator.applet", "true");
+	avProps.put("line.separator.applet", "true");
+
+	// Read in the System properties.  If something is going to be
+	// over-written, warn about it.
+	Properties sysProps = System.getProperties();
+	for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements(); ) {
+	    String key = (String) e.nextElement();
+	    String val = (String) sysProps.getProperty(key);
+	    avProps.setProperty(key, val);
+	}
+
+	// INSTALL THE PROPERTY LIST
+	System.setProperties(avProps);
+
+	// Create and install the security manager
+	System.setSecurityManager(new AppletSecurity());
+
+	// REMIND: Create and install a socket factory!
+    }
+
+    public static void handleMessage(String message) throws PluginException{
+
+    	StringTokenizer st = new StringTokenizer(message, " ");
+
+    	String type = st.nextToken();
+    	int identifier = Integer.parseInt(st.nextToken());
+
+    	String rest = "";
+    	int reference = -1;
+    	String src = null;
+
+    	String potentialReference = st.hasMoreTokens() ? st.nextToken() : "";
+
+    	// if the next token is reference, read it, else reset "rest"
+    	if (potentialReference.equals("reference")) {
+    		reference = Integer.parseInt(st.nextToken());
+    	} else {
+    		rest += potentialReference + " ";
+    	}
+
+    	String potentialSrc = st.hasMoreTokens() ? st.nextToken() : "";
+
+    	if (potentialSrc.equals("src")) {
+    		src = st.nextToken();
+    	} else {
+    		rest += potentialSrc + " ";
+    	}
+
+    	while (st.hasMoreElements()) {
+    		rest += st.nextToken();
+    		rest += " ";
+    	}
+
+    	rest = rest.trim();
+
+    	try {
+
+    		System.err.println("Breakdown -- type: " + type + " identifier: " + identifier + " reference: " + reference + " src: " + src + " rest: " + rest);
+
+    		if (rest.contains("JavaScriptGetWindow")
+    				|| rest.contains("JavaScriptGetMember")
+    				|| rest.contains("JavaScriptSetMember")
+    				|| rest.contains("JavaScriptGetSlot")
+    				|| rest.contains("JavaScriptSetSlot")
+    				|| rest.contains("JavaScriptEval")
+    				|| rest.contains("JavaScriptRemoveMember")
+    				|| rest.contains("JavaScriptCall")
+    				|| rest.contains("JavaScriptFinalize")
+    				|| rest.contains("JavaScriptToString")) {
+    			finishCallRequest(rest);
+    			return;
+    		}
+
+    		if (type.equals("instance"))
+    			PluginAppletViewer.handleMessage(identifier, reference, rest);
+    		else if (type.equals("context")) {
+    			PluginDebug.debug("Sending to PASC: " + identifier + "/" + reference + " and " + rest);
+    			PluginAppletSecurityContext.handleMessage(identifier, src, reference, rest);
+    		}
+    	} catch (Exception e) {
+    		throw new PluginException(identifier, reference, e);
+    	}
+    }
+
+    static void start(InputStream inputstream, OutputStream outputstream)
+	throws MalformedURLException, IOException
+    {
+	// Set up input and output pipes.  Use UTF-8 encoding.
+	pluginInputReader =
+	    new BufferedReader(new InputStreamReader(inputstream,
+						     Charset.forName("UTF-8")));
+        pluginInputTokenizer = new StreamTokenizer(pluginInputReader);
+        pluginInputTokenizer.resetSyntax();
+        pluginInputTokenizer.whitespaceChars('\u0000', '\u0000');
+        pluginInputTokenizer.wordChars('\u0001', '\u00FF');
+	pluginOutputWriter =
+	    new BufferedWriter(new OutputStreamWriter
+			       (outputstream, Charset.forName("UTF-8")));
+
+	
+	Thread listenerThread = new Thread() {
+
+		public void run() {
+			while (true) {
+
+				System.err.println("Waiting for data...");
+
+				int readChar = -1;
+				// blocking read, discard first character
+				try {
+					readChar = pluginInputReader.read();
+				} catch (IOException ioe) {
+					// plugin may have detached
+				}
+
+				// if not disconnected
+				if (readChar != -1) {
+					String s = read();
+					System.err.println("Got data, consuming " + s);
+					consumer.consume(s);
+				} else {
+					try {
+						// Close input/output channels to plugin.
+						pluginInputReader.close();
+						pluginOutputWriter.close();
+					} catch (IOException exception) {
+						// Deliberately ignore IOException caused by broken
+						// pipe since plugin may have already detached.
+					}
+					PluginAppletSecurityContext.contexts.get(0).store.dump();
+					System.err.println("APPLETVIEWER: exiting appletviewer");
+					System.exit(0);
+				}
+			}
+		}
+	};
+	
+	listenerThread.start();
+	
+/*
+	while(true) {
+            String message = read();
+            PluginDebug.debug(message);
+            handleMessage(message);
+            // TODO:
+            // write(queue.peek());
+	}
+*/
+    }
+
+    public static void postCallRequest(PluginCallRequest request) {
+        synchronized(queue) {
+            queue.post(request);
+        }
+    }
+
+    private static void finishCallRequest(String message) {
+        PluginDebug.debug ("DISPATCHCALLREQUESTS 1");
+        synchronized(queue) {
+        PluginDebug.debug ("DISPATCHCALLREQUESTS 2");
+            PluginCallRequest request = queue.pop();
+            
+            // make sure we give the message to the right request 
+            // in the queue.. for the love of God, MAKE SURE!
+            
+            // first let's be efficient.. if there was only one 
+            // request in queue, we're already set
+            if (queue.size() != 0) {
+
+            	int size = queue.size();
+            	int count = 0;
+
+            	while (!request.serviceable(message)) {
+            		
+            		// something is very wrong.. we have a message to 
+            		// process, but no one to service it
+            		if (count >= size) {
+            			throw new RuntimeException("Unable to find processor for message " + message);
+            		}
+            		
+        			// post request at the end of the queue
+        			queue.post(request);
+
+        			// Look at the next request
+        			request = queue.pop();
+        			
+        			count++;
+            	}
+            	
+            }
+            
+        PluginDebug.debug ("DISPATCHCALLREQUESTS 3");
+            if (request != null) {
+                PluginDebug.debug ("DISPATCHCALLREQUESTS 5");
+                synchronized(request) {
+                    request.parseReturn(message);
+                    request.notifyAll();
+                }
+        PluginDebug.debug ("DISPATCHCALLREQUESTS 6");
+        PluginDebug.debug ("DISPATCHCALLREQUESTS 7");
+            }
+        }
+        PluginDebug.debug ("DISPATCHCALLREQUESTS 8");
+    }
+
+    /**
+     * Write string to plugin.
+     * 
+     * @param message the message to write
+     *
+     * @exception IOException if an error occurs
+     */
+    static void write(String message)
+    {
+
+    	System.err.println("  PIPE: appletviewer wrote: " + message);
+        synchronized(pluginOutputWriter) {
+        	try {
+        		pluginOutputWriter.write(message, 0, message.length());
+        		pluginOutputWriter.write(0);
+        		pluginOutputWriter.flush();
+        	} catch (IOException e) {
+        		// if we are shutting down, ignore write failures as 
+        		// pipe may have closed
+        		synchronized(shuttingDown) {
+        			if (!shuttingDown) {
+        				e.printStackTrace();
+        			}
+        		}
+
+        		// either ways, if the pipe is broken, there is nothing 
+        		// we can do anymore. Don't hang around.
+        		System.err.println("Unable to write to PIPE. APPLETVIEWER exiting");        		
+        		System.exit(1);
+        	}
+		}
+
+		return;
+    /*	
+    	synchronized(writeQueue) {
+            writeQueue.add(message);
+            System.err.println("  PIPE: appletviewer wrote: " + message);
+    	}
+	*/
+
+    }
+
+    static boolean messageAvailable() {
+    	return writeQueue.size() != 0;
+    }
+
+    static String getMessage() {
+    	synchronized(writeQueue) {
+			String ret = writeQueue.size() > 0 ? writeQueue.poll() : "";
+    		return ret;
+    	}
+    }
+
+    /**
+     * Read string from plugin.
+     *
+     * @return the read string
+     *
+     * @exception IOException if an error occurs
+     */
+    static String read()
+    {
+    	try {
+    		pluginInputTokenizer.nextToken();
+    	} catch (IOException e) {
+    		throw new RuntimeException(e);
+    	}
+    	String message = pluginInputTokenizer.sval;
+    	PluginDebug.debug("  PIPE: appletviewer read: " + message);
+    	if (message == null || message.equals("shutdown")) {
+    		synchronized(shuttingDown) {
+    			shuttingDown = true;
+    		}
+    		try {
+    			// Close input/output channels to plugin.
+    			pluginInputReader.close();
+    			pluginOutputWriter.close();
+    		} catch (IOException exception) {
+    			// Deliberately ignore IOException caused by broken
+    			// pipe since plugin may have already detached.
+    		}
+    		PluginAppletSecurityContext.contexts.get(0).store.dump();
+    		System.err.println("APPLETVIEWER: exiting appletviewer");
+    		System.exit(0);
+    	}
+    	return message;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/PluginMessageConsumer.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,49 @@
+package sun.applet;
+
+import java.util.ArrayList;
+
+class PluginMessageConsumer {
+
+	int MAX_WORKERS = 3;
+	ArrayList<PluginMessageHandlerWorker> workers = new ArrayList<PluginMessageHandlerWorker>();
+
+	public PluginMessageConsumer() {
+		for (int i=0; i < MAX_WORKERS; i++) {
+			System.err.println("Creating worker " + i);
+			PluginMessageHandlerWorker worker = new PluginMessageHandlerWorker(i);
+			worker.start();
+			workers.add(worker);
+		}
+	}
+
+	public void consume(String message) {
+		
+		PluginDebug.debug("Consumer received message " + message);
+		
+		synchronized(PluginMain.readQueue) {
+			PluginMain.readQueue.add(message);
+		}
+
+		PluginDebug.debug("Message " + message + " added to queue. Looking for free worker...");
+		PluginMessageHandlerWorker worker = getFreeWorker();
+		worker.interrupt();
+	}
+
+	private PluginMessageHandlerWorker getFreeWorker() {
+		
+		// FIXME: Can be made more efficient by having an idle worker pool
+		
+		while (true) {
+			for (PluginMessageHandlerWorker worker: workers) {
+				if (worker.isFree()) {
+					PluginDebug.debug("Found free worker with id " + worker.getWorkerId());
+					return worker;
+				}
+			}
+			Thread.yield();
+		}
+
+		//throw new RuntimeException("Out of message handler workers");
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/PluginMessageHandlerWorker.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,59 @@
+package sun.applet;
+
+class PluginMessageHandlerWorker extends Thread {
+
+	private boolean free = true;
+	private int id;
+	
+	public PluginMessageHandlerWorker(int id) {
+		this.id = id;
+	}
+	
+	public void run() {
+		while (true) {
+
+			String msg = null;
+			synchronized(PluginMain.readQueue) {
+				if (PluginMain.readQueue.size() > 0) {
+					msg = PluginMain.readQueue.poll();
+				}
+			}
+			
+			if (msg != null) {
+				free = false;
+				System.err.println("Thread " + id + " picking up " + msg + " from queue...");
+
+				try {
+					PluginMain.handleMessage(msg);
+				} catch (PluginException pe) {
+					/*
+					   catch the exception and DO NOTHING. The plugin should take over after 
+					   this error and let the user know. We don't quit because otherwise the 
+					   exception will spread to the rest of the applets which is a no-no
+					 */ 
+				}
+
+				free = true;
+			} else {
+
+				// Sleep when there is nothing to do
+				try {
+					Thread.sleep(Integer.MAX_VALUE);
+					System.err.println("Consumer thread " + id + " sleeping...");
+				} catch (InterruptedException ie) {
+					System.err.println("Consumer thread " + id + " woken...");
+					// nothing.. someone woke us up, see if there 
+					// is work to do
+				}
+			}
+		}
+	}
+	
+	public int getWorkerId() {
+		return id;
+	}
+	
+	public boolean isFree() {
+		return free;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/PluginObjectStore.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,119 @@
+/* PluginObjectStore -- manage identifier-to-object mapping
+   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. */
+
+package sun.applet;
+
+import java.util.*;
+import java.lang.reflect.*;
+import java.io.*;
+
+public class PluginObjectStore
+{
+    private static HashMap<Integer, Object> objects = new HashMap();
+    private static HashMap<Integer, Integer> counts = new HashMap();
+    private static HashMap<Object, Integer> identifiers = new HashMap();
+    // FIXME:
+    //
+    // IF uniqueID == MAX_LONG, uniqueID =
+    // 0 && wrapped = true
+    //
+    // if (wrapped), check if
+    // objects.get(uniqueID) returns null
+    //
+    // if yes, use uniqueID, if no,
+    // uniqueID++ and keep checking
+    // or:
+    // stack of available ids:
+    // derefed id -> derefed id -> nextUniqueIdentifier
+    private static int nextUniqueIdentifier = 1;
+
+    public Object getObject(Integer identifier) {
+        return objects.get(identifier);
+    }
+
+    public Integer getIdentifier(Object object) {
+        if (object == null)
+            return 0;
+        return identifiers.get(object);
+    }
+
+    public void reference(Object object) {
+        Integer identifier = identifiers.get(object);
+        if (identifier == null) {
+            objects.put(nextUniqueIdentifier, object);
+            counts.put(nextUniqueIdentifier, 1);
+            identifiers.put(object, nextUniqueIdentifier);
+            System.out.println("JAVA ADDED: " + nextUniqueIdentifier);
+            System.out.println("JAVA REFERENCED: " + nextUniqueIdentifier
+                               + " to: 1");
+            nextUniqueIdentifier++;
+        } else {
+            counts.put(identifier, counts.get(identifier) + 1);
+            System.out.println("JAVA REFERENCED: " + identifier +
+                               " to: " + counts.get(identifier));
+        }
+    }
+
+    public void unreference(int identifier) {
+        Integer currentCount = counts.get(identifier);
+        if (currentCount == null)
+            System.out.println("ERROR UNREFERENCING: " + identifier);
+        if (currentCount == 1) {
+            System.out.println("JAVA DEREFERENCED: " + identifier
+                               + " to: 0");
+            Object object = objects.get(identifier);
+            objects.remove(identifier);
+            counts.remove(identifier);
+            identifiers.remove(object);
+            System.out.println("JAVA REMOVED: " + identifier);
+        } else {
+            counts.put(identifier, currentCount - 1);
+            System.out.println("JAVA DEREFERENCED: " +
+                               identifier + " to: " +
+                               counts.get(identifier));
+        }
+    }
+
+    public void dump() {
+   		Iterator i = objects.keySet().iterator();
+   		while (i.hasNext()) {
+   			Object key = i.next();
+   			System.err.println(key + "::" +  objects.get(key));
+   		}
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/TestEnv.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,172 @@
+/* TestEnv -- test JavaScript-to-Java calls
+   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. */
+
+package sun.applet;
+
+public class TestEnv
+{
+    public static int intField = 103;
+    public int intInstanceField = 7822;
+    public String stringField = "hello";
+    // z <musical G clef> <chinese water>
+    public String complexStringField = "z\uD834\uDD1E\u6C34";
+
+    public static void TestIt() {
+        System.out.println("TestIt");
+    }
+
+    public static void TestItBool(boolean arg) {
+        System.out.println("TestItBool: " + arg);
+    }
+
+    public static void TestItByte(byte arg) {
+        System.out.println("TestItByte: " + arg);
+    }
+
+    public static void TestItChar(char arg) {
+        System.out.println("TestItChar: " + arg);
+    }
+
+    public static void TestItShort(short arg) {
+        System.out.println("TestItShort: " + arg);
+    }
+
+    public static void TestItInt(int arg) {
+        System.out.println("TestItInt: " + arg);
+    }
+
+    public static void TestItLong(long arg) {
+        System.out.println("TestItLong: " + arg);
+    }
+
+    public static void TestItFloat(float arg) {
+        System.out.println("TestItFloat: " + arg);
+    }
+
+    public static void TestItDouble(double arg) {
+        System.out.println("TestItDouble: " + arg);
+    }
+
+    public static void TestItObject(TestEnv arg) {
+        System.out.println("TestItObject: " + arg);
+    }
+
+    public static void TestItObjectString(String arg) {
+        System.out.println("TestItObjectString: " + arg);
+    }
+
+    public static void TestItIntArray(int[] arg) {
+        System.out.println("TestItIntArray: " + arg);
+        for (int i = 0; i < arg.length; i++)
+            System.out.println ("ELEMENT: " + i + " " + arg[i]);
+    }
+
+    public static void TestItObjectArray(String[] arg) {
+        System.out.println("TestItObjectArray: " + arg);
+        for (int i = 0; i < arg.length; i++)
+            System.out.println ("ELEMENT: " + i + " " + arg[i]);
+    }
+
+    public static void TestItObjectArrayMulti(String[][] arg) {
+        System.out.println("TestItObjectArrayMulti: " + arg);
+        for (int i = 0; i < arg.length; i++)
+            for (int j = 0; j < arg[i].length; j++)
+                System.out.println ("ELEMENT: " + i + " " + j + " " + arg[i][j]);
+    }
+
+    public static boolean TestItBoolReturnTrue() {
+        return true;
+    }
+
+    public static boolean TestItBoolReturnFalse() {
+        return false;
+    }
+
+    public static byte TestItByteReturn() {
+        return (byte) 0xfe;
+    }
+
+    public static char TestItCharReturn() {
+        return 'K';
+    }
+
+    public static char TestItCharUnicodeReturn() {
+        return '\u6C34';
+    }
+
+    public static short TestItShortReturn() {
+        return 23;
+    }
+
+    public static int TestItIntReturn() {
+        return 3445;
+    }
+
+    public static long TestItLongReturn() {
+        return 3242883;
+    }
+
+    public static float TestItFloatReturn() {
+        return 9.21E4f;
+    }
+
+    public static double TestItDoubleReturn() {
+        return 8.33E88;
+    }
+
+    public static Object TestItObjectReturn() {
+        return new String("Thomas");
+    }
+
+    public static int[] TestItIntArrayReturn() {
+        return new int[] { 6, 7, 8 };
+    }
+
+    public static String[] TestItObjectArrayReturn() {
+        return new String[] { "Thomas", "Brigitte" };
+    }
+
+    public static String[][] TestItObjectArrayMultiReturn() {
+        return new String[][] { {"Thomas", "Brigitte"},
+                                {"Lindsay", "Michael"} };
+    }
+
+    public int TestItIntInstance(int arg) {
+        System.out.println("TestItIntInstance: " + this + " " + arg);
+        return 899;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/java/src/main/sun/applet/VoidPluginCallRequest.java	Thu Sep 18 15:49:10 2008 -0400
@@ -0,0 +1,62 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+   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. */
+
+package sun.applet;
+
+class VoidPluginCallRequest extends PluginCallRequest {
+    public VoidPluginCallRequest(String message, String returnString) {
+        super(message, returnString);
+        System.out.println ("VoidPLUGINCAlL " + message + " " + returnString);
+    }
+
+    public void parseReturn(String message) {
+        done = true;
+    }
+    
+    /**
+     * Returns whether the given message is serviceable by this object
+     * 
+     * @param message The message to service
+     * @return boolean indicating if message is serviceable
+     */
+    public boolean serviceable(String message) {
+    	return message.contains("JavaScriptFinalize") ||
+    			message.contains("JavaScriptRemoveMember") ||
+    			message.contains("JavaScriptSetMember") ||
+    			message.contains("JavaScriptSetSlot");
+    }
+}