changeset 1028:1be4e928200c

Added a JNI communication bridge between C++ and Java (commented out for now, to maintain stability from TCP) Updated processing model to handle requests in different threads, so that recursuve JS->JAVA->JS calls work (e.g.: http://www.javasonics.com/support/run_liveconnect.php?mayscript) Other bug fixes to fix exceptions and hangs
author Deepak Bhole <dbhole@redhat.com>
date Mon, 25 Aug 2008 15:15:30 -0400
parents 1842897fe307
children 94838da77197
files IcedTeaPlugin.cc patches/icedtea-liveconnect.patch
diffstat 2 files changed, 2470 insertions(+), 1279 deletions(-) [+]
line wrap: on
line diff
--- a/IcedTeaPlugin.cc	Thu Aug 21 13:02:39 2008 +0200
+++ b/IcedTeaPlugin.cc	Mon Aug 25 15:15:30 2008 -0400
@@ -134,6 +134,8 @@
 #define PLUGIN_TRACE_INSTANCE() Trace _trace ("Instance::", __func__)
 #define PLUGIN_TRACE_EVENTSINK() Trace _trace ("EventSink::", __func__)
 #define PLUGIN_TRACE_LISTENER() Trace _trace ("Listener::", __func__)
+//#define PLUGIN_TRACE_RC() Trace _trace ("ResultContainer::", __func__)
+#define PLUGIN_TRACE_RC()
 
 // Error reporting macros.
 #define PLUGIN_ERROR(message)                                       \
@@ -242,6 +244,7 @@
 static GError* channel_error = NULL;
 // Fully-qualified appletviewer executable.
 static char* appletviewer_executable = NULL;
+static char* libjvm_so = NULL;
 
 #include <nspr.h>
 
@@ -301,11 +304,20 @@
                           "void" };
 
 // FIXME: create index from security context.
-#define MESSAGE_CREATE()                                     \
+#define MESSAGE_CREATE(reference)                            \
   nsCString message ("context ");                            \
   message.AppendInt (0);                                     \
-  message += " ";                                            \
-  message += __func__;
+  message += " reference ";                                  \
+  message.AppendInt (reference);                             \
+  message += " ";											 \
+  message += __func__;                                       \
+  if (factory->resultMap[reference] == NULL) {                \
+	   factory->resultMap[reference] = new ResultContainer();  \
+	   printf("ResultMap created -- %p %d\n", factory->resultMap[reference], factory->resultMap[reference]->returnIdentifier); \
+  } \
+  else                                                      \
+	   factory->resultMap[reference]->Clear(); 
+
 
 #define MESSAGE_ADD_STRING(name)                \
   message += " ";                               \
@@ -363,55 +375,60 @@
 #define MESSAGE_SEND()                          \
   factory->SendMessageToAppletViewer (message);
 
-#define MESSAGE_RECEIVE_REFERENCE(cast, name)                           \
-  PRBool processed = PR_FALSE;                                          \
+
+#define PROCESS_PENDING_EVENTS \
+	PRBool hasPending;  \
+	factory->current->HasPendingEvents(&hasPending); \
+	if (hasPending == PR_TRUE) { \
+		PRBool processed = PR_FALSE; \
+		factory->current->ProcessNextEvent(PR_TRUE, &processed); \
+	} else { \
+		PR_Sleep(PR_INTERVAL_NO_WAIT); \
+	}
+
+#define MESSAGE_RECEIVE_REFERENCE(reference, cast, name)                \
   nsresult res = NS_OK;                                                 \
-  factory->returnIdentifier = -1;                                       \
-  printf ("RECEIVE 1\n"); \
-  while (factory->returnIdentifier == -1)                               \
+  printf ("RECEIVE 1\n");                                               \
+  while (factory->resultMap[reference]->returnIdentifier == -1)     \
     {                                                                   \
-  printf ("RECEIVE 2\n"); \
-      res = factory->current->ProcessNextEvent (PR_TRUE,                \
-                                                &processed);            \
-      PLUGIN_CHECK_RETURN (__func__, res);                              \
+      PROCESS_PENDING_EVENTS;                                           \
     }                                                                   \
   printf ("RECEIVE 3\n"); \
+  if (factory->resultMap[reference]->returnIdentifier == 0) \
+  {  \
+	  *name = NULL;                                                     \
+  } else {                                                              \
   *name =                                                               \
     reinterpret_cast<cast>                                              \
-    (factory->references.ReferenceObject (factory->returnIdentifier)); \
+    (factory->references.ReferenceObject (factory->resultMap[reference]->returnIdentifier)); \
+  } \
   printf ("RECEIVE_REFERENCE: %s result: %x = %d\n",                    \
-          __func__, *name, factory->returnIdentifier);
+          __func__, *name, factory->resultMap[reference]->returnIdentifier);
 
 // FIXME: track and free JNIIDs.
-#define MESSAGE_RECEIVE_ID(cast, id, signature)                 \
-  PRBool processed = PR_FALSE;                                  \
-  nsresult result = NS_OK;                                      \
-  factory->returnIdentifier = -1;                               \
-  while (factory->returnIdentifier == -1)                       \
-    {                                                           \
-      result = factory->current->ProcessNextEvent (PR_TRUE,     \
-                                                   &processed); \
-      PLUGIN_CHECK_RETURN (__func__, result);                   \
-    }                                                           \
-                                                                \
+#define MESSAGE_RECEIVE_ID(reference, cast, id, signature)              \
+  PRBool processed = PR_FALSE;                                          \
+  nsresult res = NS_OK;                                                 \
+  printf("RECEIVE ID 1\n");                                             \
+  while (factory->resultMap[reference]->returnIdentifier == -1)     \
+    {                                                                   \
+      PROCESS_PENDING_EVENTS;                                           \
+    }                                                                   \
+                                                                        \
   *id = reinterpret_cast<cast>                                  \
-    (new JNIID (factory->returnIdentifier, signature));
-//  \
-//   printf ("RECEIVE_ID: %s result: %x = %d, %s\n",               \
-//           __func__, *id, factory->returnIdentifier,             \
-//           signature);
-
-#define MESSAGE_RECEIVE_VALUE(type, result)                     \
-  PRBool processed = PR_FALSE;                                  \
-  nsresult res = NS_OK;                                         \
-  factory->returnValue = "";                                    \
-  while (factory->returnValue == "")                            \
-    {                                                           \
-      res = factory->current->ProcessNextEvent (PR_TRUE,        \
-                                                &processed);    \
-      PLUGIN_CHECK_RETURN (__func__, res);                      \
-    }                                                           \
-  *result = ParseValue (type, factory->returnValue);            
+    (new JNIID (factory->resultMap[reference]->returnIdentifier, signature));         \
+   printf ("RECEIVE_ID: %s result: %x = %d, %s\n",               \
+           __func__, *id, factory->resultMap[reference]->returnIdentifier,             \
+           signature);
+
+#define MESSAGE_RECEIVE_VALUE(reference, ctype, result)                    \
+  nsresult res = NS_OK;                                                    \
+  printf("RECEIVE VALUE 1\n");                                             \
+  while (factory->resultMap[reference]->returnValue == "")            \
+    {                                                                      \
+      PROCESS_PENDING_EVENTS;                                              \
+    }                                                                      \
+  *result = ParseValue (type, factory->resultMap[reference]->returnValue);            
 // \
 //   char* valueString = ValueString (type, *result);              \
 //   printf ("RECEIVE_VALUE: %s result: %x = %s\n",                \
@@ -419,72 +436,70 @@
 //   free (valueString);                                           \
 //   valueString = NULL;
 
-#define MESSAGE_RECEIVE_SIZE(result)                            \
+#define MESSAGE_RECEIVE_SIZE(reference, result)                   \
   PRBool processed = PR_FALSE;                                  \
   nsresult res = NS_OK;                                         \
-  factory->returnValue = "";                                    \
-  while (factory->returnValue == "")                            \
+  printf("RECEIVE SIZE 1\n");                                 \
+  while (factory->resultMap[reference]->returnValue == "")                        \
     {                                                           \
-      res = factory->current->ProcessNextEvent (PR_TRUE,        \
-                                                &processed);    \
-      PLUGIN_CHECK_RETURN (__func__, res);                      \
+      PROCESS_PENDING_EVENTS;                                                      \
     }                                                           \
   nsresult conversionResult;                                    \
-  *result = factory->returnValue.ToInteger (&conversionResult); \
+  *result = factory->resultMap[reference]->returnValue.ToInteger (&conversionResult); \
   PLUGIN_CHECK ("parse integer", conversionResult);             
 // \
 //   printf ("RECEIVE_SIZE: %s result: %x = %d\n",                 \
 //           __func__, result, *result);
 
 // strdup'd string must be freed by calling function.
-#define MESSAGE_RECEIVE_STRING(char_type, result)               \
+#define MESSAGE_RECEIVE_STRING(reference, char_type, result)      \
   PRBool processed = PR_FALSE;                                  \
   nsresult res = NS_OK;                                         \
-  factory->returnValue = "";                                    \
-  while (factory->returnValue == "")                            \
+  printf("RECEIVE STRING 1\n");                                 \
+  while (factory->resultMap[reference]->returnValue == "")                            \
     {                                                           \
-      res = factory->current->ProcessNextEvent (PR_TRUE,        \
-                                                &processed);    \
-      PLUGIN_CHECK_RETURN (__func__, res);                      \
+      PROCESS_PENDING_EVENTS;                                                      \
     }                                                           \
+	printf("Setting result to: %s\n", strdup (factory->resultMap[reference]->returnValue.get ())); \
   *result = reinterpret_cast<char_type const*>                  \
-    (strdup (factory->returnValue.get ()));                     
+    (strdup (factory->resultMap[reference]->returnValue.get ()));                     
 // \
 //   printf ("RECEIVE_STRING: %s result: %x = %s\n",               \
 //           __func__, result, *result);
 
 // strdup'd string must be freed by calling function.
-#define MESSAGE_RECEIVE_STRING_UCS(result)                      \
+#define MESSAGE_RECEIVE_STRING_UCS(reference, result)             \
   PRBool processed = PR_FALSE;                                  \
   nsresult res = NS_OK;                                         \
-  factory->returnValueUCS.Truncate ();                          \
-  while (factory->returnValueUCS.IsEmpty ())                    \
+  printf("RECEIVE STRING UCS 1\n");                                 \
+  while (factory->resultMap[reference]->returnValueUCS.IsEmpty())                        \
     {                                                           \
-      res = factory->current->ProcessNextEvent (PR_TRUE,        \
-                                                &processed);    \
-      PLUGIN_CHECK_RETURN (__func__, res);                      \
+      PROCESS_PENDING_EVENTS;                                                      \
     }                                                           \
-  int length = factory->returnValueUCS.Length ();               \
+  int length = factory->resultMap[reference]->returnValueUCS.Length ();               \
   jchar* newstring = static_cast<jchar*> (PR_Malloc (length));  \
   memset (newstring, 0, length);                                \
-  memcpy (newstring, factory->returnValueUCS.get (), length);   \
+  memcpy (newstring, factory->resultMap[reference]->returnValueUCS.get (), length);   \
+  std::cout << "Setting result to: " << factory->resultMap[reference]->returnValueUCS.get() << std::endl; \
   *result = static_cast<jchar const*> (newstring);
 
 // \
 //   printf ("RECEIVE_STRING: %s result: %x = %s\n",               \
 //           __func__, result, *result);
 
-#define MESSAGE_RECEIVE_BOOLEAN(result)                         \
+#define MESSAGE_RECEIVE_BOOLEAN(reference, result)                \
   PRBool processed = PR_FALSE;                                  \
   nsresult res = NS_OK;                                         \
-  factory->returnIdentifier = -1;                               \
-  while (factory->returnIdentifier == -1)                       \
+  printf("RECEIVE BOOLEAN 1\n");                             \
+  while (factory->resultMap[reference]->returnIdentifier == -1)               \
     {                                                           \
-      res = factory->current->ProcessNextEvent (PR_TRUE,        \
-                                                &processed);    \
-      PLUGIN_CHECK_RETURN (__func__, res);                      \
+      PROCESS_PENDING_EVENTS;                                                      \
     }                                                           \
-  *result = factory->returnIdentifier;
+  *result = factory->resultMap[reference]->returnIdentifier;
+//      res = factory->current->ProcessNextEvent (PR_TRUE,        \
+//                                                &processed);    \
+//      PLUGIN_CHECK_RETURN (__func__, res);                      \
+
 // \
 //   printf ("RECEIVE_BOOLEAN: %s result: %x = %s\n",              \
 //           __func__, result, *result ? "true" : "false");
@@ -524,6 +539,8 @@
 #include <nsCOMPtr.h>
 #include <nsILocalFile.h>
 #include <prthread.h>
+#include <queue>
+#include <nsIEventTarget.h>
 // // FIXME: I had to hack dist/include/xpcom/xpcom-config.h to comment
 // // out this line: #define HAVE_CPP_2BYTE_WCHAR_T 1 so that
 // // nsStringAPI.h would not trigger a compilation assertion failure:
@@ -625,8 +642,50 @@
     }
 }
 
+class ResultContainer 
+{
+	public:
+		ResultContainer();
+		~ResultContainer();
+		void Clear();
+  		PRUint32 returnIdentifier;
+		nsCString returnValue;
+		nsString returnValueUCS;
+
+};
+
+ResultContainer::ResultContainer () 
+{
+	PLUGIN_TRACE_RC();
+
+	returnIdentifier = -1;
+	returnValue.Truncate();
+	returnValueUCS.Truncate();
+}
+
+ResultContainer::~ResultContainer ()
+{
+	PLUGIN_TRACE_RC();
+
+    returnIdentifier = -1;
+	returnValue.Truncate();
+	returnValueUCS.Truncate();
+}
+
+void
+ResultContainer::Clear()
+{
+	PLUGIN_TRACE_RC();
+
+	returnIdentifier = -1;
+	returnValue.Truncate();
+	returnValueUCS.Truncate();
+}
+
 #include <nsTArray.h>
 #include <nsILiveconnect.h>
+#include <nsIProcess.h>
+#include <map>
 
 class IcedTeaJNIEnv;
 
@@ -667,16 +726,17 @@
   nsresult SetTransport (nsISocketTransport* transport);
   void Connected ();
   void Disconnected ();
+//  PRUint32 returnIdentifier;
+//  nsCString returnValue;
+//  nsString returnValueUCS;
   PRBool IsConnected ();
   nsCOMPtr<nsIAsyncInputStream> async;
   nsCOMPtr<nsIThread> current;
-  PRUint32 returnIdentifier;
-  nsCString returnValue;
-  nsString returnValueUCS;
   ReferenceHashtable references;
   // FIXME: make private?
   JNIEnv* proxyEnv;
   nsISecureEnv* secureEnv;
+  std::map<PRUint32,ResultContainer*> resultMap;
   void GetMember ();
   void SetMember ();
   void GetSlot ();
@@ -693,25 +753,53 @@
   nsresult TestAppletviewer ();
   void DisplayFailureDialog ();
   nsresult StartAppletviewer ();
+  void ProcessMessage();
+  void ConsumeMsgFromJVM();
+  nsCOMPtr<nsIThread> processThread;
   nsCOMPtr<IcedTeaEventSink> sink;
   nsCOMPtr<nsISocketTransport> transport;
   nsCOMPtr<nsIInputStream> input;
   nsCOMPtr<nsIOutputStream> output;
+  nsCOMPtr<nsIProcess> applet_viewer_process;
   PRBool connected;
   PRUint32 next_instance_identifier;
   // Does not do construction/deconstruction or reference counting.
   nsDataHashtable<nsUint32HashKey, IcedTeaPluginInstance*> instances;
   PRUint32 object_identifier_return;
+  PRMonitor *jvmMsgQueuePRMonitor;
+  std::queue<nsCString> jvmMsgQueue;
   int javascript_identifier;
   int name_identifier;
   int args_identifier;
   int string_identifier;
   int slot_index;
   int value_identifier;
+  PRBool shutting_down;
+
+/**
+ * JNI I/O related code
+ *
+ 
+  void WriteToJVM(nsCString& message);
+  void InitJVM();
+  void ReadFromJVM();
+
+  PRMonitor *jvmPRMonitor;
+  nsCOMPtr<nsIThread> readThread;
+  JavaVM *jvm;
+  JNIEnv *javaEnv;
+  jclass javaPluginClass;
+  jobject javaPluginObj;
+  jmethodID getMessageMID;
+  jmethodID postMessageMID;
+
+  */
+
 };
 
 class IcedTeaEventSink;
 
+
 class IcedTeaPluginInstance : public nsIPluginInstance,
                               public nsIJVMPluginInstance
 {
@@ -726,6 +814,7 @@
   void GetWindow ();
 
   nsIPluginInstancePeer* peer;
+  PRBool initialized;
 
 private:
 
@@ -738,12 +827,15 @@
   PRUint32 instance_identifier;
   nsCString instanceIdentifierPrefix;
 };
+
 
 #include <nsISocketProviderService.h>
 #include <nsISocketProvider.h>
 #include <nsIServerSocket.h>
 #include <nsIComponentManager.h>
 #include <nsIPluginInstance.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 class IcedTeaSocketListener : public nsIServerSocketListener
 {
@@ -1013,6 +1105,12 @@
   ~IcedTeaJNIEnv ();
 
   IcedTeaPluginFactory* factory;
+
+  PRMonitor *contextCounterPRMonitor;
+
+  int IncrementContextCounter();
+  void DecrementContextCounter();
+  int contextCounter;
 };
 
 NS_IMPL_ISUPPORTS6 (IcedTeaPluginFactory, nsIFactory, nsIPlugin, nsIJVMManager,
@@ -1029,7 +1127,8 @@
   slot_index (0),
   value_identifier (0),
   connected (PR_FALSE),
-  liveconnect (0)
+  liveconnect (0),
+  shutting_down(PR_FALSE)
 {
   PLUGIN_TRACE_FACTORY ();
   instances.Init ();
@@ -1101,6 +1200,11 @@
      getter_AddRefs (liveconnect));
   PLUGIN_CHECK_RETURN ("liveconnect", result);
 
+/*
+ * Socket initialization code for TCP/IP communication
+ *
+ */
+ 
   nsCOMPtr<nsIServerSocket> socket;
   result = manager->CreateInstanceByContractID (NS_SERVERSOCKET_CONTRACTID,
                                                 nsnull,
@@ -1110,12 +1214,22 @@
 
   // FIXME: hard-coded port
   result = socket->Init (50007, PR_TRUE, -1);
+
+
   PLUGIN_CHECK_RETURN ("socket init", result);
 
   nsCOMPtr<IcedTeaSocketListener> listener = new IcedTeaSocketListener (this);
   result = socket->AsyncListen (listener);
   PLUGIN_CHECK_RETURN ("add socket listener", result);
 
+/**
+ * JNI I/O code
+ 
+  // Initialize mutex to control access to the jvm
+  jvmPRMonitor = PR_NewMonitor();
+*/
+  jvmMsgQueuePRMonitor = PR_NewMonitor();
+
   result = StartAppletviewer ();
   PLUGIN_CHECK_RETURN ("started appletviewer", result);
 
@@ -1128,6 +1242,12 @@
   result = threadManager->GetCurrentThread (getter_AddRefs (current));
   PLUGIN_CHECK_RETURN ("current thread", result);
 
+/*
+ *
+ * Socket related code for TCP/IP communication
+ *
+ */
+ 
   PLUGIN_DEBUG ("Instance::Initialize: awaiting connection from appletviewer");
   PRBool processed;
   // FIXME: move this somewhere applet-window specific so it doesn't block page
@@ -1156,14 +1276,44 @@
   result = async->AsyncWait (this, 0, 0, current);
   PLUGIN_CHECK_RETURN ("add async wait", result);
 
-  return result;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 IcedTeaPluginFactory::Shutdown ()
 {
-  NOT_IMPLEMENTED ();
-  return NS_ERROR_NOT_IMPLEMENTED;
+  shutting_down = PR_TRUE;
+
+  nsCString shutdownStr("shutdown");
+  SendMessageToAppletViewer(shutdownStr);
+
+  // wake up process thread to tell it to shutdown
+  PRThread *prThread;
+  processThread->GetPRThread(&prThread);
+  printf("Interrupting process thread...");
+  PRStatus res = PR_Interrupt(prThread);
+  printf(" done!\n");
+
+  PRInt32 exitVal;
+  applet_viewer_process->GetExitValue(&exitVal);
+
+  PRUint32 max_sleep_time = 2000;
+  PRUint32 sleep_time = 0;
+  while ((sleep_time < max_sleep_time) && (exitVal == -1)) {
+	  printf("Appletviewer still appears to be running. Waiting...\n");
+	  PR_Sleep(200);
+	  sleep_time += 200;
+	  applet_viewer_process->GetExitValue(&exitVal);
+  }
+
+  // still running? kill it with extreme prejudice
+  applet_viewer_process->GetExitValue(&exitVal);
+  if (exitVal == -1) {
+	  printf("Appletviewer still appears to be running. Trying to kill it...\n");
+	  applet_viewer_process->Kill();
+  }
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1837,6 +1987,7 @@
 IcedTeaPluginInstance::SetWindow (nsPluginWindow* aWindow)
 {
   PLUGIN_TRACE_INSTANCE ();
+
   // Simply return if we receive a NULL window.
   if ((aWindow == NULL) || (aWindow->window == NULL))
     {
@@ -1847,6 +1998,20 @@
 
   if (window_handle)
     {
+
+       if (initialized == PR_FALSE) 
+	     {
+
+            printf("IcedTeaPluginInstance::SetWindow: Instance %p waiting for initialization...\n", this);
+
+            while (initialized == PR_FALSE) {
+              PROCESS_PENDING_EVENTS;
+//            printf("waiting for java object\n");
+            }
+
+            printf("Instance %p initialization complete...\n", this);
+       }
+
       // The window already exists.
       if (window_handle == aWindow->window)
 	{
@@ -1971,6 +2136,21 @@
 {
   PLUGIN_TRACE_INSTANCE ();
 
+  // wait for instance to initialize
+
+  if (initialized == PR_FALSE) 
+    {
+
+      printf("IcedTeaPluginInstance::SetWindow: Instance %p waiting for initialization...\n", this);
+
+      while (initialized == PR_FALSE) {
+        PROCESS_PENDING_EVENTS;
+//      printf("waiting for java object\n");
+      }
+
+      printf("Instance %p initialization complete...\n", this);
+    }
+ 
   return factory->GetJavaObject (instance_identifier, object);
 }
 
@@ -1986,19 +2166,26 @@
   // ask Java for index of CODE class
   object_identifier_return = 0;
 
+  int reference = 0;
+
   nsCString objectMessage ("instance ");
   objectMessage.AppendInt (instance_identifier);
+  objectMessage += " reference ";
+  objectMessage.AppendInt (reference);
   objectMessage += " GetJavaObject";
+  printf ("Sending object message: %s\n", objectMessage.get());
+  resultMap[reference] = new ResultContainer();
   SendMessageToAppletViewer (objectMessage);
 
   PRBool processed = PR_FALSE;
   nsresult result = NS_OK;
-  while (object_identifier_return == 0)
-    {
-      result = current->ProcessNextEvent (PR_TRUE, &processed);
-      PLUGIN_CHECK_RETURN ("wait for java object: process next event", result);
-    }
-  //printf ("GOT JAVA OBJECT IDENTIFIER: %d\n", object_identifier_return);
+
+  // wait for result
+  while (object_identifier_return == 0) {
+	  current->ProcessNextEvent(PR_TRUE, &processed);
+  }
+
+  printf ("GOT JAVA OBJECT IDENTIFIER: %d\n", object_identifier_return);
   if (object_identifier_return == 0)
     printf ("WARNING: received object identifier 0\n");
 
@@ -2052,7 +2239,21 @@
 
   printf ("  PIPE: plugin read: %s\n", message);
 
-  HandleMessage (nsCString (message));
+
+  // push message to queue
+  printf("Got response. Processing... %s\n", message);
+  PR_EnterMonitor(jvmMsgQueuePRMonitor);
+  printf("Acquired lock on queue\n");
+  jvmMsgQueue.push(nsCString(message));
+  printf("Pushed to queue\n");
+  PR_ExitMonitor(jvmMsgQueuePRMonitor);
+
+  // poke process thread
+  PRThread *prThread;
+  processThread->GetPRThread(&prThread);
+  printf("Interrupting process thread...\n");
+  PRStatus res = PR_Interrupt(prThread);
+  printf("Handler event dispatched\n");
 
   nsresult result = async->AsyncWait (this, 0, 0, current);
   PLUGIN_CHECK_RETURN ("re-add async wait", result);
@@ -2060,12 +2261,12 @@
   return NS_OK;
 }
 
-#include <nsIProcess.h>
 #include <nsIServerSocket.h>
 #include <nsNetError.h>
 #include <nsPIPluginInstancePeer.h>
 #include <nsIPluginInstanceOwner.h>
 #include <nsIRunnable.h>
+#include <iostream>
 
 class IcedTeaRunnable : public nsIRunnable
 {
@@ -2136,17 +2337,37 @@
   PLUGIN_DEBUG_TWO ("received message:", message.get());
 
   nsresult conversionResult;
-  PRUint32 space = message.FindChar (' ');
-  nsDependentCSubstring prefix = Substring (message, 0, space);
-  nsDependentCSubstring rest_prefix = Substring (message, space + 1);
-  space = rest_prefix.FindChar (' ');
-  PRUint32 identifier =
-    Substring (rest_prefix, 0, space).ToInteger (&conversionResult);
-  PLUGIN_CHECK ("parse integer", conversionResult);
-  nsDependentCSubstring rest_command = Substring (rest_prefix, space + 1);
-  space = rest_command.FindChar (' ');
-  nsDependentCSubstring command = Substring (rest_command, 0, space);
-  nsDependentCSubstring rest = Substring (rest_command, space + 1);
+  PRUint32 space;
+  char msg[message.Length()];
+  char *pch;
+
+  strcpy(msg, message.get());
+  pch = strtok (msg, " ");
+  nsDependentCSubstring prefix(pch, strlen(pch));
+  pch = strtok (NULL, " ");
+  PRUint32 identifier = nsDependentCSubstring(pch, strlen(pch)).ToInteger (&conversionResult);
+  PRUint32 reference = -1;
+
+  if (strstr(message.get(), "reference") != NULL) {
+	  pch = strtok (NULL, " "); // skip "reference" literal
+	  pch = strtok (NULL, " ");
+	  reference = nsDependentCSubstring(pch, strlen(pch)).ToInteger (&conversionResult);
+  }
+
+  pch = strtok (NULL, " ");
+  nsDependentCSubstring command(pch, strlen(pch));
+  pch = strtok (NULL, " ");
+
+  nsDependentCSubstring rest("", 0);
+  while (pch != NULL) {
+	rest += pch;
+	pch = strtok (NULL, " ");
+
+	if (pch != NULL)
+		rest += " ";
+  }
+
+  printf("Parse results: prefix: %s, identifier: %d, reference: %d, command: %s, rest: %s\n", (nsCString (prefix)).get(), identifier, reference, (nsCString (command)).get(), (nsCString (rest)).get());
 
   if (prefix == "instance")
     {
@@ -2157,6 +2378,16 @@
           if (instance != 0)
             instance->peer->ShowStatus (nsCString (rest).get ());
         }
+      else if (command == "initialized")
+        {
+          IcedTeaPluginInstance* instance = NULL;
+          instances.Get (identifier, &instance);
+          if (instance != 0) {
+			printf("Setting instance.initialized for %p from %d ", instance, instance->initialized);
+            instance->initialized = PR_TRUE;
+			printf("to %d...\n", instance->initialized);
+		  }
+		}
       else if (command == "url")
         {
           IcedTeaPluginInstance* instance = NULL;
@@ -2179,6 +2410,8 @@
         {
           IcedTeaPluginInstance* instance = NULL;
           instances.Get (identifier, &instance);
+
+		  printf("GetWindow instance: %d\n", instance);
           if (instance != 0)
             {
               nsCOMPtr<nsIRunnable> event =
@@ -2357,6 +2590,10 @@
           NS_DispatchToMainThread (event);
           printf ("POSTING ToString DONE\n");
         }
+      else if (command == "Error")
+        {
+			// FIXME: Not yet implemented
+		}
     }
   else if (prefix == "context")
     {
@@ -2369,7 +2606,9 @@
           // object_identifier_return = rest.ToInteger (&result);
           // FIXME: replace with returnIdentifier ?
           object_identifier_return = rest.ToInteger (&conversionResult);
+          printf("Patrsed integer: %d\n", object_identifier_return);
           PLUGIN_CHECK ("parse integer", conversionResult);
+
         }
       else if (command == "FindClass"
                || command == "GetSuperclass"
@@ -2389,9 +2628,10 @@
                || command == "NewGlobalRef"
                || command == "NewArray")
         {
-          returnIdentifier = rest.ToInteger (&conversionResult);
+		  resultMap[reference]->returnIdentifier = rest.ToInteger (&conversionResult);
           PLUGIN_CHECK ("parse integer", conversionResult);
-          //printf ("GOT RETURN IDENTIFIER %d\n", returnIdentifier);
+          printf ("GOT RETURN IDENTIFIER %d\n", resultMap[reference]->returnIdentifier);
+
         }
       else if (command == "GetField"
                || command == "GetStaticField"
@@ -2401,16 +2641,19 @@
                || command == "GetStringLength"
                || command == "CallMethod")
         {
-          if (returnValue != "")
-            PLUGIN_ERROR ("Return value already defined.");
-
-          returnValue = rest;
-          //printf ("PLUGIN GOT RETURN VALUE: %s\n", returnValue);
+//          if (returnValue != "")
+//            PLUGIN_ERROR ("Return value already defined.");
+          
+		   resultMap[reference]->returnValue = rest; 
+           printf ("PLUGIN GOT RETURN VALUE: %s\n", resultMap[reference]->returnValue.get());
         }
       else if (command == "GetStringUTFChars")
         {
-          if (returnValue != "")
-            PLUGIN_ERROR ("Return value already defined.");
+//          if (returnValue != "")
+//            PLUGIN_ERROR ("Return value already defined.");
+
+
+          nsCString returnValue("");
 
           // Read byte stream into return value.
           PRUint32 offset = 0;
@@ -2430,14 +2673,18 @@
                             offset - previousOffset).ToInteger (&conversionResult, 16));
               PLUGIN_CHECK ("parse integer", conversionResult);
             }
-          // printf ("PLUGIN GOT RETURN UTF-8 STRING: %s\n", returnValue.get ());
+		  resultMap[reference]->returnValue = returnValue;
+          printf ("PLUGIN GOT RETURN UTF-8 STRING: %s\n", resultMap[reference]->returnValue.get ());
         }
       else if (command == "GetStringChars")
         {
-          if (!returnValueUCS.IsEmpty ())
-            PLUGIN_ERROR ("Return value already defined.");
+ //         if (!returnValueUCS.IsEmpty ())
+//            PLUGIN_ERROR ("Return value already defined.");
 
           // Read byte stream into return value.
+		  nsString returnValueUCS;
+		  returnValueUCS.Truncate();
+
           PRUint32 offset = 0;
           PRUint32 previousOffset = 0;
 
@@ -2462,6 +2709,7 @@
               PLUGIN_CHECK ("parse integer", conversionResult);
               // FIXME: swap on big-endian systems.
               returnValueUCS += static_cast<PRUnichar> ((high << 8) | low);
+	      std::cout << "High: " << high << " Low: " << low << " RVUCS: " << returnValueUCS.get() << std::endl;
             }
           printf ("PLUGIN GOT RETURN UTF-16 STRING: %d: ",
                   returnValueUCS.Length());
@@ -2478,15 +2726,338 @@
                 printf ("?");
             }
           printf ("\n");
+		  resultMap[reference]->returnValueUCS = returnValueUCS;
+
         }
       // Do nothing for: SetStaticField, SetField, ExceptionClear,
       // DeleteGlobalRef, DeleteLocalRef
     }
 }
 
+void IcedTeaPluginFactory::ProcessMessage ()
+{
+	while (true) {
+		printf("Process thread sleeping...\n");
+		PR_Sleep(PR_INTERVAL_NO_TIMEOUT);
+		PR_ClearInterrupt();
+
+		printf("Process thread interrupted...\n");
+
+
+		// Was I interrupted for shutting down?
+		if (shutting_down == PR_TRUE) {
+			break;
+		}
+
+		ConsumeMsgFromJVM();
+	}
+}
+
+void IcedTeaPluginFactory::ConsumeMsgFromJVM ()
+{
+	PLUGIN_TRACE_INSTANCE ();
+
+	while (!jvmMsgQueue.empty()) {
+
+    	PR_EnterMonitor(jvmMsgQueuePRMonitor);
+		nsCString message = jvmMsgQueue.front();
+		jvmMsgQueue.pop();
+    	PR_ExitMonitor(jvmMsgQueuePRMonitor);
+
+		printf("Processing %s from JVM\n", message.get());
+		HandleMessage (message);
+		printf("Processing complete\n");
+	}
+
+}
+
+
+/**
+ *
+ * JNI I/O code
+ *
+
+#include <jni.h>
+
+typedef jint (JNICALL *CreateJavaVM_t)(JavaVM **pvm, void **env, void *args);
+
+void IcedTeaPluginFactory::InitJVM ()
+{
+
+  JavaVMOption options[2];
+  JavaVMInitArgs vm_args;
+  long result;
+  jmethodID mid;
+  jfieldID fid;
+  jobject jobj;
+  int i, asize;
+
+  void *handle = dlopen(libjvm_so, RTLD_NOW);
+  if (!handle) {
+    printf("Cannot open library: %s\n", dlerror());
+  }
+
+  options[0].optionString = ".";
+  options[1].optionString = "-Djava.compiler=NONE";
+//  options[2].optionString = "-Xdebug";
+//  options[3].optionString = "-Xagent";
+//  options[4].optionString = "-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n";
+
+  vm_args.version = JNI_VERSION_1_2;
+  vm_args.options = options;
+  vm_args.nOptions = 2;
+  vm_args.ignoreUnrecognized = JNI_TRUE;
+
+  PLUGIN_DEBUG("invoking vm...\n");
+
+  PR_EnterMonitor(jvmPRMonitor);
+
+  CreateJavaVM_t JNI_CreateJavaVM = (CreateJavaVM_t) dlsym(handle, "JNI_CreateJavaVM");
+  result = (*JNI_CreateJavaVM)(&jvm,(void **)&javaEnv, &vm_args);
+  if(result == JNI_ERR ) {
+    printf("Error invoking the JVM");
+	exit(1);
+    //return NS_ERROR_FAILURE;
+  }
+
+  PLUGIN_DEBUG("Looking for the PluginMain constructor...");
+
+  javaPluginClass = (javaEnv)->FindClass("Lsun/applet/PluginMain;");
+  if( javaPluginClass == NULL ) {
+    printf("can't find class PluginMain\n");
+	exit(1);
+    //return NS_ERROR_FAILURE;
+  }
+  (javaEnv)->ExceptionClear();
+  mid=(javaEnv)->GetMethodID(javaPluginClass, "<init>", "()V");
+
+  if( mid == NULL ) {
+    printf("can't find method init\n");
+	exit(1);
+    //return NS_ERROR_FAILURE;
+  }
+
+  PLUGIN_DEBUG("Creating PluginMain object...");
+
+  javaPluginObj=(javaEnv)->NewObject(javaPluginClass, mid);
+
+  if( javaPluginObj == NULL ) {
+    printf("can't create jobj\n");
+	exit(1);
+    //return NS_ERROR_FAILURE;
+  }
+
+  PLUGIN_DEBUG("PluginMain object created...");
+
+  postMessageMID = (javaEnv)->GetStaticMethodID(javaPluginClass, "postMessage", "(Ljava/lang/String;)V");
+
+  if( postMessageMID == NULL ) {
+    printf("can't find method postMessage(Ljava/lang/String;)V\n");
+	exit(1);
+  }
+
+  getMessageMID = (javaEnv)->GetStaticMethodID(javaPluginClass, "getMessage", "()Ljava/lang/String;");
+
+  if( getMessageMID == NULL ) {
+    printf("can't find method getMessage()Ljava/lang/String;\n");
+	exit(1);
+  }
+
+  jvm->DetachCurrentThread();
+
+  printf("VM Invocation complete, detached");
+
+  PR_ExitMonitor(jvmPRMonitor);
+
+  // Start another thread to periodically poll for available messages
+
+  nsCOMPtr<nsIRunnable> readThreadEvent =
+							new IcedTeaRunnableMethod<IcedTeaPluginFactory>
+							(this, &IcedTeaPluginFactory::IcedTeaPluginFactory::ReadFromJVM);
+
+  NS_NewThread(getter_AddRefs(readThread), readThreadEvent);
+
+  nsCOMPtr<nsIRunnable> processMessageEvent =
+							new IcedTeaRunnableMethod<IcedTeaPluginFactory>
+							(this, &IcedTeaPluginFactory::IcedTeaPluginFactory::ProcessMessage);
+
+  NS_NewThread(getter_AddRefs(processThread), processMessageEvent);
+
+
+  //printf("PluginMain initialized...\n");
+  //(jvm)->DestroyJavaVM();
+  //dlclose(handle);
+}
+
+void IcedTeaPluginFactory::ReadFromJVM ()
+{
+
+	PLUGIN_TRACE_INSTANCE ();
+
+	int noResponseCycles = 20;
+
+	const char *message;
+	int responseSize;
+	jstring response;
+
+	while (true) {
+
+		// Lock, attach, read, detach, unlock
+		PR_EnterMonitor(jvmPRMonitor);
+		(jvm)->AttachCurrentThread((void**)&javaEnv, NULL);
+
+		response = (jstring) (javaEnv)->CallStaticObjectMethod(javaPluginClass, getMessageMID);
+		responseSize = (javaEnv)->GetStringLength(response);
+
+		message = responseSize > 0 ? (javaEnv)->GetStringUTFChars(response, NULL) : "";
+		(jvm)->DetachCurrentThread();
+		PR_ExitMonitor(jvmPRMonitor);
+
+		if (responseSize > 0) {
+
+			noResponseCycles = 0;
+
+			PR_EnterMonitor(jvmMsgQueuePRMonitor);
+
+			printf("Async processing: %s\n", message);
+			jvmMsgQueue.push(nsCString(message));
+
+			PR_ExitMonitor(jvmMsgQueuePRMonitor);
+	
+			// poke process thread
+			PRThread *prThread;
+			processThread->GetPRThread(&prThread);
+
+			printf("Interrupting process thread...\n");
+			PRStatus res = PR_Interrupt(prThread);
+
+			// go back to bed
+			PR_Sleep(PR_INTERVAL_NO_WAIT);
+		} else {
+			//printf("Async processor sleeping...\n");
+            if (noResponseCycles >= 5) {
+			    PR_Sleep(1000);
+			} else {
+				PR_Sleep(PR_INTERVAL_NO_WAIT);
+			}
+
+            noResponseCycles++;
+		}
+	}
+}
+
+void IcedTeaPluginFactory::IcedTeaPluginFactory::WriteToJVM(nsCString& message)
+{
+
+  PLUGIN_TRACE_INSTANCE ();
+
+  PR_EnterMonitor(jvmPRMonitor);
+
+  (jvm)->AttachCurrentThread((void**)&javaEnv, NULL);
+
+  PLUGIN_DEBUG("Sending to VM:");
+  PLUGIN_DEBUG(message.get());
+  (javaEnv)->CallStaticVoidMethod(javaPluginClass, postMessageMID, (javaEnv)->NewStringUTF(message.get()));
+  PLUGIN_DEBUG("... sent!");
+
+  (jvm)->DetachCurrentThread();
+  PR_ExitMonitor(jvmPRMonitor);
+
+  return;
+
+  // Try sync read first. Why you ask? Let me tell you why! because attaching
+  // and detaching to the jvm is very expensive. In a standard run, 
+  // ReadFromJVM(), takes up 96.7% of the time, of which 66.5% is spent 
+  // attaching, and 30.7% is spent detaching. 
+
+  int responseSize;
+  jstring response;
+  int tries = 0;
+  int maxTries = 100;
+  const char* retMessage;
+
+  responseSize = 1;
+  PRBool processed = PR_FALSE;
+
+  while (responseSize > 0 || tries < maxTries) {
+
+      fflush(stdout);
+      fflush(stderr);
+
+	  //printf("trying... %d\n", tries);
+	  response = (jstring) (javaEnv)->CallStaticObjectMethod(javaPluginClass, getMessageMID);
+	  responseSize = (javaEnv)->GetStringLength(response);
+
+	  retMessage = (javaEnv)->GetStringUTFChars(response, NULL);
+
+	  if (responseSize > 0) {
+
+		    printf("Got response. Processing... %s\n", retMessage);
+   
+			PR_EnterMonitor(jvmMsgQueuePRMonitor);
+
+		    printf("Acquired lock on queue\n");
+
+			jvmMsgQueue.push(nsCString(retMessage));
+
+		    printf("Pushed to queue\n");
+
+			PR_ExitMonitor(jvmMsgQueuePRMonitor);
+
+            processed = PR_TRUE;
+
+			// If we have a response, bump tries up so we are not looping un-necessarily
+			tries = maxTries - 2;
+	  } else {
+        PR_Sleep(2);
+	  }
+	  tries++;
+  }
+
+  printf("Polling complete...\n");
+
+  (jvm)->DetachCurrentThread();
+
+  PR_ExitMonitor(jvmPRMonitor);
+
+  // wake up asynch read thread if needed
+
+  if (processed == PR_TRUE) {
+      // poke process thread
+      PRThread *prThread;
+      processThread->GetPRThread(&prThread);
+
+      printf("Interrupting process thread...\n");
+      PRStatus res = PR_Interrupt(prThread);
+
+      printf("Handler event dispatched\n");
+  } else {
+      PRThread *prThread;
+      readThread->GetPRThread(&prThread);
+
+      printf("Interrupting thread...\n");
+      PRStatus res = PR_Interrupt(prThread);
+      printf("Interrupted! %d\n", res);
+  }
+
+}
+
+*/
+
 nsresult
 IcedTeaPluginFactory::StartAppletviewer ()
 {
+
+/**
+ * JNI I/O code
+ *
+  InitJVM();
+*/
+
+/*
+ * Code to initialize separate appletviewer process that communicates over TCP/IP
+ */
+
   PLUGIN_TRACE_INSTANCE ();
   nsresult result;
 
@@ -2504,22 +3075,30 @@
   result = file->InitWithNativePath (nsCString (appletviewer_executable));
   PLUGIN_CHECK_RETURN ("init with path", result);
 
-  nsCOMPtr<nsIProcess> process;
   result = manager->CreateInstanceByContractID (NS_PROCESS_CONTRACTID,
                                                 nsnull,
                                                 NS_GET_IID (nsIProcess),
-                                                getter_AddRefs (process));
+                                                getter_AddRefs (applet_viewer_process));
   PLUGIN_CHECK_RETURN ("create process", result);
 
-  result = process->Init (file);
+  result = applet_viewer_process->Init (file);
   PLUGIN_CHECK_RETURN ("init process", result);
 
   // FIXME: hard-coded port number.
-  char const* args[1] = { "50007" };
-  result = process->Run (PR_FALSE, args, 1, nsnull);
+  char const* args[5] = { "-Xdebug", "-Xnoagent", "-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n", "sun.applet.PluginMain", "50007" };
+//  char const* args[2] = { "sun.applet.PluginMain", "50007" };
+  result = applet_viewer_process->Run (PR_FALSE, args, 5, nsnull);
   PLUGIN_CHECK_RETURN ("run process", result);
 
+  // start processing thread
+  nsCOMPtr<nsIRunnable> processMessageEvent =
+							new IcedTeaRunnableMethod<IcedTeaPluginFactory>
+							(this, &IcedTeaPluginFactory::IcedTeaPluginFactory::ProcessMessage);
+
+  NS_NewThread(getter_AddRefs(processThread), processMessageEvent);
+
   return NS_OK;
+
 }
 
 nsresult
@@ -2527,10 +3106,25 @@
 {
   PLUGIN_TRACE_INSTANCE ();
 
+  printf("Getting ready... %s %d\n", message.get(), message.Length() + 1);
+
+/*
+ * JNI I/O code
+ *
+   WriteToJVM(message);
+*/
+
+/*
+ *
+ * Code to send message to separate appletviewer process over TCP/IP
+ *
+ */
+
   PRUint32 writeCount = 0;
   // Write trailing \0 as message termination character.
   // FIXME: check that message is a valid UTF-8 string.
   //  printf ("MESSAGE: %s\n", message.get ());
+  message.Insert('-',0);
   nsresult result = output->Write (message.get (),
                                    message.Length () + 1,
                                    &writeCount);
@@ -2547,6 +3141,7 @@
   printf ("  PIPE: plugin wrote: %s\n", message.get ());
 
   return NS_OK;
+
 }
 
 PRUint32
@@ -2572,6 +3167,7 @@
   window_height (0),
   peer(0),
   liveconnect_window (0),
+  initialized(PR_FALSE),
   instanceIdentifierPrefix ("")
 {
   PLUGIN_TRACE_INSTANCE ();
@@ -2586,6 +3182,7 @@
 void
 IcedTeaPluginInstance::GetWindow ()
 {
+
   nsresult result;
   printf ("HERE 22: %d\n", liveconnect_window);
   // principalsArray, numPrincipals and securitySupports
@@ -3032,11 +3629,15 @@
 #include <nsITransport.h>
 #include <nsNetCID.h>
 #include <nsServiceManagerUtils.h>
+#include <iostream>
 
 IcedTeaJNIEnv::IcedTeaJNIEnv (IcedTeaPluginFactory* factory)
 : factory (factory)
 {
   PLUGIN_TRACE_JNIENV ();
+  contextCounter = 1;
+
+  contextCounterPRMonitor = PR_NewMonitor();
 }
 
 IcedTeaJNIEnv::~IcedTeaJNIEnv ()
@@ -3044,6 +3645,29 @@
   PLUGIN_TRACE_JNIENV ();
 }
 
+int
+IcedTeaJNIEnv::IncrementContextCounter ()
+{
+
+	PLUGIN_TRACE_JNIENV ();
+
+    PR_EnterMonitor(contextCounterPRMonitor);
+    contextCounter++;
+    PR_ExitMonitor(contextCounterPRMonitor);
+
+	return contextCounter;
+}
+
+void
+IcedTeaJNIEnv::DecrementContextCounter ()
+{
+	PLUGIN_TRACE_JNIENV ();
+
+    PR_EnterMonitor(contextCounterPRMonitor);
+    contextCounter--;
+    PR_ExitMonitor(contextCounterPRMonitor);
+}
+
 NS_IMETHODIMP
 IcedTeaJNIEnv::NewObject (jclass clazz,
                           jmethodID methodID,
@@ -3052,12 +3676,15 @@
                           nsISecurityContext* ctx)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (clazz);
   MESSAGE_ADD_ID (methodID);
   MESSAGE_ADD_ARGS (methodID, args);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_REFERENCE (jobject, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_REFERENCE (reference, jobject, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3070,12 +3697,16 @@
                            nsISecurityContext* ctx)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (obj);
   MESSAGE_ADD_ID (methodID);
   MESSAGE_ADD_ARGS (methodID, args);
+  std::cout << "CALLMETHOD -- OBJ: " << obj << " METHOD: " << methodID << " ARGS: " << args << std::endl;
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_VALUE (type, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_VALUE (reference, type, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3332,11 +3963,14 @@
                          nsISecurityContext* ctx)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (obj);
   MESSAGE_ADD_ID (fieldID);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_VALUE (type, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_VALUE (reference, type, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3348,12 +3982,13 @@
                          nsISecurityContext* ctx)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  MESSAGE_CREATE (-1);
   MESSAGE_ADD_TYPE (type);
   MESSAGE_ADD_REFERENCE (obj);
   MESSAGE_ADD_ID (fieldID);
   MESSAGE_ADD_VALUE (fieldID, val);
   MESSAGE_SEND ();
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
   return NS_OK;
 }
 
@@ -3366,12 +4001,15 @@
                                  nsISecurityContext* ctx)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (clazz);
   MESSAGE_ADD_ID (methodID);
   MESSAGE_ADD_ARGS (methodID, args);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_VALUE (type, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_VALUE (reference, type, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3383,11 +4021,14 @@
                                nsISecurityContext* ctx)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (clazz);
   MESSAGE_ADD_ID (fieldID);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_VALUE (type, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_VALUE (reference, type, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3399,12 +4040,13 @@
                                nsISecurityContext* ctx)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  MESSAGE_CREATE (-1);
   MESSAGE_ADD_TYPE (type);
   MESSAGE_ADD_REFERENCE (clazz);
   MESSAGE_ADD_ID (fieldID);
   MESSAGE_ADD_VALUE (fieldID, val);
   MESSAGE_SEND ();
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
   return NS_OK;
 }
 
@@ -3433,10 +4075,13 @@
                           jclass* clazz)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_STRING (name);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_REFERENCE (jclass, clazz);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_REFERENCE (reference, jclass, clazz);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3445,10 +4090,13 @@
                               jclass* super)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (sub);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_REFERENCE (jclass, super);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_REFERENCE (reference, jclass, super);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3458,11 +4106,14 @@
                                  jboolean* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (sub);
   MESSAGE_ADD_REFERENCE (super);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_BOOLEAN (result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_BOOLEAN (reference, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3489,10 +4140,13 @@
 IcedTeaJNIEnv::ExceptionOccurred (jthrowable* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_SEND ();
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
   // FIXME: potential leak here: when is result free'd?
-  MESSAGE_RECEIVE_REFERENCE (jthrowable, result);
+  MESSAGE_RECEIVE_REFERENCE (reference, jthrowable, result);
+  DecrementContextCounter ();
   printf ("GOT RESUlT: %x\n", *result);
   return NS_OK;
 }
@@ -3509,8 +4163,9 @@
 IcedTeaJNIEnv::ExceptionClear (void)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  MESSAGE_CREATE (-1);
   MESSAGE_SEND ();
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
   return NS_OK;
 }
 
@@ -3527,10 +4182,13 @@
                              jobject* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (lobj);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_REFERENCE(jobject, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_REFERENCE(reference, jobject, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3538,9 +4196,10 @@
 IcedTeaJNIEnv::DeleteGlobalRef (jobject gref)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  MESSAGE_CREATE (-1);
   MESSAGE_ADD_REFERENCE (gref);
   MESSAGE_SEND ();
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
   factory->references.UnreferenceObject (ID (gref));
   return NS_OK;
 }
@@ -3549,10 +4208,11 @@
 IcedTeaJNIEnv::DeleteLocalRef (jobject obj)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  MESSAGE_CREATE (-1);
   MESSAGE_ADD_REFERENCE (obj);
   MESSAGE_SEND ();
-  factory->references.UnreferenceObject (ID (obj));
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+//  factory->references.UnreferenceObject (ID (obj));
   return NS_OK;
 }
 
@@ -3582,10 +4242,13 @@
                                jclass* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (obj);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_REFERENCE (jclass, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_REFERENCE (reference, jclass, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3595,11 +4258,14 @@
                              jboolean* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (obj);
   MESSAGE_ADD_REFERENCE (clazz);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_BOOLEAN (result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_BOOLEAN (reference, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3610,13 +4276,19 @@
                             jmethodID* id)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (clazz);
   MESSAGE_ADD_STRING (name);
-  printf ("SIGNATURE: %s %s\n", __func__, sig);
+  std::cout << "Args: " << clazz << " " << name << " " << sig << " " << *id << "@" << id << std::endl;
+  printf ("SIGNATURE: %s %s %s\n", __func__, name, sig);
+  std::cout << "Storing it at: " << id << " Currently it is: " << *id << std::endl;
   MESSAGE_ADD_STRING (sig);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_ID (jmethodID, id, sig);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_ID (reference, jmethodID, id, sig);
+  DecrementContextCounter ();
+  std::cout << "GETMETHODID -- Name: " << name << " SIG: " << sig << " METHOD: " << id << " METHODVAL: " << *id << std::endl;
   return NS_OK;
 }
 
@@ -3627,13 +4299,16 @@
                            jfieldID* id)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (clazz);
   MESSAGE_ADD_STRING (name);
-  printf ("SIGNATURE: %s %s\n", __func__, sig);
+  printf ("SIGNATURE: %s %s %s\n", __func__, name, sig);
   MESSAGE_ADD_STRING (sig);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_ID (jfieldID, id, sig);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_ID (reference, jfieldID, id, sig);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3644,13 +4319,16 @@
                                   jmethodID* id)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (clazz);
   MESSAGE_ADD_STRING (name);
   printf ("SIGNATURE: %s %s\n", __func__, sig);
   MESSAGE_ADD_STRING (sig);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_ID (jmethodID, id, sig);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_ID (reference, jmethodID, id, sig);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3661,13 +4339,16 @@
                                  jfieldID* id)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (clazz);
   MESSAGE_ADD_STRING (name);
   printf ("SIGNATURE: %s %s\n", __func__, sig);
   MESSAGE_ADD_STRING (sig);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_ID (jfieldID, id, sig);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_ID (reference, jfieldID, id, sig);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3677,11 +4358,14 @@
                           jstring* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_SIZE (len);
   MESSAGE_ADD_STRING_UCS (unicode, len);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_REFERENCE (jstring, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_REFERENCE (reference, jstring, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3690,10 +4374,13 @@
                                 jsize* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (str);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_SIZE (result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_SIZE (reference, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3705,10 +4392,14 @@
   PLUGIN_TRACE_JNIENV ();
   if (isCopy)
     *isCopy = JNI_TRUE;
-  MESSAGE_CREATE ();
+
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (str);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_STRING_UCS (result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_STRING_UCS (reference, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3726,10 +4417,13 @@
                              jstring* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_STRING_UTF (utf);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_REFERENCE (jstring, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_REFERENCE (reference, jstring, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3738,10 +4432,13 @@
                                    jsize* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (str);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_SIZE (result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_SIZE (reference, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3753,10 +4450,14 @@
   PLUGIN_TRACE_JNIENV ();
   if (isCopy)
     *isCopy = JNI_TRUE;
-  MESSAGE_CREATE ();
+
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (str);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_STRING (char, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_STRING (reference, char, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3774,10 +4475,13 @@
                                jsize* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (array);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_SIZE (result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_SIZE (reference, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3788,12 +4492,15 @@
                                jobjectArray* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_SIZE (len);
   MESSAGE_ADD_REFERENCE (clazz);
   MESSAGE_ADD_REFERENCE (init);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_REFERENCE (jobjectArray, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_REFERENCE (reference, jobjectArray, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3803,11 +4510,14 @@
                                       jobject* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_REFERENCE (array);
   MESSAGE_ADD_SIZE (index);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_REFERENCE (jobject, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_REFERENCE (reference, jobject, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3817,11 +4527,12 @@
                                       jobject val)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  MESSAGE_CREATE (-1);
   MESSAGE_ADD_REFERENCE (array);
   MESSAGE_ADD_SIZE (index);
   MESSAGE_ADD_REFERENCE (val);
   MESSAGE_SEND ();
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
   return NS_OK;
 }
 
@@ -3832,11 +4543,14 @@
                          jarray* result)
 {
   PLUGIN_TRACE_JNIENV ();
-  MESSAGE_CREATE ();
+  int reference = IncrementContextCounter ();
+  MESSAGE_CREATE (reference);
   MESSAGE_ADD_TYPE (element_type);
   MESSAGE_ADD_SIZE (len);
   MESSAGE_SEND ();
-  MESSAGE_RECEIVE_REFERENCE (jarray, result);
+  printf("MSG SEND COMPLETE. NOW RECEIVING...\n");
+  MESSAGE_RECEIVE_REFERENCE (reference, jarray, result);
+  DecrementContextCounter ();
   return NS_OK;
 }
 
@@ -3970,17 +4684,20 @@
       PLUGIN_ERROR ("Failed to create plugin shared object filename.");
       return NS_ERROR_OUT_OF_MEMORY;
     }
-  nsCString executableString (dirname (filename));
+  nsCString executable (dirname (filename));
   free (filename);
   filename = NULL;
 
-  executableString += nsCString ("/../../bin/pluginappletviewer");
+  //executableString += nsCString ("/../../bin/pluginappletviewer");
+  executable += nsCString ("/../../bin/java");
+  //executable += nsCString ("/client/libjvm.so");
 
   // Never freed.
-  appletviewer_executable = strdup (executableString.get ());
+  appletviewer_executable = strdup (executable.get ());
+  //libjvm_so = strdup (executable.get ());
   if (!appletviewer_executable)
     {
-      PLUGIN_ERROR ("Failed to create appletviewer executable name.");
+      PLUGIN_ERROR ("Failed to create java executable name.");
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
--- a/patches/icedtea-liveconnect.patch	Thu Aug 21 13:02:39 2008 +0200
+++ b/patches/icedtea-liveconnect.patch	Mon Aug 25 15:15:30 2008 -0400
@@ -1,7 +1,7 @@
 diff -urN openjdk.orig/jdk/make/sun/Makefile openjdk/jdk/make/sun/Makefile
---- openjdk.orig/jdk/make/sun/Makefile	2007-10-12 03:54:06.000000000 -0400
-+++ openjdk/jdk/make/sun/Makefile	2007-10-12 17:39:04.000000000 -0400
-@@ -63,6 +63,7 @@
+--- openjdk.orig/jdk/make/sun/Makefile	2008-07-10 15:54:44.000000000 -0400
++++ openjdk/jdk/make/sun/Makefile	2008-08-19 16:15:28.000000000 -0400
+@@ -66,6 +66,7 @@
            $(HEADLESS_SUBDIR) $(DGA_SUBDIR) \
  	  font jpeg cmm applet rmi beans $(JDBC_SUBDIR) \
  	  jawt text nio launcher management $(ORG_SUBDIR) \
@@ -9,9 +9,86 @@
            native2ascii serialver tools jconsole
  
  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-08-19 16:15:28.000000000 -0400
+@@ -0,0 +1,73 @@
++#
++# Copyright 1995-2007 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.
++#
++
++#
++# Makefile for building all of sun tools
++#
++
++BUILDDIR = ..
++PRODUCT  = sun
++include $(BUILDDIR)/common/Defs.gmk
++
++# Rhino/Mozilla java sources
++ORG_EXISTS := $(call DirExists,$(CLOSED_SRC)/share/classes/sun/org,,)
++ifneq ("$(ORG_EXISTS)", "")
++  ORG_SUBDIR = org
++endif
++
++# Non windows subdirs
++ifneq ($(PLATFORM), windows)
++  ifndef OPENJDK
++    ifeq ($(PLATFORM), solaris)
++      ifneq ($(ARCH), amd64)
++        DGA_SUBDIR = jdga
++      endif
++    endif
++  endif
++  ifeq ($(MOTIF_REQUIRED), true)
++    MOTIF_SUBDIRS   = motif12 motif21
++  endif
++  HEADLESS_SUBDIR = headless
++  XAWT_SUBDIR     = xawt
++endif
++
++ifndef OPENJDK
++  JDBC_SUBDIR = jdbc
++endif
++ifdef OPENJDK
++  RENDER_SUBDIR = pisces
++else
++  RENDER_SUBDIR = dcpr
++endif
++SUBDIRS = jar security javazic misc net audio $(RENDER_SUBDIR) image \
++	  awt splashscreen $(XAWT_SUBDIR) $(MOTIF_SUBDIRS) \
++          $(HEADLESS_SUBDIR) $(DGA_SUBDIR) \
++	  font jpeg cmm applet rmi beans $(JDBC_SUBDIR) \
++	  jawt text nio launcher management $(ORG_SUBDIR) \
++          native2ascii serialver tools jconsole
++
++all build clean clobber::
++	$(SUBDIRS-loop)
++
 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	2007-10-12 17:37:54.000000000 -0400
++++ openjdk/jdk/make/sun/plugin/Makefile	2008-08-19 16:15:28.000000000 -0400
 @@ -0,0 +1,53 @@
 +#
 +# Copyright 1995-2005 Sun Microsystems, Inc.  All Rights Reserved.
@@ -66,10 +143,132 @@
 +JAVA_ARGS = "{ \"sun.applet.PluginMain\" }"
 +include $(BUILDDIR)/common/Program.gmk
 +
-diff -urN openjdk/jdk/src/share/classes/sun/applet.orig/PluginAppletSecurityContext.java openjdk/jdk/src/share/classes/sun/applet/PluginAppletSecurityContext.java
---- openjdk/jdk/src/share/classes/sun/applet.orig/PluginAppletSecurityContext.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginAppletSecurityContext.java	2008-02-23 05:36:30.000000000 -0500
-@@ -0,0 +1,789 @@
+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-08-21 13:23:32.000000000 -0400
+@@ -0,0 +1,58 @@
++/* 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;
++    }
++}
++
+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-08-21 13:23:32.000000000 -0400
+@@ -0,0 +1,56 @@
++/* 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;
++    }
++}
+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-08-21 13:23:33.000000000 -0400
+@@ -0,0 +1,807 @@
 +/* PluginAppletSecurityContext -- execute plugin JNI messages
 +   Copyright (C) 2008  Red Hat
 +
@@ -113,756 +312,774 @@
 +import java.lang.reflect.*;
 +import java.io.*;
 +
-+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) {
-+        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);
-+            try {
-+                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(Class.forName(arrayType),
-+                                                           dims).getClass());
-+                    } else {
-+                        typeList.add(Class.forName(elem));
-+                    }
-+                }
-+            } catch (ClassNotFoundException e) {
-+                throw new RuntimeException(e);
-+            }
-+        }
-+        if (typeList.size() == 0) {
-+            throw new IllegalArgumentException("Invalid JNI signature '" +
-+                                               signature + "'");
-+        }
-+    }
-+
-+    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[] {});
-+    }
++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) {
++		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);
++			try {
++				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(
++									Class.forName(arrayType), dims).getClass());
++					} else {
++						typeList.add(Class.forName(elem));
++					}
++				}
++			} catch (ClassNotFoundException e) {
++				throw new RuntimeException(e);
++			}
++		}
++		if (typeList.size() == 0) {
++			throw new IllegalArgumentException("Invalid JNI signature '"
++					+ signature + "'");
++		}
++	}
++
++	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();
-+
-+    // 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?
-+        contexts.put(0, new PluginAppletSecurityContext(0));
-+    }
-+
-+    public PluginAppletSecurityContext (int identifier)
-+    {
-+        this.identifier = identifier;
-+    }
-+
-+    public static <V> V parseCall(String s, 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);
-+        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 message)
-+    {
-+        contexts.get(identifier).handleMessage(message);
-+    }
-+
-+    public void handleMessage(String message)
-+    {
-+        try {
-+            if (message.startsWith("FindClass")) {
-+                ClassLoader cl = null;
-+                Class c = null;
-+                cl = liveconnectLoader;
-+                String className
-+                    = message.substring("FindClass".length()
-+                                        + 1).replace('/', '.');
-+                c = cl.loadClass(className);
-+
-+                store.reference(c);
-+
-+                write ("FindClass " + store.getIdentifier(c));
-+            } else if (message.startsWith("GetStaticMethodID")
-+                       || message.startsWith("GetMethodID")) {
-+                String[] args = message.split(" ");
-+                Integer classID = parseCall(args[1], Integer.class);
-+                String methodName = parseCall(args[2], String.class);
-+                Signature signature = parseCall(args[3], 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);
-+                }
-+                write (args[0] + " " + store.getIdentifier(o));
-+            } else if (message.startsWith("GetStaticFieldID")
-+                       || message.startsWith("GetFieldID")) {
-+                String[] args = message.split(" ");
-+                Integer classID = parseCall(args[1], Integer.class);
-+                String fieldName = parseCall(args[2], String.class);
-+                Signature signature = parseCall(args[3], Signature.class);
-+
-+                Class c = (Class) store.getObject(classID);
-+                Field f = null;
-+                f = c.getField(fieldName);
-+
-+                store.reference(f);
-+
-+                write ("GetStaticFieldID " + store.getIdentifier(f));
-+            } else if (message.startsWith("GetStaticField")) {
-+                String[] args = message.split(" ");
-+                String type = parseCall(args[1], String.class);
-+                Integer classID = parseCall(args[1], Integer.class);
-+                Integer fieldID = parseCall(args[2], 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 ("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 ("GetStaticField " + ret);
-+                } else {
-+                    // Track returned object.
-+                    store.reference(ret);
-+                    write ("GetStaticField " + store.getIdentifier(ret));
-+                }
-+            } else if (message.startsWith("SetStaticField")) {
-+                String[] args = message.split(" ");
-+                String type = parseCall(args[1], String.class);
-+                Integer classID = parseCall(args[2], Integer.class);
-+                Integer fieldID = parseCall(args[3], 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("SetStaticField");
-+            } else if (message.startsWith("SetField")) {
-+                String[] args = message.split(" ");
-+                String type = parseCall(args[1], String.class);
-+                Integer objectID = parseCall(args[2], Integer.class);
-+                Integer fieldID = parseCall(args[3], 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("SetField");
-+            } else if (message.startsWith("GetObjectArrayElement")) {
-+                String[] args = message.split(" ");
-+                Integer arrayID = parseCall(args[1], Integer.class);
-+                Integer index = parseCall(args[2], 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("GetObjectArrayElement " + store.getIdentifier(ret));
-+            } else if (message.startsWith("SetObjectArrayElement")) {
-+                String[] args = message.split(" ");
-+                Integer arrayID = parseCall(args[1], Integer.class);
-+                Integer index = parseCall(args[2], Integer.class);
-+                Integer objectID = parseCall(args[3], Integer.class);
-+
-+                Object[] o = (Object[]) store.getObject(arrayID);
-+                Object toSet = (Object) store.getObject(objectID);
-+
-+                o[index] = toSet;
-+
-+                write("SetObjectArrayElement");
-+            } else if (message.startsWith("GetArrayLength")) {
-+                String[] args = message.split(" ");
-+                Integer arrayID = parseCall(args[1], 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("GetArrayLength " + Array.getLength(o));
-+            } else if (message.startsWith("GetField")) {
-+                String[] args = message.split(" ");
-+                String type = parseCall(args[1], String.class);
-+                Integer objectID = parseCall(args[1], Integer.class);
-+                Integer fieldID = parseCall(args[2], 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 ("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 ("GetField " + ret);
-+                } else {
-+                    // Track returned object.
-+                    store.reference(ret);
-+                    write ("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 ("GetObjectClass " + store.getIdentifier(c));
-+            } else if (message.startsWith("CallStaticMethod")) {
-+                String[] args = message.split(" ");
-+                Integer classID = parseCall(args[1], Integer.class);
-+                Integer methodID = parseCall(args[2], 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 ("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 ("CallStaticMethod " + ret);
-+                } else if (m.getReturnType() == Character.TYPE) {
-+                    char ch = (Character) ret;
-+                    int high = (((int) ch) >> 8)  & 0x0ff;
-+                    int low = ((int) ch) & 0x0ff;
-+                    write ("CallStaticMethod " + low + "_" + high);
-+                } else {
-+                    // Track returned object.
-+                    store.reference(ret);
-+                    write ("CallStaticMethod " + store.getIdentifier(ret));
-+                }
-+            } else if (message.startsWith("CallMethod")) {
-+                String[] args = message.split(" ");
-+                Integer objectID = parseCall(args[1], Integer.class);
-+                Integer methodID = parseCall(args[2], 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]);
-+                    //System.out.println ("GOT ARG: " + argTypes[i] + " " + arguments[i]);
-+                }
-+
-+                System.out.println ("Calling " + m);
-+                Object ret = null;
-+                ret = m.invoke (o, arguments);
-+
-+                if (ret == null) {
-+                    write ("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 ("CallMethod " + ret);
-+                } else if (m.getReturnType() == Character.TYPE) {
-+                    char ch = (Character) ret;
-+                    int high = (((int) ch) >> 8)  & 0x0ff;
-+                    int low = ((int) ch) & 0x0ff;
-+                    write ("CallMethod " + low + "_" + high);
-+                } else {
-+                    // Track returned object.
-+                    store.reference(ret);
-+                    write ("CallMethod " + store.getIdentifier(ret));
-+                }
-+            } else if (message.startsWith("GetSuperclass")) {
-+                String[] args = message.split(" ");
-+                Integer classID = parseCall(args[1], Integer.class);
-+                Class c = null;
-+                Class ret = null;
-+
-+                c = (Class) store.getObject(classID);
-+                ret = c.getSuperclass();
-+                store.reference(ret);
-+
-+                write("GetSuperclass " + store.getIdentifier(ret));
-+            } else if (message.startsWith("IsAssignableFrom")) {
-+                String[] args = message.split(" ");
-+                Integer classID = parseCall(args[1], Integer.class);
-+                Integer superclassID = parseCall(args[2], Integer.class);
-+
-+                boolean result = false;
-+                Class clz = (Class) store.getObject(classID);
-+                Class sup = (Class) store.getObject(superclassID);
-+
-+                result = sup.isAssignableFrom(clz);
-+
-+                write("IsAssignableFrom " + (result ? "1" : "0"));
-+            } else if (message.startsWith("IsInstanceOf")) {
-+                String[] args = message.split(" ");
-+                Integer objectID = parseCall(args[1], Integer.class);
-+                Integer classID = parseCall(args[2], Integer.class);
-+
-+                boolean result = false;
-+                Object o = (Object) store.getObject(objectID);
-+                Class c = (Class) store.getObject(classID);
-+
-+                result = c.isInstance(o);
-+
-+                write("IsInstanceOf " + (result ? "1" : "0"));
-+            } else if (message.startsWith("GetStringUTFLength")) {
-+                String[] args = message.split(" ");
-+                Integer stringID = parseCall(args[1], 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("GetStringUTFLength " + o.length());
-+            } else if (message.startsWith("GetStringLength")) {
-+                String[] args = message.split(" ");
-+                Integer stringID = parseCall(args[1], 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("GetStringLength " + o.length());
-+            } else if (message.startsWith("GetStringUTFChars")) {
-+                String[] args = message.split(" ");
-+                Integer stringID = parseCall(args[1], 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("GetStringUTFChars " + buf);
-+            } else if (message.startsWith("GetStringChars")) {
-+                String[] args = message.split(" ");
-+                Integer stringID = parseCall(args[1], 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("GetStringChars " + buf);
-+            } else if (message.startsWith("NewArray")) {
-+                String[] args = message.split(" ");
-+                String type = parseCall(args[1], String.class);
-+                Integer length = parseCall(args[2], 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 ("NewArray " + store.getIdentifier(newArray));
-+            } else if (message.startsWith("NewObjectArray")) {
-+                String[] args = message.split(" ");
-+                Integer length = parseCall(args[1], Integer.class);
-+                Integer classID = parseCall(args[2], Integer.class);
-+                Integer objectID = parseCall(args[3], 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 ("NewObjectArray " + store.getIdentifier(newArray));
-+            } else if (message.startsWith("NewObject")) {
-+                String[] args = message.split(" ");
-+                Integer classID = parseCall(args[1], Integer.class);
-+                Integer methodID = parseCall(args[2], 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 ("NewObject " + store.getIdentifier(ret));
-+            } else if (message.startsWith("NewString")) {
-+                System.out.println ("MESSAGE: " + message);
-+                String[] args = message.split(" ");
-+                Integer strlength = parseCall(args[1], 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], 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 ("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], 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 ("NewStringUTF " + store.getIdentifier(ret));
-+            } else if (message.startsWith("ExceptionOccurred")) {
-+                System.out.println ("EXCEPTION: " + throwable);
-+                if (throwable != null)
-+                    store.reference(throwable);
-+                write ("ExceptionOccurred " + store.getIdentifier(throwable));
-+            } else if (message.startsWith("ExceptionClear")) {
-+                if (throwable != null)
-+                    store.unreference(store.getIdentifier(throwable));
-+                throwable = null;
-+                write("ExceptionClear");
-+            } else if (message.startsWith("DeleteGlobalRef")) {
-+                String[] args = message.split(" ");
-+                Integer id = parseCall(args[1], Integer.class);
-+                store.unreference(id);
-+                write ("DeleteGlobalRef");
-+            } else if (message.startsWith("DeleteLocalRef")) {
-+                String[] args = message.split(" ");
-+                Integer id = parseCall(args[1], Integer.class);
-+                store.unreference(id);
-+                write ("DeleteLocalRef");
-+            } else if (message.startsWith("NewGlobalRef")) {
-+                String[] args = message.split(" ");
-+                Integer id = parseCall(args[1], Integer.class);
-+                store.reference(store.getObject(id));
-+                write ("NewGlobalRef " + id);
-+            }
-+        } catch (Throwable t) {
-+            t.printStackTrace();
-+            throwable = t;
-+        }
-+    }
-+
-+    public void write(String message) {
-+        PluginMain.write("context " + identifier + " " + message);
-+    }
++public class PluginAppletSecurityContext {
++	// Context identifier -> PluginAppletSecurityContext object.
++	// FIXME: make private
++	public static HashMap<Integer, PluginAppletSecurityContext> contexts = new HashMap();
++
++	// 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?
++		contexts.put(0, new PluginAppletSecurityContext(0));
++	}
++
++	public PluginAppletSecurityContext(int identifier) {
++		this.identifier = identifier;
++	}
++
++	public static <V> V parseCall(String s, 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);
++		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, int reference,
++			String message) {
++		contexts.get(identifier).handleMessage(reference, message);
++	}
++
++	public void handleMessage(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], Integer.class);
++				String methodName = parseCall(args[2], String.class);
++				Signature signature = parseCall(args[3], 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], Integer.class);
++				String fieldName = parseCall(args[2], String.class);
++				Signature signature = parseCall(args[3], 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], String.class);
++				Integer classID = parseCall(args[1], Integer.class);
++				Integer fieldID = parseCall(args[2], 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], String.class);
++				Integer classID = parseCall(args[2], Integer.class);
++				Integer fieldID = parseCall(args[3], 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], String.class);
++				Integer objectID = parseCall(args[2], Integer.class);
++				Integer fieldID = parseCall(args[3], 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], Integer.class);
++				Integer index = parseCall(args[2], 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], Integer.class);
++				Integer index = parseCall(args[2], Integer.class);
++				Integer objectID = parseCall(args[3], 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], 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], String.class);
++				Integer objectID = parseCall(args[1], Integer.class);
++				Integer fieldID = parseCall(args[2], 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], Integer.class);
++				Integer methodID = parseCall(args[2], 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], Integer.class);
++				Integer methodID = parseCall(args[2], 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], 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], Integer.class);
++				Integer superclassID = parseCall(args[2], 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], Integer.class);
++				Integer classID = parseCall(args[2], 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], 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], 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], 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], 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], String.class);
++				Integer length = parseCall(args[2], 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], Integer.class);
++				Integer classID = parseCall(args[2], Integer.class);
++				Integer objectID = parseCall(args[3], 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], Integer.class);
++				Integer methodID = parseCall(args[2], 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], 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], 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], 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], Integer.class);
++				store.unreference(id);
++				write(reference, "DeleteGlobalRef");
++			} else if (message.startsWith("DeleteLocalRef")) {
++				String[] args = message.split(" ");
++				Integer id = parseCall(args[1], Integer.class);
++				store.unreference(id);
++				write(reference, "DeleteLocalRef");
++			} else if (message.startsWith("NewGlobalRef")) {
++				String[] args = message.split(" ");
++				Integer id = parseCall(args[1], Integer.class);
++				store.reference(store.getObject(id));
++				write(reference, "NewGlobalRef " + id);
++			}
++		} catch (Throwable t) {
++			t.printStackTrace();
++			throwable = t;
++			PluginException p = new PluginException(reference, t);
++		}
++	}
++
++	public void write(int reference, String message) {
++		PluginDebug.debug("appletviewer writing " + message);
++		PluginMain.write("context " + identifier + " reference " + reference
++				+ " " + message);
++	}
 +}
-diff -urN openjdk/jdk/src/share/classes/sun/applet/PluginAppletViewer.java openjdk/jdk/src/share/classes/sun/applet/PluginAppletViewer.java
---- openjdk.orig/jdk/src/share/classes/sun/applet/PluginAppletViewer.java	2008-06-24 22:55:57.286013713 -0400
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginAppletViewer.java	2008-06-29 10:20:41.000000000 -0400
-@@ -0,0 +1,1349 @@
+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-08-21 13:23:33.000000000 -0400
+@@ -0,0 +1,1384 @@
 + /*
 +  * Copyright 1995-2004 Sun Microsystems, Inc.  All Rights Reserved.
 +  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -986,7 +1203,7 @@
 + 	this.statusMsgStream = statusMsgStream;
 +         this.identifier = identifier;
 +         // FIXME: when/where do we remove this?
-+         System.out.println ("PARSING: PUTTING " + identifier + " " + this);
++         PluginDebug.debug ("PARSING: PUTTING " + identifier + " " + this);
 +         applets.put(identifier, this);
 + 
 + 	try {
@@ -1071,60 +1288,77 @@
 + 	panel.addAppletListener(new AppletEventListener(this));
 + 
 + 	// Start the applet
-+         showStatus(amh.getMessage("status.start"));
++    showStatus(amh.getMessage("status.start"));
 + 	initEventQueue();
++ 	
++ 	try {
++ 	    write("initialized");
++ 	} catch (IOException ioe) {
++ 		ioe.printStackTrace();
++ 	}
 +     }
 + 
 +     /**
 +      * Handle an incoming message from the plugin.
 +      */
-+     public static void handleMessage(int identifier, String message)
++     public static void handleMessage(int identifier, int reference, String message)
 +     {
++         PluginDebug.debug("PAV handling: " + message);
++
 +         try {
-+             if (message.startsWith("tag")) {
-+                 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);
-+                 System.out.println ("REQUEST TAG: " + request.tag + " " +
-+                                         Thread.currentThread());
-+                 if (request.handle != 0) {
-+                     System.out.println ("REQUEST TAG, PARSING " +
-+                                         Thread.currentThread());
-+                     PluginAppletViewer.parse
-+                         (identifier, request.handle,
-+                          new StringReader(request.tag),
-+                          new URL(request.documentbase));
-+                     requests.remove(identifier);
-+                 }
++        	 if (message.startsWith("tag")) {
++        		 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")) {
-+                 PluginParseRequest request = requests.get(identifier);
-+                 if (request == null) {
-+                     request = new PluginParseRequest();
-+                     requests.put(identifier, request);
-+                 }
-+                 request.handle = Long.parseLong
-+                     (message.substring("handle".length() + 1));
-+                 System.out.println ("REQUEST HANDLE: " + request.handle);
-+                 if (request.tag != null) {
-+                     System.out.println ("REQUEST HANDLE, PARSING " +
-+                                         Thread.currentThread());
-+                     PluginAppletViewer.parse
-+                         (identifier, request.handle,
-+                          new StringReader(request.tag),
-+                          new URL(request.documentbase));
-+                     requests.remove(identifier);
-+                     System.out.println ("REQUEST HANDLE, DONE PARSING " +
-+                                         Thread.currentThread());
-+                 }
++            	 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 {
-+                     System.out.println ("HANDLING MESSAGE " + message + " instance " + identifier + " " + Thread.currentThread());
-+                 applets.get(identifier).handleMessage(message);
++                 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 + " " +
@@ -1132,7 +1366,7 @@
 +         }
 +     }
 + 
-+     public void handleMessage(String message)
++     public void handleMessage(int reference, String message)
 +     {
 +         if (message.startsWith("width")) {
 +             int width =
@@ -1147,13 +1381,29 @@
 +         } else if (message.startsWith("GetJavaObject")) {
 +             // FIXME: how do we determine what security context this
 +             // object should belong to?
-+             Object o = panel.getApplet();
++             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
++            	 }
++             }
++
++             PluginDebug.debug ("Looking for object " + o + " panel is " + panel.getClass());
 +             PluginAppletSecurityContext.contexts.get(0).store.reference(o);
-+             System.out.println ("WRITING 1: " + "context 0 GetJavaObject "
++             PluginDebug.debug ("WRITING 1: " + "context 0 reference " + reference + " GetJavaObject "
 +                                 + PluginAppletSecurityContext.contexts.get(0).store.getIdentifier(o));
-+             PluginMain.write("context 0 GetJavaObject "
++             PluginMain.write("context 0 reference " + reference + " GetJavaObject "
 +                              + PluginAppletSecurityContext.contexts.get(0).store.getIdentifier(o));
-+             System.out.println ("WRITING 1 DONE");
++             PluginDebug.debug ("WRITING 1 DONE");
 +         }
 +     }
 + 
@@ -1353,6 +1603,7 @@
 +      * Ignore.
 +      */
 +     public void showDocument(URL url) {
++    	 PluginDebug.debug("Showing document...");
 + 	showDocument(url, "_self");
 +     }
 + 
@@ -1385,28 +1636,29 @@
 +     }
 + 
 +     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;
++    	 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.
@@ -1664,9 +1916,9 @@
 +     // FIXME: make this private and access it from JSObject using
 +     // reflection.
 +     private void write(String message) throws IOException {
-+         System.out.println ("WRITING 2: " + "instance " + identifier + " " + message);
++         System.err.println ("WRITING 2: " + "instance " + identifier + " " + message);
 +         PluginMain.write("instance " + identifier + " " + message);
-+         System.out.println ("WRITING 2 DONE");
++         System.err.println ("WRITING 2 DONE");
 +     }
 + 
 +     // FIXME: make this private and access it from JSObject using
@@ -2212,10 +2464,101 @@
 + 	}
 +     }
 + }
-diff -urN openjdk/jdk/src/share/classes/sun/applet.orig/PluginMain.java openjdk/jdk/src/share/classes/sun/applet/PluginMain.java
---- openjdk/jdk/src/share/classes/sun/applet.orig/PluginMain.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginMain.java	2008-02-22 20:48:32.000000000 -0500
-@@ -0,0 +1,282 @@
+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-08-21 13:23:33.000000000 -0400
+@@ -0,0 +1,54 @@
++/* 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);
++}
+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-08-21 13:23:34.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-08-21 13:23:34.000000000 -0400
+@@ -0,0 +1,12 @@
++package sun.applet;
++
++public class PluginException extends Exception {
++
++	public PluginException (int instance, Throwable t) {
++		t.printStackTrace();
++		this.setStackTrace(t.getStackTrace());
++		
++		String message = "instance " + instance + " 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-08-21 13:49:53.000000000 -0400
+@@ -0,0 +1,474 @@
 +/*
 + * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -2248,6 +2591,7 @@
 +import java.net.*;
 +import java.nio.charset.Charset;
 +import java.util.*;
++
 +import sun.net.www.ParseUtil;
 +
 +class RequestQueue {
@@ -2290,28 +2634,124 @@
 +
 +    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;
++
 +    /**
 +     * 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);
++
++    	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);
++    	}
++
++/*
++    	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();
++		}
 +	}
-+	// INSTALL THE SECURITY MANAGER
-+	init();
-+        int port = 0;
-+        try {
-+            port = Integer.parseInt(args[0]);
-+        } catch (NumberFormatException e) {
-+            System.err.println("Failed to parse port number: " + e);
-+            System.exit(1);
-+        }
-+        Socket socket = new Socket("localhost", port);
-+	start(socket.getInputStream(), socket.getOutputStream());
-+	System.exit(0);
++    
++    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() {
@@ -2367,33 +2807,60 @@
 +	// REMIND: Create and install a socket factory!
 +    }
 +
-+    private static void handleMessage(String message) {
-+        int index = message.indexOf(' ');
-+        String first = message.substring(0, index);
-+        message = message.substring(index + 1);
-+        index = message.indexOf(' ');
-+        String second = message.substring(0, index);
-+        int identifier = Integer.parseInt(second);
-+        message = message.substring(index + 1);
-+
-+        if (message.contains("JavaScriptGetWindow")
-+            || message.contains("JavaScriptGetMember")
-+            || message.contains("JavaScriptSetMember")
-+            || message.contains("JavaScriptGetSlot")
-+            || message.contains("JavaScriptSetSlot")
-+            || message.contains("JavaScriptEval")
-+            || message.contains("JavaScriptRemoveMember")
-+            || message.contains("JavaScriptCall")
-+            || message.contains("JavaScriptFinalize")
-+            || message.contains("JavaScriptToString")) {
-+            finishCallRequest(message);
-+            return;
-+        }
-+
-+        if (first.equals("instance"))
-+            PluginAppletViewer.handleMessage(identifier, message);
-+        else if (first.equals("context"))
-+            PluginAppletSecurityContext.handleMessage(identifier, message);
++    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;
++
++    	rest = st.nextToken();
++
++    	// if the next token is reference, read it, else reset "rest"
++    	if (rest.equals("reference")) {
++    		reference = Integer.parseInt(st.nextToken());
++    		rest = "";
++    	} else {
++    		rest += " ";
++    	}
++
++    	while (st.hasMoreElements()) {
++    		rest += st.nextToken();
++    		rest += " ";
++    	}
++
++    	rest = rest.trim();
++
++    	try {
++
++    		System.err.println("Breakdown -- type: " + type + " identifier: " + identifier + " reference: " + reference + " 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, reference, rest);
++    		}
++    	} catch (Exception e) {
++    		throw new PluginException(identifier, e);
++    	}
 +    }
 +
 +    static void start(InputStream inputstream, OutputStream outputstream)
@@ -2411,12 +2878,55 @@
 +	    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) {
@@ -2426,22 +2936,22 @@
 +    }
 +
 +    private static void finishCallRequest(String message) {
-+        System.out.println ("DISPATCHCALLREQUESTS 1");
++        PluginDebug.debug ("DISPATCHCALLREQUESTS 1");
 +        synchronized(queue) {
-+        System.out.println ("DISPATCHCALLREQUESTS 2");
++        PluginDebug.debug ("DISPATCHCALLREQUESTS 2");
 +            PluginCallRequest request = queue.pop();
-+        System.out.println ("DISPATCHCALLREQUESTS 3");
++        PluginDebug.debug ("DISPATCHCALLREQUESTS 3");
 +            if (request != null) {
-+                System.out.println ("DISPATCHCALLREQUESTS 5");
++                PluginDebug.debug ("DISPATCHCALLREQUESTS 5");
 +                synchronized(request) {
 +                    request.parseReturn(message);
 +                    request.notifyAll();
 +                }
-+        System.out.println ("DISPATCHCALLREQUESTS 6");
-+        System.out.println ("DISPATCHCALLREQUESTS 7");
++        PluginDebug.debug ("DISPATCHCALLREQUESTS 6");
++        PluginDebug.debug ("DISPATCHCALLREQUESTS 7");
 +            }
 +        }
-+        System.out.println ("DISPATCHCALLREQUESTS 8");
++        PluginDebug.debug ("DISPATCHCALLREQUESTS 8");
 +    }
 +
 +    /**
@@ -2453,17 +2963,41 @@
 +     */
 +    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) {
-+                throw new RuntimeException(e);
-+            }
-+
++        	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
++        		if (!shuttingDown) {
++        			throw new RuntimeException(e);
++        		}
++        	}
++		}
++
++		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;
++    	}
 +    }
 +
 +    /**
@@ -2475,33 +3009,147 @@
 +     */
 +    static String read()
 +    {
-+        try {
-+            pluginInputTokenizer.nextToken();
-+        } catch (IOException e) {
-+            throw new RuntimeException(e);
-+        }
-+	String message = pluginInputTokenizer.sval;
-+        System.err.println("  PIPE: appletviewer read: " + message);
-+	if (message == null || message.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);
-+	}
-+	return message;
++    	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")) {
++    		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/jdk/src/share/classes/sun/applet.orig/PluginObjectStore.java openjdk/jdk/src/share/classes/sun/applet/PluginObjectStore.java
---- openjdk/jdk/src/share/classes/sun/applet.orig/PluginObjectStore.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/PluginObjectStore.java	2008-02-23 05:35:59.000000000 -0500
-@@ -0,0 +1,117 @@
+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-08-21 13:23:35.000000000 -0400
+@@ -0,0 +1,46 @@
++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
++		
++		for (PluginMessageHandlerWorker worker: workers) {
++			if (worker.isFree()) {
++				PluginDebug.debug("Found free worker with id " + worker.getWorkerId());
++				return worker;
++			}
++		}
++		
++		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-08-21 13:23:35.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-08-21 13:23:35.000000000 -0400
+@@ -0,0 +1,119 @@
 +/* PluginObjectStore -- manage identifier-to-object mapping
 +   Copyright (C) 2008  Red Hat
 +
@@ -2613,15 +3261,17 @@
 +    }
 +
 +    public void dump() {
-+        Iterator i = objects.keySet().iterator();
-+        while (i.hasNext())
-+            System.out.println(i.next());
++   		Iterator i = objects.keySet().iterator();
++   		while (i.hasNext()) {
++   			Object key = i.next();
++   			System.err.println(key + "::" +  objects.get(key));
++   		}
 +    }
 +}
 +
-diff -urN openjdk/jdk/src/share/classes/sun/applet.orig/TestEnv.java openjdk/jdk/src/share/classes/sun/applet/TestEnv.java
---- openjdk/jdk/src/share/classes/sun/applet.orig/TestEnv.java	1969-12-31 19:00:00.000000000 -0500
-+++ openjdk/jdk/src/share/classes/sun/applet/TestEnv.java	2008-02-23 05:28:05.000000000 -0500
+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-08-21 13:23:36.000000000 -0400
 @@ -0,0 +1,172 @@
 +/* TestEnv -- test JavaScript-to-Java calls
 +   Copyright (C) 2008  Red Hat
@@ -2795,185 +3445,9 @@
 +        return 899;
 +    }
 +}
---- 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-07-14 11:06:02.000000000 -0400
-@@ -0,0 +1,54 @@
-+/* 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);
-+}
---- 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-07-14 11:07:57.000000000 -0400
-@@ -0,0 +1,58 @@
-+/* 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;
-+    }
-+}
-+
---- 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-07-14 11:08:07.000000000 -0400
-@@ -0,0 +1,56 @@
-+/* 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;
-+    }
-+}
+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-07-14 11:08:20.000000000 -0400
++++ openjdk/jdk/src/share/classes/sun/applet/VoidPluginCallRequest.java	2008-08-21 13:23:36.000000000 -0400
 @@ -0,0 +1,49 @@
 +/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
 +   Copyright (C) 2008  Red Hat