changeset 1051:f9d81fd1466d

Merging with latest from main repo
author Deepak Bhole <dbhole@redhat.com>
date Wed, 24 Sep 2008 11:44:16 -0400
parents 30567fe7d579 (diff) d2579e023b0e (current diff)
children 098f7819fe90
files ChangeLog Makefile.am
diffstat 37 files changed, 4606 insertions(+), 4166 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Sep 22 10:39:01 2008 -0400
+++ b/ChangeLog	Wed Sep 24 11:44:16 2008 -0400
@@ -1,11 +1,63 @@
+2008-09-23  Deepak Bhole  <dbhole@redhat.com>
+	* IcedTeaPlugin.cc: Updated to call new plugin main class. Add function to
+	correctly recognize JS context.
+	* Makefile.am: Update to create new IcedTeaPlugin.jar
+	* patches/icedtea-liveconnect.patch: Update patch and remove all new .java
+	files
+	* plugin/icedtea/java/src/main/netscape/javascript/JSException.java: Moved
+	out of rt/ overlay.
+	* plugin/icedtea/java/src/main/netscape/javascript/JSObject.java: Same.
+	* plugin/icedtea/java/src/main/netscape/javascript/JSProxy.java: Same.
+	* plugin/icedtea/java/src/main/netscape/javascript/JSRunnable.java: Same.
+	* plugin/icedtea/java/src/main/netscape/javascript/JSUtil.java: Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/GetMemberPluginCallRequest.java:
+	Moved out of icedtea-liveconnect.patch and refactored.
+	* plugin/icedtea/org/classpath/icedtea/plugin/GetWindowPluginCallRequest.java:
+	Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/PluginAppletSecurityContext.java:
+	Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/PluginCallRequestFactoryImpl.java:
+	Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/PluginMain.java: Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/PluginMessageConsumer.java:
+	Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/PluginMessageHandlerWorker.java:
+	Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/PluginObjectStore.java:
+	Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/PluginStreamHandlerImpl.java:
+	Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/RequestQueue.java: Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/TestEnv.java: Same.
+	* plugin/icedtea/org/classpath/icedtea/plugin/VoidPluginCallRequest.java:
+	Same.
+	* plugin/icedtea/sun/applet/AppletSecurityContext.java: Same.
+	* plugin/icedtea/sun/applet/AppletSecurityContextManager.java: Same.
+	* plugin/icedtea/sun/applet/PluginAppletViewer.java: Same.
+	* plugin/icedtea/sun/applet/PluginCallRequest.java: Same.
+	* plugin/icedtea/sun/applet/PluginCallRequestFactory.java: Same.
+	* plugin/icedtea/sun/applet/PluginClassLoader.java: Same.
+	* plugin/icedtea/sun/applet/PluginDebug.java: Same.
+	* plugin/icedtea/sun/applet/PluginException.java: Same.
+	* plugin/icedtea/sun/applet/PluginStreamHandler.java: Same.
+	* rt/net/sourceforge/jnlp/Launcher.java: Print exception trace if launch
+	fails.
+	* rt/net/sourceforge/jnlp/runtime/JNLPRuntime.java: Set ServiceManagerStub
+	before SecurityManager is set.
+	* rt/netscape/javascript/JSException.java: Move to plugin/icedtea dir.
+	* rt/netscape/javascript/JSObject.java: Same.
+	* rt/netscape/javascript/JSProxy.java: Same.
+	* rt/netscape/javascript/JSRunnable.java: Same.
+	* rt/netscape/javascript/JSUtil.java: Same.
+
 2008-09-22  Lillian Angel  <langel@redhat.com>
-	    DJ Lucas  <dj@linuxfromscratch.org>
-
-	* Makefile.am: Added new env var JAR_ACCEPTS_STDIN_LIST.
-	* acinclude.m4: Added check to determine whether jar supports
-	stdin file args.
-	* patches/icedtea-ecj.patch: Updated patch.
-	* AUTHORS: Added DJ Lucas.
+			DJ Lucas  <dj@linuxfromscratch.org>
+
+		* Makefile.am: Added new env var JAR_ACCEPTS_STDIN_LIST.
+		* acinclude.m4: Added check to determine whether jar supports
+		stdin file args.
+		* patches/icedtea-ecj.patch: Updated patch.
+		* AUTHORS: Added DJ Lucas.
 
 2008-09-18  Lillian Angel  <langel@redhat.com>
 
--- a/IcedTeaPlugin.cc	Mon Sep 22 10:39:01 2008 -0400
+++ b/IcedTeaPlugin.cc	Wed Sep 24 11:44:16 2008 -0400
@@ -244,6 +244,7 @@
 static GError* channel_error = NULL;
 // Fully-qualified appletviewer executable.
 static char* appletviewer_executable = NULL;
+static char* extra_jars = NULL;
 static char* libjvm_so = NULL;
 
 class IcedTeaPluginFactory;
@@ -313,7 +314,10 @@
 // FIXME: create index from security context.
 #define MESSAGE_CREATE(reference)                            \
   const char* addr; \
+  char context[16]; \
   GetCurrentPageAddress(&addr); \
+  GetCurrentContextAddr(context); \
+  printf("Addr: %s , Context: %s\n", addr, context);\
 \
   nsCString message ("context ");                            \
   message.AppendInt (0);                                     \
@@ -1149,7 +1153,8 @@
 
   int IncrementContextCounter();
   void DecrementContextCounter();
-  void GetCurrentPageAddress(const char **addr);
+  nsresult GetCurrentContextAddr(char *addr);
+  nsresult GetCurrentPageAddress(const char **addr);
   int contextCounter;
 };
 
@@ -3184,9 +3189,9 @@
   PLUGIN_CHECK_RETURN ("init process", result);
 
   // FIXME: hard-coded port number.
-  char const* args[5] = { "-Xdebug", "-Xnoagent", "-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n", "sun.applet.PluginMain", "50007" };
+  char const* args[8] = { "-classpath", extra_jars, "-Xdebug", "-Xnoagent", "-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n", "org.classpath.icedtea.plugin.PluginMain", "50007" };
 //  char const* args[2] = { "sun.applet.PluginMain", "50007" };
-  result = applet_viewer_process->Run (PR_FALSE, args, 5, nsnull);
+  result = applet_viewer_process->Run (PR_FALSE, args, 8, nsnull);
   PLUGIN_CHECK_RETURN ("run process", result);
 
   // start processing thread
@@ -3763,6 +3768,7 @@
 #include <nsIPrincipal.h>
 #include <nsIScriptSecurityManager.h>
 #include <nsIURI.h>
+#include <xpcjsid.h>
 
 IcedTeaJNIEnv::IcedTeaJNIEnv (IcedTeaPluginFactory* factory)
 : factory (factory)
@@ -3801,17 +3807,69 @@
     PR_ExitMonitor(contextCounterPRMonitor);
 }
 
-void
+#include <nsIJSContextStack.h>
+
+nsresult
+IcedTeaJNIEnv::GetCurrentContextAddr(char *addr)
+{
+    PLUGIN_TRACE_JNIENV ();
+
+    // Get JSContext from stack.
+    nsCOMPtr<nsIJSContextStack> mJSContextStack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
+    if (mJSContextStack) {
+        JSContext *cx;
+        if (NS_FAILED(mJSContextStack->Peek(&cx)))
+            return NS_ERROR_FAILURE;
+
+        printf("Context1: %p\n", cx);
+
+        // address cannot be more than 8 bytes (8 bytes = 64 bits)
+		sprintf(addr, "%p", cx);
+
+        printf("Context2: %s\n", addr);
+	}
+
+	return NS_OK;
+}
+
+nsresult
 IcedTeaJNIEnv::GetCurrentPageAddress(const char **addr)
 {
+
+    PLUGIN_TRACE_JNIENV ();
+
     nsIPrincipal *prin;
 	nsCOMPtr<nsIScriptSecurityManager> sec_man(do_GetService("@mozilla.org/scriptsecuritymanager;1"));
 
-    sec_man->GetSubjectPrincipal(&prin);
+    if (sec_man) {
+    
+		PRBool isEnabled = PR_FALSE;
+    	sec_man->IsCapabilityEnabled("UniversalBrowserRead", &isEnabled);
+
+		if (isEnabled == PR_FALSE) {
+			printf("UniversalBrowserRead is NOT enabled\n");
+		} else {
+			printf("UniversalBrowserRead IS enabled\n");
+		}
+
+    	sec_man->IsCapabilityEnabled("UniversalBrowserWrite", &isEnabled);
+
+		if (isEnabled == PR_FALSE) {
+			printf("UniversalBrowserWrite is NOT enabled\n");
+		} else {
+			printf("UniversalBrowserWrite IS enabled\n");
+		}
+	}
+
+    if (sec_man)
+	{
+    	sec_man->GetSubjectPrincipal(&prin);
+	} else {
+		return NS_ERROR_FAILURE;
+	}
 
    if (prin)
    {
-
        nsIURI *uri;
        prin->GetURI(&uri);
 
@@ -3820,8 +3878,19 @@
            nsCAutoString str;
            uri->GetSpec(str);
            NS_CStringGetData(str, addr);
+	   } else {
+		   return NS_ERROR_FAILURE;
 	   }
+   } else {
+	   return NS_ERROR_FAILURE;
    }
+
+
+	nsCOMPtr<nsIJSID> js_id(do_GetService("@mozilla.org/js/xpc/ID;1"));
+	printf("JS ID is: %s\n", js_id->GetID()->ToString());
+
+    return NS_OK;
+
 }
 
 NS_IMETHODIMP
@@ -4846,15 +4915,24 @@
       return NS_ERROR_OUT_OF_MEMORY;
     }
   nsCString executable (dirname (filename));
+  nsCString jar(dirname (filename));
+  nsCString extrajars("");
   free (filename);
   filename = NULL;
 
   //executableString += nsCString ("/../../bin/pluginappletviewer");
   executable += nsCString ("/../../bin/java");
+  extrajars += jar;
+  extrajars += nsCString("/IcedTeaPlugin.jar");
+  extrajars += ":";
+  extrajars += jar;
+  extrajars += nsCString("/rt.jar");
+
   //executable += nsCString ("/client/libjvm.so");
 
   // Never freed.
   appletviewer_executable = strdup (executable.get ());
+  extra_jars = strdup (extrajars.get ());
   //libjvm_so = strdup (executable.get ());
   if (!appletviewer_executable)
     {
@@ -4862,6 +4940,12 @@
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
+  if (!extra_jars)
+    {
+      PLUGIN_ERROR ("Failed to create plugin jar name.");
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
   if (factory_created == PR_TRUE)
   {
 	  // wait for factory to initialize
--- a/Makefile.am	Mon Sep 22 10:39:01 2008 -0400
+++ b/Makefile.am	Wed Sep 24 11:44:16 2008 -0400
@@ -12,15 +12,15 @@
 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
+LIVECONNECT = $(abs_top_srcdir)/plugin/icedtea/
 else
 ICEDTEAPLUGIN_CLEAN =
 ICEDTEAPLUGIN_TARGET =
+ICEDTEAPLUGIN_JAR =
 PLUGIN_PATCH = patches/icedtea-plugin.patch
-EXCLUDE_LIVECONNECT = | grep -v 'netscape/javascript'
-LIVECONNECT_DIR =
+LIVECONNECT = 
 if ENABLE_PLUGIN
 GCJWEBPLUGIN_CLEAN = clean-gcjwebplugin
 GCJWEBPLUGIN_TARGET = gcjwebplugin.so
@@ -586,6 +586,9 @@
 	  echo WARNING make clean-patch before retrying a fix ; \
 	  false; \
 	fi
+if ENABLE_LIVECONNECT
+	cp -a plugin/icedtea/sun/applet/*java openjdk/jdk/src/share/classes/sun/applet/
+endif
 
 clean-patch:
 	rm -f stamps/patch.stamp
@@ -604,6 +607,10 @@
 	if ! test x$${all_patches_ok} = "xyes" ; then \
 	  echo "WARNING Not all patches reverted cleanly" ; \
 	fi
+	for file in plugin/icedtea/sun/applet/*java ; \
+	do \
+		rm -f openjdk/jdk/src/share/classes/sun/applet/`basename $file` ; \
+	done ;
 
 stamps/patch-fsg.stamp: stamps/extract.stamp
 	mkdir -p stamps ; \
@@ -895,7 +902,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) \
@@ -906,6 +913,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 \
@@ -946,7 +957,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) \
@@ -957,6 +968,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 \
@@ -1188,8 +1203,7 @@
 
 # rt-closed.jar class files.
 rt-source-files.txt: stamps/extract.stamp stamps/copy-source-files.stamp
-	find $(abs_top_srcdir)/rt $(abs_top_builddir)/rt -name '*.java' \
-	  $(EXCLUDE_LIVECONNECT) \
+	find $(abs_top_srcdir)/rt $(abs_top_builddir)/rt $(LIVECONNECT) -name '*.java' \
 	  | sort -u > $@
 
 stamps/rt-class-files.stamp: rt-source-files.txt
@@ -1224,10 +1238,10 @@
 	if ! test -d $(ICEDTEA_BOOT_DIR) ; \
 	then \
 	  $(JAR) cf $@ -C lib/rt com -C lib/rt java \
-            -C lib/rt javax -C lib/rt net $(LIVECONNECT_DIR) -C lib/rt sun ; \
+            -C lib/rt javax -C lib/rt net -C lib/rt sun ; \
 	else \
 	  $(ICEDTEA_BOOT_DIR)/bin/jar cf $@ -C lib/rt com -C lib/rt java \
-            -C lib/rt javax -C lib/rt net $(LIVECONNECT_DIR) -C lib/rt sun ; \
+            -C lib/rt javax -C lib/rt net -C lib/rt sun ; \
 	fi
 	if test -d bootstrap/ecj/jre/lib ; \
 	then \
@@ -1303,6 +1317,7 @@
 	  $(GTK_CFLAGS) \
 	  $(XULRUNNER_CFLAGS) \
 	  -fPIC -c -o $@ $<
+
 IcedTeaPlugin.so: IcedTeaPlugin.o
 	$(CXX) $(CXXFLAGS) \
 	  $< \
@@ -1310,6 +1325,20 @@
 	  $(XULRUNNER_LIBS) \
 	  -shared -o $@
 
+# icedtea plugin jar for java-side classes
+IcedTeaPlugin.jar:
+	mkdir -p $(BUILD_OUTPUT_DIR)/plugin/icedtea/classes
+	(cd plugin/icedtea/; \
+	  $(ICEDTEA_BOOT_DIR)/bin/javac -g \
+	  -d ../../$(BUILD_OUTPUT_DIR)/plugin/icedtea/classes \
+	  -bootclasspath $(ICEDTEA_BOOT_DIR)/jre/lib/rt.jar \
+	  netscape/javascript/*.java org/classpath/icedtea/plugin/*.java \
+	)
+
+	$(JAR) cf $@ \
+	-C $(BUILD_OUTPUT_DIR)/plugin/icedtea/classes org/classpath/icedtea/plugin \
+	-C $(BUILD_OUTPUT_DIR)/plugin/icedtea/classes netscape/javascript
+
 clean-IcedTeaPlugin:
 	rm -f IcedTeaPlugin.o
 	rm -f IcedTeaPlugin.so
--- a/patches/icedtea-liveconnect.patch	Mon Sep 22 10:39:01 2008 -0400
+++ b/patches/icedtea-liveconnect.patch	Wed Sep 24 11:44:16 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");
-+    }
-+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/netscape/javascript/JSException.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,140 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package netscape.javascript;
+
+/**
+ * JSException is an exception which is thrown when JavaScript code
+ * returns an error.
+ */
+
+public
+class JSException extends RuntimeException {
+    public static final int EXCEPTION_TYPE_EMPTY = -1;
+    public static final int EXCEPTION_TYPE_VOID = 0;
+    public static final int EXCEPTION_TYPE_OBJECT = 1;
+    public static final int EXCEPTION_TYPE_FUNCTION = 2;
+    public static final int EXCEPTION_TYPE_STRING = 3;
+    public static final int EXCEPTION_TYPE_NUMBER = 4;
+    public static final int EXCEPTION_TYPE_BOOLEAN = 5;
+    public static final int EXCEPTION_TYPE_ERROR = 6;
+
+    public String filename;
+    public int lineno;
+    public String source;
+    public int tokenIndex;
+    public int wrappedExceptionType;
+    public Object wrappedException;
+
+    /**
+     * Constructs a JSException without a detail message.
+     * A detail message is a String that describes this particular exception.
+     *
+     * @deprecated Not for public use in future versions.
+     */
+    public JSException() {
+	super();
+        filename = "unknown";
+        lineno = 0;
+        source = "";
+        tokenIndex = 0;
+	wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
+    }
+
+    /**
+     * Constructs a JSException with a detail message.
+     * A detail message is a String that describes this particular exception.
+     * @param s the detail message
+     *
+     * @deprecated Not for public use in future versions.
+     */
+    public JSException(String s) {
+	super(s);
+        filename = "unknown";
+        lineno = 0;
+        source = "";
+        tokenIndex = 0;
+	wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
+    }
+
+    /**
+     * Constructs a JSException with a wrapped JavaScript exception object.
+     * This constructor needs to be public so that Java users can throw 
+     * exceptions to JS cleanly.
+     */
+    public JSException(int wrappedExceptionType, Object wrappedException) {
+	super();
+	this.wrappedExceptionType = wrappedExceptionType;
+	this.wrappedException = wrappedException;
+    }
+    
+    /**
+     * Constructs a JSException with a detail message and all the
+     * other info that usually comes with a JavaScript error.
+     * @param s the detail message
+     *
+     * @deprecated Not for public use in future versions.
+     */
+    public JSException(String s, String filename, int lineno,
+                       String source, int tokenIndex) {
+	super(s);
+        this.filename = filename;
+        this.lineno = lineno;
+        this.source = source;
+        this.tokenIndex = tokenIndex;
+	wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
+    }
+
+    /**
+     * Instance method getWrappedExceptionType returns the int mapping of the
+     * type of the wrappedException Object.
+     */
+    public int getWrappedExceptionType() {
+	return wrappedExceptionType;
+    }
+
+    /**
+     * Instance method getWrappedException.
+     */
+    public Object getWrappedException() {
+	return wrappedException;
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/netscape/javascript/JSObject.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,258 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* more doc todo:
+ *  threads
+ *  gc
+ *  
+ *
+ */
+
+package netscape.javascript;
+
+import java.applet.Applet;
+import java.io.IOException;
+import sun.applet.PluginAppletViewer;
+
+/**
+ * JSObject allows Java to manipulate objects that are
+ * defined in JavaScript.
+ * Values passed from Java to JavaScript are converted as
+ * follows:<ul>
+ * <li>JSObject is converted to the original JavaScript object
+ * <li>Any other Java object is converted to a JavaScript wrapper,
+ *   which can be used to access methods and fields of the java object.
+ *   Converting this wrapper to a string will call the toString method
+ *   on the original object, converting to a number will call the
+ *   doubleValue method if possible and fail otherwise.  Converting
+ *   to a boolean will try to call the booleanValue method in the
+ *   same way.
+ * <li>Java arrays are wrapped with a JavaScript object that understands
+ *   array.length and array[index]
+ * <li>A Java boolean is converted to a JavaScript boolean
+ * <li>Java byte, char, short, int, long, float, and double are converted
+ *   to JavaScript numbers
+ * </ul>
+ * Values passed from JavaScript to Java are converted as follows:<ul>
+ * <li>objects which are wrappers around java objects are unwrapped
+ * <li>other objects are wrapped with a JSObject
+ * <li>strings, numbers and booleans are converted to String, Double,
+ *   and Boolean objects respectively
+ * </ul>
+ * This means that all JavaScript values show up as some kind
+ * of java.lang.Object in Java.  In order to make much use of them,
+ * you will have to cast them to the appropriate subclass of Object,
+ * e.g. <code>(String) window.getMember("name");</code> or
+ * <code>(JSObject) window.getMember("document");</code>.
+ */
+public final class JSObject {
+    /* the internal object data */
+    private int                               internal;
+    private long                              long_internal;
+
+    /**
+     * initialize
+     */
+    private static void initClass() {
+        System.err.println ("JSObject.initClass");
+    }
+
+    static {
+        System.err.println ("JSObject INITIALIZER");
+    }
+
+    /**
+     * it is illegal to construct a JSObject manually
+     */
+    // FIXME: make private!
+    public JSObject(int jsobj_addr) {
+        System.err.println ("JSObject int CONSTRUCTOR");
+        internal = jsobj_addr;
+    }
+
+    private JSObject(long jsobj_addr) {
+        System.err.println ("JSObject long CONSTRUCTOR");
+        long_internal = jsobj_addr;
+    }
+
+    /**
+     * Retrieves a named member of a JavaScript object. 
+     * Equivalent to "this.<i>name</i>" in JavaScript.
+     */
+    public Object	getMember(String name)
+    {
+        System.err.println ("JSObject.getMember " + name);
+
+        Object o = PluginAppletViewer.getMember(internal, name);
+        System.out.println ("JSObject.getMember GOT " + o);
+        return o;
+    }
+
+
+    /**
+     * Retrieves an indexed member of a JavaScript object.
+     * Equivalent to "this[<i>index</i>]" in JavaScript.
+     */
+    //    public Object		getMember(int index) { return getSlot(index); }
+    public Object	getSlot(int index)
+    {
+        System.err.println ("JSObject.getSlot " + index);
+
+        return PluginAppletViewer.getSlot(internal, index);
+    }
+
+
+    /**
+     * Sets a named member of a JavaScript object. 
+     * Equivalent to "this.<i>name</i> = <i>value</i>" in JavaScript.
+     */
+    public void 		setMember(String name, Object value)
+    {
+        System.err.println ("JSObject.setMember " + name + " " + value);
+
+        PluginAppletViewer.setMember(internal, name, value);
+    }
+
+    /**
+     * Sets an indexed member of a JavaScript object. 
+     * Equivalent to "this[<i>index</i>] = <i>value</i>" in JavaScript.
+     */
+    //    public void 		setMember(int index, Object value) {
+    //        setSlot(index, value);
+    //    }
+    public void 		setSlot(int index, Object value)
+    {
+        System.err.println ("JSObject.setSlot " + index + " " + value);
+
+        PluginAppletViewer.setSlot(internal, index, value);
+    }
+
+
+    // TODO: toString, finalize.
+
+    /**
+     * Removes a named member of a JavaScript object.
+     */
+    public void 		removeMember(String name)
+    {
+        System.err.println ("JSObject.removeMember " + name);
+
+        PluginAppletViewer.removeMember(internal, name);
+    }
+
+
+    /**
+     * Calls a JavaScript method.
+     * Equivalent to "this.<i>methodName</i>(<i>args</i>[0], <i>args</i>[1], ...)" in JavaScript.
+     */
+    public Object	call(String methodName, Object args[])
+    {
+        System.err.print ("JSObject.call " + methodName);
+        for (int i = 0; i < args.length; i++)
+            System.err.print (" " + args[i]);
+        System.err.println("");
+        return PluginAppletViewer.call(internal, methodName, args);
+    }
+
+
+    /**
+     * Evaluates a JavaScript expression. The expression is a string 
+     * of JavaScript source code which will be evaluated in the context
+     * given by "this".
+     */
+    public Object	eval(String s)
+    {
+        System.err.println("JSObject.eval " + s);
+        return PluginAppletViewer.eval(internal, s);
+    }
+
+
+    /**
+     * Converts a JSObject to a String.
+     */
+    public String        toString()
+    {
+        System.err.println("JSObject.toString");
+        return PluginAppletViewer.javascriptToString(internal);
+    }
+
+
+    // should use some sort of identifier rather than String
+    // is "property" the right word?
+    //    native String[]                         listProperties();
+
+
+    /**
+     * get a JSObject for the window containing the given applet
+     */
+    public static JSObject	getWindow(Applet applet)
+    {
+        System.err.println("JSObject.getWindow");
+        // FIXME: handle long case as well.
+        int internal = 0;
+        internal = ((PluginAppletViewer)
+                    applet.getAppletContext()).getWindow();
+        System.out.println ("GOT IT: " + internal);
+        return new JSObject(internal);
+    }
+
+
+    /**
+     * Finalization decrements the reference count on the corresponding
+     * JavaScript object.
+     */
+    protected void	finalize()
+    {
+        System.err.println("JSObject.finalize ");
+        PluginAppletViewer.JavaScriptFinalize(internal);
+    }
+
+
+    /**
+     * Override java.lang.Object.equals() because identity is not preserved
+     * with instances of JSObject.
+     */
+    public boolean equals(Object obj)
+    {
+        System.err.println("JSObject.equals " + obj);
+
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/netscape/javascript/JSProxy.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,58 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * The JSProxy interface allows applets and plugins to
+ * share javascript contexts.
+ */
+
+package netscape.javascript;
+import java.applet.Applet;
+
+public interface JSProxy {
+    Object  getMember(JSObject jso, String name);
+    Object  getSlot(JSObject jso, int index);
+    void    setMember(JSObject jso, String name, Object value);
+    void    setSlot(JSObject jso, int index, Object value);
+    void    removeMember(JSObject jso, String name);
+    Object  call(JSObject jso, String methodName, Object args[]);
+    Object  eval(JSObject jso, String s);
+    String      toString(JSObject jso);
+    JSObject    getWindow(Applet applet);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/netscape/javascript/JSRunnable.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,70 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package netscape.javascript;
+
+/**
+ * Runs a JavaScript object with a run() method in a separate thread.
+ */
+public class JSRunnable implements Runnable {
+	private JSObject runnable;
+
+	public JSRunnable(JSObject runnable) {
+		this.runnable = runnable;
+		synchronized(this) {
+			new Thread(this).start();
+			try {
+				this.wait();
+			} catch (InterruptedException ie) {
+			}
+		}
+	}
+	
+	public void run() {
+		try {
+			runnable.call("run", null);
+			synchronized(this) {
+				notifyAll();
+			}
+		} catch (Throwable t) {
+			System.err.println(t);
+			t.printStackTrace(System.err);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/netscape/javascript/JSUtil.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,59 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* ** */
+
+package netscape.javascript;
+import java.io.*;
+
+public class JSUtil {
+
+    /* Return the stack trace of an exception or error as a String */
+    public static String getStackTrace(Throwable t) {
+	ByteArrayOutputStream captureStream;
+	PrintWriter p;
+	
+	captureStream = new ByteArrayOutputStream();
+	p = new PrintWriter(captureStream);
+
+	t.printStackTrace(p);
+	p.flush();
+
+	return captureStream.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/org/classpath/icedtea/plugin/GetMemberPluginCallRequest.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,78 @@
+/* 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 org.classpath.icedtea.plugin;
+
+import sun.applet.AppletSecurityContextManager;
+import sun.applet.PluginCallRequest;
+
+public 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 = AppletSecurityContextManager.getSecurityContext(0).getObject(Integer.parseInt(args[1]));
+        setDone(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");
+    }
+    
+    public Object getObject() {
+    	return this.object;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/org/classpath/icedtea/plugin/GetWindowPluginCallRequest.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,76 @@
+/* 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 org.classpath.icedtea.plugin;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+import sun.applet.PluginCallRequest;
+
+
+public 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]);
+        setDone(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");
+    }
+
+    public Integer getObject() {
+    	return this.internal;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/org/classpath/icedtea/plugin/PluginAppletSecurityContext.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,855 @@
+/* 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 org.classpath.icedtea.plugin;
+
+import java.io.FilePermission;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import sun.applet.AppletSecurityContext;
+import sun.applet.PluginDebug;
+import sun.applet.PluginException;
+
+
+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 extends AppletSecurityContext {
+	
+	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;
+
+	public PluginAppletSecurityContext(int identifier) {
+		this.identifier = identifier;
+	}
+
+	private 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.");
+	}
+
+	private 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 void addClassLoader(String id, ClassLoader cl) {
+		this.classLoaders.put(id, cl);
+	}
+	
+	public void handleMessage(String src, int reference, 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);
+
+				final Constructor m = (Constructor) store.getObject(methodID);
+				Class[] argTypes = m.getParameterTypes();
+
+				// System.out.println ("NEWOBJ: HERE1");
+				final 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]);
+				}
+				
+				Object ret = m.newInstance(arguments);
+				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(this.streamhandler, identifier, reference, t);
+		}
+	}
+
+	private void write(int reference, String message) {
+		PluginDebug.debug("appletviewer writing " + message);
+		streamhandler.write("context " + identifier + " reference " + reference
+				+ " " + message);
+	}
+	
+	public void dumpStore() {
+		store.dump();
+	}
+
+	public Object getObject(int identifier) {
+		return store.getObject(identifier);		
+	}
+
+	public int getIdentifier(Object o) {
+		return store.getIdentifier(o);
+	}
+
+	public void store(Object o) {
+		store.reference(o);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/org/classpath/icedtea/plugin/PluginCallRequestFactoryImpl.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,22 @@
+package org.classpath.icedtea.plugin;
+
+import sun.applet.PluginCallRequest;
+import sun.applet.PluginCallRequestFactory;
+
+public class PluginCallRequestFactoryImpl implements PluginCallRequestFactory {
+
+	public PluginCallRequest getPluginCallRequest(String id, String message, String returnString) {
+
+		if (id == "member") {
+			return new GetMemberPluginCallRequest(message, returnString);
+		} else if (id == "void") {
+			return new VoidPluginCallRequest(message, returnString);
+		} else if (id == "window") {
+			return new GetWindowPluginCallRequest(message, returnString);
+		} else {
+			throw new RuntimeException ("Unknown plugin call request type requested from factory");
+		}
+		
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/org/classpath/icedtea/plugin/PluginMain.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,193 @@
+/*
+ * 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 org.classpath.icedtea.plugin;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.Socket;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import sun.applet.AppletSecurityContext;
+import sun.applet.AppletSecurityContextManager;
+import sun.applet.PluginAppletViewer;
+import sun.applet.PluginStreamHandler;
+
+/**
+ * The main entry point into PluginAppletViewer.
+ */
+public class PluginMain
+{
+	final boolean redirectStreams = true;
+	static PluginStreamHandler streamHandler;
+	
+    // 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 AppletSecurityContext securityContext;
+
+    /**
+     * 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);
+    	}
+
+    	PluginMain pm = new PluginMain();
+    	
+    }
+
+    public PluginMain() {
+    	
+    	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();
+
+    	connect(50007);
+    	
+    	securityContext = new PluginAppletSecurityContext(0);
+    	securityContext.setStreamhandler(streamHandler);
+    	AppletSecurityContextManager.addContext(0, securityContext);
+		
+		PluginAppletViewer.setStreamhandler(streamHandler);
+		PluginAppletViewer.setPluginCallRequestFactory(new PluginCallRequestFactoryImpl());
+
+		// Streams set. Start processing.
+		streamHandler.startProcessing();
+    }
+
+	public void connect(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 {
+			streamHandler = new PluginStreamHandlerImpl(socket.getInputStream(), socket.getOutputStream());
+	    	System.err.println("Streams initialized");
+		} catch (IOException ioe) {
+			ioe.printStackTrace();
+		}
+	}
+
+	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 boolean messageAvailable() {
+    	return streamHandler.messageAvailable();
+    }
+
+    static String getMessage() {
+    	return streamHandler.getMessage();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/org/classpath/icedtea/plugin/PluginMessageConsumer.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,76 @@
+package org.classpath.icedtea.plugin;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+import sun.applet.PluginDebug;
+import sun.applet.PluginStreamHandler;
+
+
+
+class PluginMessageConsumer {
+
+	int MAX_WORKERS = 3;
+	LinkedList<String> readQueue = new LinkedList<String>();
+	ArrayList<PluginMessageHandlerWorker> workers = new ArrayList<PluginMessageHandlerWorker>();
+	PluginStreamHandler streamHandler = null;
+
+	public PluginMessageConsumer(PluginStreamHandler streamHandler) {
+		
+		this.streamHandler = streamHandler;
+
+		for (int i=0; i < MAX_WORKERS; i++) {
+			System.err.println("Creating worker " + i);
+			PluginMessageHandlerWorker worker = new PluginMessageHandlerWorker(streamHandler, i);
+			worker.start();
+			workers.add(worker);
+		}
+	}
+
+	public void consume(String message) {
+		
+		PluginDebug.debug("Consumer received message " + message);
+		
+		synchronized(readQueue) {
+			readQueue.add(message);
+		}
+
+		PluginDebug.debug("Message " + message + " added to queue. Looking for free worker...");
+		final PluginMessageHandlerWorker worker = getFreeWorker();
+
+		synchronized(readQueue) {
+			if (readQueue.size() > 0) {
+				worker.setmessage(readQueue.poll());
+			}
+		}
+
+		AccessController.doPrivileged(new PrivilegedAction() {
+			public Object run () {
+				worker.interrupt();
+				return null;
+			}
+		});
+	}
+
+	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());
+					// mark it busy before returning
+					worker.busy();
+					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/org/classpath/icedtea/plugin/PluginMessageHandlerWorker.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,79 @@
+package org.classpath.icedtea.plugin;
+
+import sun.applet.PluginException;
+import sun.applet.PluginStreamHandler;
+
+class PluginMessageHandlerWorker extends Thread {
+
+	private boolean free = true;
+	private int id;
+	private String message = null;
+	PluginStreamHandler streamHandler = null;
+	
+	public PluginMessageHandlerWorker(PluginStreamHandler streamHandler, int id) {
+		this.id = id;
+		this.streamHandler = streamHandler;
+	}
+
+	public void setmessage(String message) {
+		this.message = message;
+	}
+
+	public void run() {
+		while (true) {
+
+			if (message != null) {
+				
+				// ideally, whoever returns things object should mark it 
+				// busy first, but just in case..
+				busy();
+				System.err.println("Thread " + id + " picking up " + message + " from queue...");
+
+				try {
+					streamHandler.handleMessage(message);
+				} 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
+					 */ 
+				}
+
+				this.message = null;
+			} 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
+				}
+			}
+			
+			// mark ourselves free again
+			free();
+		}
+	}
+	
+	
+	
+	public int getWorkerId() {
+		return id;
+	}
+
+	public void busy() {
+		this.free = false;
+	}
+
+	
+	public void free() {
+		this.free = true;
+	}
+	
+	public boolean isFree() {
+		return free;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/org/classpath/icedtea/plugin/PluginObjectStore.java	Wed Sep 24 11:44:16 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 org.classpath.icedtea.plugin;
+
+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/org/classpath/icedtea/plugin/PluginStreamHandlerImpl.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,362 @@
+package org.classpath.icedtea.plugin;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StreamTokenizer;
+import java.net.MalformedURLException;
+import java.nio.charset.Charset;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.LinkedList;
+import java.util.StringTokenizer;
+
+import sun.applet.AppletSecurityContextManager;
+import sun.applet.PluginAppletViewer;
+import sun.applet.PluginCallRequest;
+import sun.applet.PluginDebug;
+import sun.applet.PluginException;
+import sun.applet.PluginStreamHandler;
+
+public class PluginStreamHandlerImpl implements PluginStreamHandler {
+
+    private BufferedReader pluginInputReader;
+    private StreamTokenizer pluginInputTokenizer;
+    private BufferedWriter pluginOutputWriter;
+    
+    private RequestQueue queue = new RequestQueue();
+
+	LinkedList<String> writeQueue = new LinkedList<String>();
+
+	PluginMessageConsumer consumer;
+	Boolean shuttingDown = false;
+	
+	PluginAppletViewer pav;
+	
+    public PluginStreamHandlerImpl(InputStream inputstream, OutputStream outputstream)
+    throws MalformedURLException, IOException
+    {
+
+    	System.err.println("Current context CL=" + Thread.currentThread().getContextClassLoader());
+    	try {
+			pav = (PluginAppletViewer) ClassLoader.getSystemClassLoader().loadClass("sun.applet.PluginAppletViewer").newInstance();
+			System.err.println("Loaded: " + pav + " CL=" + pav.getClass().getClassLoader());
+		} catch (InstantiationException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (IllegalAccessException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (ClassNotFoundException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
+    	System.err.println("Creating consumer...");
+    	consumer = new PluginMessageConsumer(this);
+
+    	// 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")));
+
+    	/*
+	while(true) {
+            String message = read();
+            PluginDebug.debug(message);
+            handleMessage(message);
+            // TODO:
+            // write(queue.peek());
+	}
+    	 */
+    }
+
+    public void startProcessing() {
+
+    	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.
+    					}
+    					AppletSecurityContextManager.dumpStore(0);
+    					System.err.println("APPLETVIEWER: exiting appletviewer");
+    					System.exit(0);
+    				}
+    			}
+    		}
+    	};
+
+    	listenerThread.start();    	
+    }
+    
+    public 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.
+    	    }
+    	    AppletSecurityContextManager.dumpStore(0);
+    	    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");
+    }
+    
+    public void handleMessage(String message) throws PluginException {
+
+    	StringTokenizer st = new StringTokenizer(message, " ");
+
+    	String type = st.nextToken();
+    	final 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;
+    		}
+
+    		final int freference = reference;
+    		final String frest = rest;
+
+    		if (type.equals("instance")) {
+    			PluginAppletViewer.handleMessage(identifier, freference,frest);
+    		} else if (type.equals("context")) {
+    			PluginDebug.debug("Sending to PASC: " + identifier + "/" + reference + " and " + rest);
+    			AppletSecurityContextManager.handleMessage(identifier, src, reference, rest);
+    		}
+    	} catch (Exception e) {
+    		throw new PluginException(this, identifier, reference, e);
+    	}
+    }
+
+    public void postCallRequest(PluginCallRequest request) {
+        synchronized(queue) {
+   			queue.post(request);
+        }
+    }
+
+    private 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");
+    }
+
+    /**
+     * Read string from plugin.
+     *
+     * @return the read string
+     *
+     * @exception IOException if an error occurs
+     */
+    private 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.
+    		}
+    		AppletSecurityContextManager.dumpStore(0);
+    		System.err.println("APPLETVIEWER: exiting appletviewer");
+    		System.exit(0);
+    	}
+    	return message;
+    }
+    
+    /**
+     * Write string to plugin.
+     * 
+     * @param message the message to write
+     *
+     * @exception IOException if an error occurs
+     */
+    public 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);
+    	}
+	*/
+
+    }
+    
+    public boolean messageAvailable() {
+    	return writeQueue.size() != 0;
+    }
+
+    public String getMessage() {
+    	synchronized(writeQueue) {
+			String ret = writeQueue.size() > 0 ? writeQueue.poll() : "";
+    		return ret;
+    	}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/org/classpath/icedtea/plugin/RequestQueue.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,40 @@
+package org.classpath.icedtea.plugin;
+
+import sun.applet.PluginCallRequest;
+
+public class RequestQueue {
+    PluginCallRequest head = null;
+    PluginCallRequest tail = null;
+    private int size = 0;
+
+    public void post(PluginCallRequest request) {
+    	System.err.println("Securitymanager=" + System.getSecurityManager());
+        if (head == null) {
+            head = tail = request;
+            tail.setNext(null);
+        } else {
+            tail.setNext(request);
+            tail = request;
+            tail.setNext(null);
+        }
+        
+        size++;
+    }
+
+    public PluginCallRequest pop() {
+        if (head == null)
+            return null;
+
+        PluginCallRequest ret = head;
+        head = head.getNext();
+        ret.setNext(null);
+
+        size--;
+        
+        return ret;
+    }
+    
+    public int size() {
+    	return size;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/org/classpath/icedtea/plugin/TestEnv.java	Wed Sep 24 11:44:16 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 org.classpath.icedtea.plugin;
+
+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/org/classpath/icedtea/plugin/VoidPluginCallRequest.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,69 @@
+/* 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 org.classpath.icedtea.plugin;
+
+import sun.applet.PluginCallRequest;
+
+public class VoidPluginCallRequest extends PluginCallRequest {
+    public VoidPluginCallRequest(String message, String returnString) {
+        super(message, returnString);
+        System.out.println ("VoidPLUGINCAlL " + message + " " + returnString);
+    }
+
+    public void parseReturn(String message) {
+    	setDone(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");
+    }
+    
+    public Object getObject() {
+    	return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/sun/applet/AppletSecurityContext.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,25 @@
+package sun.applet;
+
+import java.util.HashMap;
+
+public abstract class AppletSecurityContext {
+
+	public static PluginStreamHandler streamhandler;
+
+	public static void setStreamhandler(PluginStreamHandler sh) {
+		streamhandler = sh;
+	}
+	
+	public abstract void handleMessage(String src, int reference, String message);
+	
+	public abstract void addClassLoader(String id, ClassLoader cl);
+	
+	public abstract void dumpStore();
+	
+	public abstract Object getObject(int identifier);
+	
+	public abstract int getIdentifier(Object o);
+	
+	public abstract void store(Object o);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/sun/applet/AppletSecurityContextManager.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,27 @@
+package sun.applet;
+
+import java.util.HashMap;
+
+public class AppletSecurityContextManager {
+
+	// Context identifier -> PluginAppletSecurityContext object.
+	// FIXME: make private
+	private static HashMap<Integer, AppletSecurityContext> contexts = new HashMap();
+	
+	public static void addContext(int identifier, AppletSecurityContext context) {
+		contexts.put(identifier, context);
+	}
+	
+	public static AppletSecurityContext getSecurityContext(int identifier) {
+		return contexts.get(identifier);
+	}
+
+	public static void dumpStore(int identifier) {
+		contexts.get(identifier).dumpStore();
+	}
+	
+	public static void handleMessage(int identifier, String src, int reference,	String message) {
+		System.err.println(identifier + " -- " + src + " -- " + reference + " -- " + message + " CONTEXT= " + contexts.get(identifier));
+		contexts.get(identifier).handleMessage(src, reference, message);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/sun/applet/PluginAppletViewer.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,1481 @@
+ /*
+  * Copyright 1995-2004 Sun Microsystems, Inc.  All Rights Reserved.
+  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  *
+  * This code is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU General Public License version 2 only, as
+  * published by the Free Software Foundation.  Sun designates this
+  * particular file as subject to the "Classpath" exception as provided
+  * by Sun in the LICENSE file that accompanied this code.
+  *
+  * This code is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  * version 2 for more details (a copy is included in the LICENSE file that
+  * accompanied this code).
+  *
+  * You should have received a copy of the GNU General Public License version
+  * 2 along with this work; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+  *
+  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+  * CA 95054 USA or visit www.sun.com if you need additional information or
+  * have any questions.
+  */
+ 
+ package sun.applet;
+ 
+ import java.applet.Applet;
+import java.applet.AppletContext;
+import java.applet.AudioClip;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Label;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.net.SocketPermission;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+
+import net.sourceforge.jnlp.NetxPanel;
+
+import sun.awt.AppContext;
+import sun.awt.SunToolkit;
+import sun.awt.X11.XEmbeddedFrame;
+import sun.misc.Ref;
+ 
+ /**
+  * 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();
+     
+     private static PluginStreamHandler streamhandler;
+     
+     private static PluginCallRequestFactory requestFactory;
+
+     /**
+      * Null constructor to allow instantiation via newInstance()
+      */
+     public PluginAppletViewer() {
+     }
+     
+     /**
+      * 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);
+ 
+         AccessController.doPrivileged(new PrivilegedAction() {
+             public Object run() {
+            	 	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);
+            	 	}
+                 return null;
+             }
+         });  
+
+ 	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) {
+   		 ie.printStackTrace();
+   	 }
+    }
+
+    PluginDebug.debug("Applet initialized");
+    
+    // Applet initialized. Find out it's classloader and add it to the list
+    AppletSecurityContextManager.getSecurityContext(0).addClassLoader(Integer.toString(identifier), a.getClass().getClassLoader());
+
+     }
+ 
+ 	public static void setStreamhandler(PluginStreamHandler sh) {
+		streamhandler = sh;
+	}
+     
+ 	public static void setPluginCallRequestFactory(PluginCallRequestFactory rf) {
+		requestFactory = rf;
+	}
+ 	
+     /**
+      * 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 TAG 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) {
+            		 ie.printStackTrace();
+            	 }
+             }
+
+             System.err.println ("Looking for object " + o + " panel is " + panel.getClass());
+             AppletSecurityContextManager.getSecurityContext(0).store(o);
+             System.err.println ("WRITING 1: " + "context 0 reference " + reference + " GetJavaObject "
+                                 + AppletSecurityContextManager.getSecurityContext(0).getIdentifier(o));
+             streamhandler.write("context 0 reference " + reference + " GetJavaObject "
+                              + AppletSecurityContextManager.getSecurityContext(0).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.
+    	 PrivilegedAction pa = new PrivilegedAction() {
+    		 public Object run() {
+    			 return System.getProperty("appletviewer.send.event");
+    		 }
+    	 };
+ 	String eventList = (String) AccessController.doPrivileged(pa); 
+ 
+ 	if (eventList == null) {
+ 	    // Add the standard events onto the event queue.
+ 	    panel.sendEvent(AppletPanel.APPLET_LOAD);
+ 	    panel.sendEvent(AppletPanel.APPLET_INIT);
+ 	    panel.sendEvent(AppletPanel.APPLET_START);
+ 	} else {
+ 	    // We're testing AppletViewer.  Force the specified set of events
+ 	    // onto the event queue, wait for the events to be processed, and
+ 	    // exit.
+ 
+ 	    // The list of events that will be executed is provided as a
+ 	    // ","-separated list.  No error-checking will be done on the list.
+   	    String [] events = 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
+ 	    // streamhandler.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
+ 	    // streamhandler.pluginOutputStream has been closed.
+ 	}
+     }
+ 
+     public int getWindow() {
+    	 System.out.println ("STARTING getWindow");
+    	 PluginCallRequest request = requestFactory.getPluginCallRequest("window",
+    			 							"instance " + identifier + " " + "GetWindow", 
+    			 							"JavaScriptGetWindow");
+    	 System.out.println ("STARTING postCallRequest");
+		 streamhandler.postCallRequest(request);
+    	 System.out.println ("STARTING postCallRequest done");
+    	 streamhandler.write(request.getMessage());
+    	 try {
+    		 System.out.println ("wait request 1");
+    		 synchronized(request) {
+    			 System.out.println ("wait request 2");
+    			 while ((Integer) request.getObject() == 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 (Integer) request.getObject();
+     }
+ 
+     // FIXME: make private, access via reflection.
+     public static Object getMember(int internal, String name)
+     {
+    	 AppletSecurityContextManager.getSecurityContext(0).store(name);
+         int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+ 
+         // Prefix with dummy instance for convenience.
+         PluginCallRequest request = requestFactory.getPluginCallRequest("member", 
+        		 							"instance " + 0 + " GetMember " + internal + " " + nameID, 
+        		 							"JavaScriptGetMember");
+         streamhandler.postCallRequest(request);
+         streamhandler.write(request.getMessage());
+         try {
+             System.err.println ("wait getMEM request 1");
+             synchronized(request) {
+                 System.err.println ("wait getMEM request 2");
+                 while (request.isDone() == false)
+                     request.wait();
+                 System.err.println ("wait getMEM request 3 GOT: " + request.getObject().getClass());
+             }
+         } catch (InterruptedException e) {
+             throw new RuntimeException("Interrupted waiting for call request.",
+                                        e);
+         }
+         System.err.println (" getMember DONE");
+         return request.getObject();
+     }
+ 
+     public static void setMember(int internal, String name, Object value) {
+    	 AppletSecurityContextManager.getSecurityContext(0).store(name);
+         int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+         AppletSecurityContextManager.getSecurityContext(0).store(value);
+         int valueID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(value);
+ 
+         // Prefix with dummy instance for convenience.
+         PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+        		 							"instance " + 0 + " SetMember " + internal + " " + nameID + " " + valueID, 
+        		 							"JavaScriptSetMember");
+         streamhandler.postCallRequest(request);
+         streamhandler.write(request.getMessage());
+         try {
+             System.out.println ("wait setMem request: " + request.getMessage());
+             System.out.println ("wait setMem request 1");
+             synchronized(request) {
+                 System.out.println ("wait setMem request 2");
+                 while (request.isDone() == 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) {
+    	 AppletSecurityContextManager.getSecurityContext(0).store(value);
+         int valueID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(value);
+ 
+         // Prefix with dummy instance for convenience.
+         PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+        		 						"instance " + 0 + " SetSlot " + internal + " " + index + " " + valueID, 
+        		 						"JavaScriptSetSlot");
+         streamhandler.postCallRequest(request);
+         streamhandler.write(request.getMessage());
+         try {
+             System.out.println ("wait setSlot request 1");
+             synchronized(request) {
+                 System.out.println ("wait setSlot request 2");
+                 while (request.isDone() == 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.
+         PluginCallRequest request = requestFactory.getPluginCallRequest("member", 
+        		 								"instance " + 0 + " GetSlot " + internal + " " + index, 
+        		 								"JavaScriptGetSlot");
+         streamhandler.postCallRequest(request);
+         streamhandler.write(request.getMessage());
+         try {
+             System.out.println ("wait getSlot request 1");
+             synchronized(request) {
+                 System.out.println ("wait getSlot request 2");
+                 while (request.isDone() == 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.getObject();
+     }
+ 
+     public static Object eval(int internal, String s)
+     {
+    	 AppletSecurityContextManager.getSecurityContext(0).store(s);
+         int stringID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(s);
+         // Prefix with dummy instance for convenience.
+         // FIXME: rename GetMemberPluginCallRequest ObjectPluginCallRequest.
+         PluginCallRequest request = requestFactory.getPluginCallRequest("member",	
+        		 								"instance " + 0 + " Eval " + internal + " " + stringID, 
+        		 								"JavaScriptEval");
+         streamhandler.postCallRequest(request);
+         streamhandler.write(request.getMessage());
+         try {
+             System.out.println ("wait eval request 1");
+             synchronized(request) {
+                 System.out.println ("wait eval request 2");
+                 while (request.isDone() == 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.getObject();
+     }
+ 
+     public static void removeMember (int internal, String name) {
+    	 AppletSecurityContextManager.getSecurityContext(0).store(name);
+         int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+ 
+         // Prefix with dummy instance for convenience.
+         PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+        		 						"instance " + 0 + " RemoveMember " + internal + " " + nameID, 
+        		 						"JavaScriptRemoveMember");
+         streamhandler.postCallRequest(request);
+         streamhandler.write(request.getMessage());
+         try {
+             System.out.println ("wait removeMember request 1");
+             synchronized(request) {
+                 System.out.println ("wait removeMember request 2");
+                 while (request.isDone() == 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.
+    	 AppletSecurityContextManager.getSecurityContext(0).store(name);
+         int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+         AppletSecurityContextManager.getSecurityContext(0).store(args);
+         int argsID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(args);
+ 
+         // Prefix with dummy instance for convenience.
+         PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+        		 							"instance " + 0 + " Call " + internal + " " + nameID + " " + argsID, 
+        		 							"JavaScriptCall");
+         streamhandler.postCallRequest(request);
+         streamhandler.write(request.getMessage());
+         try {
+             System.out.println ("wait call request 1");
+             synchronized(request) {
+                 System.out.println ("wait call request 2");
+                 while (request.isDone() == 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.getObject();
+     }
+ 
+     public static void JavaScriptFinalize(int internal)
+     {
+         // Prefix with dummy instance for convenience.
+         PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+        		 						"instance " + 0 + " Finalize " + internal, 
+        		 						"JavaScriptFinalize");
+         streamhandler.postCallRequest(request);
+         streamhandler.write(request.getMessage());
+         try {
+             System.out.println ("wait finalize request 1");
+             synchronized(request) {
+                 System.out.println ("wait finalize request 2");
+                 while (request.isDone() == 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.
+         PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+        		 								"instance " + 0 + " ToString " + internal, 
+        		 								"JavaScriptToString");
+         streamhandler.postCallRequest(request);
+         streamhandler.write(request.getMessage());
+         try {
+             System.out.println ("wait ToString request 1");
+             synchronized(request) {
+                 System.out.println ("wait ToString request 2");
+                 while (request.isDone() == 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.getObject();
+     }
+ 
+     // 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);
+         streamhandler.write("instance " + identifier + " " + message);
+         System.err.println ("WRITING 2 DONE");
+     }
+
+     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
+         }
+ 
+         AccessController.doPrivileged(new PrivilegedAction() {
+             public Object run() {
+            	 panel.createAppletThread();
+                 return null;
+             }
+         });     
+    
+ 	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 {
+    	 final int fIdentifier = identifier;
+    	 final long fHandle = handle;
+    	 final Reader fIn = in;
+    	 final URL fUrl = url;
+    	 PrivilegedAction pa = new PrivilegedAction() {
+    		 public Object run() {
+    			 try {
+    				 parse(fIdentifier, fHandle, fIn, fUrl, System.out, new PluginAppletViewerFactory());
+    			 } catch (IOException ioe) {
+    				 return ioe;
+    			 }
+    	         
+    			 return null;
+    		 }
+    	 };
+
+    	 Object ret = AccessController.doPrivileged(pa);
+    	 if (ret instanceof IOException) {
+    		 throw (IOException) ret;
+    	 }
+     }
+ 
+     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();
+     }
+ 
+
+     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/sun/applet/PluginCallRequest.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,85 @@
+/* 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;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+// FIXME: for each type of request extend a new (anonymous?)
+// PluginCallRequest.
+public 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 String getMessage() {
+    	return this.message;
+    }
+    
+    public String getReturnString() {
+    	return this.returnString;
+    }
+    
+    public boolean isDone() {
+    	return this.done;
+    }
+    
+    public boolean setDone(boolean done) {
+    	return this.done = done;
+    }
+    
+    public void setNext(PluginCallRequest next) {
+    	this.next = next;
+    }
+    
+    public PluginCallRequest getNext() {
+    	return this.next;
+    }
+
+    public abstract void parseReturn(String message);
+    
+    public abstract boolean serviceable(String message);
+    
+    public abstract Object getObject();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/sun/applet/PluginCallRequestFactory.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,7 @@
+package sun.applet;
+
+public interface PluginCallRequestFactory {
+
+	public PluginCallRequest getPluginCallRequest(String id, String message, String returnString);
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/sun/applet/PluginClassLoader.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,13 @@
+package sun.applet;
+
+public class PluginClassLoader extends ClassLoader {
+
+	public PluginClassLoader() {
+		super();
+	}
+
+	public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+		return super.loadClass(name, resolve);
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/sun/applet/PluginDebug.java	Wed Sep 24 11:44:16 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/sun/applet/PluginException.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,15 @@
+package sun.applet;
+
+
+public class PluginException extends Exception {
+
+	public PluginException (PluginStreamHandler sh, int instance, int reference, Throwable t) {
+		t.printStackTrace();
+		this.setStackTrace(t.getStackTrace());
+		
+		AppletSecurityContextManager.dumpStore(0);
+
+		String message = "instance " + instance + " reference " + reference + " Error " + t.getMessage();
+		sh.write(message);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/sun/applet/PluginStreamHandler.java	Wed Sep 24 11:44:16 2008 -0400
@@ -0,0 +1,20 @@
+package sun.applet;
+
+
+public interface PluginStreamHandler {
+
+	public void postMessage(String s);
+
+	public void handleMessage(String message) throws PluginException;
+
+	public void postCallRequest(PluginCallRequest request);
+
+	public void write(String message);
+
+	public boolean messageAvailable();
+
+	public String getMessage();
+	
+	public void startProcessing();
+
+}
\ No newline at end of file
--- a/rt/net/sourceforge/jnlp/Launcher.java	Mon Sep 22 10:39:01 2008 -0400
+++ b/rt/net/sourceforge/jnlp/Launcher.java	Wed Sep 24 11:44:16 2008 -0400
@@ -592,6 +592,7 @@
                 }
             }
             catch (LaunchException ex) {
+                ex.printStackTrace();
                 exception = ex;
                 // Exit if we can't launch the application.
                 System.exit(0);
--- a/rt/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Mon Sep 22 10:39:01 2008 -0400
+++ b/rt/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Wed Sep 24 11:44:16 2008 -0400
@@ -135,6 +135,8 @@
         if (baseDir == null)
             throw new IllegalStateException(JNLPRuntime.getMessage("BNoBase"));
 
+        ServiceManager.setServiceManagerStub(new XServiceManagerStub()); // ignored if we're running under Web Start
+	
         policy = new JNLPPolicy();
         security = new JNLPSecurityManager(); // side effect: create JWindow
 
@@ -143,8 +145,6 @@
             System.setSecurityManager(security);
         }
 
-        ServiceManager.setServiceManagerStub(new XServiceManagerStub()); // ignored if we're running under Web Start
-
         initialized = true;
     }
 
--- a/rt/netscape/javascript/JSException.java	Mon Sep 22 10:39:01 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code, released
- * March 31, 1998.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package netscape.javascript;
-
-/**
- * JSException is an exception which is thrown when JavaScript code
- * returns an error.
- */
-
-public
-class JSException extends RuntimeException {
-    public static final int EXCEPTION_TYPE_EMPTY = -1;
-    public static final int EXCEPTION_TYPE_VOID = 0;
-    public static final int EXCEPTION_TYPE_OBJECT = 1;
-    public static final int EXCEPTION_TYPE_FUNCTION = 2;
-    public static final int EXCEPTION_TYPE_STRING = 3;
-    public static final int EXCEPTION_TYPE_NUMBER = 4;
-    public static final int EXCEPTION_TYPE_BOOLEAN = 5;
-    public static final int EXCEPTION_TYPE_ERROR = 6;
-
-    public String filename;
-    public int lineno;
-    public String source;
-    public int tokenIndex;
-    public int wrappedExceptionType;
-    public Object wrappedException;
-
-    /**
-     * Constructs a JSException without a detail message.
-     * A detail message is a String that describes this particular exception.
-     *
-     * @deprecated Not for public use in future versions.
-     */
-    public JSException() {
-	super();
-        filename = "unknown";
-        lineno = 0;
-        source = "";
-        tokenIndex = 0;
-	wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
-    }
-
-    /**
-     * Constructs a JSException with a detail message.
-     * A detail message is a String that describes this particular exception.
-     * @param s the detail message
-     *
-     * @deprecated Not for public use in future versions.
-     */
-    public JSException(String s) {
-	super(s);
-        filename = "unknown";
-        lineno = 0;
-        source = "";
-        tokenIndex = 0;
-	wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
-    }
-
-    /**
-     * Constructs a JSException with a wrapped JavaScript exception object.
-     * This constructor needs to be public so that Java users can throw 
-     * exceptions to JS cleanly.
-     */
-    public JSException(int wrappedExceptionType, Object wrappedException) {
-	super();
-	this.wrappedExceptionType = wrappedExceptionType;
-	this.wrappedException = wrappedException;
-    }
-    
-    /**
-     * Constructs a JSException with a detail message and all the
-     * other info that usually comes with a JavaScript error.
-     * @param s the detail message
-     *
-     * @deprecated Not for public use in future versions.
-     */
-    public JSException(String s, String filename, int lineno,
-                       String source, int tokenIndex) {
-	super(s);
-        this.filename = filename;
-        this.lineno = lineno;
-        this.source = source;
-        this.tokenIndex = tokenIndex;
-	wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
-    }
-
-    /**
-     * Instance method getWrappedExceptionType returns the int mapping of the
-     * type of the wrappedException Object.
-     */
-    public int getWrappedExceptionType() {
-	return wrappedExceptionType;
-    }
-
-    /**
-     * Instance method getWrappedException.
-     */
-    public Object getWrappedException() {
-	return wrappedException;
-    }
-
-}
-
--- a/rt/netscape/javascript/JSObject.java	Mon Sep 22 10:39:01 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,258 +0,0 @@
-/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code, released
- * March 31, 1998.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/* more doc todo:
- *  threads
- *  gc
- *  
- *
- */
-
-package netscape.javascript;
-
-import java.applet.Applet;
-import java.io.IOException;
-import sun.applet.PluginAppletViewer;
-
-/**
- * JSObject allows Java to manipulate objects that are
- * defined in JavaScript.
- * Values passed from Java to JavaScript are converted as
- * follows:<ul>
- * <li>JSObject is converted to the original JavaScript object
- * <li>Any other Java object is converted to a JavaScript wrapper,
- *   which can be used to access methods and fields of the java object.
- *   Converting this wrapper to a string will call the toString method
- *   on the original object, converting to a number will call the
- *   doubleValue method if possible and fail otherwise.  Converting
- *   to a boolean will try to call the booleanValue method in the
- *   same way.
- * <li>Java arrays are wrapped with a JavaScript object that understands
- *   array.length and array[index]
- * <li>A Java boolean is converted to a JavaScript boolean
- * <li>Java byte, char, short, int, long, float, and double are converted
- *   to JavaScript numbers
- * </ul>
- * Values passed from JavaScript to Java are converted as follows:<ul>
- * <li>objects which are wrappers around java objects are unwrapped
- * <li>other objects are wrapped with a JSObject
- * <li>strings, numbers and booleans are converted to String, Double,
- *   and Boolean objects respectively
- * </ul>
- * This means that all JavaScript values show up as some kind
- * of java.lang.Object in Java.  In order to make much use of them,
- * you will have to cast them to the appropriate subclass of Object,
- * e.g. <code>(String) window.getMember("name");</code> or
- * <code>(JSObject) window.getMember("document");</code>.
- */
-public final class JSObject {
-    /* the internal object data */
-    private int                               internal;
-    private long                              long_internal;
-
-    /**
-     * initialize
-     */
-    private static void initClass() {
-        System.err.println ("JSObject.initClass");
-    }
-
-    static {
-        System.err.println ("JSObject INITIALIZER");
-    }
-
-    /**
-     * it is illegal to construct a JSObject manually
-     */
-    // FIXME: make private!
-    public JSObject(int jsobj_addr) {
-        System.err.println ("JSObject int CONSTRUCTOR");
-        internal = jsobj_addr;
-    }
-
-    private JSObject(long jsobj_addr) {
-        System.err.println ("JSObject long CONSTRUCTOR");
-        long_internal = jsobj_addr;
-    }
-
-    /**
-     * Retrieves a named member of a JavaScript object. 
-     * Equivalent to "this.<i>name</i>" in JavaScript.
-     */
-    public Object	getMember(String name)
-    {
-        System.err.println ("JSObject.getMember " + name);
-
-        Object o = PluginAppletViewer.getMember(internal, name);
-        System.out.println ("JSObject.getMember GOT " + o);
-        return o;
-    }
-
-
-    /**
-     * Retrieves an indexed member of a JavaScript object.
-     * Equivalent to "this[<i>index</i>]" in JavaScript.
-     */
-    //    public Object		getMember(int index) { return getSlot(index); }
-    public Object	getSlot(int index)
-    {
-        System.err.println ("JSObject.getSlot " + index);
-
-        return PluginAppletViewer.getSlot(internal, index);
-    }
-
-
-    /**
-     * Sets a named member of a JavaScript object. 
-     * Equivalent to "this.<i>name</i> = <i>value</i>" in JavaScript.
-     */
-    public void 		setMember(String name, Object value)
-    {
-        System.err.println ("JSObject.setMember " + name + " " + value);
-
-        PluginAppletViewer.setMember(internal, name, value);
-    }
-
-    /**
-     * Sets an indexed member of a JavaScript object. 
-     * Equivalent to "this[<i>index</i>] = <i>value</i>" in JavaScript.
-     */
-    //    public void 		setMember(int index, Object value) {
-    //        setSlot(index, value);
-    //    }
-    public void 		setSlot(int index, Object value)
-    {
-        System.err.println ("JSObject.setSlot " + index + " " + value);
-
-        PluginAppletViewer.setSlot(internal, index, value);
-    }
-
-
-    // TODO: toString, finalize.
-
-    /**
-     * Removes a named member of a JavaScript object.
-     */
-    public void 		removeMember(String name)
-    {
-        System.err.println ("JSObject.removeMember " + name);
-
-        PluginAppletViewer.removeMember(internal, name);
-    }
-
-
-    /**
-     * Calls a JavaScript method.
-     * Equivalent to "this.<i>methodName</i>(<i>args</i>[0], <i>args</i>[1], ...)" in JavaScript.
-     */
-    public Object	call(String methodName, Object args[])
-    {
-        System.err.print ("JSObject.call " + methodName);
-        for (int i = 0; i < args.length; i++)
-            System.err.print (" " + args[i]);
-        System.err.println("");
-        return PluginAppletViewer.call(internal, methodName, args);
-    }
-
-
-    /**
-     * Evaluates a JavaScript expression. The expression is a string 
-     * of JavaScript source code which will be evaluated in the context
-     * given by "this".
-     */
-    public Object	eval(String s)
-    {
-        System.err.println("JSObject.eval " + s);
-        return PluginAppletViewer.eval(internal, s);
-    }
-
-
-    /**
-     * Converts a JSObject to a String.
-     */
-    public String        toString()
-    {
-        System.err.println("JSObject.toString");
-        return PluginAppletViewer.javascriptToString(internal);
-    }
-
-
-    // should use some sort of identifier rather than String
-    // is "property" the right word?
-    //    native String[]                         listProperties();
-
-
-    /**
-     * get a JSObject for the window containing the given applet
-     */
-    public static JSObject	getWindow(Applet applet)
-    {
-        System.err.println("JSObject.getWindow");
-        // FIXME: handle long case as well.
-        int internal = 0;
-        internal = ((PluginAppletViewer)
-                    applet.getAppletContext()).getWindow();
-        System.out.println ("GOT IT: " + internal);
-        return new JSObject(internal);
-    }
-
-
-    /**
-     * Finalization decrements the reference count on the corresponding
-     * JavaScript object.
-     */
-    protected void	finalize()
-    {
-        System.err.println("JSObject.finalize ");
-        PluginAppletViewer.JavaScriptFinalize(internal);
-    }
-
-
-    /**
-     * Override java.lang.Object.equals() because identity is not preserved
-     * with instances of JSObject.
-     */
-    public boolean equals(Object obj)
-    {
-        System.err.println("JSObject.equals " + obj);
-
-        return false;
-    }
-
-}
--- a/rt/netscape/javascript/JSProxy.java	Mon Sep 22 10:39:01 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code, released
- * March 31, 1998.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/**
- * The JSProxy interface allows applets and plugins to
- * share javascript contexts.
- */
-
-package netscape.javascript;
-import java.applet.Applet;
-
-public interface JSProxy {
-    Object  getMember(JSObject jso, String name);
-    Object  getSlot(JSObject jso, int index);
-    void    setMember(JSObject jso, String name, Object value);
-    void    setSlot(JSObject jso, int index, Object value);
-    void    removeMember(JSObject jso, String name);
-    Object  call(JSObject jso, String methodName, Object args[]);
-    Object  eval(JSObject jso, String s);
-    String      toString(JSObject jso);
-    JSObject    getWindow(Applet applet);
-}
--- a/rt/netscape/javascript/JSRunnable.java	Mon Sep 22 10:39:01 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code, released
- * March 31, 1998.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package netscape.javascript;
-
-/**
- * Runs a JavaScript object with a run() method in a separate thread.
- */
-public class JSRunnable implements Runnable {
-	private JSObject runnable;
-
-	public JSRunnable(JSObject runnable) {
-		this.runnable = runnable;
-		synchronized(this) {
-			new Thread(this).start();
-			try {
-				this.wait();
-			} catch (InterruptedException ie) {
-			}
-		}
-	}
-	
-	public void run() {
-		try {
-			runnable.call("run", null);
-			synchronized(this) {
-				notifyAll();
-			}
-		} catch (Throwable t) {
-			System.err.println(t);
-			t.printStackTrace(System.err);
-		}
-	}
-}
--- a/rt/netscape/javascript/JSUtil.java	Mon Sep 22 10:39:01 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code, released
- * March 31, 1998.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-/* ** */
-
-package netscape.javascript;
-import java.io.*;
-
-public class JSUtil {
-
-    /* Return the stack trace of an exception or error as a String */
-    public static String getStackTrace(Throwable t) {
-	ByteArrayOutputStream captureStream;
-	PrintWriter p;
-	
-	captureStream = new ByteArrayOutputStream();
-	p = new PrintWriter(captureStream);
-
-	t.printStackTrace(p);
-	p.flush();
-
-	return captureStream.toString();
-    }
-}