changeset 1643:4ec5e065fb53

- Added support for FindClass, GetClassName, GetMethodID, GetToStringValue, NewObject and NewStringUTF. - Split the request wait code in Java processor into a generic function. - Centralized all debug output calls. - ICEDTEAPLUGIN_DEBUG flag now supported. - Dynamic cookie fetching support ported over from current plugin. - Added support for modifying JS objects via SetMember calls. - Message processing model made more robust by using dedicated processing threads, rather than dynamically initialized threads. With this commit, http://www.apl.jhu.edu/~hall/CWP-Sources/CWP-Examples/Chapter19/Everest.html now works.
author Deepak Bhole <dbhole@redhat.com>
date Thu, 23 Jul 2009 11:39:18 -0400
parents d20bab985f89
children 090e738a38e7
files ChangeLog plugin/icedteanp/IcedTeaJavaRequestProcessor.cc plugin/icedteanp/IcedTeaJavaRequestProcessor.h plugin/icedteanp/IcedTeaNPPlugin.cc plugin/icedteanp/IcedTeaNPPlugin.h plugin/icedteanp/IcedTeaPluginRequestProcessor.cc plugin/icedteanp/IcedTeaPluginRequestProcessor.h plugin/icedteanp/IcedTeaPluginUtils.cc plugin/icedteanp/IcedTeaPluginUtils.h plugin/icedteanp/IcedTeaRunnable.cc plugin/icedteanp/IcedTeaRunnable.h plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java
diffstat 12 files changed, 1505 insertions(+), 480 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Jul 17 06:04:59 2009 -0400
+++ b/ChangeLog	Thu Jul 23 11:39:18 2009 -0400
@@ -1,3 +1,26 @@
+2009-07-23  Deepak Bhole  <dbhole@redhat.com>
+
+	* plugin/icedteanp/IcedTeaJavaRequestProcessor.c: Added support for
+	FindClass, GetClassName, GetMethodID, GetToStringValue, NewObject and 
+	NewStringUTF. Split the request wait code into a generic function.
+	* plugin/icedteanp/IcedTeaNPPlugin.cc: Centralize debug output calls. Obey
+	the ICEDTEAPLUGIN_DEBUG flag. Support dynamic cookie fetching.
+	* plugin/icedteanp/IcedTeaPluginRequestProcessor.c: Update multi-threaded
+	processing model. Support SetMember. Set up a dedicated message queue
+	processor (arbitrarily scalable).
+	* plugin/icedteanp/IcedTeaPluginRequestProcessor.h: Add function and
+	variable declerations as needed by the .cc file.
+	* plugin/icedteanp/IcedTeaPluginUtils.cc: Use only long and long long for
+	memory address translation. Add additional utility methods.
+	* plugin/icedteanp/IcedTeaPluginUtils.h: Update as needed by the .cc file.
+	* plugin/icedteanp/IcedTeaRunnable.h: New file. Represents a dispatchable
+	event, extends nsIRunnable.
+	* plugin/icedteanp/IcedTeaRunnable.h: New file. Header for
+	IcedTeaRunnable.cc.
+	* plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java: Fix
+	signature handling to remove the need for return type. Add support for
+	GetToStringValue and GetClassName.
+
 2009-07-17  Gary Benson  <gbenson@redhat.com>
 
 	* ports/hotspot/src/share/vm/shark/sharkBuilder.hpp
--- a/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc	Fri Jul 17 06:04:59 2009 -0400
+++ b/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc	Thu Jul 23 11:39:18 2009 -0400
@@ -67,7 +67,8 @@
 			// Gather the results
 
 			// GetStringUTFChars
-			if (message_parts->at(4) == "GetStringUTFChars")
+			if (message_parts->at(4) == "GetStringUTFChars" ||
+				message_parts->at(4) == "GetToStringValue")
 			{
 				// first item is length, and it is radix 10
 				int length = strtol(message_parts->at(5).c_str(), NULL, 10);
@@ -82,6 +83,31 @@
 
 				IcedTeaPluginUtilities::getUTF16LEString(length, 6 /* start at */, message_parts, result->return_wstring);
 				result_ready = true;
+			} else if (message_parts->at(4) == "FindClass")
+			{
+				result->return_identifier = atoi(message_parts->at(5).c_str());
+				result->return_string->append(message_parts->at(5)); // store it as a string as well, for easy access
+				result_ready = true;
+			} else if (message_parts->at(4) == "GetClassName")
+			{
+				result->return_identifier = atoi(message_parts->at(5).c_str());
+				result->return_string->append(message_parts->at(5));  // store it as a string as well, for easy access
+				result_ready = true;
+			} else if (message_parts->at(4) == "GetMethodID")
+			{
+				result->return_identifier = atoi(message_parts->at(5).c_str());
+				result->return_string->append(message_parts->at(5)); // store it as a string as well, for easy access
+				result_ready = true;
+			} else if (message_parts->at(4) == "NewObject")
+			{
+				result->return_identifier = atoi(message_parts->at(5).c_str());
+				result->return_string->append(message_parts->at(5)); // store it as a string as well, for easy access
+				result_ready = true;
+			} else if (message_parts->at(4) == "NewStringUTF")
+			{
+				result->return_identifier = atoi(message_parts->at(5).c_str());
+				result->return_string->append(message_parts->at(5));  // store it as a string as well, for easy access
+				result_ready = true;
 			}
 
 			delete message_parts;
@@ -119,6 +145,8 @@
 
 JavaRequestProcessor::~JavaRequestProcessor()
 {
+    PLUGIN_DEBUG_0ARG("JavaRequestProcessor::~JavaRequestProcessor\n");
+
 	if (result)
 	{
 		if (result->error_msg)
@@ -134,32 +162,12 @@
 	}
 }
 
-/**
- * Given a string id, fetches the actual string from Java side
- *
- * @param request_data The JavaRequest struct containing request relevant information
- * @return A JavaResultData struct containing the result of the request
- */
-
-JavaResultData*
-JavaRequestProcessor::getString(JavaRequest* request_data)
+void
+JavaRequestProcessor::postAndWaitForResponse(std::string* message)
 {
-	std::string string_id;
-	std::string* message;
-
-	this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
-	this->reference = IcedTeaPluginUtilities::getReference();
-
-	string_id = request_data->data->at(0);
-
-	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
-
-    message->append(" GetStringUTFChars "); // get it in UTF8
-    message->append(string_id);
-
     struct timespec t;
     clock_gettime(CLOCK_REALTIME, &t);
-    t.tv_sec += 60; // 1 minute timeout
+    t.tv_sec += REQUESTTIMEOUT; // 1 minute timeout
 
     result_ready = false;
     java_to_plugin_bus->subscribe(this);
@@ -174,7 +182,7 @@
         bool timedout = false;
 
 		if (!result_ready && (curr_t.tv_sec < t.tv_sec))
-			sleep(1);
+			usleep(2000);
 		else
 			break;
 
@@ -187,9 +195,195 @@
     }
 
     java_to_plugin_bus->unSubscribe(this);
+}
+
+/**
+ * Given an object id, fetches the toString() value from Java
+ *
+ * @param object_id The ID of the object
+ * @return A JavaResultData struct containing the result of the request
+ */
+
+JavaResultData*
+JavaRequestProcessor::getToStringValue(std::string object_id)
+{
+	std::string* message;
+
+	this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+	this->reference = IcedTeaPluginUtilities::getReference();
+
+	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+
+    message->append(" GetToStringValue "); // get it in UTF8
+    message->append(object_id);
+
+    postAndWaitForResponse(message);
+
 	IcedTeaPluginUtilities::releaseReference();
+    delete message;
+
+	return result;
+}
+
+/**
+ * Given a string id, fetches the actual string from Java side
+ *
+ * @param string_id The ID of the string
+ * @return A JavaResultData struct containing the result of the request
+ */
+
+JavaResultData*
+JavaRequestProcessor::getString(std::string string_id)
+{
+	std::string* message;
+
+	this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+	this->reference = IcedTeaPluginUtilities::getReference();
+
+	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+
+    message->append(" GetStringUTFChars "); // get it in UTF8
+    message->append(string_id);
+
+    postAndWaitForResponse(message);
+
+	IcedTeaPluginUtilities::releaseReference();
+    delete message;
+
+	return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::findClass(std::string name)
+{
+	std::string* message;
+
+	this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+	this->reference = IcedTeaPluginUtilities::getReference();
+
+	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+
+    message->append(" FindClass ");
+    message->append(name);
+
+    postAndWaitForResponse(message);
 
     delete message;
 
 	return result;
 }
+
+JavaResultData*
+JavaRequestProcessor::getClassName(std::string ID)
+{
+	std::string* message;
+
+	this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+	this->reference = IcedTeaPluginUtilities::getReference();
+
+	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+
+    message->append(" GetClassName ");
+    message->append(ID);
+
+    postAndWaitForResponse(message);
+
+    delete message;
+
+	return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getMethodID(std::string objectID, NPIdentifier methodName,
+                                  std::vector<std::string> args)
+{
+	JavaRequestProcessor* java_request;
+	std::string* message;
+    std::string* signature;
+
+    signature = new std::string();
+    *signature += "(";
+
+    // FIXME: Need to determine how to extract array types and complex java objects
+    for (int i=0; i < args.size(); i++)
+    {
+    	*signature += args[i];
+    }
+
+    *signature += ")";
+
+	this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+	this->reference = IcedTeaPluginUtilities::getReference();
+
+	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+	*message += " GetMethodID ";
+	*message += objectID;
+	*message += " ";
+	*message += browser_functions.utf8fromidentifier(methodName);
+	*message += " ";
+	*message += *signature;
+
+	postAndWaitForResponse(message);
+
+	IcedTeaPluginUtilities::releaseReference();
+	delete signature;
+	delete message;
+
+	return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::newObject(std::string objectID, std::string methodID,
+                                  std::vector<std::string> args)
+{
+	JavaRequestProcessor* java_request;
+	std::string* message;
+
+	this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+	this->reference = IcedTeaPluginUtilities::getReference();
+
+	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+	*message += " NewObject ";
+	*message += objectID;
+	*message += " ";
+	*message += methodID;
+	*message += " ";
+
+	for (int i=0; i < args.size(); i++)
+	{
+		*message += args[i];
+		*message += " ";
+	}
+
+	postAndWaitForResponse(message);
+
+	IcedTeaPluginUtilities::releaseReference();
+	delete message;
+
+	return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::newString(std::string str)
+{
+	JavaRequestProcessor* java_request;
+	std::string* utf_string = new std::string();
+	std::string* message;
+
+	IcedTeaPluginUtilities::convertStringToUTF8(&str, utf_string);
+
+	this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+	this->reference = IcedTeaPluginUtilities::getReference();
+
+	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+	message->append(" NewStringUTF ");
+	message->append(*utf_string);
+
+	postAndWaitForResponse(message);
+
+	IcedTeaPluginUtilities::releaseReference();
+	delete utf_string;
+	delete message;
+
+	return result;
+}
--- a/plugin/icedteanp/IcedTeaJavaRequestProcessor.h	Fri Jul 17 06:04:59 2009 -0400
+++ b/plugin/icedteanp/IcedTeaJavaRequestProcessor.h	Thu Jul 23 11:39:18 2009 -0400
@@ -46,6 +46,8 @@
 #include "IcedTeaNPPlugin.h"
 #include "IcedTeaPluginUtils.h"
 
+#define REQUESTTIMEOUT 60
+
 /*
  * This struct holds data specific to a Java operation requested by the plugin
  */
@@ -97,11 +99,41 @@
     	bool result_ready;
     	JavaResultData* result;
 
+    	/* Post message on bus and wait */
+    	void postAndWaitForResponse(std::string* message);
+
     public:
     	JavaRequestProcessor();
     	~JavaRequestProcessor();
     	virtual bool newMessageOnBus(const char* message);
-    	JavaResultData* getString(JavaRequest* request_data);
+
+    	/* Returns the toString() value, given an object identifier */
+    	JavaResultData* getToStringValue(std::string object_id);
+
+    	/* Returns the string, given the identifier */
+    	JavaResultData* getString(std::string string_id);
+
+    	/* Returns the method ID from Java side */
+    	JavaResultData* getMethodID1(NPObject* obj, NPIdentifier methodName,
+                        std::vector<NPVariant> args);
+
+    	/* Returns the method id */
+    	JavaResultData* getMethodID(std::string objectID, NPIdentifier methodName,
+                                    std::vector<std::string> args);
+
+    	/* Creates a new object */
+    	JavaResultData* newObject(std::string objectID, std::string methodID,
+                                    std::vector<std::string> args);
+
+    	/* Returns the class ID */
+    	JavaResultData* findClass(std::string name);
+
+    	/* Returns the type class name */
+    	JavaResultData* getClassName(std::string ID);
+
+    	/* Creates a new string in the Java store */
+    	JavaResultData* newString(std::string str);
+
 };
 
 #endif /* ICEDTEAJAVAREQUESTPROCESSOR_H_ */
--- a/plugin/icedteanp/IcedTeaNPPlugin.cc	Fri Jul 17 06:04:59 2009 -0400
+++ b/plugin/icedteanp/IcedTeaNPPlugin.cc	Thu Jul 23 11:39:18 2009 -0400
@@ -71,14 +71,6 @@
  #include "IcedTeaScriptablePluginObject.h"
 #include "IcedTeaNPPlugin.h"
 
-// Debugging macros.
-#define PLUGIN_DEBUG(message)                                           \
-  g_print ("GCJ PLUGIN: thread %p: %s\n", g_thread_self (), message)
-
-#define PLUGIN_DEBUG_TWO(first, second)                                 \
-  g_print ("GCJ PLUGIN: thread %p: %s %s\n", g_thread_self (),          \
-           first, second)
-
 // Error reporting macros.
 #define PLUGIN_ERROR(message)                                       \
   g_printerr ("%s:%d: thread %p: Error: %s\n", __FILE__, __LINE__,  \
@@ -180,7 +172,7 @@
 // Various message buses carrying information to/from Java, and internally
 MessageBus* plugin_to_java_bus = new MessageBus();
 MessageBus* java_to_plugin_bus = new MessageBus();
-MessageBus* internal_bus = new MessageBus();
+//MessageBus* internal_bus = new MessageBus();
 
 // Processor for plugin requests
 PluginRequestProcessor* plugin_req_proc = new PluginRequestProcessor();
@@ -265,6 +257,8 @@
 static GPid appletviewer_pid = -1;
 static guint appletviewer_watch_id = -1;
 
+int plugin_debug = getenv ("ICEDTEAPLUGIN_DEBUG") != NULL;
+
 // Functions prefixed by GCJ_ are instance functions.  They are called
 // by the browser and operate on instances of GCJPluginData.
 // Functions prefixed by plugin_ are static helper functions.
@@ -289,7 +283,22 @@
          int16 argc, char* argn[], char* argv[],
          NPSavedData* saved)
 {
-  PLUGIN_DEBUG ("GCJ_New");
+  PLUGIN_DEBUG_0ARG("GCJ_New\n");
+
+  static NPObject *window_ptr;
+  NPIdentifier identifier;
+  NPVariant member_ptr;
+  browser_functions.getvalue(instance, NPNVWindowNPObject, &window_ptr);
+  identifier = browser_functions.getstringidentifier("document");
+  printf("Looking for %p %p %p (%s)\n", instance, window_ptr, identifier, "document");
+  if (!browser_functions.hasproperty(instance, window_ptr, identifier))
+  {
+	printf("%s not found!\n", "document");
+  }
+  browser_functions.getproperty(instance, window_ptr, identifier, &member_ptr);
+
+  PLUGIN_DEBUG_1ARG("Got variant %p\n", &member_ptr);
+
 
   NPError np_error = NPERR_NO_ERROR;
   GCJPluginData* data = NULL;
@@ -390,9 +399,6 @@
 
   instance->pdata = data;
 
-  java_to_plugin_bus->subscribe(plugin_req_proc);
-  plugin_to_java_bus->subscribe(java_req_proc);
-
   goto cleanup_done;
 
  cleanup_appletviewer_mutex:
@@ -428,7 +434,7 @@
   g_hash_table_insert(id_to_instance_map, GINT_TO_POINTER(instance_counter), instance);
   instance_counter++;
 
-  PLUGIN_DEBUG ("GCJ_New return");
+  PLUGIN_DEBUG_0ARG ("GCJ_New return\n");
 
   return np_error;
 }
@@ -475,14 +481,14 @@
   // clean up any older pip
   unlink (in_pipe_name);
 
-  PLUGIN_DEBUG_TWO ("GCJ_New: creating input fifo:", in_pipe_name);
+  PLUGIN_DEBUG_1ARG ("GCJ_New: creating input fifo: %s", in_pipe_name);
   if (mkfifo (in_pipe_name, 0700) == -1 && errno != EEXIST)
     {
       PLUGIN_ERROR_TWO ("Failed to create input pipe", strerror (errno));
       np_error = NPERR_GENERIC_ERROR;
       goto cleanup_in_pipe_name;
     }
-  PLUGIN_DEBUG_TWO ("GCJ_New: created input fifo:", in_pipe_name);
+  PLUGIN_DEBUG_1ARG ("GCJ_New: created input fifo: %s\n", in_pipe_name);
 
   // Create plugin-to-appletviewer pipe which we refer to as the
   // output pipe.
@@ -501,14 +507,14 @@
   // clean up any older pip
   unlink (out_pipe_name);
 
-  PLUGIN_DEBUG_TWO ("GCJ_New: creating output fifo:", out_pipe_name);
+  PLUGIN_DEBUG_1ARG ("GCJ_New: creating output fifo: %s\n", out_pipe_name);
   if (mkfifo (out_pipe_name, 0700) == -1 && errno != EEXIST)
     {
       PLUGIN_ERROR_TWO ("Failed to create output pipe", strerror (errno));
       np_error = NPERR_GENERIC_ERROR;
       goto cleanup_out_pipe_name;
     }
-  PLUGIN_DEBUG_TWO ("GCJ_New: created output fifo:", out_pipe_name);
+  PLUGIN_DEBUG_1ARG ("GCJ_New: created output fifo: %s\n", out_pipe_name);
 
   // Start a separate appletviewer process for each applet, even if
   // there are multiple applets in the same page.  We may need to
@@ -599,9 +605,9 @@
 
   // cleanup_out_pipe:
   // Delete output pipe.
-  PLUGIN_DEBUG_TWO ("GCJ_New: deleting input fifo:", in_pipe_name);
+  PLUGIN_DEBUG_1ARG ("GCJ_New: deleting input fifo: %s\n", in_pipe_name);
   unlink (out_pipe_name);
-  PLUGIN_DEBUG_TWO ("GCJ_New: deleted input fifo:", in_pipe_name);
+  PLUGIN_DEBUG_1ARG ("GCJ_New: deleted input fifo: %s\n", in_pipe_name);
 
  cleanup_out_pipe_name:
   g_free (out_pipe_name);
@@ -609,9 +615,9 @@
 
   // cleanup_in_pipe:
   // Delete input pipe.
-  PLUGIN_DEBUG_TWO ("GCJ_New: deleting output fifo:", out_pipe_name);
+  PLUGIN_DEBUG_1ARG ("GCJ_New: deleting output fifo: %s\n", out_pipe_name);
   unlink (in_pipe_name);
-  PLUGIN_DEBUG_TWO ("GCJ_New: deleted output fifo:", out_pipe_name);
+  PLUGIN_DEBUG_1ARG ("GCJ_New: deleted output fifo: %s\n", out_pipe_name);
 
  cleanup_in_pipe_name:
   g_free (in_pipe_name);
@@ -627,7 +633,7 @@
 NPError
 GCJ_GetValue (NPP instance, NPPVariable variable, void* value)
 {
-  PLUGIN_DEBUG ("GCJ_GetValue");
+  PLUGIN_DEBUG_0ARG ("GCJ_GetValue\n");
 
   NPError np_error = NPERR_NO_ERROR;
 
@@ -636,7 +642,7 @@
     // This plugin needs XEmbed support.
     case NPPVpluginNeedsXEmbed:
       {
-        PLUGIN_DEBUG ("GCJ_GetValue: returning TRUE for NeedsXEmbed.");
+        PLUGIN_DEBUG_0ARG ("GCJ_GetValue: returning TRUE for NeedsXEmbed.\n");
         PRBool* bool_value = (PRBool*) value;
         *bool_value = PR_TRUE;
       }
@@ -653,7 +659,7 @@
       break;
     }
 
-  PLUGIN_DEBUG ("GCJ_GetValue return");
+  PLUGIN_DEBUG_0ARG ("GCJ_GetValue return\n");
 
   return np_error;
 }
@@ -661,7 +667,7 @@
 NPError
 GCJ_Destroy (NPP instance, NPSavedData** save)
 {
-  PLUGIN_DEBUG ("GCJ_Destroy");
+  PLUGIN_DEBUG_0ARG ("GCJ_Destroy\n");
 
   GCJPluginData* data = (GCJPluginData*) instance->pdata;
 
@@ -671,7 +677,7 @@
       plugin_data_destroy (instance);
     }
 
-  PLUGIN_DEBUG ("GCJ_Destroy return");
+  PLUGIN_DEBUG_0ARG ("GCJ_Destroy return\n");
 
   return NPERR_NO_ERROR;
 }
@@ -679,7 +685,7 @@
 NPError
 GCJ_SetWindow (NPP instance, NPWindow* window)
 {
-  PLUGIN_DEBUG ("GCJ_SetWindow");
+  PLUGIN_DEBUG_0ARG ("GCJ_SetWindow");
 
   if (instance == NULL)
     {
@@ -701,7 +707,7 @@
   // Simply return if we receive a NULL window.
   if ((window == NULL) || (window->window == NULL))
     {
-      PLUGIN_DEBUG ("GCJ_SetWindow: got NULL window.");
+      PLUGIN_DEBUG_0ARG ("GCJ_SetWindow: got NULL window.\n");
 
       return NPERR_NO_ERROR;
     }
@@ -712,7 +718,7 @@
       if (data->window_handle == window->window)
     {
           // The parent window is the same as in previous calls.
-          PLUGIN_DEBUG ("GCJ_SetWindow: window already exists.");
+          PLUGIN_DEBUG_0ARG ("GCJ_SetWindow: window already exists.\n");
 
           // Critical region.  Read data->appletviewer_mutex and send
           // a message to the appletviewer.
@@ -727,7 +733,7 @@
           // SetWindow call.
           if (window->width != data->window_width)
         {
-                  PLUGIN_DEBUG ("GCJ_SetWindow: window width changed.");
+                  PLUGIN_DEBUG_0ARG ("GCJ_SetWindow: window width changed.\n");
           // The width of the plugin window has changed.
 
                   // Store the new width.
@@ -737,7 +743,7 @@
 
           if (window->height != data->window_height)
         {
-                  PLUGIN_DEBUG ("GCJ_SetWindow: window height changed.");
+                  PLUGIN_DEBUG_0ARG ("GCJ_SetWindow: window height changed.\n");
           // The height of the plugin window has changed.
 
                   // Store the new height.
@@ -759,7 +765,7 @@
       else
         {
               // The appletviewer is not running.
-          PLUGIN_DEBUG ("GCJ_SetWindow: appletviewer is not running.");
+          PLUGIN_DEBUG_0ARG ("GCJ_SetWindow: appletviewer is not running.\n");
         }
 
           g_mutex_unlock (data->appletviewer_mutex);
@@ -768,12 +774,12 @@
     {
       // The parent window has changed.  This branch does run but
       // doing nothing in response seems to be sufficient.
-      PLUGIN_DEBUG ("GCJ_SetWindow: parent window changed.");
+      PLUGIN_DEBUG_0ARG ("GCJ_SetWindow: parent window changed.\n");
     }
     }
   else
     {
-      PLUGIN_DEBUG ("GCJ_SetWindow: setting window.");
+      PLUGIN_DEBUG_0ARG ("GCJ_SetWindow: setting window.\n");
 
       // Critical region.  Send messages to appletviewer.
       g_mutex_lock (data->appletviewer_mutex);
@@ -797,7 +803,7 @@
       data->window_handle = window->window;
     }
 
-  PLUGIN_DEBUG ("GCJ_SetWindow return");
+  PLUGIN_DEBUG_0ARG ("GCJ_SetWindow return\n");
 
   return NPERR_NO_ERROR;
 }
@@ -806,9 +812,9 @@
 GCJ_NewStream (NPP instance, NPMIMEType type, NPStream* stream,
                NPBool seekable, uint16* stype)
 {
-  PLUGIN_DEBUG ("GCJ_NewStream");
+  PLUGIN_DEBUG_0ARG ("GCJ_NewStream\n");
 
-  PLUGIN_DEBUG ("GCJ_NewStream return");
+  PLUGIN_DEBUG_0ARG ("GCJ_NewStream return\n");
 
   return NPERR_NO_ERROR;
 }
@@ -816,17 +822,17 @@
 void
 GCJ_StreamAsFile (NPP instance, NPStream* stream, const char* filename)
 {
-  PLUGIN_DEBUG ("GCJ_StreamAsFile");
+  PLUGIN_DEBUG_0ARG ("GCJ_StreamAsFile\n");
 
-  PLUGIN_DEBUG ("GCJ_StreamAsFile return");
+  PLUGIN_DEBUG_0ARG ("GCJ_StreamAsFile return\n");
 }
 
 NPError
 GCJ_DestroyStream (NPP instance, NPStream* stream, NPReason reason)
 {
-  PLUGIN_DEBUG ("GCJ_DestroyStream");
+  PLUGIN_DEBUG_0ARG ("GCJ_DestroyStream\n");
 
-  PLUGIN_DEBUG ("GCJ_DestroyStream return");
+  PLUGIN_DEBUG_0ARG ("GCJ_DestroyStream return\n");
 
   return NPERR_NO_ERROR;
 }
@@ -834,9 +840,9 @@
 int32
 GCJ_WriteReady (NPP instance, NPStream* stream)
 {
-  PLUGIN_DEBUG ("GCJ_WriteReady");
+  PLUGIN_DEBUG_0ARG ("GCJ_WriteReady\n");
 
-  PLUGIN_DEBUG ("GCJ_WriteReady return");
+  PLUGIN_DEBUG_0ARG ("GCJ_WriteReady return\n");
 
   return 0;
 }
@@ -845,9 +851,9 @@
 GCJ_Write (NPP instance, NPStream* stream, int32 offset, int32 len,
            void* buffer)
 {
-  PLUGIN_DEBUG ("GCJ_Write");
+  PLUGIN_DEBUG_0ARG ("GCJ_Write\n");
 
-  PLUGIN_DEBUG ("GCJ_Write return");
+  PLUGIN_DEBUG_0ARG ("GCJ_Write return\n");
 
   return 0;
 }
@@ -855,17 +861,17 @@
 void
 GCJ_Print (NPP instance, NPPrint* platformPrint)
 {
-  PLUGIN_DEBUG ("GCJ_Print");
+  PLUGIN_DEBUG_0ARG ("GCJ_Print\n");
 
-  PLUGIN_DEBUG ("GCJ_Print return");
+  PLUGIN_DEBUG_0ARG ("GCJ_Print return\n");
 }
 
 int16
 GCJ_HandleEvent (NPP instance, void* event)
 {
-  PLUGIN_DEBUG ("GCJ_HandleEvent");
+  PLUGIN_DEBUG_0ARG ("GCJ_HandleEvent\n");
 
-  PLUGIN_DEBUG ("GCJ_HandleEvent return");
+  PLUGIN_DEBUG_0ARG ("GCJ_HandleEvent return\n");
 
   return 0;
 }
@@ -874,17 +880,17 @@
 GCJ_URLNotify (NPP instance, const char* url, NPReason reason,
                void* notifyData)
 {
-  PLUGIN_DEBUG ("GCJ_URLNotify");
+  PLUGIN_DEBUG_0ARG ("GCJ_URLNotify\n");
 
-  PLUGIN_DEBUG ("GCJ_URLNotify return");
+  PLUGIN_DEBUG_0ARG ("GCJ_URLNotify return\n");
 }
 
 jref
 GCJ_GetJavaClass (void)
 {
-  PLUGIN_DEBUG ("GCJ_GetJavaClass");
+  PLUGIN_DEBUG_0ARG ("GCJ_GetJavaClass\n");
 
-  PLUGIN_DEBUG ("GCJ_GetJavaClass return");
+  PLUGIN_DEBUG_0ARG ("GCJ_GetJavaClass return\n");
 
   return 0;
 }
@@ -892,7 +898,6 @@
 NS_IMETHODIMP
 get_cookie_info(const char* siteAddr, char** cookieString)
 {
-
   nsresult rv;
   nsCOMPtr<nsIScriptSecurityManager> sec_man =
     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
@@ -931,7 +936,7 @@
 static void
 plugin_data_new (GCJPluginData** data)
 {
-  PLUGIN_DEBUG ("plugin_data_new");
+  PLUGIN_DEBUG_0ARG ("plugin_data_new");
 
   *data = (GCJPluginData*)
     (*browser_functions.memalloc) (sizeof (struct GCJPluginData));
@@ -940,7 +945,7 @@
   if (*data)
     memset (*data, 0, sizeof (struct GCJPluginData));
 
-  PLUGIN_DEBUG ("plugin_data_new return");
+  PLUGIN_DEBUG_0ARG ("plugin_data_new return\n");
 }
 
 // Documentbase retrieval.  This function gets the current document's
@@ -952,7 +957,7 @@
 static gchar*
 plugin_get_documentbase (NPP instance)
 {
-  PLUGIN_DEBUG ("plugin_get_documentbase");
+  PLUGIN_DEBUG_0ARG ("plugin_get_documentbase");
 
   nsIPluginInstance* xpcom_instance = NULL;
   nsIPluginInstancePeer* peer = NULL;
@@ -1004,7 +1009,7 @@
   NS_RELEASE (peer);
 
  cleanup_done:
-  PLUGIN_DEBUG ("plugin_get_documentbase return");
+  PLUGIN_DEBUG_0ARG ("plugin_get_documentbase return\n");
 
   return documentbase_copy;
 }
@@ -1016,7 +1021,7 @@
 {
   GtkWidget* dialog = NULL;
 
-  PLUGIN_DEBUG ("plugin_display_failure_dialog");
+  PLUGIN_DEBUG_0ARG ("plugin_display_failure_dialog");
 
   dialog = gtk_message_dialog_new (NULL,
                                    GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -1028,7 +1033,7 @@
   gtk_dialog_run (GTK_DIALOG (dialog));
   gtk_widget_destroy (dialog);
 
-  PLUGIN_DEBUG ("plugin_display_failure_dialog return");
+  PLUGIN_DEBUG_0ARG ("plugin_display_failure_dialog return\n");
 }
 
 
@@ -1042,7 +1047,7 @@
                          GIOCondition condition,
                          gpointer plugin_data)
 {
-  PLUGIN_DEBUG ("plugin_in_pipe_callback");
+  PLUGIN_DEBUG_0ARG ("plugin_in_pipe_callback\n");
 
   gboolean keep_installed = TRUE;
 
@@ -1077,18 +1082,18 @@
 
   if (condition & (G_IO_ERR | G_IO_HUP))
     {
-      PLUGIN_DEBUG ("appletviewer has stopped.");
+      PLUGIN_DEBUG_0ARG ("appletviewer has stopped.\n");
       keep_installed = FALSE;
     }
 
-  PLUGIN_DEBUG ("plugin_in_pipe_callback return");
+  PLUGIN_DEBUG_0ARG ("plugin_in_pipe_callback return\n");
 
   return keep_installed;
 }
 
 void consume_message(gchar* message) {
 
-  g_print ("  PIPE: plugin read: %s\n", message);
+	PLUGIN_DEBUG_1ARG ("  PIPE: plugin read: %s\n", message);
 
   if (g_str_has_prefix (message, "instance"))
     {
@@ -1117,8 +1122,8 @@
           gchar* decoded_url = (gchar*) malloc(strlen(parts[3])*sizeof(gchar) + sizeof(gchar));
           decode_url(parts[3], &decoded_url);
 
-          PLUGIN_DEBUG_TWO ("plugin_in_pipe_callback: opening URL", decoded_url);
-          PLUGIN_DEBUG_TWO ("plugin_in_pipe_callback: URL target", parts[4]);
+          PLUGIN_DEBUG_1ARG ("plugin_in_pipe_callback: opening URL %s\n", decoded_url);
+          PLUGIN_DEBUG_1ARG ("plugin_in_pipe_callback: URL target %s\n", parts[4]);
 
           NPError np_error =
             (*browser_functions.geturl) (data->owner, decoded_url, parts[4]);
@@ -1140,7 +1145,7 @@
 
           // join the rest
           gchar* status_message = g_strjoinv(" ", parts);
-          PLUGIN_DEBUG_TWO ("plugin_in_pipe_callback: setting status", status_message);
+          PLUGIN_DEBUG_1ARG ("plugin_in_pipe_callback: setting status %s\n", status_message);
           (*browser_functions.status) (data->owner, status_message);
 
           g_free(status_message);
@@ -1148,7 +1153,7 @@
         }
       else if (g_str_has_prefix (parts[1], "internal"))
     	{
-    	  internal_bus->post(message);
+    	  //s->post(message);
     	}
       else
         {
@@ -1201,6 +1206,29 @@
         proxy_host = NULL;
         g_free(proxy_port);
         proxy_port = NULL;
+      } else if (g_str_has_prefix(parts[1], "PluginCookieInfo"))
+      {
+        GError *error = g_error_new(ITNP_PLUGIN_ERROR, 0, "");
+
+        gchar* decoded_url = (gchar*) malloc(strlen(parts[2])*sizeof(gchar) + sizeof(gchar));
+        decode_url(parts[2], &decoded_url);
+
+        gchar* cookie_info = g_strconcat ("plugin PluginCookieInfo ", parts[2], " ", NULL);
+        gchar* cookie_string;
+        if (get_cookie_info(decoded_url, &cookie_string) == NS_OK)
+        {
+            cookie_info = g_strconcat (cookie_info, cookie_string, NULL);
+        }
+
+        PLUGIN_DEBUG_1ARG("Cookie info: %s\n", cookie_info);
+        plugin_send_message_to_appletviewer(cookie_info);
+
+        g_free(decoded_url);
+        decoded_url = NULL;
+        g_free(cookie_string);
+        cookie_string = NULL;
+        g_free(cookie_info);
+        cookie_info = NULL;
       }
     }
   else
@@ -1309,6 +1337,42 @@
   PLUGIN_DEBUG_4ARG("Proxy info for %s: %s %s %s\n", siteAddr, *proxy_scheme, *proxy_host, *proxy_port);
 }
 
+/*
+void get_cookie_info(const char* siteAddr, char** cookie_string)
+{
+	nsresult rv;
+	nsCOMPtr<nsIScriptSecurityManager> sec_man = do_GetService(
+			NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
+
+	if (!sec_man) {
+		return NS_ERROR_FAILURE;
+	}
+
+	nsCOMPtr<nsIIOService> io_svc = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
+
+	if (NS_FAILED(rv) || !io_svc) {
+		return NS_ERROR_FAILURE;
+	}
+
+	nsCOMPtr<nsIURI> uri;
+	io_svc->NewURI(nsCString(siteAddr), NULL, NULL, getter_AddRefs(uri));
+
+	nsCOMPtr<nsICookieService> cookie_svc = do_GetService(
+			NS_COOKIESERVICE_CONTRACTID, &rv);
+
+	if (NS_FAILED(rv) || !cookie_svc) {
+		return NS_ERROR_FAILURE;
+	}
+
+	rv = cookie_svc->GetCookieString(uri, NULL, cookieString);
+
+	if (NS_FAILED(rv) || !*cookieString) {
+		return NS_ERROR_FAILURE;
+	}
+
+	return NS_OK;
+}*/
+
 // plugin_out_pipe_callback is called when the appletviewer crashes or
 // is killed.  It may be called after data has been destroyed in which
 // case it simply returns FALSE to remove itself from the glib main
@@ -1318,13 +1382,13 @@
                           GIOCondition condition,
                           gpointer plugin_data)
 {
-  PLUGIN_DEBUG ("plugin_out_pipe_callback");
+  PLUGIN_DEBUG_0ARG ("plugin_out_pipe_callback\n");
 
   GCJPluginData* data = (GCJPluginData*) plugin_data;
 
-  PLUGIN_DEBUG ("plugin_out_pipe_callback: appletviewer has stopped.");
+  PLUGIN_DEBUG_0ARG ("plugin_out_pipe_callback: appletviewer has stopped.\n");
 
-  PLUGIN_DEBUG ("plugin_out_pipe_callback return");
+  PLUGIN_DEBUG_0ARG ("plugin_out_pipe_callback return\n");
 
   return FALSE;
 }
@@ -1332,7 +1396,7 @@
 static NPError
 plugin_test_appletviewer ()
 {
-  PLUGIN_DEBUG ("plugin_test_appletviewer");
+  PLUGIN_DEBUG_0ARG ("plugin_test_appletviewer\n");
   NPError error = NPERR_NO_ERROR;
 
   gchar* command_line[3] = { NULL, NULL, NULL };
@@ -1364,26 +1428,34 @@
   g_free (command_line[2]);
   command_line[2] = NULL;
 
-  PLUGIN_DEBUG ("plugin_test_appletviewer return");
+  PLUGIN_DEBUG_0ARG ("plugin_test_appletviewer return\n");
   return error;
 }
 
 static NPError
 plugin_start_appletviewer (GCJPluginData* data)
 {
-  PLUGIN_DEBUG ("plugin_start_appletviewer");
+  PLUGIN_DEBUG_0ARG ("plugin_start_appletviewer\n");
   NPError error = NPERR_NO_ERROR;
 
-  gchar* command_line[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
+  gchar** command_line;
 
-  command_line[0] = g_strdup (appletviewer_executable);
-  // Output from plugin's perspective is appletviewer's input.
-  // Input from plugin's perspective is appletviewer's output.
-  command_line[1] = g_strdup("-Xdebug");
-  command_line[2] = g_strdup("-Xnoagent");
-  command_line[3] = g_strdup("-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n");
-  command_line[4] = g_strdup("sun.applet.PluginMain");
-  command_line[5] = NULL;
+  if (plugin_debug)
+  {
+      command_line = (gchar**) malloc(sizeof(gchar*)*6);
+      command_line[0] = g_strdup(appletviewer_executable);
+      command_line[1] = g_strdup("-Xdebug");
+      command_line[2] = g_strdup("-Xnoagent");
+      command_line[3] = g_strdup("-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n");
+      command_line[4] = g_strdup("sun.applet.PluginMain");
+      command_line[5] = NULL;
+   } else
+   {
+       command_line = (gchar**) malloc(sizeof(gchar)*3);
+       command_line[0] = g_strdup(appletviewer_executable);
+       command_line[1] = g_strdup("sun.applet.PluginMain");
+       command_line[2] = NULL;
+   }
 
   if (!g_spawn_async (NULL, command_line, NULL, (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD,
                       NULL, NULL, &appletviewer_pid, &channel_error))
@@ -1404,14 +1476,21 @@
   command_line[0] = NULL;
   g_free (command_line[1]);
   command_line[1] = NULL;
-  g_free (command_line[2]);
-  command_line[2] = NULL;
-  g_free (command_line[3]);
-  command_line[3] = NULL;
-  g_free (command_line[4]);
-  command_line[4] = NULL;
-  g_free (command_line[5]);
-  command_line[5] = NULL;
+
+  if (plugin_debug)
+  {
+      g_free (command_line[2]);
+      command_line[2] = NULL;
+      g_free (command_line[3]);
+      command_line[3] = NULL;
+      g_free (command_line[4]);
+      command_line[4] = NULL;
+      g_free (command_line[5]);
+      command_line[5] = NULL;
+  }
+
+  g_free(command_line);
+  command_line = NULL;
 
   if (appletviewer_pid)
     {
@@ -1420,7 +1499,7 @@
     }
 
 
-  PLUGIN_DEBUG ("plugin_start_appletviewer return");
+  PLUGIN_DEBUG_0ARG ("plugin_start_appletviewer return\n");
   return error;
 }
 
@@ -1429,7 +1508,7 @@
 static gchar*
 plugin_create_applet_tag (int16 argc, char* argn[], char* argv[])
 {
-  PLUGIN_DEBUG ("plugin_create_applet_tag");
+  PLUGIN_DEBUG_0ARG ("plugin_create_applet_tag\n");
 
   gchar* applet_tag = g_strdup ("<EMBED ");
   gchar* parameters = g_strdup ("");
@@ -1501,7 +1580,7 @@
   g_free (parameters);
   parameters = NULL;
 
-  PLUGIN_DEBUG ("plugin_create_applet_tag return");
+  PLUGIN_DEBUG_0ARG ("plugin_create_applet_tag return\n");
 
   return applet_tag;
 }
@@ -1511,7 +1590,7 @@
 void
 plugin_send_message_to_appletviewer (gchar const* message)
 {
-  PLUGIN_DEBUG ("plugin_send_message_to_appletviewer");
+  PLUGIN_DEBUG_0ARG ("plugin_send_message_to_appletviewer\n");
 
   if (jvm_up)
     {
@@ -1556,10 +1635,10 @@
       g_free (newline_message);
       newline_message = NULL;
 
-      g_print ("  PIPE: plugin wrote: %s\n", message);
+      PLUGIN_DEBUG_1ARG ("  PIPE: plugin wrote: %s\n", message);
     }
 
-  PLUGIN_DEBUG ("plugin_send_message_to_appletviewer return");
+  PLUGIN_DEBUG_0ARG ("plugin_send_message_to_appletviewer return\n");
 }
 
 // Stop the appletviewer process.  When this is called the
@@ -1578,7 +1657,7 @@
 static void
 plugin_stop_appletviewer ()
 {
-  PLUGIN_DEBUG ("plugin_stop_appletviewer");
+  PLUGIN_DEBUG_0ARG ("plugin_stop_appletviewer\n");
 
   if (jvm_up)
     {
@@ -1654,21 +1733,21 @@
   jvm_up = FALSE;
   sleep(2); /* Needed to prevent crashes during debug (when JDWP port is not freed by the kernel right away) */
 
-  PLUGIN_DEBUG ("plugin_stop_appletviewer return");
+  PLUGIN_DEBUG_0ARG ("plugin_stop_appletviewer return\n");
 }
 
 static void appletviewer_monitor(GPid pid, gint status, gpointer data)
 {
-    PLUGIN_DEBUG ("appletviewer_monitor");
+    PLUGIN_DEBUG_0ARG ("appletviewer_monitor\n");
     jvm_up = FALSE;
     pid = -1;
-    PLUGIN_DEBUG ("appletviewer_monitor return");
+    PLUGIN_DEBUG_0ARG ("appletviewer_monitor return\n");
 }
 
 static void
 plugin_data_destroy (NPP instance)
 {
-  PLUGIN_DEBUG ("plugin_data_destroy");
+  PLUGIN_DEBUG_0ARG ("plugin_data_destroy\n");
 
   GCJPluginData* tofree = (GCJPluginData*) instance->pdata;
 
@@ -1700,7 +1779,7 @@
   (*browser_functions.memfree) (tofree);
   tofree = NULL;
 
-  PLUGIN_DEBUG ("plugin_data_destroy return");
+  PLUGIN_DEBUG_0ARG ("plugin_data_destroy return\n");
 }
 
 // FACTORY FUNCTIONS
@@ -1717,7 +1796,7 @@
 NPError
 NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable)
 {
-  PLUGIN_DEBUG ("NP_Initialize");
+  PLUGIN_DEBUG_0ARG ("NP_Initialize\n");
 
   if (initialized)
     return NPERR_NO_ERROR;
@@ -1882,9 +1961,18 @@
 
   plugin_instance_mutex = g_mutex_new ();
 
-  PLUGIN_DEBUG_TWO ("NP_Initialize: using", appletviewer_executable);
+  PLUGIN_DEBUG_1ARG ("NP_Initialize: using %s\n", appletviewer_executable);
+
+  PLUGIN_DEBUG_0ARG ("NP_Initialize return\n");
 
-  PLUGIN_DEBUG ("NP_Initialize return");
+  java_to_plugin_bus->subscribe(plugin_req_proc);
+  plugin_to_java_bus->subscribe(java_req_proc);
+  //internal_bus->subscribe(java_req_proc);
+  //internal_bus->subscribe(plugin_req_proc);
+
+  pthread_create (&plugin_request_processor_thread1, NULL, &queue_processor, (void*) plugin_req_proc);
+  pthread_create (&plugin_request_processor_thread2, NULL, &queue_processor, (void*) plugin_req_proc);
+  pthread_create (&plugin_request_processor_thread3, NULL, &queue_processor, (void*) plugin_req_proc);
 
   return NPERR_NO_ERROR;
 
@@ -1917,9 +2005,9 @@
 char*
 NP_GetMIMEDescription (void)
 {
-  PLUGIN_DEBUG ("NP_GetMIMEDescription");
+  PLUGIN_DEBUG_0ARG ("NP_GetMIMEDescription\n");
 
-  PLUGIN_DEBUG ("NP_GetMIMEDescription return");
+  PLUGIN_DEBUG_0ARG ("NP_GetMIMEDescription return\n");
 
   return (char*) PLUGIN_MIME_DESC;
 }
@@ -1929,7 +2017,7 @@
 NPError
 NP_GetValue (void* future, NPPVariable variable, void* value)
 {
-  PLUGIN_DEBUG ("NP_GetValue");
+  PLUGIN_DEBUG_0ARG ("NP_GetValue\n");
 
   NPError result = NPERR_NO_ERROR;
   gchar** char_value = (gchar**) value;
@@ -1937,12 +2025,12 @@
   switch (variable)
     {
     case NPPVpluginNameString:
-      PLUGIN_DEBUG ("NP_GetValue: returning plugin name.");
+      PLUGIN_DEBUG_0ARG ("NP_GetValue: returning plugin name.\n");
       *char_value = g_strdup (PLUGIN_NAME " " PACKAGE_VERSION);
       break;
 
     case NPPVpluginDescriptionString:
-      PLUGIN_DEBUG ("NP_GetValue: returning plugin description.");
+      PLUGIN_DEBUG_0ARG ("NP_GetValue: returning plugin description.\n");
       *char_value = g_strdup (PLUGIN_DESC);
       break;
 
@@ -1952,7 +2040,7 @@
       break;
     }
 
-  PLUGIN_DEBUG ("NP_GetValue return");
+  PLUGIN_DEBUG_0ARG ("NP_GetValue return\n");
 
   return result;
 }
@@ -1962,7 +2050,7 @@
 NPError
 NP_Shutdown (void)
 {
-  PLUGIN_DEBUG ("NP_Shutdown");
+  PLUGIN_DEBUG_0ARG ("NP_Shutdown\n");
 
   // Free mutex.
   if (plugin_instance_mutex)
@@ -2011,9 +2099,9 @@
 
   // cleanup_out_pipe:
   // Delete output pipe.
-  PLUGIN_DEBUG_TWO ("NP_Shutdown: deleting output fifo:", out_pipe_name);
+  PLUGIN_DEBUG_1ARG ("NP_Shutdown: deleting output fifo: %s\n", out_pipe_name);
   unlink (out_pipe_name);
-  PLUGIN_DEBUG_TWO ("NP_Shutdown: deleted output fifo:", out_pipe_name);
+  PLUGIN_DEBUG_1ARG ("NP_Shutdown: deleted output fifo: %s\n", out_pipe_name);
 
   // cleanup_out_pipe_name:
   g_free (out_pipe_name);
@@ -2021,9 +2109,9 @@
 
   // cleanup_in_pipe:
   // Delete input pipe.
-  PLUGIN_DEBUG_TWO ("NP_Shutdown: deleting input fifo:", in_pipe_name);
+  PLUGIN_DEBUG_1ARG ("NP_Shutdown: deleting input fifo: %s\n", in_pipe_name);
   unlink (in_pipe_name);
-  PLUGIN_DEBUG_TWO ("NP_Shutdown: deleted input fifo:", in_pipe_name);
+  PLUGIN_DEBUG_1ARG ("NP_Shutdown: deleted input fifo: %s\n", in_pipe_name);
 
   // cleanup_in_pipe_name:
   g_free (in_pipe_name);
@@ -2031,7 +2119,22 @@
 
   initialized = false;
 
-  PLUGIN_DEBUG ("NP_Shutdown return");
+  pthread_cancel(plugin_request_processor_thread1);
+  pthread_cancel(plugin_request_processor_thread2);
+  pthread_cancel(plugin_request_processor_thread3);
+
+  java_to_plugin_bus->unSubscribe(plugin_req_proc);
+  plugin_to_java_bus->unSubscribe(java_req_proc);
+  //internal_bus->unSubscribe(java_req_proc);
+  //internal_bus->unSubscribe(plugin_req_proc);
+
+  delete plugin_req_proc;
+  delete java_req_proc;
+  delete java_to_plugin_bus;
+  delete plugin_to_java_bus;
+  //delete internal_bus;
+
+  PLUGIN_DEBUG_0ARG ("NP_Shutdown return\n");
 
   return NPERR_NO_ERROR;
 }
--- a/plugin/icedteanp/IcedTeaNPPlugin.h	Fri Jul 17 06:04:59 2009 -0400
+++ b/plugin/icedteanp/IcedTeaNPPlugin.h	Thu Jul 23 11:39:18 2009 -0400
@@ -54,6 +54,14 @@
 #include "IcedTeaPluginUtils.h"
 #include "IcedTeaPluginRequestProcessor.h"
 
+// Queue processing threads
+static pthread_t plugin_request_processor_thread1;
+static pthread_t plugin_request_processor_thread2;
+static pthread_t plugin_request_processor_thread3;
+
+// debug switch
+extern int plugin_debug;
+
 // Browser function table.
 extern NPNetscapeFuncs browser_functions;
 
@@ -64,7 +72,7 @@
 extern MessageBus* java_to_plugin_bus;
 
 // internal messages (e.g ones that need processing in main thread)
-extern MessageBus* internal_bus;
+//extern MessageBus* internal_bus;
 
 // subscribes to plugin_to_java_bus and sends messages over the link
 extern JavaMessageSender java_request_processor;
@@ -79,7 +87,7 @@
 int get_id_from_instance(NPP* instance);
 
 /* Sends a message to the appletviewer */
-void plugin_send_message_to_appletviewer (gchar const* message);
+void plugin_send_message_to_appletviewer(gchar const* message);
 
 /* Returns a scriptable npobject */
 NPObject* get_scriptable_object(NPP instance);
@@ -87,4 +95,7 @@
 /* Creates a new scriptable plugin object and returns it */
 NPObject* allocate_scriptable_object(NPP npp, NPClass *aClass);
 
+/* SIGUSR1 handler */
+void sigusr1handler();
+
 #endif	/* __ICEDTEANPPLUGIN_H__ */
--- a/plugin/icedteanp/IcedTeaPluginRequestProcessor.cc	Fri Jul 17 06:04:59 2009 -0400
+++ b/plugin/icedteanp/IcedTeaPluginRequestProcessor.cc	Thu Jul 23 11:39:18 2009 -0400
@@ -44,6 +44,11 @@
  * information, script execution and variable get/set
  */
 
+// Initialize static members used by the queue processing framework
+pthread_mutex_t message_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t syn_write_mutex = PTHREAD_MUTEX_INITIALIZER;
+std::vector< std::vector<std::string>* >* message_queue = new std::vector< std::vector<std::string>* >();
+
 /**
  * Given the window pointer, returns the instance associated with it
  *
@@ -55,18 +60,18 @@
 getInstanceFromMemberPtr(void* member_ptr)
 {
 
-	NPP instance = NULL;
-	PLUGIN_DEBUG_1ARG("getInstanceFromMemberPtr looking for %p\n", member_ptr);
+    NPP instance = NULL;
+    PLUGIN_DEBUG_1ARG("getInstanceFromMemberPtr looking for %p\n", member_ptr);
 
-	std::map<void*, NPP>::iterator iterator = instance_map->find(member_ptr);
+    std::map<void*, NPP>::iterator iterator = instance_map->find(member_ptr);
 
-	if (iterator != instance_map->end())
-	{
-		instance = instance_map->find(member_ptr)->second;
-		PLUGIN_DEBUG_2ARG("getInstanceFromMemberPtr found %p. Instance = %p\n", member_ptr, instance);
-	}
+    if (iterator != instance_map->end())
+    {
+        instance = instance_map->find(member_ptr)->second;
+        PLUGIN_DEBUG_2ARG("getInstanceFromMemberPtr found %p. Instance = %p\n", member_ptr, instance);
+    }
 
-	return instance;
+    return instance;
 }
 
 /**
@@ -79,8 +84,8 @@
 void
 storeInstanceID(void* member_ptr, NPP instance)
 {
-	PLUGIN_DEBUG_2ARG("Storing instance %p with key %p\n", instance, member_ptr);
-	instance_map->insert(std::make_pair(member_ptr, instance));
+    PLUGIN_DEBUG_2ARG("Storing instance %p with key %p\n", instance, member_ptr);
+    instance_map->insert(std::make_pair(member_ptr, instance));
 }
 
 /**
@@ -91,8 +96,10 @@
 
 PluginRequestProcessor::PluginRequestProcessor()
 {
-	this->pendingRequests = new std::map<pthread_t, uintmax_t>();
-	instance_map = new std::map<void*, NPP>();
+    this->pendingRequests = new std::map<pthread_t, uintmax_t>();
+    instance_map = new std::map<void*, NPP>();
+
+    internal_req_ref_counter = 0;
 }
 
 /**
@@ -103,11 +110,13 @@
 
 PluginRequestProcessor::~PluginRequestProcessor()
 {
-	if (pendingRequests)
-		delete pendingRequests;
+    PLUGIN_DEBUG_0ARG("PluginRequestProcessor::~PluginRequestProcessor\n");
 
-	if (instance_map)
-		delete instance_map;
+    if (pendingRequests)
+        delete pendingRequests;
+
+    if (instance_map)
+        delete instance_map;
 
 }
 
@@ -121,66 +130,49 @@
 bool
 PluginRequestProcessor::newMessageOnBus(const char* message)
 {
-	PLUGIN_DEBUG_1ARG("PluginRequestProcessor processing %s\n", message);
-
-	std::string type;
-	std::string command;
-	int counter = 0;
+    PLUGIN_DEBUG_1ARG("PluginRequestProcessor processing %s\n", message);
 
-	std::vector<std::string>* message_parts = IcedTeaPluginUtilities::strSplit(message, " ");
+    std::string type;
+    std::string command;
+    int counter = 0;
 
-	std::vector<std::string>::iterator the_iterator;
-	the_iterator = message_parts->begin();
-
-	IcedTeaPluginUtilities::printStringVector("PluginRequestProcessor::newMessageOnBus:", message_parts);
+    std::vector<std::string>* message_parts = IcedTeaPluginUtilities::strSplit(message, " ");
 
-	// Prioritize internal requests
-	if (message_parts->at(0) == "internal")
-	{
-		if (message_parts->at(1) == "SendMember")
-		{
-			// first item is length, and it is radix 10
-			int length = strtol(message_parts->at(3).c_str(), NULL, 10);
+    std::vector<std::string>::iterator the_iterator;
+    the_iterator = message_parts->begin();
 
-			std::vector<std::string*>* send_string_req = new std::vector<std::string*>();
-			std::string* member_name = new std::string();
+    IcedTeaPluginUtilities::printStringVector("PluginRequestProcessor::newMessageOnBus:", message_parts);
 
-			// pack parent id and member name
-			send_string_req->push_back(&(message_parts->at(0)));
-			IcedTeaPluginUtilities::getUTF8String(length, 4 /* start at */, message_parts, member_name);
-			send_string_req->push_back(member_name);
+    type = message_parts->at(0);
+    command = message_parts->at(2);
 
-			// make the internal request
-			this->_sendMember(send_string_req);
-
-			// free the memory
-			delete send_string_req;
-			delete message_parts;
-
-			return true; // request processed
-		}
-	}
-
-	type = message_parts->at(0);
-	command = message_parts->at(2);
+    if (type == "instance")
+    {
+        if (command == "GetWindow")
+        {
+            // Window can be queried from the main thread only. And this call
+            // returns immediately, so we do it in the same thread.
+            this->sendWindow(message_parts);
+            return true;
+        } else if (command == "GetMember" ||
+                   command == "SetMember" ||
+                   command == "ToString")
+        {
 
-	if (type == "instance")
-	{
-		if (command == "GetWindow")
-		{
-			// Window can be queried from the main thread only. And this call
-			// returns immediately, so we do it in the same thread.
-			this->sendWindow(message_parts);
-			return true;
-		} else if (command == "GetMember")
-		{
-			this->dispatch(&sendMember, message_parts, NULL);
-			return true;
-		}
-	}
+        	// Update queue synchronously
+        	pthread_mutex_lock(&message_queue_mutex);
+            message_queue->push_back(message_parts);
+            pthread_mutex_unlock(&message_queue_mutex);
 
-	// If we got here, it means we couldn't process the message. Let the caller know.
-	return false;
+            return true;
+        }
+
+    }
+
+    delete message_parts;
+
+    // If we got here, it means we couldn't process the message. Let the caller know.
+    return false;
 }
 
 /**
@@ -198,16 +190,27 @@
 
 void PluginRequestProcessor::dispatch(void* func_ptr (void*), std::vector<std::string>* message_parts, std::string* src)
 {
-	pthread_t thread;
-	ThreadData* tdata = new ThreadData();
+    pthread_t thread;
+    int tries = 0;
+    ThreadData* tdata = new ThreadData();
 
-	IcedTeaPluginUtilities::printStringVector("PluginRequestProcessor::dispatch:", message_parts);
+    IcedTeaPluginUtilities::printStringVector("PluginRequestProcessor::dispatch:", message_parts);
+
+    tdata->source = src;
+    tdata->message_parts = message_parts;
 
-	tdata->source = src;
-	tdata->message_parts = message_parts;
+    printf("Threads MAX=%ld, Thread data=%p\n", sysconf(_SC_THREAD_THREADS_MAX), tdata);
+    while (pthread_create (&thread, NULL, func_ptr, (void*) tdata) == 11 && tries++ < 100)
+    {
+        printf("Couldn't create thread. Sleeping and then retrying. TC=%d\n", thread_count);
+        usleep(1000000);
+    }
+    uintmax_t start_time = (uintmax_t) time(NULL);
+    pthread_mutex_lock(&tc_mutex);
+    thread_count++;
+    pthread_mutex_unlock(&tc_mutex);
 
-	pthread_create (&thread, NULL, func_ptr, (void*) tdata);
-	uintmax_t start_time = (uintmax_t) time(NULL);
+    PLUGIN_DEBUG_2ARG("pthread %p created. Thread count=%d\n", thread, thread_count);
 }
 
 /**
@@ -219,38 +222,210 @@
 void
 PluginRequestProcessor::sendWindow(std::vector<std::string>* message_parts)
 {
-	std::string type;
-	std::string command;
-	std::string* response;
-	std::string* window_ptr_str;
-	int id;
+    std::string type;
+    std::string command;
+    std::string* response;
+    std::string* window_ptr_str;
+    static NPObject* window_ptr;
+    int id;
+
+    type = message_parts->at(0);
+    id = atoi(message_parts->at(1).c_str());
+    command = message_parts->at(2);
+
+    NPP instance;
+    get_instance_from_id(id, instance);
+
+    browser_functions.getvalue(instance, NPNVWindowNPObject, &window_ptr);
+    PLUGIN_DEBUG_3ARG("ID=%d, Instance=%p, WindowPTR = %p\n", id, instance, window_ptr);
+
+    window_ptr_str = IcedTeaPluginUtilities::JSIDToString(window_ptr);
+
+    // We need the context 0 for backwards compatibility with the Java side
+    response = IcedTeaPluginUtilities::constructMessagePrefix(0);
+    *response += " JavaScriptGetWindow ";
+    *response += *window_ptr_str;
+
+    plugin_to_java_bus->post(response->c_str());
+
+    delete response;
+    delete window_ptr_str;
+    delete message_parts;
+
+    // store the instance pointer for future reference
+    storeInstanceID(window_ptr, instance);
+}
 
-	type = message_parts->at(0);
-	id = atoi(message_parts->at(1).c_str());
-	command = message_parts->at(2);
+/**
+ * Sends the string value of the requested variable
+ *
+ * @param message_parts The request message.
+ */
+void
+PluginRequestProcessor::sendString(std::vector<std::string>* message_parts)
+{
+    std::string variant_ptr;
+    NPVariant* variant;
+    std::string* variant_string;
+    std::string* variant_string_id;
+    JavaRequestProcessor* java_request;
+    JavaResultData* java_result;
+    std::string* response;
+    int instance;
+
+    instance = atoi(message_parts->at(1).c_str());
+    variant_ptr = message_parts->at(3);
+
+    variant = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(variant_ptr);
+    variant_string = IcedTeaPluginUtilities::NPVariantToString(*variant);
+
+    java_request = new JavaRequestProcessor();
+    java_result = java_request->newString(*variant_string);
 
-	NPP instance;
-	get_instance_from_id(id, instance);
+    if (java_result->error_occured)
+    {
+        printf("Unable to process NewString request. Error occurred: %s\n", java_result->error_msg);
+        //goto cleanup;
+    }
+
+    variant_string_id = java_result->return_string;
+
+    // We need the context 0 for backwards compatibility with the Java side
+    response = IcedTeaPluginUtilities::constructMessagePrefix(instance);
+    *response += " JavaScriptToString ";
+    *response += *variant_string_id;
+
+    plugin_to_java_bus->post(response->c_str());
+
+    cleanup:
+    delete java_request;
+    delete response;
+    delete variant_string;
+    delete message_parts;
+
+    pthread_mutex_lock(&tc_mutex);
+    thread_count--;
+    pthread_mutex_unlock(&tc_mutex);
+}
+
+/**
+ * Sets variable to given value
+ *
+ * @param message_parts The request message.
+ */
 
-	static NPObject *window_ptr;
-	browser_functions.getvalue(instance, NPNVWindowNPObject, &window_ptr);
-	PLUGIN_DEBUG_3ARG("ID=%d, Instance=%p, WindowPTR = %p\n", id, instance, window_ptr);
+void
+PluginRequestProcessor::setMember(std::vector<std::string>* message_parts)
+{
+    std::string valueID;
+    std::string propertyNameID;
+    std::string* property_name = new std::string();
+    std::string* value = new std::string();
+    std::string* type = new std::string();
+    std::string* value_variant_ptr_str;
+    std::vector<std::string*>* internal_request_params = new std::vector<std::string*>();
+
+    NPObject* member;
+    nsCOMPtr<nsIRunnable> event;
+    ResultData* rdata = new ResultData();
+
+    JavaRequestProcessor* java_request;
+    JavaResultData* java_result;
+
+    IcedTeaPluginUtilities::printStringVector("PluginRequestProcessor::_setMember - ", message_parts);
+
+    member = reinterpret_cast <NPObject*> (IcedTeaPluginUtilities::stringToJSID(message_parts->at(3)));
+    propertyNameID = message_parts->at(4);
+    valueID = message_parts->at(5);
+
+    java_request = new JavaRequestProcessor();
+    java_result = java_request->getString(propertyNameID);
 
-	window_ptr_str = IcedTeaPluginUtilities::JSIDToString(window_ptr);
+    // the result we want is in result_string (assuming there was no error)
+    if (java_result->error_occured)
+    {
+        printf("Unable to get member name for setMember. Error occurred: %s\n", java_result->error_msg);
+        goto cleanup;
+    }
+
+    // Copy into local variable before disposing the object
+    property_name->append(*(java_result->return_string));
+    delete java_request;
+
+    // Based on the value ID, find the type and string value
+    // FIXME: Complex java objects not yet peered
+
+    java_request = new JavaRequestProcessor();
+    java_result = java_request->getClassName(valueID);
+
+    // the result we want is in result_string (assuming there was no error)
+    if (java_result->error_occured)
+    {
+        printf("Unable to get class name for setMember. Error occurred: %s\n", java_result->error_msg);
+        goto cleanup;
+    }
+
+    // Copy into local variable before disposing the object
+    type->append(*(java_result->return_string));
+    delete java_request;
 
-	// We need the context 0 for backwards compatibility with the Java side
-	response = IcedTeaPluginUtilities::constructMessagePrefix(0);
-	*response += " JavaScriptGetWindow ";
-	*response += *window_ptr_str;
+    java_request = new JavaRequestProcessor();
+    java_result = java_request->getToStringValue(valueID);
+
+    // the result we want is in result_string (assuming there was no error)
+    if (java_result->error_occured)
+    {
+        printf("Unable to get value for setMember. Error occurred: %s\n", java_result->error_msg);
+        goto cleanup;
+    }
+
+    value->append(*(java_result->return_string));
 
-	plugin_to_java_bus->post(response->c_str());
+    internal_request_params->push_back(IcedTeaPluginUtilities::JSIDToString(member));
+    internal_request_params->push_back(property_name);
+    internal_request_params->push_back(type);
+    internal_request_params->push_back(value);
+
+    rdata->result_ready = false;
+    event = new IcedTeaRunnableMethod(&_setMember, (void*) internal_request_params, rdata);
+    NS_DispatchToMainThread(event, 0);
+
+    cleanup:
+    delete message_parts;
+    delete java_request;
 
-	delete response;
-	delete window_ptr_str;
-	delete message_parts;
+    // property_name, type and value are deleted by _setMember
+    pthread_mutex_lock(&tc_mutex);
+    thread_count--;
+    pthread_mutex_unlock(&tc_mutex);
+}
 
-	// store the instance pointer for future reference
-	storeInstanceID(window_ptr, instance);
+void
+convertToNPVariant(std::string value, std::string type, NPVariant* result_variant)
+{
+    if (type == "java.lang.Byte" ||
+        type == "java.lang.Char" ||
+        type == "java.lang.Short" ||
+        type == "java.lang.Integer") {
+        int i = atoi(value.c_str());
+        INT32_TO_NPVARIANT(i, *result_variant);
+    } else if (type == "java.lang.Long" ||
+               type == "java.lang.Double" ||
+               type == "java.lang.Float")
+    {
+        double d = atof(value.c_str());
+        DOUBLE_TO_NPVARIANT(d, *result_variant);
+    } else if (type == "java.lang.Boolean")
+    {
+        bool b = (value == "true");
+        BOOLEAN_TO_NPVARIANT(b, *result_variant);
+    } else if (type == "java.lang.String")
+    {
+        STRINGZ_TO_NPVARIANT(value.c_str(), *result_variant);
+    } else if (type.substr(0,1) == "[")
+    {
+        // FIXME: Set up object peering
+    }
 }
 
 /**
@@ -261,160 +436,299 @@
  * does whatever it can seperately, and then makes an internal request that
  * causes _sendMember to do the rest of the work.
  *
- * @param tdata A ThreadData structure holding information needed by this function.
- */
-
-void*
-sendMember(void* tdata)
-{
-	// member initialization
-	std::vector<std::string>* message_parts;
-	std::vector<std::string>* compound_data;
-	JavaRequestProcessor* java_request;
-	JavaRequest* java_request_data;
-	std::string* member_id = new std::string();
-	std::string* parent_id = new std::string();
-	std::string* member_name_utf = new std::string();
-	std::string* internal_request = new std::string();
-	int id;
-
-	/** Data extraction **/
-
-	// extract data passed from parent thread
-	ThreadData *data;
-	data = (ThreadData*) tdata;
-	message_parts = data->message_parts;
-
-	// debug printout of parent thread data
-	IcedTeaPluginUtilities::printStringVector("PluginRequestProcessor::getMember:", message_parts);
-
-	// store info in local variables for easy access
-	id = atoi(message_parts->at(1).c_str());
-	*parent_id += message_parts->at(3);
-	*member_id += message_parts->at(4);
-
-	/** Request data from Java **/
-
-	// create a compound request data structure to pass to getString
-	compound_data = new std::vector<std::string>();
-	compound_data->push_back(*member_id);
-
-	// make a new request for getString, to get the name of the identifier
-	java_request = new JavaRequestProcessor();
-	java_request_data = new JavaRequest();
-	java_request_data->instance = id;
-	java_request_data->data = compound_data;
-	java_request_data->source = data->source != NULL ? data->source : new std::string("file://");
-	JavaResultData* result = java_request->getString(java_request_data);
-
-	// the result we want is in result_string (assuming there was no error)
-	if (result->error_occured)
-	{
-		printf("Unable to process getMember request. Error occurred: %s\n", result->error_msg);
-		goto cleanup;
-	}
-
-	/** Make an internal request for the main thread to handle**/
-    IcedTeaPluginUtilities::convertStringToUTF8(result->return_string, member_name_utf);
-
-    // Ask main thread to do the send
-    *internal_request = "internal SendMember ";
-    *internal_request += *parent_id;
-    *internal_request += " ";
-    *internal_request += *member_name_utf;
-
-    java_to_plugin_bus->post(internal_request->c_str());
-
-	// Now be a good citizen and help keep the heap free of garbage
-	cleanup:
-	delete data; // thread data that caller allocated for us
-	delete java_request; // request object
-	delete java_request_data; // request data
-	delete member_id; // member id string
-	delete compound_data; // compound data object
-	delete message_parts; // message_parts vector that was allocated by the caller
-	delete internal_request; // delete the string that held the internal request data
-}
-
-/**
- * Given the parent id and the member name, sends the member pointer to Java.
- *
- * @param message_parts Vector containing the parent pointer and member name
+ * @param message_parts The request message
  */
 
 void
-PluginRequestProcessor::_sendMember(std::vector<std::string*>* message_parts)
+PluginRequestProcessor::sendMember(std::vector<std::string>* message_parts)
 {
-	std::string* member_ptr_str;
-	std::string* member;
-	std::string* parent;
+    // member initialization
+    std::vector<std::string>* args;
+    JavaRequestProcessor* java_request;
+    JavaResultData* java_result;
+    ResultData* member_data;
+    std::string* member_id = new std::string();
+    std::string* parent_id = new std::string();
+    std::string* jsObjectClassID = new std::string();
+    std::string* jsObjectConstructorID = new std::string();
+    std::string* response = new std::string();
+    nsCOMPtr<nsIRunnable> event;
 
-	NPObject *window_ptr;
-	NPVariant member_ptr;
-	NPP instance;
-	NPIdentifier identifier;
-	std::string* response;
+    std::vector<std::string*>* internal_request_params = new std::vector<std::string*>();
+    int method_id;
+    int instance;
+    long reference;
 
-	IcedTeaPluginUtilities::printStringPtrVector(" - ", message_parts);
+    // debug printout of parent thread data
+    IcedTeaPluginUtilities::printStringVector("PluginRequestProcessor::getMember:", message_parts);
+
+    // store info in local variables for easy access
+    instance = atoi(message_parts->at(1).c_str());
+    *parent_id += message_parts->at(3);
+    *member_id += message_parts->at(4);
+
+    /** Request data from Java **/
 
-	parent = message_parts->at(0);
-	member = message_parts->at(1);
+    // make a new request for getString, to get the name of the identifier
+    java_request = new JavaRequestProcessor();
+    java_result = java_request->getString(*member_id);
 
-	std::cout << "MEMBER=" << *member << std::endl;
+    // the result we want is in result_string (assuming there was no error)
+    if (java_result->error_occured)
+    {
+        printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
+        //goto cleanup;
+    }
 
-	// Get the corresponding windowId
-	identifier = browser_functions.getstringidentifier(member->c_str());
+    /** Make an internal request for the main thread to handle, to get the member pointer **/
 
-	// Get the window pointer
-	window_ptr = reinterpret_cast <NPObject*> (IcedTeaPluginUtilities::stringToJSID(parent->c_str()));
+    reference = internal_req_ref_counter++;
+
+    internal_request_params->push_back(parent_id);
+    internal_request_params->push_back(java_result->return_string);
+
+    member_data = new ResultData();
+    member_data->result_ready = false;
 
-	// Get the associated instance
-	instance = getInstanceFromMemberPtr(window_ptr);
+    event = new IcedTeaRunnableMethod(&_getMember, (void*) internal_request_params, member_data);
+    NS_DispatchToMainThread(event, 0);
 
-	printf("[2] Instance=%p, window=%p, identifier=%p -- %s::%s\n", instance, window_ptr, identifier, parent->c_str(), member->c_str());
+    while (!member_data->result_ready) // wait till ready
+    {
+        usleep(2000);
+    }
 
-	// Get the NPVariant corresponding to this member
-    browser_functions.getproperty(instance, window_ptr, identifier, &member_ptr);
+    PLUGIN_DEBUG_1ARG("Member PTR after internal request: %s\n", member_data->return_string->c_str());
 
-    PLUGIN_DEBUG_4ARG("[3] Instance=%p, window=%p, identifier=%p, variant=%p\n", instance, window_ptr, identifier, &member_ptr);
+    internal_req_ref_counter--;
 
-    if (NPVARIANT_IS_VOID(member_ptr))
-    {
-        printf("VOID %d\n", member_ptr);
-    }
-    else if (NPVARIANT_IS_NULL(member_ptr))
-    {
-        printf("NULL\n", member_ptr);
-    }
-    else if (NPVARIANT_IS_BOOLEAN(member_ptr))
+    delete java_request;
+    java_request = new JavaRequestProcessor();
+    java_result = java_request->findClass("netscape.javascript.JSObject");
+
+    // the result we want is in result_string (assuming there was no error)
+    if (java_result->error_occured)
     {
-        printf("BOOL: %d\n", NPVARIANT_TO_BOOLEAN(member_ptr));
+        printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
+        //goto cleanup;
     }
-    else if (NPVARIANT_IS_INT32(member_ptr))
-    {
-        printf("INT32: %d\n", NPVARIANT_TO_INT32(member_ptr));
-    }
-    else if (NPVARIANT_IS_DOUBLE(member_ptr))
+
+    *jsObjectClassID += *(java_result->return_string);
+
+    // We have the result. Free the request memory
+    delete java_request;
+
+    java_request = new JavaRequestProcessor();
+
+    args = new std::vector<std::string>();
+    std::string longArg = "J";
+    args->push_back(longArg);
+
+    java_result = java_request->getMethodID(
+            *(jsObjectClassID),
+            browser_functions.getstringidentifier("<init>"),
+            *args);
+
+    // the result we want is in result_string (assuming there was no error)
+    if (java_result->error_occured)
     {
-        printf("DOUBLE: %f\n", NPVARIANT_TO_DOUBLE(member_ptr));
+        printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
+        //goto cleanup;
     }
-    else if (NPVARIANT_IS_STRING(member_ptr))
+
+    *jsObjectConstructorID += *(java_result->return_string);
+
+    delete args;
+    delete java_request;
+
+    // We have the method id. Now create a new object.
+
+    java_request = new JavaRequestProcessor();
+    args = new std::vector<std::string>();
+    args->push_back(*(member_data->return_string));
+    java_result = java_request->newObject(*jsObjectClassID,
+                                          *jsObjectConstructorID,
+                                          *args);
+
+    // the result we want is in result_string (assuming there was no error)
+    if (java_result->error_occured)
     {
-        printf("STRING: %s\n", NPVARIANT_TO_STRING(member_ptr).utf8characters);
-    }
-    else
-    {
-        printf("OBJ: %p\n", NPVARIANT_TO_OBJECT(member_ptr));
+        printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
+        //goto cleanup;
     }
 
-    member_ptr_str = IcedTeaPluginUtilities::JSIDToString(&member_ptr);
 
     response = IcedTeaPluginUtilities::constructMessagePrefix(0);
-    *response += " JavaScriptGetMember ";
-    *response += *member_ptr_str;
+    response->append(" JavaScriptGetMember ");
+    response->append(java_result->return_string->c_str());
+    plugin_to_java_bus->post(response->c_str());
+
+
+    // Now be a good citizen and help keep the heap free of garbage
+    cleanup:
+    delete args;
+    delete java_request; // request object
+    delete member_id; // member id string
+    delete message_parts; // message_parts vector that was allocated by the caller
+    delete internal_request_params; // delete the internal requests params vector
+    delete jsObjectClassID; // delete object that holds the jsobject
+    delete member_data->return_string;
+    delete member_data;
+
+    pthread_mutex_lock(&tc_mutex);
+    thread_count--;
+    pthread_mutex_unlock(&tc_mutex);
+}
+
+void*
+queue_processor(void* data)
+{
+
+    PluginRequestProcessor* processor = (PluginRequestProcessor*) data;
+    std::vector<std::string>* message_parts = NULL;
+    std::string command;
+
+    PLUGIN_DEBUG_1ARG("Queue processor initialized. Queue = %p\n", message_queue);
+
+    while (true)
+    {
+        pthread_mutex_lock(&message_queue_mutex);
+        if (message_queue->size() > 0)
+        {
+            message_parts = message_queue->front();
+            message_queue->erase(message_queue->begin());
+        }
+        pthread_mutex_unlock(&message_queue_mutex);
+
+        if (message_parts)
+        {
+            PLUGIN_DEBUG_0ARG("Processing engaged\n");
+
+            command = message_parts->at(2);
+
+            if (command == "GetMember")
+            {
+                processor->sendMember(message_parts);
+            } else if (command == "ToString")
+            {
+                processor->sendString(message_parts);
+            } else if (command == "SetMember")
+            {
+                processor->setMember(message_parts);
+            } else
+            {
+                // Nothing matched
+                IcedTeaPluginUtilities::printStringVector("Error: Unable to process message: ", message_parts);
+
+            }
+
+            PLUGIN_DEBUG_0ARG("Processing dis-engaged\n");
+        } else
+        {
+            usleep(20000);
+            pthread_testcancel();
+        }
+
+        message_parts = NULL;
+    }
+
+    PLUGIN_DEBUG_0ARG("Queue processing stopped.\n");
+}
+
+/******************************************
+ * Functions delegated to the main thread *
+ ******************************************/
 
-	plugin_to_java_bus->post(response->c_str());
+void*
+_setMember(void* data, ResultData* result)
+{
+    std::string* property_name;
+    std::string* value;
+    std::string* type;
+    std::string* response;
+    std::vector<std::string*>* message_parts = (std::vector<std::string*>*) data;
+
+    NPP instance;
+    NPVariant* value_variant = new NPVariant();
+    NPObject* member;
+    NPIdentifier property;
+
+    IcedTeaPluginUtilities::printStringPtrVector("PluginRequestProcessor::_setMember - ", message_parts);
+
+    member = reinterpret_cast <NPObject*> (IcedTeaPluginUtilities::stringToJSID(*(message_parts->at(0))));
+    property_name = message_parts->at(1);
+    type = message_parts->at(2);
+    value = message_parts->at(3);
+
+    instance = getInstanceFromMemberPtr(member);
+    convertToNPVariant(*value, *type, value_variant);
+
+    PLUGIN_DEBUG_4ARG("Setting %s on instance %p, object %p to value %s\n", property_name->c_str(), instance, member, value_variant);
+
+    property = browser_functions.getstringidentifier(property_name->c_str());
+    browser_functions.setproperty(instance, member, property, value_variant);
+
+    response = IcedTeaPluginUtilities::constructMessagePrefix(0);
+    response->append(" JavaScriptSetMember ");
+    plugin_to_java_bus->post(response->c_str());
+
+    // free memory
+    IcedTeaPluginUtilities::freeStringPtrVector(message_parts);
+    delete value_variant;
+    delete response;
+
+    result->result_ready = true;
+
+}
 
-	delete member_ptr_str;
-	delete response;
+void*
+_getMember(void* data, ResultData* result)
+{
+    std::string* parent_ptr_str;
+    std::string* member_name;
+
+    NPObject* parent_ptr;
+    NPVariant member_ptr;
+    std::string* member_ptr_str;
+    NPP instance;
+    NPIdentifier member_identifier;
+
+    std::vector<std::string*>* message_parts = (std::vector<std::string*>*) data;
+
+    IcedTeaPluginUtilities::printStringPtrVector("PluginRequestProcessor::_getMember - ", message_parts);
+
+    parent_ptr_str = message_parts->at(0);
+    member_name = message_parts->at(1);
+
+    // Get the corresponding windowId
+    member_identifier = browser_functions.getstringidentifier(member_name->c_str());
+
+    // Get the window pointer
+    parent_ptr = reinterpret_cast <NPObject*> (IcedTeaPluginUtilities::stringToJSID(parent_ptr_str->c_str()));
+
+    // Get the associated instance
+    instance = getInstanceFromMemberPtr(parent_ptr);
+
+    // Get the NPVariant corresponding to this member
+    PLUGIN_DEBUG_4ARG("Looking for %p %p %p (%s)\n", instance, parent_ptr, member_identifier,member_name->c_str());
+
+    if (!browser_functions.hasproperty(instance, parent_ptr, member_identifier))
+    {
+        printf("%s not found!\n", member_name->c_str());
+    }
+    browser_functions.getproperty(instance, parent_ptr, member_identifier, &member_ptr);
+
+    IcedTeaPluginUtilities::printNPVariant(member_ptr);
+    member_ptr_str = IcedTeaPluginUtilities::JSIDToString(NPVARIANT_TO_OBJECT(member_ptr));
+    PLUGIN_DEBUG_2ARG("Got variant %p (integer value = %s)\n", NPVARIANT_TO_OBJECT(member_ptr), member_ptr_str->c_str());
+
+    result->return_string = member_ptr_str;
+    result->result_ready = true;
+
+    // store member -> instance link
+    storeInstanceID(NPVARIANT_TO_OBJECT(member_ptr), instance);
+
+    PLUGIN_DEBUG_0ARG("_getMember returning.\n");
+
+    return result;
 }
--- a/plugin/icedteanp/IcedTeaPluginRequestProcessor.h	Fri Jul 17 06:04:59 2009 -0400
+++ b/plugin/icedteanp/IcedTeaPluginRequestProcessor.h	Thu Jul 23 11:39:18 2009 -0400
@@ -48,6 +48,7 @@
 #include <npapi.h>
 #include <npupp.h>
 
+#include "IcedTeaRunnable.h"
 #include "IcedTeaPluginUtils.h"
 #include "IcedTeaJavaRequestProcessor.h"
 
@@ -61,22 +62,46 @@
 	std::string* source;
 } ThreadData;
 
+
 /* Map holding window pointer<->instance relationships */
 static std::map<void*, NPP>* instance_map;
 
+/* Internal request reference counter */
+static long internal_req_ref_counter;
+
 // JS request processor methods
 static NPP getInstanceFromMemberPtr(void* member_ptr);
 static void storeInstanceID(void* member_ptr, NPP instance);
 static void* requestFromMainThread();
-static void* sendMember(void* tdata);
-static void* setMember(void* tdata);
 static void* getSlot(void* tdata);
 static void* setSlot(void* tdata);
 static void* eval(void* tdata);
 static void* removeMember(void* tdata);
 static void* call(void* tdata);
 static void* finalize(void* tdata);
-static void* toString(void* tdata);
+
+/* Given a value and type, performs the appropriate Java->JS type
+ * mapping and puts it in the given variant */
+
+static void convertToNPVariant(std::string value, std::string type, NPVariant* result_variant);
+
+// Internal methods that need to run in main thread
+void* _getMember(void* message_parts, ResultData* result);
+void* _setMember(void* message_parts, ResultData* result);
+
+static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER;
+static int thread_count = 0;
+
+void* queue_processor(void* data);
+
+/* Mutex to ensure that the request queue is accessed synchronously */
+extern pthread_mutex_t message_queue_mutex;
+
+/* Mutex to ensure synchronized writes */
+extern pthread_mutex_t syn_write_mutex;
+
+/* Queue for holding messages that get processed in a separate thread */
+extern std::vector< std::vector<std::string>* >* message_queue;
 
 /**
  * Processes requests made TO the plugin (by java or anyone else)
@@ -92,17 +117,23 @@
     	void dispatch(void* func_ptr (void*), std::vector<std::string>* message, std::string* src);
 
     	/* Send main window pointer to Java */
-    	void sendWindow(std::vector<std::string>* message);
-
-    	/* Given parent id and member name, send member pointer to java */
-    	void _sendMember(std::vector<std::string*>* message_parts);
+    	void sendWindow(std::vector<std::string>* message_parts);
 
     public:
-    	PluginRequestProcessor(); /*Constructor */
+    	PluginRequestProcessor(); /* Constructor */
     	~PluginRequestProcessor(); /* Destructor */
 
     	/* Process new requests (if applicable) */
         virtual bool newMessageOnBus(const char* message);
+
+        /* Send member ID to Java */
+        void sendMember(std::vector<std::string>* message_parts);
+
+        /* Set member to given value */
+        void setMember(std::vector<std::string>* message_parts);
+
+        /* Send string value of requested object */
+        void sendString(std::vector<std::string>* message_parts);
 };
 
 #endif // __ICEDTEAPLUGINREQUESTPROCESSOR_H__
--- a/plugin/icedteanp/IcedTeaPluginUtils.cc	Fri Jul 17 06:04:59 2009 -0400
+++ b/plugin/icedteanp/IcedTeaPluginUtils.cc	Thu Jul 23 11:39:18 2009 -0400
@@ -146,15 +146,17 @@
 	char* id_str = (char*) malloc(sizeof(char)*20); // max = long long = 8446744073709551615 == 19 chars
 
 	if (sizeof(void*) == sizeof(long long))
+	{
 		sprintf(id_str, "%llu", id);
-	else if (sizeof(void*) == sizeof(long))
-		sprintf(id_str, "%lu", id);
-	else // else addresses are int (32-bit)
-		sprintf(id_str, "%du", id);
+	}
+	else
+	{
+		sprintf(id_str, "%lu", id); // else use long
+	}
 
 	*result += id_str;
 
-	printf("Converting pointer %p to %s\n", id, id_str);
+	PLUGIN_DEBUG_2ARG("Converting pointer %p to %s\n", id, id_str);
 	free(id_str);
 
 	return result;
@@ -173,19 +175,15 @@
 	void* ptr;
 	if (sizeof(void*) == sizeof(long long))
 	{
-		printf("Casting \"%s\" -- %llu\n", id_str.c_str(), atol(id_str.c_str()));
-		ptr = reinterpret_cast <void*> ((unsigned long) atol(id_str.c_str()));
-	} else if (sizeof(void*) == sizeof(long))
-	{
-		printf("Casting \"%s\" -- %lu\n", id_str.c_str(), atoi(id_str.c_str()));
-		ptr = reinterpret_cast <void*> ((unsigned int)  atoi(id_str.c_str()));
+		PLUGIN_DEBUG_2ARG("Casting (long long) \"%s\" -- %llu\n", id_str.c_str(), strtoull(id_str.c_str(), NULL, 0));
+		ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str.c_str(), NULL, 0));
 	} else
 	{
-		printf("Casting \"%s\" -- %du\n", id_str.c_str(), atoi(id_str.c_str()));
-		ptr = reinterpret_cast <void*> ((unsigned int)  atoi(id_str.c_str()));
+		PLUGIN_DEBUG_2ARG("Casting (long) \"%s\" -- %lu\n", id_str.c_str(), strtoul(id_str.c_str(), NULL, 0));
+		ptr = reinterpret_cast <void*> ((unsigned long)  strtoul(id_str.c_str(), NULL, 0));
 	}
 
-	printf("Casted: %p\n", ptr);
+	PLUGIN_DEBUG_1ARG("Casted: %p\n", ptr);
 
 	return ptr;
 }
@@ -444,6 +442,119 @@
 	delete str;
 }
 
+std::string*
+IcedTeaPluginUtilities::variantToClassName(NPVariant variant)
+{
+
+	std::string* java_type = new std::string();
+
+	if (NPVARIANT_IS_VOID(variant))
+	{
+		*java_type += "V";
+	} else if (NPVARIANT_IS_BOOLEAN(variant))
+	{
+		*java_type += "Z";
+	} else if (NPVARIANT_IS_INT32(variant))
+	{
+		*java_type += "I";
+	} else if (NPVARIANT_IS_DOUBLE(variant))
+	{
+		*java_type += "D";
+	} else if (NPVARIANT_IS_STRING(variant))
+	{
+		*java_type += "Ljava/lang/String;";
+	} else if (NPVARIANT_IS_OBJECT(variant))
+	{
+		printf("** Unimplemented: IcedTeaPluginUtilities::variantToClassName(variant type=obj)\n");
+	} else if (NPVARIANT_IS_NULL(variant))
+	{
+		printf("** Unimplemented: IcedTeaPluginUtilities::variantToClassName(variant type=null)\n");
+	} else
+	{
+		printf("** Unimplemented: IcedTeaPluginUtilities::variantToClassName(variant type=unknown)\n");
+	}
+
+	return java_type;
+}
+
+void
+IcedTeaPluginUtilities::printNPVariant(NPVariant variant)
+{
+    if (NPVARIANT_IS_VOID(variant))
+    {
+    	PLUGIN_DEBUG_1ARG("VOID %d\n", variant);
+    }
+    else if (NPVARIANT_IS_NULL(variant))
+    {
+    	PLUGIN_DEBUG_1ARG("NULL\n", variant);
+    }
+    else if (NPVARIANT_IS_BOOLEAN(variant))
+    {
+    	PLUGIN_DEBUG_1ARG("BOOL: %d\n", NPVARIANT_TO_BOOLEAN(variant));
+    }
+    else if (NPVARIANT_IS_INT32(variant))
+    {
+    	PLUGIN_DEBUG_1ARG("INT32: %d\n", NPVARIANT_TO_INT32(variant));
+    }
+    else if (NPVARIANT_IS_DOUBLE(variant))
+    {
+    	PLUGIN_DEBUG_1ARG("DOUBLE: %f\n", NPVARIANT_TO_DOUBLE(variant));
+    }
+    else if (NPVARIANT_IS_STRING(variant))
+    {
+    	PLUGIN_DEBUG_1ARG("STRING: %s\n", NPVARIANT_TO_STRING(variant).utf8characters);
+    }
+    else
+    {
+    	PLUGIN_DEBUG_1ARG("OBJ: %p\n", NPVARIANT_TO_OBJECT(variant));
+    }
+}
+
+std::string*
+IcedTeaPluginUtilities::NPVariantToString(NPVariant variant)
+{
+	char* str = (char*) malloc(sizeof(char)*32); // enough for everything except string
+
+    if (NPVARIANT_IS_VOID(variant))
+    {
+        sprintf(str, "%p", variant);
+    }
+    else if (NPVARIANT_IS_NULL(variant))
+    {
+    	sprintf(str, "NULL");
+    }
+    else if (NPVARIANT_IS_BOOLEAN(variant))
+    {
+    	if (NPVARIANT_TO_BOOLEAN(variant))
+    		sprintf(str, "true");
+    	else
+    		sprintf(str, "false");
+    }
+    else if (NPVARIANT_IS_INT32(variant))
+    {
+    	sprintf(str, "%d", NPVARIANT_TO_INT32(variant));
+    }
+    else if (NPVARIANT_IS_DOUBLE(variant))
+    {
+    	sprintf(str, "%f", NPVARIANT_TO_DOUBLE(variant));;
+    }
+    else if (NPVARIANT_IS_STRING(variant))
+    {
+    	free(str);
+    	str = (char*) malloc(sizeof(char)*NPVARIANT_TO_STRING(variant).utf8length);
+    	sprintf(str, "%s", NPVARIANT_TO_STRING(variant).utf8characters);
+    }
+    else
+    {
+        sprintf(str, "[Object %p]", variant);
+    }
+
+    std::string* ret = new std::string(str);
+    free(str);
+
+    return ret;
+}
+
 /******************************************
  * Begin JavaMessageSender implementation *
  ******************************************
@@ -506,6 +617,8 @@
 
 MessageBus::~MessageBus()
 {
+    PLUGIN_DEBUG_0ARG("MessageBus::~MessageBus\n");
+
 	int ret;
 
 	ret = pthread_mutex_destroy(&subscriber_mutex);
--- a/plugin/icedteanp/IcedTeaPluginUtils.h	Fri Jul 17 06:04:59 2009 -0400
+++ b/plugin/icedteanp/IcedTeaPluginUtils.h	Thu Jul 23 11:39:18 2009 -0400
@@ -54,9 +54,6 @@
 #include <string>
 #include <vector>
 
-/* Debug output macros */
-static int plugin_debug = 1;
-
 #define PLUGIN_DEBUG_0ARG(str) \
   do                                        \
   {                                         \
@@ -175,6 +172,12 @@
 
     	/* Prints contents of given string pointer vector */
     	static void printStringPtrVector(const char* prefix, std::vector<std::string*>* cv);
+
+    	static std::string* variantToClassName(NPVariant variant);
+
+    	static void printNPVariant(NPVariant variant);
+
+    	static std::string* NPVariantToString(NPVariant variant);
 };
 
 /*
@@ -225,11 +228,11 @@
         /* Queued messages */
         std::queue<char*> msgQueue;
 
-        ~MessageBus();
-
     public:
     	MessageBus();
 
+        ~MessageBus();
+
         /* subscribe to this bus */
         void subscribe(BusSubscriber* b);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedteanp/IcedTeaRunnable.cc	Thu Jul 23 11:39:18 2009 -0400
@@ -0,0 +1,74 @@
+/* IcedTeaRunnable.cc
+
+   Copyright (C) 2009  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. */
+
+#include <stdio.h>
+#include "IcedTeaRunnable.h"
+
+NS_IMPL_ISUPPORTS1 (IcedTeaRunnable, nsIRunnable)
+
+IcedTeaRunnable::IcedTeaRunnable ()
+{
+}
+
+IcedTeaRunnable::~IcedTeaRunnable ()
+{
+}
+
+NS_IMETHODIMP
+IcedTeaRunnable::Run ()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+IcedTeaRunnableMethod::IcedTeaRunnableMethod (Method method, void* thread_data, ResultData* result)
+: method (method),
+  thread_data(thread_data),
+  result(result)
+{
+}
+
+IcedTeaRunnableMethod::~IcedTeaRunnableMethod ()
+{
+ }
+
+NS_IMETHODIMP
+IcedTeaRunnableMethod::Run ()
+{
+    (*method) (thread_data, result);
+    return NS_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedteanp/IcedTeaRunnable.h	Thu Jul 23 11:39:18 2009 -0400
@@ -0,0 +1,102 @@
+/* IcedTeaRunnable.h
+
+   Copyright (C) 2009  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. */
+
+#ifndef __ICEDTEARUNNABLE_H__
+#define __ICEDTEARUNNABLE_H__
+
+#define MOZILLA 1
+#if MOZILLA
+
+#include <nsIRunnable.h>
+#include <string>
+
+/*
+ * This struct holds the result from the main-thread dispatched method
+ */
+typedef struct result_data
+{
+	// Return identifier (if applicable)
+    int return_identifier;
+
+    // Return string (if applicable)
+    std::string* return_string;
+
+    // Return wide/mb string (if applicable)
+    std::wstring* return_wstring;
+
+    // Error message (if an error occurred)
+    std::string* error_msg;
+
+    // Boolean indicating if an error occurred
+    bool error_occured;
+
+    // If this result is ready
+    bool result_ready;
+
+} ResultData;
+
+class IcedTeaRunnable : public nsIRunnable
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIRUNNABLE
+
+  IcedTeaRunnable ();
+
+  ~IcedTeaRunnable ();
+};
+
+class IcedTeaRunnableMethod : public IcedTeaRunnable
+{
+public:
+
+  typedef void* (*Method) (void*, ResultData*);
+
+  IcedTeaRunnableMethod (Method, void* thread_data, ResultData* result);
+  NS_IMETHOD Run ();
+
+  ~IcedTeaRunnableMethod ();
+
+  Method method;
+  void* thread_data;
+  ResultData* result;
+};
+
+#endif /* MOZILLA */
+
+#endif /* __ICEDTEARUNNABLE_H__ */
--- a/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java	Fri Jul 17 06:04:59 2009 -0400
+++ b/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java	Thu Jul 23 11:39:18 2009 -0400
@@ -118,6 +118,8 @@
 			return "double";
 
 		case SIGNATURE_ENDFUNC:
+			return null;
+
 		case SIGNATURE_FUNC:
 			return nextTypeName();
 
@@ -135,6 +137,10 @@
 		String elem;
 		while (currentIndex < signature.length()) {
 			elem = nextTypeName();
+			
+			if (elem == null) // end of signature
+				continue;
+			
 			// System.out.println ("NEXT TYPE: " + elem);
 			Class primitive = primitiveNameToType(elem);
 			if (primitive != null)
@@ -169,7 +175,7 @@
 				}
 			}
 		}
-		if (typeList.size() == 0) {
+		if (signature.length() < 2) {
 			throw new IllegalArgumentException("Invalid JNI signature '"
 					+ signature + "'");
 		}
@@ -218,7 +224,7 @@
 	}
 
 	public Class[] getClassArray() {
-		return typeList.subList(0, typeList.size() - 1).toArray(new Class[] {});
+		return typeList.subList(0, typeList.size()).toArray(new Class[] {});
 	}
 }
 
@@ -805,7 +811,25 @@
 				PluginDebug.debug("Java: GetStringChars: " + o);
 				PluginDebug.debug("  String BYTES: " + buf);
 				write(reference, "GetStringChars " + buf);
-			} else if (message.startsWith("NewArray")) {
+			} else if (message.startsWith("GetToStringValue")) {
+                String[] args = message.split(" ");
+                Integer objectID = parseCall(args[1], null, Integer.class);
+
+                String o = null;
+                byte[] b = null;
+                StringBuffer buf = null;
+                o = store.getObject(objectID).toString();
+                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));
+
+                write(reference, "GetToStringValue " + buf);
+            } else if (message.startsWith("NewArray")) {
 				String[] args = message.split(" ");
 				String type = parseCall(args[1], null, String.class);
 				Integer length = parseCall(args[2], null, Integer.class);
@@ -879,53 +903,49 @@
 
 				write(reference, "NewObject " + store.getIdentifier(ret));
 
-			} else if (message.startsWith("NewString")) {
-				PluginDebug.debug("MESSAGE: " + message);
-				String[] args = message.split(" ");
-				Integer strlength = parseCall(args[1], null, 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], null, Integer.class);
-					PluginDebug.debug("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");
-				PluginDebug.debug("NEWSTRING: " + ret);
+			} else if (message.startsWith("NewStringUTF")) {
+                PluginDebug.debug("MESSAGE: " + message);
+                String[] args = message.split(" ");
+                int length = new Integer(args[1]);
+                byte[] byteArray = new byte[length + 1];
+                String ret = null;
+                int i = 2;
+                int c = Integer.parseInt(args[i++], 16);
+                while (i < length) {
+                    byteArray[i-2] = (byte) c;
+                    c = Integer.parseInt(args[i++], 16);
+                }
+
+                byteArray[i] = (byte) 0;
+                ret = new String(byteArray, "UTF-8");
+                PluginDebug.debug("NEWSTRINGUTF: " + 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")) {
-				PluginDebug.debug("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], null, 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");
-				PluginDebug.debug("NEWSTRINGUTF: " + ret);
+                store.reference(ret);
+                write(reference, "NewStringUTF " + store.getIdentifier(ret));
+			} else if (message.startsWith("NewString")) {
+                PluginDebug.debug("MESSAGE: " + message);
+                String[] args = message.split(" ");
+                Integer strlength = parseCall(args[1], null, 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], null, Integer.class);
+                    PluginDebug.debug("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");
+                PluginDebug.debug("NEWSTRING: " + ret);
 
-				store.reference(ret);
-				write(reference, "NewStringUTF " + store.getIdentifier(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("ExceptionOccurred")) {
 				PluginDebug.debug("EXCEPTION: " + throwable);
 				if (throwable != null)
@@ -952,7 +972,12 @@
 				Integer id = parseCall(args[1], null, Integer.class);
 				store.reference(store.getObject(id));
 				write(reference, "NewGlobalRef " + id);
-			}
+			} else if (message.startsWith("GetClassName")) {
+				String[] args = message.split(" ");
+				Integer objectID = parseCall(args[1], null, Integer.class);
+				Object o = (Object) store.getObject(objectID);
+				write(reference, "GetClassName " + o.getClass().getName());
+			} 
 		} catch (Throwable t) {
 			t.printStackTrace();
 			String msg = t.getCause() != null ? t.getCause().getMessage() : t.getMessage();
@@ -1018,8 +1043,8 @@
 		
 		prepopulateClass("netscape/javascript/JSObject");
 		classID = prepopulateClass("netscape/javascript/JSException");
-		prepopulateMethod(classID, "<init>", "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)V");
-		prepopulateMethod(classID, "<init>", "(ILjava/lang/Object;)V");
+		prepopulateMethod(classID, "<init>", "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)");
+		prepopulateMethod(classID, "<init>", "(ILjava/lang/Object;)");
 		prepopulateField(classID, "lineno");
 		prepopulateField(classID, "tokenIndex");
 		prepopulateField(classID, "source");
@@ -1028,51 +1053,51 @@
 		prepopulateField(classID, "wrappedException");
 		
 		classID = prepopulateClass("netscape/javascript/JSUtil");
-		prepopulateMethod(classID, "getStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/String;");
+		prepopulateMethod(classID, "getStackTrace", "(Ljava/lang/Throwable;)");
 
 		prepopulateClass("java/lang/Object");
 		classID = prepopulateClass("java/lang/Class");
-		prepopulateMethod(classID, "getMethods", "()[Ljava/lang/reflect/Method;");
-		prepopulateMethod(classID, "getConstructors", "()[Ljava/lang/reflect/Constructor;");
-		prepopulateMethod(classID, "getFields", "()[Ljava/lang/reflect/Field;");
-		prepopulateMethod(classID, "getName", "()Ljava/lang/String;");
-		prepopulateMethod(classID, "isArray", "()Z");
-		prepopulateMethod(classID, "getComponentType", "()Ljava/lang/Class;");
-		prepopulateMethod(classID, "getModifiers", "()I");
+		prepopulateMethod(classID, "getMethods", "()");
+		prepopulateMethod(classID, "getConstructors", "()");
+		prepopulateMethod(classID, "getFields", "()");
+		prepopulateMethod(classID, "getName", "()");
+		prepopulateMethod(classID, "isArray", "()");
+		prepopulateMethod(classID, "getComponentType", "()");
+		prepopulateMethod(classID, "getModifiers", "()");
 		
 
 		classID = prepopulateClass("java/lang/reflect/Method");
-		prepopulateMethod(classID, "getName", "()Ljava/lang/String;");
-		prepopulateMethod(classID, "getParameterTypes", "()[Ljava/lang/Class;");
-		prepopulateMethod(classID, "getReturnType", "()Ljava/lang/Class;");
-		prepopulateMethod(classID, "getModifiers", "()I");
+		prepopulateMethod(classID, "getName", "()");
+		prepopulateMethod(classID, "getParameterTypes", "()");
+		prepopulateMethod(classID, "getReturnType", "()");
+		prepopulateMethod(classID, "getModifiers", "()");
 
 		classID = prepopulateClass("java/lang/reflect/Constructor");
-		prepopulateMethod(classID, "getParameterTypes", "()[Ljava/lang/Class;");
-		prepopulateMethod(classID, "getModifiers", "()I");
+		prepopulateMethod(classID, "getParameterTypes", "()");
+		prepopulateMethod(classID, "getModifiers", "()");
 		
 		classID = prepopulateClass("java/lang/reflect/Field");
-		prepopulateMethod(classID, "getName", "()Ljava/lang/String;");
-		prepopulateMethod(classID, "getType", "()Ljava/lang/Class;");
-		prepopulateMethod(classID, "getModifiers", "()I");
+		prepopulateMethod(classID, "getName", "()");
+		prepopulateMethod(classID, "getType", "()");
+		prepopulateMethod(classID, "getModifiers", "()");
 		
 		classID = prepopulateClass("java/lang/reflect/Array");
-		prepopulateMethod(classID, "newInstance", "(Ljava/lang/Class;I)Ljava/lang/Object;");
+		prepopulateMethod(classID, "newInstance", "(Ljava/lang/Class;I)");
 		
 		classID = prepopulateClass("java/lang/Throwable");
-		prepopulateMethod(classID, "toString", "()Ljava/lang/String;");
-		prepopulateMethod(classID, "getMessage", "()Ljava/lang/String;");
+		prepopulateMethod(classID, "toString", "()");
+		prepopulateMethod(classID, "getMessage", "()");
 		
 		classID = prepopulateClass("java/lang/System");
-		prepopulateMethod(classID, "identityHashCode", "(Ljava/lang/Object;)I");
+		prepopulateMethod(classID, "identityHashCode", "(Ljava/lang/Object;)");
 		
 		classID = prepopulateClass("java/lang/Boolean");
-		prepopulateMethod(classID, "booleanValue", "()D");
-		prepopulateMethod(classID, "<init>", "(Z)V");
+		prepopulateMethod(classID, "booleanValue", "()");
+		prepopulateMethod(classID, "<init>", "(Z)");
 
 		classID = prepopulateClass("java/lang/Double");
-		prepopulateMethod(classID, "doubleValue", "()D");
-		prepopulateMethod(classID, "<init>", "(D)V");
+		prepopulateMethod(classID, "doubleValue", "()");
+		prepopulateMethod(classID, "<init>", "(D)");
 
 		classID = prepopulateClass("java/lang/Void");
 		prepopulateField(classID, "TYPE");