changeset 1996:dfd69fa0c812

Updates to NP plugin. - Plugin request processor threads now use condition based wait rather than periodic polling - Added support for fetching field information and values, and method invocation from JS -> Java - Added support for static calls (e.g. System.out.println(...)) from JS - Implented a cost-based overloaded method resolver for when JS calls an overloaded Java method with ambiguous types.
author Deepak Bhole <dbhole@redhat.com>
date Thu, 06 Aug 2009 10:43:31 -0400
parents 34fd2f476040
children c1c108662db8
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.h plugin/icedteanp/IcedTeaScriptablePluginObject.cc plugin/icedteanp/IcedTeaScriptablePluginObject.h plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java
diffstat 14 files changed, 2073 insertions(+), 262 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Oct 02 21:34:18 2009 +0100
+++ b/ChangeLog	Thu Aug 06 10:43:31 2009 -0400
@@ -1,3 +1,30 @@
+2009-08-06  Deepak Bhole  <dbhole@redhat.com>
+
+	* plugin/icedteanp/IcedTeaJavaRequestProcessor.cc: Handle error messages
+	from Java side. Add referencing/de-referencing support, and support for
+	fetching fields, invoking methods, and returning applet instances.
+	* plugin/icedteanp/IcedTeaJavaRequestProcessor.h: Decrease timeout to 20
+	seconds. Declare new functions created in the associated .cc file.
+	* plugin/icedteanp/IcedTeaNPPlugin.cc: Add support for dynamic NPObject
+	creation per instance. Add a new global pthread_cond_t for message
+	availability.
+	* plugin/icedteanp/IcedTeaNPPlugin.h: Misc. changes related to the above
+	associated file.
+	* plugin/icedteanp/IcedTeaPluginRequestProcessor.cc: Use condition based
+	wait for message availability, rather than periodic poll.
+	* plugin/icedteanp/IcedTeaPluginRequestProcessor.h: Make
+	getInstanceFromMemberPtr and storeInstanceID global.
+	* plugin/icedteanp/IcedTeaPluginUtils.cc: Force use of file:// src until
+	security subsystem is implemented.
+	* plugin/icedteanp/IcedTeaScriptablePluginObject.cc: Created skeletons for
+	Java and JavaPackage NPObjects, and implemented hasProperty, hasMethod,
+	getProperty and getMethod.
+	* plugin/icedteanp/IcedTeaScriptablePluginObject.h: Appropriate header
+	changes associated with the above.
+	* plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java: New file.
+	Uses a cost-based approach to resolve overloaded methods when JavaScript
+	calls Java methods with potentially ambiguous type arguments.
+
 2009-10-02  Andrew John Hughes  <ahughes@redhat.com>
 
 	* Makefile.am:
--- a/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc	Thu Aug 06 10:43:31 2009 -0400
@@ -66,9 +66,22 @@
 		{
 			// Gather the results
 
-			// GetStringUTFChars
-			if (message_parts->at(4) == "GetStringUTFChars" ||
-				message_parts->at(4) == "GetToStringValue")
+			// Let's get errors out of the way first
+			if (message_parts->at(4) == "Error")
+			{
+				for (int i=5; i < message_parts->size(); i++)
+				{
+					result->error_msg->append(message_parts->at(i));
+					result->error_msg->append(" ");
+				}
+
+				printf("Error on Java side: %s\n", result->error_msg->c_str());
+
+				result->error_occurred = true;
+				result_ready = true;
+			}
+			else 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);
@@ -83,30 +96,49 @@
 
 				IcedTeaPluginUtilities::getUTF16LEString(length, 6 /* start at */, message_parts, result->return_wstring);
 				result_ready = true;
-			} else if (message_parts->at(4) == "FindClass")
+			} else if ((message_parts->at(4) == "FindClass") ||
+			        (message_parts->at(4) == "GetClassName") ||
+			        (message_parts->at(4) == "GetClassID") ||
+			        (message_parts->at(4) == "GetMethodID") ||
+			        (message_parts->at(4) == "GetStaticMethodID") ||
+			        (message_parts->at(4) == "GetObjectClass") ||
+                    (message_parts->at(4) == "NewObject") ||
+                    (message_parts->at(4) == "NewStringUTF") ||
+                    (message_parts->at(4) == "HasPackage") ||
+                    (message_parts->at(4) == "HasMethod") ||
+                    (message_parts->at(4) == "HasField") ||
+                    (message_parts->at(4) == "GetStaticFieldID") ||
+                    (message_parts->at(4) == "GetFieldID") ||
+                    (message_parts->at(4) == "GetField") ||
+                    (message_parts->at(4) == "GetStaticField") ||
+                    (message_parts->at(4) == "GetJavaObject"))
 			{
 				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")
+			}  else if ((message_parts->at(4) == "DeleteLocalRef") ||
+		                (message_parts->at(4) == "NewGlobalRef"))
 			{
-				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_ready = true; // nothing else to do
+			} else if ((message_parts->at(4) == "CallMethod") ||
+
+					   (message_parts->at(4) == "CallStaticMethod"))
 			{
-				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
+
+			    if (message_parts->at(5) == "literalreturn")
+                {
+			        // literal returns don't have a corresponding jni id
+			        result->return_identifier = 0;
+			        result->return_string->append(message_parts->at(6));
+
+                } else
+			    {
+                    // Else it is a complex object
+
+			        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;
 			}
 
@@ -130,9 +162,10 @@
 	// caller frees this
 	result = new JavaResultData();
 	result->error_msg = new std::string();
+	result->return_identifier = 0;
 	result->return_string = new std::string();
 	result->return_wstring = new std::wstring();
-	result->error_occured = false;
+	result->error_occurred = false;
 
 	result_ready = false;
 }
@@ -162,6 +195,22 @@
 	}
 }
 
+/**
+ * Resets the results
+ */
+void
+JavaRequestProcessor::resetResult()
+{
+	// caller frees this
+	result->error_msg->clear();
+	result->return_identifier = 0;
+	result->return_string->clear();
+	result->return_wstring->clear();
+	result->error_occurred = false;
+
+	result_ready = false;
+}
+
 void
 JavaRequestProcessor::postAndWaitForResponse(std::string* message)
 {
@@ -179,10 +228,14 @@
     do
     {
     	clock_gettime(CLOCK_REALTIME, &curr_t);
-        bool timedout = false;
 
 		if (!result_ready && (curr_t.tv_sec < t.tv_sec))
-			usleep(2000);
+		{
+			if (g_main_context_pending(NULL))
+				g_main_context_iteration(NULL, false);
+			else
+				usleep(2000);
+		}
 		else
 			break;
 
@@ -190,6 +243,9 @@
 
     if (curr_t.tv_sec >= t.tv_sec)
     {
+    	result->error_occurred = true;
+    	result->error_msg->append("Error: Timed out when waiting for response");
+
     	// Report error
     	PLUGIN_DEBUG_1ARG("Error: Timed out when waiting for response to %s\n", message->c_str());
     }
@@ -253,6 +309,57 @@
 	return result;
 }
 
+/**
+ * Decrements reference count by 1
+ *
+ * @param object_id The ID of the object
+ */
+
+void
+JavaRequestProcessor::deleteReference(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(" DeleteLocalRef ");
+    message->append(object_id);
+
+    postAndWaitForResponse(message);
+
+    IcedTeaPluginUtilities::releaseReference();
+    delete message;
+}
+
+/**
+ * Increments reference count by 1
+ *
+ * @param object_id The ID of the object
+ */
+
+void
+JavaRequestProcessor::addReference(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(" NewGlobalRef ");
+    message->append(object_id);
+
+    postAndWaitForResponse(message);
+
+    IcedTeaPluginUtilities::releaseReference();
+    delete message;
+
+}
+
 JavaResultData*
 JavaRequestProcessor::findClass(std::string name)
 {
@@ -274,7 +381,7 @@
 }
 
 JavaResultData*
-JavaRequestProcessor::getClassName(std::string ID)
+JavaRequestProcessor::getClassName(std::string objectID)
 {
 	std::string* message;
 
@@ -284,7 +391,7 @@
 	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
 
     message->append(" GetClassName ");
-    message->append(ID);
+    message->append(objectID);
 
     postAndWaitForResponse(message);
 
@@ -294,7 +401,139 @@
 }
 
 JavaResultData*
-JavaRequestProcessor::getMethodID(std::string objectID, NPIdentifier methodName,
+JavaRequestProcessor::getClassID(std::string objectID)
+{
+    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(" GetClassID ");
+    message->append(objectID);
+
+    postAndWaitForResponse(message);
+
+    delete message;
+
+    return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getFieldID(std::string classID, std::string fieldName)
+{
+	JavaResultData* java_result;
+	JavaRequestProcessor* java_request = new JavaRequestProcessor();
+	std::string* message;
+
+	java_result = java_request->newString(fieldName);
+
+	this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+	this->reference = IcedTeaPluginUtilities::getReference();
+
+	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+	message->append(" GetFieldID ");
+	message->append(classID);
+	message->append(" ");
+	message->append(java_result->return_string->c_str());
+
+	postAndWaitForResponse(message);
+
+	IcedTeaPluginUtilities::releaseReference();
+
+	delete java_request;
+	delete message;
+
+	return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getStaticFieldID(std::string classID, std::string fieldName)
+{
+    JavaResultData* java_result;
+    JavaRequestProcessor* java_request = new JavaRequestProcessor();
+    std::string* message;
+
+    java_result = java_request->newString(fieldName);
+
+    this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+    this->reference = IcedTeaPluginUtilities::getReference();
+
+    message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+    message->append(" GetStaticFieldID ");
+    message->append(classID);
+    message->append(" ");
+    message->append(java_result->return_string->c_str());
+
+    postAndWaitForResponse(message);
+
+    IcedTeaPluginUtilities::releaseReference();
+
+    delete java_request;
+    delete message;
+
+    return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getField(std::string classID, std::string fieldName)
+{
+    JavaResultData* java_result;
+    JavaRequestProcessor* java_request = new JavaRequestProcessor();
+    std::string* message;
+
+    java_result = java_request->getFieldID(classID, fieldName);
+
+    this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+    this->reference = IcedTeaPluginUtilities::getReference();
+
+    message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+    message->append(" GetField ");
+    message->append(classID);
+    message->append(" ");
+    message->append(java_result->return_string->c_str());
+
+    postAndWaitForResponse(message);
+
+    IcedTeaPluginUtilities::releaseReference();
+
+    delete java_request;
+    delete message;
+
+    return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getStaticField(std::string classID, std::string fieldName)
+{
+    JavaResultData* java_result;
+    JavaRequestProcessor* java_request = new JavaRequestProcessor();
+    std::string* message;
+
+    java_result = java_request->getStaticFieldID(classID, fieldName);
+
+    this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+    this->reference = IcedTeaPluginUtilities::getReference();
+
+    message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+    message->append(" GetStaticField ");
+    message->append(classID);
+    message->append(" ");
+    message->append(java_result->return_string->c_str());
+
+    postAndWaitForResponse(message);
+
+    IcedTeaPluginUtilities::releaseReference();
+
+    delete java_request;
+    delete message;
+
+    return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getMethodID(std::string classID, NPIdentifier methodName,
                                   std::vector<std::string> args)
 {
 	JavaRequestProcessor* java_request;
@@ -317,7 +556,7 @@
 
 	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
 	*message += " GetMethodID ";
-	*message += objectID;
+	*message += classID;
 	*message += " ";
 	*message += browser_functions.utf8fromidentifier(methodName);
 	*message += " ";
@@ -333,6 +572,235 @@
 }
 
 JavaResultData*
+JavaRequestProcessor::getStaticMethodID(std::string classID, 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 += " GetStaticMethodID ";
+    *message += classID;
+    *message += " ";
+    *message += browser_functions.utf8fromidentifier(methodName);
+    *message += " ";
+    *message += *signature;
+
+    postAndWaitForResponse(message);
+
+    IcedTeaPluginUtilities::releaseReference();
+    delete signature;
+    delete message;
+
+    return result;
+}
+
+int
+JavaRequestProcessor::createJavaObjectFromVariant(NPVariant variant)
+{
+	JavaResultData* java_result;
+
+	std::string className;
+	std::string jsObjectClassID = std::string();
+	std::string jsObjectConstructorID = std::string();
+
+	std::string stringArg = std::string();
+	std::vector<std::string> args = std::vector<std::string>();
+
+	JavaRequestProcessor java_request = JavaRequestProcessor();
+	bool alreadyCreated = false;
+
+    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))
+    {
+    	className = "java.lang.Boolean";
+
+    	if (NPVARIANT_TO_BOOLEAN(variant))
+    		stringArg = "true";
+    	else
+    		stringArg = "false";
+
+    }
+    else if (NPVARIANT_IS_INT32(variant))
+    {
+    	className = "java.lang.Integer";
+
+    	char* valueStr = (char*) malloc(sizeof(char)*32);
+    	sprintf(valueStr, "%d", NPVARIANT_TO_INT32(variant));
+    	stringArg += valueStr;
+    	free(valueStr);
+    }
+    else if (NPVARIANT_IS_DOUBLE(variant))
+    {
+    	className = "java.lang.Double";
+
+    	char* valueStr = (char*) malloc(sizeof(char)*1024);
+    	sprintf(valueStr, "%d", NPVARIANT_TO_DOUBLE(variant));
+    	stringArg += valueStr;
+    	free(valueStr);
+    }
+    else if (NPVARIANT_IS_STRING(variant))
+    {
+    	className = "java.lang.String";
+
+    	stringArg += NPVARIANT_TO_STRING(variant).utf8characters;
+    } else {
+    	alreadyCreated = true;
+    }
+
+    if (!alreadyCreated) {
+		java_result = java_request.findClass(className.c_str());
+
+		// the result we want is in result_string (assuming there was no error)
+		if (java_result->error_occurred) {
+			printf("Unable to find classid for %s\n", className.c_str());
+			return 0;
+		}
+
+		jsObjectClassID.append(*(java_result->return_string));
+		java_request.resetResult();
+
+		std::string stringClassName = "Ljava/lang/String;";
+		args.push_back(stringClassName);
+
+		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_occurred) {
+			printf("Unable to find string constructor for %s\n", className.c_str());
+			return 0;
+		}
+
+		jsObjectConstructorID.append(*(java_result->return_string));
+		java_request.resetResult();
+
+		// We have class id and constructor ID. So we know we can create the object.. now create the string
+		java_result = java_request.newString(stringArg);
+
+		if (java_result->error_occurred) {
+			printf("Unable to create requested object\n");
+			return 0;
+		}
+
+		return java_result->return_identifier;
+
+	}
+
+    std::string classId = std::string(((IcedTeaScriptableJavaObject*) NPVARIANT_TO_OBJECT(variant))->getClassID());
+    std::string instanceId = std::string(((IcedTeaScriptableJavaObject*) NPVARIANT_TO_OBJECT(variant))->getInstanceID());
+
+    if (instanceId.length() == 0)
+    	return atoi(classId.c_str());
+    else
+    	return atoi(instanceId.c_str());
+}
+
+JavaResultData*
+JavaRequestProcessor::callStaticMethod(std::string classID, std::string methodName,
+									   const NPVariant* args, int numArgs)
+{
+    return call(true, classID, methodName, args, numArgs);
+}
+
+JavaResultData*
+JavaRequestProcessor::callMethod(std::string objectID, std::string methodName,
+                                       const NPVariant* args, int numArgs)
+{
+    return call(false, objectID, methodName, args, numArgs);
+}
+
+JavaResultData*
+JavaRequestProcessor::call(bool isStatic, std::string objectID,
+                           std::string methodName,
+                           const NPVariant* args, int numArgs)
+{
+	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);
+
+    if (isStatic)
+        *message += " CallStaticMethod ";
+    else
+        *message += " CallMethod ";
+
+    *message += objectID;
+    *message += " ";
+    *message += methodName;
+    *message += " ";
+
+	// First, we need to load the arguments into the java-side table
+	for (int i=0; i < numArgs; i++) {
+		int objectID = createJavaObjectFromVariant(args[i]);
+		if (objectID == 0)
+		{
+			result->error_occurred = true;
+			result->error_msg->append("Unable to create arguments");
+			delete message;
+			return result;
+		}
+
+		char* id = (char*) malloc(sizeof(char)*32);
+		sprintf(id, "%d", objectID);
+		*message += id;
+		*message += " ";
+		free(id);
+	}
+
+	postAndWaitForResponse(message);
+
+    IcedTeaPluginUtilities::releaseReference();
+    delete message;
+
+    return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getObjectClass(std::string objectID)
+{
+    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 += " GetObjectClass ";
+    *message += objectID;
+
+    postAndWaitForResponse(message);
+
+    IcedTeaPluginUtilities::releaseReference();
+    delete message;
+
+    return result;
+}
+
+JavaResultData*
 JavaRequestProcessor::newObject(std::string objectID, std::string methodID,
                                   std::vector<std::string> args)
 {
@@ -366,24 +834,126 @@
 JavaResultData*
 JavaRequestProcessor::newString(std::string str)
 {
-	JavaRequestProcessor* java_request;
-	std::string* utf_string = new std::string();
+	std::string utf_string = std::string();
 	std::string* message;
 
-	IcedTeaPluginUtilities::convertStringToUTF8(&str, utf_string);
+	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);
+	message->append(utf_string);
+
+	postAndWaitForResponse(message);
+
+	IcedTeaPluginUtilities::releaseReference();
+	delete message;
+
+	return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::hasPackage(std::string package_name)
+{
+	JavaResultData* java_result;
+	JavaRequestProcessor* java_request = new JavaRequestProcessor();
+	std::string* message;
+
+	java_result = java_request->newString(package_name);
+
+	this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+	this->reference = IcedTeaPluginUtilities::getReference();
+
+	message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+	message->append(" HasPackage ");
+	message->append(java_result->return_string->c_str());
 
 	postAndWaitForResponse(message);
 
 	IcedTeaPluginUtilities::releaseReference();
-	delete utf_string;
+
+	delete java_request;
 	delete message;
 
 	return result;
 }
+
+JavaResultData*
+JavaRequestProcessor::hasMethod(std::string classID, std::string method_name)
+{
+    JavaResultData* java_result;
+    JavaRequestProcessor* java_request = new JavaRequestProcessor();
+    std::string* message;
+
+    java_result = java_request->newString(method_name);
+
+    this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+    this->reference = IcedTeaPluginUtilities::getReference();
+
+    message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+    message->append(" HasMethod ");
+    message->append(classID);
+    message->append(" ");
+    message->append(java_result->return_string->c_str());
+
+    postAndWaitForResponse(message);
+
+    IcedTeaPluginUtilities::releaseReference();
+
+    delete java_request;
+    delete message;
+
+    return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::hasField(std::string classID, std::string method_name)
+{
+    JavaResultData* java_result;
+    JavaRequestProcessor* java_request = new JavaRequestProcessor();
+    std::string* message;
+
+    java_result = java_request->newString(method_name);
+
+    this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+    this->reference = IcedTeaPluginUtilities::getReference();
+
+    message = IcedTeaPluginUtilities::constructMessagePrefix(0, reference);
+    message->append(" HasField ");
+    message->append(classID);
+    message->append(" ");
+    message->append(java_result->return_string->c_str());
+
+    postAndWaitForResponse(message);
+
+    IcedTeaPluginUtilities::releaseReference();
+
+    delete java_request;
+    delete message;
+
+    return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getAppletObjectInstance(std::string instanceID)
+{
+    std::string message = std::string();
+    char* ref_str;
+
+    this->reference = IcedTeaPluginUtilities::getReference();
+    ref_str = IcedTeaPluginUtilities::itoa(reference);
+
+    message = "instance ";
+    message += instanceID;
+    message += " reference ";
+    message += ref_str;
+    message += " GetJavaObject";
+
+    postAndWaitForResponse(&message);
+
+    IcedTeaPluginUtilities::releaseReference();
+
+    return result;
+}
--- a/plugin/icedteanp/IcedTeaJavaRequestProcessor.h	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaJavaRequestProcessor.h	Thu Aug 06 10:43:31 2009 -0400
@@ -45,8 +45,9 @@
 
 #include "IcedTeaNPPlugin.h"
 #include "IcedTeaPluginUtils.h"
+#include "IcedTeaScriptablePluginObject.h"
 
-#define REQUESTTIMEOUT 60
+#define REQUESTTIMEOUT 20
 
 /*
  * This struct holds data specific to a Java operation requested by the plugin
@@ -72,6 +73,7 @@
  */
 typedef struct java_result_data
 {
+
 	// Return identifier (if applicable)
     int return_identifier;
 
@@ -85,7 +87,7 @@
     std::string* error_msg;
 
     // Boolean indicating if an error occurred
-    bool error_occured;
+    bool error_occurred;
 
 } JavaResultData;
 
@@ -102,11 +104,28 @@
     	/* Post message on bus and wait */
     	void postAndWaitForResponse(std::string* message);
 
+    	/* Creates a argument on java-side with appropriate type */
+    	int createJavaObjectFromVariant(NPVariant variant);
+
+    	// Call a method, static or otherwise, depending on supplied arg
+        JavaResultData* call(bool isStatic, std::string objectID,
+                             std::string methodName, const NPVariant* args,
+                             int numArgs);
+
     public:
     	JavaRequestProcessor();
     	~JavaRequestProcessor();
     	virtual bool newMessageOnBus(const char* message);
 
+    	/* Resets the results */
+    	void resetResult();
+
+    	/* Increments reference count by 1 */
+    	void addReference(std::string object_id);
+
+    	/* Decrements reference count by 1 */
+    	void deleteReference(std::string object_id);
+
     	/* Returns the toString() value, given an object identifier */
     	JavaResultData* getToStringValue(std::string object_id);
 
@@ -117,10 +136,37 @@
     	JavaResultData* getMethodID1(NPObject* obj, NPIdentifier methodName,
                         std::vector<NPVariant> args);
 
+    	/* Returns the field object */
+        JavaResultData* getField(std::string classID, std::string fieldName);
+
+        /* Returns the static field object */
+        JavaResultData* getStaticField(std::string classID, std::string fieldName);
+
+        /* Returns the field id */
+        JavaResultData* getFieldID(std::string classID, std::string fieldName);
+
+        /* Returns the static field id */
+    	JavaResultData* getStaticFieldID(std::string classID, std::string fieldName);
+
     	/* Returns the method id */
-    	JavaResultData* getMethodID(std::string objectID, NPIdentifier methodName,
+    	JavaResultData* getMethodID(std::string classID, NPIdentifier methodName,
                                     std::vector<std::string> args);
 
+        /* Returns the static method id */
+        JavaResultData* getStaticMethodID(std::string classID, NPIdentifier methodName,
+                                     std::vector<std::string> args);
+
+        /* Calls a static method */
+        JavaResultData* callStaticMethod(std::string classID, std::string methodName,
+                                         const NPVariant* args, int numArgs);
+
+        /* Calls a method on an instance */
+        JavaResultData* callMethod(std::string objectID, std::string methodName,
+								   const NPVariant* args, int numArgs);
+
+        /* Returns the class of the given object */
+        JavaResultData* getObjectClass(std::string objectID);
+
     	/* Creates a new object */
     	JavaResultData* newObject(std::string objectID, std::string methodID,
                                     std::vector<std::string> args);
@@ -129,11 +175,25 @@
     	JavaResultData* findClass(std::string name);
 
     	/* Returns the type class name */
-    	JavaResultData* getClassName(std::string ID);
+    	JavaResultData* getClassName(std::string objectID);
+
+    	/* Returns the type class id */
+    	JavaResultData* getClassID(std::string objectID);
 
     	/* Creates a new string in the Java store */
     	JavaResultData* newString(std::string str);
 
+    	/* Check if package exists */
+    	JavaResultData* hasPackage(std::string package_name);
+
+        /* Check if method exists */
+        JavaResultData* hasMethod(std::string classID, std::string method_name);
+
+        /* Check if field exists */
+        JavaResultData* hasField(std::string classID, std::string method_name);
+
+        /* Returns the instance ID of the java applet */
+        JavaResultData* getAppletObjectInstance(std::string instanceID);
 };
 
 #endif /* ICEDTEAJAVAREQUESTPROCESSOR_H_ */
--- a/plugin/icedteanp/IcedTeaNPPlugin.cc	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaNPPlugin.cc	Thu Aug 06 10:43:31 2009 -0400
@@ -203,9 +203,6 @@
   guint32 window_width;
   // The last plugin window height sent to us by the browser.
   guint32 window_height;
-
-  // The scriptable plugin object
-  NPObject* scriptable_plugin_object;
 };
 
 // Documentbase retrieval type-punning union.
@@ -259,6 +256,8 @@
 
 int plugin_debug = getenv ("ICEDTEAPLUGIN_DEBUG") != NULL;
 
+pthread_cond_t cond_message_available = PTHREAD_COND_INITIALIZER;
+
 // 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.
@@ -352,36 +351,20 @@
 
   // Documentbase retrieval.
   documentbase = plugin_get_documentbase (instance);
-  if (!documentbase)
+  if (documentbase)
     {
-      PLUGIN_ERROR ("Documentbase retrieval failed."
-                    " Browser not Mozilla-based?");
-      //goto cleanup_appletviewer_mutex;
-    }
+      // => dummy plugin instantiation
 
-  // Send applet tag message to appletviewer.
-  applet_tag = plugin_create_applet_tag (argc, argn, argv);
-
-  tag_message = (gchar*) malloc(strlen(applet_tag)*sizeof(gchar) + 1024);
-  g_sprintf(tag_message, "instance %d tag %s %s", instance_counter, documentbase, applet_tag);
 
-  //plugin_send_message_to_appletviewer (data, data->instance_string);
-  plugin_send_message_to_appletviewer (tag_message);
+      // Send applet tag message to appletviewer.
+      applet_tag = plugin_create_applet_tag (argc, argn, argv);
 
-  //send cookie information
-  char* cookie_string;
-  if (get_cookie_info(documentbase, &cookie_string) == NS_OK)
-    {
-      cookie_info = (gchar*) malloc(sizeof(cookie_string) + 1024);
-      g_sprintf(cookie_info, "instance %d cookie %s", instance_counter, cookie_string);
+      tag_message = (gchar*) malloc(strlen(applet_tag)*sizeof(gchar) + 1024);
+      g_sprintf(tag_message, "instance %d tag %s %s", instance_counter, documentbase, applet_tag);
+
+      //plugin_send_message_to_appletviewer (data, data->instance_string);
+      plugin_send_message_to_appletviewer (tag_message);
     }
-  else
-    {
-      cookie_info = (gchar*) malloc(1024);
-      g_sprintf(cookie_info, "instance %d cookie", instance_counter);
-    }
-
-  plugin_send_message_to_appletviewer (cookie_info);
 
   g_mutex_unlock (data->appletviewer_mutex);
 
@@ -392,11 +375,6 @@
   // Set back-pointer to owner instance.
   data->owner = instance;
 
-  printf("Creating scriptable object..");
-  npPluginObj = get_scriptable_object(instance);
-
-  data->scriptable_plugin_object = npPluginObj;
-
   instance->pdata = data;
 
   goto cleanup_done;
@@ -430,6 +408,7 @@
   documentbase = NULL;
 
   // store an identifier for this plugin
+  PLUGIN_DEBUG_2ARG("Mapping id instance_counter and instance %p", instance_counter, instance);
   g_hash_table_insert(instance_to_id_map, instance, GINT_TO_POINTER(instance_counter));
   g_hash_table_insert(id_to_instance_map, GINT_TO_POINTER(instance_counter), instance);
   instance_counter++;
@@ -481,7 +460,7 @@
   // clean up any older pip
   unlink (in_pipe_name);
 
-  PLUGIN_DEBUG_1ARG ("GCJ_New: creating input fifo: %s", in_pipe_name);
+  PLUGIN_DEBUG_1ARG ("GCJ_New: creating input fifo: %s\n", in_pipe_name);
   if (mkfifo (in_pipe_name, 0700) == -1 && errno != EEXIST)
     {
       PLUGIN_ERROR_TWO ("Failed to create input pipe", strerror (errno));
@@ -649,8 +628,7 @@
       break;
     case NPPVpluginScriptableNPObject:
       {
-         GCJPluginData *data = (GCJPluginData*) instance->pdata;
-         *(NPObject **)value = data->scriptable_plugin_object;
+         *(NPObject **)value = get_scriptable_object(instance);
       }
       break;
     default:
@@ -685,7 +663,7 @@
 NPError
 GCJ_SetWindow (NPP instance, NPWindow* window)
 {
-  PLUGIN_DEBUG_0ARG ("GCJ_SetWindow");
+  PLUGIN_DEBUG_0ARG ("GCJ_SetWindow\n");
 
   if (instance == NULL)
     {
@@ -936,7 +914,7 @@
 static void
 plugin_data_new (GCJPluginData** data)
 {
-  PLUGIN_DEBUG_0ARG ("plugin_data_new");
+  PLUGIN_DEBUG_0ARG ("plugin_data_new\n");
 
   *data = (GCJPluginData*)
     (*browser_functions.memalloc) (sizeof (struct GCJPluginData));
@@ -957,7 +935,7 @@
 static gchar*
 plugin_get_documentbase (NPP instance)
 {
-  PLUGIN_DEBUG_0ARG ("plugin_get_documentbase");
+  PLUGIN_DEBUG_0ARG ("plugin_get_documentbase\n");
 
   nsIPluginInstance* xpcom_instance = NULL;
   nsIPluginInstancePeer* peer = NULL;
@@ -995,7 +973,7 @@
 
   if (!documentbase)
     {
-      PLUGIN_ERROR ("documentbase is NULL.");
+      // NULL => dummy instantiation for LiveConnect
       goto cleanup_plugintaginfo2;
     }
 
@@ -1021,7 +999,7 @@
 {
   GtkWidget* dialog = NULL;
 
-  PLUGIN_DEBUG_0ARG ("plugin_display_failure_dialog");
+  PLUGIN_DEBUG_0ARG ("plugin_display_failure_dialog\n");
 
   dialog = gtk_message_dialog_new (NULL,
                                    GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -1243,7 +1221,7 @@
                                        GINT_TO_POINTER(id));
 }
 
-int get_id_from_instance(NPP* instance)
+int get_id_from_instance(NPP instance)
 {
     return GPOINTER_TO_INT(g_hash_table_lookup(instance_to_id_map,
                                                    instance));
@@ -1337,42 +1315,6 @@
   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
@@ -2143,27 +2085,50 @@
 get_scriptable_object(NPP instance)
 {
 
-	NPObject* scriptable_object;
+    printf("Calling plugin_get_documentbase\n");
+    gchar* document_base = plugin_get_documentbase(instance);
+    NPObject* obj;
+
+    if (!document_base) // dummy instance/package?
+    {
+        obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(instance, "");
+    } else
+    {
+        JavaRequestProcessor java_request = JavaRequestProcessor();
+        JavaResultData* java_result;
+        std::string instance_id = std::string();
+        std::string applet_class_id = std::string();
+
+        int id = get_id_from_instance(instance);
+        gchar* id_str = g_strdup_printf ("%d", id);
+
+        java_result = java_request.getAppletObjectInstance(id_str);
+
+        g_free(id_str);
 
-	NPClass* np_class = new NPClass();
-	np_class->structVersion = NP_CLASS_STRUCT_VERSION;
-	np_class->allocate = allocate_scriptable_object;
-	np_class->deallocate = IcedTeaScriptablePluginObject::deAllocate;
-	np_class->invalidate = IcedTeaScriptablePluginObject::invalidate;
-	np_class->hasMethod = IcedTeaScriptablePluginObject::hasMethod;
-	np_class->invoke = IcedTeaScriptablePluginObject::invoke;
-	np_class->invokeDefault = IcedTeaScriptablePluginObject::invokeDefault;
-	np_class->hasProperty = IcedTeaScriptablePluginObject::hasProperty;
-	np_class->getProperty = IcedTeaScriptablePluginObject::getProperty;
-	np_class->setProperty = IcedTeaScriptablePluginObject::setProperty;
-	np_class->removeProperty = IcedTeaScriptablePluginObject::removeProperty;
-	np_class->enumerate = IcedTeaScriptablePluginObject::enumerate;
-	np_class->construct = IcedTeaScriptablePluginObject::construct;
+        if (java_result->error_occurred)
+        {
+            printf("Error: Unable to fetch applet instance id from Java side.\n");
+            return NULL;
+        }
+
+        instance_id.append(*(java_result->return_string));
+
+        java_request.resetResult();
+        java_result = java_request.getClassID(instance_id);
 
-	scriptable_object = browser_functions.createobject(instance, np_class);
-	PLUGIN_DEBUG_1ARG("Returning new scriptable class: %p\n", scriptable_object);
+        if (java_result->error_occurred)
+        {
+            printf("Error: Unable to fetch applet instance id from Java side.\n");
+            return NULL;
+        }
 
-	return scriptable_object;
+        applet_class_id.append(*(java_result->return_string));
+
+        obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(instance, applet_class_id, instance_id);
+    }
+
+	return obj;
 }
 
 NPObject*
--- a/plugin/icedteanp/IcedTeaNPPlugin.h	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaNPPlugin.h	Thu Aug 06 10:43:31 2009 -0400
@@ -59,6 +59,9 @@
 static pthread_t plugin_request_processor_thread2;
 static pthread_t plugin_request_processor_thread3;
 
+// Condition on which the queue processor waits
+extern pthread_cond_t cond_message_available;
+
 // debug switch
 extern int plugin_debug;
 
@@ -89,13 +92,10 @@
 /* Sends a message to the appletviewer */
 void plugin_send_message_to_appletviewer(gchar const* message);
 
-/* Returns a scriptable npobject */
+/* Returns an appropriate (package/object) scriptable npobject */
 NPObject* get_scriptable_object(NPP instance);
 
 /* 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 Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaPluginRequestProcessor.cc	Thu Aug 06 10:43:31 2009 -0400
@@ -164,6 +164,9 @@
             message_queue->push_back(message_parts);
             pthread_mutex_unlock(&message_queue_mutex);
 
+            // Broadcast that a message is now available
+            pthread_cond_broadcast(&cond_message_available);
+
             return true;
         }
 
@@ -282,7 +285,7 @@
     java_request = new JavaRequestProcessor();
     java_result = java_request->newString(*variant_string);
 
-    if (java_result->error_occured)
+    if (java_result->error_occurred)
     {
         printf("Unable to process NewString request. Error occurred: %s\n", java_result->error_msg);
         //goto cleanup;
@@ -342,7 +345,7 @@
     java_result = java_request->getString(propertyNameID);
 
     // the result we want is in result_string (assuming there was no error)
-    if (java_result->error_occured)
+    if (java_result->error_occurred)
     {
         printf("Unable to get member name for setMember. Error occurred: %s\n", java_result->error_msg);
         goto cleanup;
@@ -359,7 +362,7 @@
     java_result = java_request->getClassName(valueID);
 
     // the result we want is in result_string (assuming there was no error)
-    if (java_result->error_occured)
+    if (java_result->error_occurred)
     {
         printf("Unable to get class name for setMember. Error occurred: %s\n", java_result->error_msg);
         goto cleanup;
@@ -373,7 +376,7 @@
     java_result = java_request->getToStringValue(valueID);
 
     // the result we want is in result_string (assuming there was no error)
-    if (java_result->error_occured)
+    if (java_result->error_occurred)
     {
         printf("Unable to get value for setMember. Error occurred: %s\n", java_result->error_msg);
         goto cleanup;
@@ -474,7 +477,7 @@
     java_result = java_request->getString(*member_id);
 
     // the result we want is in result_string (assuming there was no error)
-    if (java_result->error_occured)
+    if (java_result->error_occurred)
     {
         printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
         //goto cleanup;
@@ -507,7 +510,7 @@
     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)
+    if (java_result->error_occurred)
     {
         printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
         //goto cleanup;
@@ -530,7 +533,7 @@
             *args);
 
     // the result we want is in result_string (assuming there was no error)
-    if (java_result->error_occured)
+    if (java_result->error_occurred)
     {
         printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
         //goto cleanup;
@@ -551,7 +554,7 @@
                                           *args);
 
     // the result we want is in result_string (assuming there was no error)
-    if (java_result->error_occured)
+    if (java_result->error_occurred)
     {
         printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
         //goto cleanup;
@@ -587,6 +590,7 @@
     PluginRequestProcessor* processor = (PluginRequestProcessor*) data;
     std::vector<std::string>* message_parts = NULL;
     std::string command;
+    pthread_mutex_t wait_mutex = PTHREAD_MUTEX_INITIALIZER; // This is needed for API compat. and is unused
 
     PLUGIN_DEBUG_1ARG("Queue processor initialized. Queue = %p\n", message_queue);
 
@@ -602,8 +606,6 @@
 
         if (message_parts)
         {
-            PLUGIN_DEBUG_0ARG("Processing engaged\n");
-
             command = message_parts->at(2);
 
             if (command == "GetMember")
@@ -614,7 +616,10 @@
                 processor->sendString(message_parts);
             } else if (command == "SetMember")
             {
+            	// write methods are synchronized
+            	pthread_mutex_lock(&syn_write_mutex);
                 processor->setMember(message_parts);
+                pthread_mutex_unlock(&syn_write_mutex);
             } else
             {
                 // Nothing matched
@@ -622,10 +627,9 @@
 
             }
 
-            PLUGIN_DEBUG_0ARG("Processing dis-engaged\n");
         } else
         {
-            usleep(20000);
+        	pthread_cond_wait(&cond_message_available, &wait_mutex);
             pthread_testcancel();
         }
 
--- a/plugin/icedteanp/IcedTeaPluginRequestProcessor.h	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaPluginRequestProcessor.h	Thu Aug 06 10:43:31 2009 -0400
@@ -70,8 +70,8 @@
 static long internal_req_ref_counter;
 
 // JS request processor methods
-static NPP getInstanceFromMemberPtr(void* member_ptr);
-static void storeInstanceID(void* member_ptr, NPP instance);
+extern NPP getInstanceFromMemberPtr(void* member_ptr);
+extern void storeInstanceID(void* member_ptr, NPP instance);
 static void* requestFromMainThread();
 static void* getSlot(void* tdata);
 static void* setSlot(void* tdata);
--- a/plugin/icedteanp/IcedTeaPluginUtils.cc	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaPluginUtils.cc	Thu Aug 06 10:43:31 2009 -0400
@@ -85,7 +85,9 @@
 std::string*
 IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference)
 {
-	std::string* result = new std::string();
+    // Until security is implemented, use file:// source for _everything_
+
+	/*std::string* result = new std::string();
 	char* context_str = itoa(context);
 	char* reference_str = itoa(reference);
 
@@ -97,7 +99,9 @@
 	free(context_str);
 	free(reference_str);
 
-	return result;
+	return result;*/
+
+    return IcedTeaPluginUtilities::constructMessagePrefix(context, reference, "file://");
 }
 
 /**
@@ -112,7 +116,7 @@
 
 std::string*
 IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference,
-		                                       char* address)
+		                                       const char* address)
 {
 	std::string* result = new std::string();
 	char* context_str = itoa(context);
--- a/plugin/icedteanp/IcedTeaPluginUtils.h	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaPluginUtils.h	Thu Aug 06 10:43:31 2009 -0400
@@ -129,7 +129,7 @@
 
     	/* Constructs message prefix with given context, reference and src */
     	static std::string* constructMessagePrefix(int context, int reference,
-    			                    char* address);
+    			                    const char* address);
 
     	/* Converts given pointer to a string representation */
     	static std::string* JSIDToString(void* id);
@@ -244,4 +244,11 @@
         void post(const char* message);
 };
 
+/*
+ * JNI map used for mediating between NPVariants and Java objects
+ *
+ *
+ *
+ */
+
 #endif // __ICEDTEAPLUGINUTILS_H__
--- a/plugin/icedteanp/IcedTeaRunnable.h	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaRunnable.h	Thu Aug 06 10:43:31 2009 -0400
@@ -48,7 +48,7 @@
 /*
  * This struct holds the result from the main-thread dispatched method
  */
-typedef struct result_data
+typedef struct java_result
 {
 	// Return identifier (if applicable)
     int return_identifier;
--- a/plugin/icedteanp/IcedTeaScriptablePluginObject.cc	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaScriptablePluginObject.cc	Thu Aug 06 10:43:31 2009 -0400
@@ -41,6 +41,7 @@
 IcedTeaScriptablePluginObject::IcedTeaScriptablePluginObject(NPP instance)
 {
 	this->instance = instance;
+	storeInstanceID(this, instance);
 }
 
 void
@@ -59,6 +60,7 @@
 IcedTeaScriptablePluginObject::hasMethod(NPObject *npobj, NPIdentifier name)
 {
 	printf ("** Unimplemented: IcedTeaScriptablePluginObject::hasMethod %p\n", npobj);
+	return false;
 }
 
 bool
@@ -66,6 +68,7 @@
 			uint32_t argCount,NPVariant *result)
 {
 	printf ("** Unimplemented: IcedTeaScriptablePluginObject::invoke %p\n", npobj);
+	return false;
 }
 
 bool
@@ -73,36 +76,50 @@
 			       uint32_t argCount, NPVariant *result)
 {
 	printf ("** Unimplemented: IcedTeaScriptablePluginObject::invokeDefault %p\n", npobj);
+	return false;
 }
 
 bool
 IcedTeaScriptablePluginObject::hasProperty(NPObject *npobj, NPIdentifier name)
 {
 	printf ("** Unimplemented: IcedTeaScriptablePluginObject::hasProperty %p\n", npobj);
+	return false;
 }
 
 bool
 IcedTeaScriptablePluginObject::getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
 {
-	printf ("** Unimplemented: IcedTeaScriptablePluginObject::getProperty %p\n", npobj);
+	// Package request?
+	if (!strcmp(browser_functions.utf8fromidentifier(name), "java"))
+	{
+		//NPObject* obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(getInstanceFromMemberPtr(npobj), name);
+		//OBJECT_TO_NPVARIANT(obj, *result);
+
+		//printf ("Filling variant %p with object %p\n", result);
+	}
+
+	return false;
 }
 
 bool
 IcedTeaScriptablePluginObject::setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value)
 {
 	printf ("** Unimplemented: IcedTeaScriptablePluginObject::setProperty %p\n", npobj);
+	return false;
 }
 
 bool
 IcedTeaScriptablePluginObject::removeProperty(NPObject *npobj, NPIdentifier name)
 {
 	printf ("** Unimplemented: IcedTeaScriptablePluginObject::removeProperty %p\n", npobj);
+	return false;
 }
 
 bool
 IcedTeaScriptablePluginObject::enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
 {
 	printf ("** Unimplemented: IcedTeaScriptablePluginObject::enumerate %p\n", npobj);
+	return false;
 }
 
 bool
@@ -110,4 +127,533 @@
 	           NPVariant *result)
 {
 	printf ("** Unimplemented: IcedTeaScriptablePluginObject::construct %p\n", npobj);
+	return false;
 }
+
+NPObject*
+allocate_scriptable_jp_object(NPP npp, NPClass *aClass)
+{
+    PLUGIN_DEBUG_0ARG("Allocating new scriptable Java Package object\n");
+    return new IcedTeaScriptableJavaPackageObject(npp);
+}
+
+NPObject*
+IcedTeaScriptablePluginObject::get_scriptable_java_package_object(NPP instance, const NPUTF8* name)
+{
+
+	NPObject* scriptable_object;
+
+	NPClass* np_class = new NPClass();
+	np_class->structVersion = NP_CLASS_STRUCT_VERSION;
+	np_class->allocate = allocate_scriptable_jp_object;
+	np_class->deallocate = IcedTeaScriptableJavaPackageObject::deAllocate;
+	np_class->invalidate = IcedTeaScriptableJavaPackageObject::invalidate;
+	np_class->hasMethod = IcedTeaScriptableJavaPackageObject::hasMethod;
+	np_class->invoke = IcedTeaScriptableJavaPackageObject::invoke;
+	np_class->invokeDefault = IcedTeaScriptableJavaPackageObject::invokeDefault;
+	np_class->hasProperty = IcedTeaScriptableJavaPackageObject::hasProperty;
+	np_class->getProperty = IcedTeaScriptableJavaPackageObject::getProperty;
+	np_class->setProperty = IcedTeaScriptableJavaPackageObject::setProperty;
+	np_class->removeProperty = IcedTeaScriptableJavaPackageObject::removeProperty;
+	np_class->enumerate = IcedTeaScriptableJavaPackageObject::enumerate;
+	np_class->construct = IcedTeaScriptableJavaPackageObject::construct;
+
+	scriptable_object = browser_functions.createobject(instance, np_class);
+	PLUGIN_DEBUG_3ARG("Returning new scriptable package class: %p from instance %p with name %s\n", scriptable_object, instance, name);
+
+    ((IcedTeaScriptableJavaPackageObject*) scriptable_object)->setPackageName(name);
+
+	storeInstanceID(scriptable_object, instance);
+
+	return scriptable_object;
+}
+
+IcedTeaScriptableJavaPackageObject::IcedTeaScriptableJavaPackageObject(NPP instance)
+{
+	this->instance = instance;
+	this->package_name = new std::string();
+}
+
+IcedTeaScriptableJavaPackageObject::~IcedTeaScriptableJavaPackageObject()
+{
+    delete this->package_name;
+}
+
+void
+IcedTeaScriptableJavaPackageObject::setPackageName(const NPUTF8* name)
+{
+    this->package_name->append(name);
+}
+
+std::string
+IcedTeaScriptableJavaPackageObject::getPackageName()
+{
+    return this->package_name->c_str();
+}
+
+void
+IcedTeaScriptableJavaPackageObject::deAllocate(NPObject *npobj)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::deAllocate %p\n", npobj);
+}
+
+void
+IcedTeaScriptableJavaPackageObject::invalidate(NPObject *npobj)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::invalidate %p\n", npobj);
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::hasMethod(NPObject *npobj, NPIdentifier name)
+{
+    // Silly caller. Methods are for objects!
+	return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args,
+			uint32_t argCount,NPVariant *result)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::invoke %p\n", npobj);
+	return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::invokeDefault(NPObject *npobj, const NPVariant *args,
+			       uint32_t argCount, NPVariant *result)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::invokeDefault %p\n", npobj);
+	return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::hasProperty(NPObject *npobj, NPIdentifier name)
+{
+	PLUGIN_DEBUG_1ARG("IcedTeaScriptableJavaPackageObject::hasProperty %s\n", browser_functions.utf8fromidentifier(name));
+
+	bool hasProperty = false;
+	JavaResultData* java_result;
+	JavaRequestProcessor* java_request = new JavaRequestProcessor();
+
+	printf("\"%s\"\n", ((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName().c_str());
+
+	std::string property_name = ((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName();
+	if (property_name.length() > 0)
+	    property_name += ".";
+	property_name += browser_functions.utf8fromidentifier(name);
+
+	printf("\"%s\" \"%s\" \"%s\" = \"%s\"\n",
+	          ((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName().c_str(), ".",
+	          browser_functions.utf8fromidentifier(name), property_name.c_str());
+
+	java_result = java_request->hasPackage(property_name);
+
+	if (!java_result->error_occurred && java_result->return_identifier != 0) hasProperty = true;
+
+	// No such package. Do we have a class with that name?
+	if (!hasProperty)
+	{
+		java_request->resetResult();
+		java_result = java_request->findClass(property_name);
+	}
+
+	if (java_result->return_identifier != 0) hasProperty = true;
+
+	delete java_request;
+
+	return hasProperty;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
+{
+
+	PLUGIN_DEBUG_1ARG("IcedTeaScriptableJavaPackageObject::getProperty %s\n", browser_functions.utf8fromidentifier(name));
+
+	bool isPropertyClass = false;
+	JavaResultData* java_result;
+	JavaRequestProcessor java_request = JavaRequestProcessor();
+
+	std::string property_name = ((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName();
+	if (property_name.length() > 0)
+	    property_name += ".";
+	property_name += browser_functions.utf8fromidentifier(name);
+
+	java_result = java_request.findClass(property_name);
+	isPropertyClass = (java_result->return_identifier == 0);
+
+	//NPIdentifier property = browser_functions.getstringidentifier(property_name.c_str());
+
+	NPObject* obj;
+
+	if (isPropertyClass)
+	{
+		PLUGIN_DEBUG_0ARG("Returning package object\n");
+		obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(
+                                  getInstanceFromMemberPtr(npobj),
+                                  property_name.c_str());
+	}
+	else
+	{
+		PLUGIN_DEBUG_0ARG("Returning Java object\n");
+		obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(getInstanceFromMemberPtr(npobj), *(java_result->return_string), "0");
+	}
+
+	OBJECT_TO_NPVARIANT(obj, *result);
+
+	return true;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::setProperty %p\n", npobj);
+	return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::removeProperty(NPObject *npobj, NPIdentifier name)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::removeProperty %p\n", npobj);
+	return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::enumerate %p\n", npobj);
+	return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::construct(NPObject *npobj, const NPVariant *args, uint32_t argCount,
+	           NPVariant *result)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::construct %p\n", npobj);
+	return false;
+}
+
+NPObject*
+allocate_scriptable_java_object(NPP npp, NPClass *aClass)
+{
+    PLUGIN_DEBUG_0ARG("Allocating new scriptable Java Package object\n");
+    return new IcedTeaScriptableJavaObject(npp);
+}
+
+NPObject*
+IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(NPP instance, std::string class_id, std::string instance_id)
+{
+	NPObject* scriptable_object;
+
+	NPClass* np_class = new NPClass();
+	np_class->structVersion = NP_CLASS_STRUCT_VERSION;
+	np_class->allocate = allocate_scriptable_java_object;
+	np_class->deallocate = IcedTeaScriptableJavaObject::deAllocate;
+	np_class->invalidate = IcedTeaScriptableJavaObject::invalidate;
+	np_class->hasMethod = IcedTeaScriptableJavaObject::hasMethod;
+	np_class->invoke = IcedTeaScriptableJavaObject::invoke;
+	np_class->invokeDefault = IcedTeaScriptableJavaObject::invokeDefault;
+	np_class->hasProperty = IcedTeaScriptableJavaObject::hasProperty;
+	np_class->getProperty = IcedTeaScriptableJavaObject::getProperty;
+	np_class->setProperty = IcedTeaScriptableJavaObject::setProperty;
+	np_class->removeProperty = IcedTeaScriptableJavaObject::removeProperty;
+	np_class->enumerate = IcedTeaScriptableJavaObject::enumerate;
+	np_class->construct = IcedTeaScriptableJavaObject::construct;
+
+	scriptable_object = browser_functions.createobject(instance, np_class);
+	PLUGIN_DEBUG_2ARG("Returning new scriptable class: %p from instance %p\n", scriptable_object, instance);
+
+	((IcedTeaScriptableJavaObject*) scriptable_object)->setClassIdentifier(class_id);
+
+	if (instance_id != "0")
+	    ((IcedTeaScriptableJavaObject*) scriptable_object)->setInstanceIdentifier(instance_id);
+
+	storeInstanceID(scriptable_object, instance);
+
+	return scriptable_object;
+}
+
+IcedTeaScriptableJavaObject::IcedTeaScriptableJavaObject(NPP instance)
+{
+	this->instance = instance;
+	this->class_id = new std::string();
+	this->instance_id = new std::string();
+}
+
+IcedTeaScriptableJavaObject::~IcedTeaScriptableJavaObject()
+{
+	delete this->class_id;
+	delete this->instance_id;
+}
+
+void
+IcedTeaScriptableJavaObject::setClassIdentifier(std::string class_id)
+{
+	this->class_id->append(class_id);
+}
+
+void
+IcedTeaScriptableJavaObject::setInstanceIdentifier(std::string instance_id)
+{
+	this->instance_id->append(instance_id);
+}
+
+void
+IcedTeaScriptableJavaObject::deAllocate(NPObject *npobj)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaObject::deAllocate %p\n", npobj);
+}
+
+void
+IcedTeaScriptableJavaObject::invalidate(NPObject *npobj)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaObject::invalidate %p\n", npobj);
+}
+
+bool
+IcedTeaScriptableJavaObject::hasMethod(NPObject *npobj, NPIdentifier name)
+{
+    bool hasMethod = false;
+    JavaResultData* java_result;
+    JavaRequestProcessor* java_request = new JavaRequestProcessor();
+
+    std::string classId = std::string(((IcedTeaScriptableJavaObject*) npobj)->getClassID());
+    std::string methodName = browser_functions.utf8fromidentifier(name);
+
+    java_result = java_request->hasMethod(classId, methodName);
+    hasMethod = java_result->return_identifier != 0;
+
+    delete java_request;
+
+    return hasMethod;
+}
+
+bool
+IcedTeaScriptableJavaObject::invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args,
+			uint32_t argCount,NPVariant *result)
+{
+    NPUTF8* method_name = browser_functions.utf8fromidentifier(name);
+
+    // Extract arg type array
+    printf ("IcedTeaScriptableJavaObject::invoke %s. Args follow.\n", method_name);
+    for (int i=0; i < argCount; i++)
+    {
+        IcedTeaPluginUtilities::printNPVariant(args[i]);
+    }
+
+    JavaResultData* java_result;
+    JavaRequestProcessor java_request = JavaRequestProcessor();
+
+    NPObject* obj;
+    std::string instance_id = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
+    std::string class_id = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
+    std::string callee;
+    std::string source;
+
+    if (instance_id.length() == 0) // Static
+    {
+        printf("Calling static method\n");
+        callee = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
+        java_result = java_request.callStaticMethod(callee, browser_functions.utf8fromidentifier(name), args, argCount);
+    } else
+    {
+        printf("Calling method normally\n");
+        callee = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
+        java_result = java_request.callMethod(callee, browser_functions.utf8fromidentifier(name), args, argCount);
+    }
+
+    if (java_result->error_occurred)
+    {
+        return false;
+    }
+
+    if (java_result->return_identifier == 0)
+    {
+        // VOID/BOOLEAN/NUMBER
+
+        if (*(java_result->return_string) == "void")
+        {
+            PLUGIN_DEBUG_0ARG("Method call returned void\n");
+            VOID_TO_NPVARIANT(*result);
+        } else if (*(java_result->return_string) == "true")
+        {
+            PLUGIN_DEBUG_0ARG("Method call returned a boolean (true)\n");
+            BOOLEAN_TO_NPVARIANT(true, *result);
+        } else if (*(java_result->return_string) == "false")
+        {
+            PLUGIN_DEBUG_0ARG("Method call returned a boolean (false)\n");
+            BOOLEAN_TO_NPVARIANT(false, *result);
+        } else
+        {
+            double d = strtod(java_result->return_string->c_str(), NULL);
+
+            // See if it is convertible to int
+            if (java_result->return_string->find(".") != std::string::npos ||
+                d < -(0x7fffffffL - 1L) ||
+                d > 0x7fffffffL)
+            {
+                PLUGIN_DEBUG_1ARG("Method call returned a double %f\n", d);
+                DOUBLE_TO_NPVARIANT(d, *result);
+            } else
+            {
+                int32_t i = (int32_t) d;
+                PLUGIN_DEBUG_1ARG("Method call returned an int %d\n", i);
+                INT32_TO_NPVARIANT(i, *result);
+            }
+        }
+    } else {
+        // Else this is a complex java object
+        std::string return_obj_instance_id = std::string();
+        std::string return_obj_class_id = std::string();
+        std::string return_obj_class_name = std::string();
+        return_obj_instance_id.append(*(java_result->return_string));
+
+        // Find out the class name first, because string is a special case
+        java_request.resetResult();
+        java_result = java_request.getClassName(return_obj_instance_id);
+
+        if (java_result->error_occurred)
+        {
+            return false;
+        }
+
+        return_obj_class_name.append(*(java_result->return_string));
+
+        if (return_obj_class_name == "java.lang.String")
+        {
+            // String is a special case as NPVariant can handle it directly
+            java_request.resetResult();
+            java_result = java_request.getString(return_obj_instance_id);
+
+            if (java_result->error_occurred)
+            {
+                return false;
+            }
+
+            // needs to be on the heap
+            NPUTF8* return_str = (NPUTF8*) browser_functions.memalloc(sizeof(NPUTF8)*java_result->return_string->size() + 1);
+            strcpy(return_str, java_result->return_string->c_str());
+
+            PLUGIN_DEBUG_1ARG("Method call returned a string %s\n", return_str);
+            STRINGZ_TO_NPVARIANT(return_str, *result);
+            printf("%p -- %p\n", return_str, result->value.stringValue.utf8characters);
+
+            // delete string from java side, as it is no longer needed
+            java_request.deleteReference(return_obj_instance_id);
+        } else {
+
+            // Else this is a regular class. Reference the class object so
+            // we can construct an NPObject with it and the instance
+
+            java_request.resetResult();
+            java_result = java_request.findClass(return_obj_class_name);
+
+            if (java_result->error_occurred)
+            {
+                return false;
+            }
+
+            return_obj_class_id.append(*(java_result->return_string));
+
+            NPObject* obj;
+            obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(getInstanceFromMemberPtr(npobj), return_obj_class_id, return_obj_instance_id);
+
+            OBJECT_TO_NPVARIANT(obj, *result);
+        }
+    }
+
+    PLUGIN_DEBUG_0ARG("IcedTeaScriptableJavaObject::invoke returning.\n");
+	return true;
+}
+
+bool
+IcedTeaScriptableJavaObject::invokeDefault(NPObject *npobj, const NPVariant *args,
+			       uint32_t argCount, NPVariant *result)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaObject::invokeDefault %p\n", npobj);
+	return false;
+}
+
+bool
+IcedTeaScriptableJavaObject::hasProperty(NPObject *npobj, NPIdentifier name)
+{
+    PLUGIN_DEBUG_1ARG("IcedTeaScriptableJavaObject::hasProperty %s\n", browser_functions.utf8fromidentifier(name));
+
+	bool hasProperty = false;
+	JavaResultData* java_result;
+	JavaRequestProcessor* java_request = new JavaRequestProcessor();
+
+	std::string class_id = std::string(((IcedTeaScriptableJavaObject*) npobj)->getClassID());
+	std::string fieldName = browser_functions.utf8fromidentifier(name);
+
+    java_result = java_request->hasField(class_id, fieldName);
+
+	hasProperty = java_result->return_identifier != 0;
+
+	delete java_request;
+
+	return hasProperty;
+}
+
+bool
+IcedTeaScriptableJavaObject::getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
+{
+    PLUGIN_DEBUG_1ARG("IcedTeaScriptableJavaObject::getProperty %s\n", browser_functions.utf8fromidentifier(name));
+
+    bool isPropertyClass = false;
+    JavaResultData* java_result;
+    JavaRequestProcessor java_request = JavaRequestProcessor();
+
+    NPObject* obj;
+    std::string instance_id = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
+    std::string class_id = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
+    std::string callee = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
+
+    java_result = java_request.getField(callee, browser_functions.utf8fromidentifier(name));
+
+    std::string object_id = *(java_result->return_string);
+
+    // get the class of this object
+    java_request.resetResult();
+    java_result = java_request.getObjectClass(object_id);
+
+    if (java_result->error_occurred)
+    {
+        return false;
+    }
+
+    obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(getInstanceFromMemberPtr(npobj), *(java_result->return_string), object_id);
+
+    OBJECT_TO_NPVARIANT(obj, *result);
+
+    return true;
+}
+
+bool
+IcedTeaScriptableJavaObject::setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaObject::setProperty %p\n", npobj);
+	return false;
+}
+
+bool
+IcedTeaScriptableJavaObject::removeProperty(NPObject *npobj, NPIdentifier name)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaObject::removeProperty %p\n", npobj);
+	return false;
+}
+
+bool
+IcedTeaScriptableJavaObject::enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaObject::enumerate %p\n", npobj);
+	return false;
+}
+
+bool
+IcedTeaScriptableJavaObject::construct(NPObject *npobj, const NPVariant *args, uint32_t argCount,
+	           NPVariant *result)
+{
+	printf ("** Unimplemented: IcedTeaScriptableJavaObject::construct %p\n", npobj);
+	return false;
+}
--- a/plugin/icedteanp/IcedTeaScriptablePluginObject.h	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/IcedTeaScriptablePluginObject.h	Thu Aug 06 10:43:31 2009 -0400
@@ -41,6 +41,9 @@
 
 #include "npupp.h"
 
+#include "IcedTeaJavaRequestProcessor.h"
+#include "IcedTeaNPPlugin.h"
+
 /**
  * IcedTeaScriptablePluginObject, an extended NPObject that implements
  * static functions whose pointers are supplied to NPClass.
@@ -82,6 +85,107 @@
 
         static bool construct(NPObject *npobj, const NPVariant *args,
                 uint32_t argCount, NPVariant *result);
+
+        static NPObject* get_scriptable_java_package_object(NPP instance, const NPUTF8* name);
+};
+
+NPObject* voidallocate_scriptable_jp_object(NPP npp, NPClass *aClass);
+
+class IcedTeaScriptableJavaPackageObject: public NPObject
+{
+
+    private:
+    	NPP instance;
+    	std::string* package_name;
+
+    public:
+    	IcedTeaScriptableJavaPackageObject(NPP instance);
+
+    	~IcedTeaScriptableJavaPackageObject();
+
+    	void setPackageName(const NPUTF8* name);
+
+    	std::string getPackageName();
+
+        static void deAllocate(NPObject *npobj);
+
+        static void invalidate(NPObject *npobj);
+
+        static bool hasMethod(NPObject *npobj, NPIdentifier name);
+
+        static bool invoke(NPObject *npobj, NPIdentifier name,
+                const NPVariant *args, uint32_t argCount, NPVariant *result);
+
+        static bool invokeDefault(NPObject *npobj, const NPVariant *args,
+                uint32_t argCount, NPVariant *result);
+
+        static bool hasProperty(NPObject *npobj, NPIdentifier name);
+
+        static bool getProperty(NPObject *npobj, NPIdentifier name,
+                NPVariant *result);
+
+        static bool setProperty(NPObject *npobj, NPIdentifier name,
+                const NPVariant *value);
+
+        static bool removeProperty(NPObject *npobj, NPIdentifier name);
+
+        static bool enumerate(NPObject *npobj, NPIdentifier **value,
+                uint32_t *count);
+
+        static bool construct(NPObject *npobj, const NPVariant *args,
+                uint32_t argCount, NPVariant *result);
+
+        static NPObject* get_scriptable_java_object(NPP instance, std::string class_id, std::string instance_id);
+};
+
+class IcedTeaScriptableJavaObject: public NPObject
+{
+
+    private:
+    	NPP instance;
+    	std::string* class_id;
+    	std::string* instance_id;
+
+    public:
+    	IcedTeaScriptableJavaObject(NPP instance);
+
+    	~IcedTeaScriptableJavaObject();
+
+    	void setClassIdentifier(std::string class_id);
+
+    	void setInstanceIdentifier(std::string instance_id);
+
+    	std::string getClassID() { return *class_id; }
+
+    	std::string getInstanceID() { return *instance_id; }
+
+        static void deAllocate(NPObject *npobj);
+
+        static void invalidate(NPObject *npobj);
+
+        static bool hasMethod(NPObject *npobj, NPIdentifier name);
+
+        static bool invoke(NPObject *npobj, NPIdentifier name,
+                const NPVariant *args, uint32_t argCount, NPVariant *result);
+
+        static bool invokeDefault(NPObject *npobj, const NPVariant *args,
+                uint32_t argCount, NPVariant *result);
+
+        static bool hasProperty(NPObject *npobj, NPIdentifier name);
+
+        static bool getProperty(NPObject *npobj, NPIdentifier name,
+                NPVariant *result);
+
+        static bool setProperty(NPObject *npobj, NPIdentifier name,
+                const NPVariant *value);
+
+        static bool removeProperty(NPObject *npobj, NPIdentifier name);
+
+        static bool enumerate(NPObject *npobj, NPIdentifier **value,
+                uint32_t *count);
+
+        static bool construct(NPObject *npobj, const NPVariant *args,
+                uint32_t argCount, NPVariant *result);
 };
 
 #endif /* __ICEDTEASCRIPTABLEPLUGINOBJECT_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java	Thu Aug 06 10:43:31 2009 -0400
@@ -0,0 +1,480 @@
+/* MethodOverloadResolver -- Resolves overloaded methods
+   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. */
+
+package sun.applet;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+/* 
+ * This class resolved overloaded methods in Java objects using a cost 
+ * based-approach as described here:
+ *
+ * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
+ */
+
+public class MethodOverloadResolver {
+
+    private static boolean debugging = false;
+    
+    public static void main(String[] args) {
+        testMethodResolver();
+    }
+
+    public static void testMethodResolver() {
+        debugging = true;
+
+        ArrayList<Object[]> list = new ArrayList<Object[]>(20);
+        FooClass fc = new FooClass();
+        
+        // Numeric to java primitive
+        // foo_i has Integer and int params
+        String s1 = "foo_string_int(S,I)";
+        String s1a = "foo_string_int(S,S)";
+        Object[] o1 = { fc.getClass(), "foo_string_int", "blah", 42 };
+        list.add(o1);
+        Object[] o1a = { fc.getClass(), "foo_string_int", "blah", "42.42" };
+        list.add(o1a);
+        
+        // Null to non-primitive type
+        // foo_i is overloaded with Integer and int 
+        String s2 = "foo_string_int(N)";
+        Object[] o2 = { fc.getClass(), "foo_string_int", "blah", null };
+        list.add(o2);
+        
+        // foo_jsobj is overloaded with JSObject and String params
+        String s3 = "foo_jsobj(LLowCostSignatureComputer/JSObject;)";
+        Object[] o3 = { fc.getClass(), "foo_jsobj", new JSObject() };
+        list.add(o3);
+
+        // foo_classtype is overloaded with Number and Integer
+        String s4 = "foo_classtype(Ljava/lang/Integer;)";
+        Object[] o4 = { fc.getClass(), "foo_classtype", 42 };
+        list.add(o4);
+        
+        // foo_multiprim is overloaded with int, long and float types
+        String s5 = "foo_multiprim(I)";
+        String s6 = "foo_multiprim(F)";
+        String s6a = "foo_multiprim(D)";
+        
+        Object[] o5 = { fc.getClass(), "foo_multiprim", new Integer(42) };
+        Object[] o6 = { fc.getClass(), "foo_multiprim", new Float(42.42) };
+        Object[] o6a = { fc.getClass(), "foo_multiprim", new Double(42.42) };
+        list.add(o5);
+        list.add(o6);
+        list.add(o6a);
+        
+        // foo_float has float, String and JSObject type
+        String s7 = "foo_float(I)";
+        Object[] o7 = { fc.getClass(), "foo_float", new Integer(42) };
+        list.add(o7);
+
+        // foo_multiprim(float) is what this should convert
+        String s8 = "foo_float(S)";
+        Object[] o8 = { fc.getClass(), "foo_float", "42" };
+        list.add(o8);
+        
+        // foo_class is overloaded with BarClass 2 and 3
+        String s9 = "foo_class(LLowCostSignatureComputer/BarClass3;)";
+        Object[] o9 = { fc.getClass(), "foo_class", new BarClass3() };
+        list.add(o9);
+
+        // foo_strandbyteonly takes string and byte
+        String s10 = "foo_strandbyteonly(I)";
+        Object[] o10 = { fc.getClass(), "foo_strandbyteonly", 42 };
+        list.add(o10);
+
+        // JSOBject to string
+        String s11 = "foo_strandbyteonly(LLowCostSignatureComputer/JSObject;)";
+        Object[] o11 = { fc.getClass(), "foo_strandbyteonly", new JSObject() };
+        list.add(o11);
+
+        // jsobject to string and int to float
+        String s12 = "foo_str_and_float(S,I)";
+        Object[] o12 = { fc.getClass(), "foo_str_and_float", new JSObject(), new Integer(42) };
+        list.add(o12);
+        
+        // call for which no match will be found
+        String s13 = "foo_int_only(JSObject)";
+        Object[] o13 = { fc.getClass(), "foo_int_only", new JSObject() };
+        list.add(o13);
+        
+        // method with no args
+        String s14 = "foo_noargs()";
+        Object[] o14 = { fc.getClass(), "foo_noargs" };
+        list.add(o14);
+        
+        for (Object[] o : list) {
+            Object[] methodAndArgs = getMatchingMethod(o);
+            if (debugging)
+                if (methodAndArgs != null)
+                    System.out.println("Best match: " + methodAndArgs[0] + "\n");
+                else
+                    System.out.println("No match found.\n");
+                
+        }
+    }
+
+    /* 
+     * Cost based overload resolution algorithm based on cost rules specified here:
+     * 
+     * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
+     */
+
+    public static Object[] getMatchingMethod(Object[] callList) {
+        Object[] ret = null;
+        Class c = (Class) callList[0];
+        String methodName = (String) callList[1];
+
+        Method[] matchingMethods = getMatchingMethods(c, methodName, callList.length - 2);
+        
+        if (debugging)
+            System.out.println("getMatchingMethod called with: " + printList(callList));
+
+        int lowestCost = Integer.MAX_VALUE;
+
+        ArrayList<Object> paramList = new ArrayList<Object>();
+
+        for (Method matchingMethod : matchingMethods) {
+
+            int methodCost = 0;
+            Class[] paramTypes = matchingMethod.getParameterTypes();
+            Object[] methodAndArgs = new Object[paramTypes.length + 1];
+            methodAndArgs[0] = matchingMethod;
+
+            // Figure out which of the matched methods best represents what we
+            // want
+            for (int i = 0; i < paramTypes.length; i++) {
+                Class paramTypeClass = paramTypes[i];
+                Object suppliedParam = callList[i + 2];
+                Class suppliedParamClass = suppliedParam != null ? suppliedParam
+                        .getClass()
+                        : null;
+
+                Object[] costAndCastedObj = getCostAndCastedObject(
+                        suppliedParam, paramTypeClass);
+                methodCost += (Integer) costAndCastedObj[0];
+                Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
+                        : paramTypeClass.cast(costAndCastedObj[1]);
+                methodAndArgs[i + 1] = castedObj;
+
+                Class castedObjClass = castedObj == null ? null : castedObj
+                        .getClass();
+                Boolean castedObjIsPrim = castedObj == null ? null : castedObj
+                        .getClass().isPrimitive();
+
+                if (debugging)
+                    System.out.println("Param " + i + " of method "
+                            + matchingMethod + " has cost "
+                            + (Integer) costAndCastedObj[0]
+                            + " original param type " + suppliedParamClass
+                            + " casted to " + castedObjClass + " isPrimitive="
+                            + castedObjIsPrim + " value " + castedObj);
+            }
+
+            if ((methodCost > 0 && methodCost < lowestCost) || 
+                 paramTypes.length == 0) {
+                ret = methodAndArgs;
+                lowestCost = methodCost;
+            }
+
+        }
+
+        return ret;
+    }
+
+    private static Object[] getCostAndCastedObject(Object suppliedParam, Class paramTypeClass) {
+        
+        Object[] ret = new Object[2];
+        Integer cost = new Integer(0);
+        Object castedObj;
+
+        Class suppliedParamClass = suppliedParam != null ? suppliedParam.getClass() : null ;
+
+        // If this is null, there are only 2 possible cases
+        if (suppliedParamClass == null) {
+            castedObj = null; // if value is null.. well, it is null
+
+            if (!paramTypeClass.isPrimitive()) {
+                cost += 2; // Null to any non-primitive type
+            } else {
+                cost = Integer.MIN_VALUE; // Null to primitive not allowed
+            }
+        } else if (paramTypeClass.isPrimitive() && paramTypeClass.equals(getPrimitive(suppliedParam))) {
+            cost += 1; // Numeric type to the analogous Java primitive type
+            castedObj = suppliedParam; // Let auto-boxing handle it
+        } else if (suppliedParamClass.equals(paramTypeClass)) {
+           cost += 3; // Class type to Class type where the types are equal
+           castedObj = suppliedParam;
+        } else if (isNum(suppliedParam) && 
+                       (paramTypeClass.isPrimitive() ||
+                        java.lang.Number.class.isAssignableFrom(paramTypeClass) ||
+                        java.lang.Character.class.isAssignableFrom(paramTypeClass) ||
+                        java.lang.Byte.class.isAssignableFrom(paramTypeClass)
+                       )
+                   ) {
+            cost += 4; // Numeric type to a different primitive type 
+            castedObj = getNum(suppliedParam.toString(), paramTypeClass);
+        } else if (suppliedParam instanceof java.lang.String &&
+                    isNum(suppliedParam) &&
+                        (paramTypeClass.isInstance(java.lang.Number.class) ||
+                         paramTypeClass.isInstance(java.lang.Character.class) ||
+                         paramTypeClass.isInstance(java.lang.Byte.class) ||
+                         paramTypeClass.isPrimitive())
+                   ) {
+            cost += 5; // String to numeric type
+            castedObj = getNum(suppliedParam.toString(), paramTypeClass);
+        } else if (paramTypeClass.isAssignableFrom(suppliedParamClass)) {
+            cost += 6; // Class type to superclass type;
+            castedObj = paramTypeClass.cast(suppliedParam);
+        } else if (paramTypeClass.equals(java.lang.String.class)) {
+            cost += 7; // Any Java value to String
+            castedObj = suppliedParam.toString();
+        } else if (suppliedParam instanceof JSObject &&
+                   paramTypeClass.equals(String.class)) {
+            cost += 8; // JSObject to String
+            castedObj = suppliedParam.toString();
+        } else if (suppliedParam instanceof JSObject &&
+                   paramTypeClass.isArray()) {
+            cost += 10; // JSObject to Java array 
+            castedObj = (JSObject) suppliedParam; // FIXME: Arrays not yet handled
+        } else {
+            cost = Integer.MIN_VALUE; // Not allowed
+            castedObj = null;
+        }
+        
+        ret[0] = cost;
+        ret[1] = castedObj;
+
+        return ret;
+
+    }
+    
+    private static Method[] getMatchingMethods(Class c, String name, int paramCount) {
+        Method[] allMethods = c.getMethods();
+        ArrayList<Method> matchingMethods = new ArrayList(5);
+        
+        for (Method m: allMethods) {
+            if (m.getName().equals(name) && m.getParameterTypes().length == paramCount)
+                matchingMethods.add(m);
+        }
+
+        return matchingMethods.toArray(new Method[0]);
+    }
+
+    private static Class getPrimitive(Object o) {
+        
+        if (o instanceof java.lang.Byte) {
+            return java.lang.Byte.TYPE;
+        } else if (o instanceof java.lang.Character) {
+            return java.lang.Character.TYPE;
+        } else if (o instanceof java.lang.Short) {
+            return java.lang.Short.TYPE;
+        } else if (o instanceof java.lang.Integer) {
+            return java.lang.Integer.TYPE;
+        } else if (o instanceof java.lang.Long) {
+            return java.lang.Long.TYPE;
+        } else if (o instanceof java.lang.Float) {
+            return java.lang.Float.TYPE;
+        } else if (o instanceof java.lang.Double) {
+            return java.lang.Double.TYPE;
+        }
+
+        return o.getClass();
+    }
+
+    private static boolean isNum (Object o) {
+        
+        if (o instanceof java.lang.Number)
+            return true;
+        
+        if (!(o instanceof java.lang.String))
+            return false;
+
+        try {
+            Long.parseLong((String) o); // whole number test
+            return true;
+        } catch (NumberFormatException nfe) {}
+        
+        try {
+            Float.parseFloat((String) o); // decimal
+            return true;
+        } catch (NumberFormatException nfe) {}
+        
+        return false;
+    }
+
+    private static Object getNum (String s, Class c) throws NumberFormatException {
+
+        Number n;
+        if (s.contains("."))
+            n = new Double(s);
+        else
+            n = new Long(s);
+
+        // See if we need to collapse first
+        if (c.equals(java.lang.Integer.class) ||
+            c.equals(java.lang.Integer.TYPE)) {
+            return n.intValue();
+        }
+
+        if (c.equals(java.lang.Long.class) ||
+            c.equals(java.lang.Long.TYPE)) {
+            return n.longValue();
+        }
+
+        if (c.equals(java.lang.Short.class) ||
+            c.equals(java.lang.Short.TYPE)) {
+            return n.shortValue();
+        }
+        
+        if (c.equals(java.lang.Float.class) ||
+            c.equals(java.lang.Float.TYPE)) {
+            return n.floatValue();
+        }
+        
+        if (c.equals(java.lang.Double.class) ||
+            c.equals(java.lang.Double.TYPE)) {
+            return n.doubleValue();
+        }
+
+        if (c.equals(java.lang.Byte.class) ||
+            c.equals(java.lang.Byte.TYPE)) {
+            return n.byteValue();
+        }
+
+        if (c.equals(java.lang.Character.class) ||
+                c.equals(java.lang.Character.TYPE)) {
+            return s.charAt(0);
+        }
+
+        return n;
+    }
+
+    private static String printList (Object[] oList) {
+        
+        String ret = "";
+        
+        ret += "{ ";
+        for (Object o : oList) {
+            
+            String oStr = o != null ? o.toString() + " [" + o.getClass() + "]" : "null";
+            
+            ret += oStr;
+            ret += ", ";
+        }
+        ret = ret.substring(0, ret.length()-2); // remove last ", "
+        ret += " }";
+
+        return ret;
+    }
+}
+
+/** Begin test classes **/
+
+class FooClass {
+
+    // Normal, null => non primitive type
+    public void foo(Boolean b) {
+
+    }
+
+    // Class -> primitive
+    public void foo(boolean b) {
+
+    }
+
+    // First type full match, second Class -> Primitive
+    public void foo(Boolean b, int i) {
+
+    }
+
+    // Full match
+    public void foo(Boolean b, Integer i) {
+
+    }
+
+    // First type full match, second Class -> Primitive ambiguity
+    public void foo(Boolean b, short s) {
+
+    }
+
+    public void foo_string_int(String s, int i) {}
+
+    public void foo_string_int(String s, Integer i) {}
+
+    public void foo_jsobj(JSObject j) {}
+
+    public void foo_jsobj(String s) {}
+
+    public void foo_classtype(java.lang.Number num) {}
+
+    public void foo_classtype(java.lang.Integer integer) {}
+
+    public void foo_multiprim(int i) {}
+
+    public void foo_multiprim(long l) {}
+
+    public void foo_multiprim(float f) {}
+    
+    public void foo_multiprim(double d) {}
+
+    public void foo_float(float f) {}
+    
+    public void foo_float(String s) {}
+    
+    public void foo_float(JSObject j) {}
+
+    public void foo_class(BarClass1 b) {}
+
+    public void foo_class(BarClass2 b) {}
+
+    public void foo_strandbyteonly(String s) {}
+    
+    public void foo_strandbyteonly(byte b) {}
+    
+    public void foo_str_and_float(String s, Float f) {}
+    
+    public void foo_int_only (int i) {}
+    
+    public void foo_noargs() {}
+}
+
+class BarClass1 {}
+class BarClass2 extends BarClass1 {}
+class BarClass3 extends BarClass2 {}
+class JSObject {}
--- a/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java	Fri Oct 02 21:34:18 2009 +0100
+++ b/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java	Thu Aug 06 10:43:31 2009 -0400
@@ -57,6 +57,8 @@
 import java.util.Hashtable;
 import java.util.List;
 
+import sun.reflect.generics.repository.MethodRepository;
+
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
 
 
@@ -199,7 +201,7 @@
 
 		return c;
 	}
-	
+
 	public static Class primitiveNameToType(String name) {
 		if (name.equals("void"))
 			return Void.TYPE;
@@ -335,7 +337,15 @@
 				Signature signature = parseCall(args[3], ((Class) store.getObject(classID)).getClassLoader(), Signature.class);
 				Object[] a = signature.getClassArray();
 
-				Class c = (Class) store.getObject(classID);
+				Class c;
+
+				if (message.startsWith("GetStaticMethodID") || 
+				    methodName.equals("<init>") || 
+				    methodName.equals("<clinit>"))
+					c = (Class) store.getObject(classID);
+				else
+					c = store.getObject(classID).getClass();
+
 				Method m = null;
 				Constructor cs = null;
 				Object o = null;
@@ -353,10 +363,13 @@
 					|| message.startsWith("GetFieldID")) {
 				String[] args = message.split(" ");
 				Integer classID = parseCall(args[1], null, Integer.class);
-				String fieldName = parseCall(args[2], null, String.class);
-				Signature signature = parseCall(args[3], ((Class) store.getObject(classID)).getClassLoader(), Signature.class);
+				Integer fieldID = parseCall(args[2], null, Integer.class);
+				String fieldName = (String) store.getObject(fieldID);
 
 				Class c = (Class) store.getObject(classID);
+
+				PluginDebug.debug("GetStaticFieldID/GetFieldID got class=" + c.getName());
+				
 				Field f = null;
 				f = c.getField(fieldName);
 
@@ -575,101 +588,61 @@
 				store.reference(c);
 
 				write(reference, "GetObjectClass " + store.getIdentifier(c));
-			} else if (message.startsWith("CallStaticMethod")) {
+			} else if (message.startsWith("CallMethod") ||
+					   message.startsWith("CallStaticMethod")) {
 				String[] args = message.split(" ");
-				Integer classID = parseCall(args[1], null, Integer.class);
-				Integer methodID = parseCall(args[2], null, Integer.class);
+				Integer objectID = parseCall(args[1], null, Integer.class);
+				String methodName = parseCall(args[2], null, String.class);
+				Object o = null;
+				Class c;
 
-				PluginDebug.debug("GETTING: " + methodID);
-				final Method m = (Method) store.getObject(methodID);
-				PluginDebug.debug("GOT: " + m);
-				Class[] argTypes = m.getParameterTypes();
-
-				Object[] arguments = new Object[argTypes.length];
-				for (int i = 0; i < argTypes.length; i++) {
-					arguments[i] = parseArgs(args[3 + i], argTypes[i]);
-					// System.out.println ("GOT ARG: " + argTypes[i] + " " +
-					// arguments[i]);
+				if (message.startsWith("CallMethod")) {
+					o = (Object) store.getObject(objectID);
+					c = o.getClass();
+				} else {
+					c = (Class) store.getObject(objectID);
 				}
 
-				// System.out.println ("Calling " + m);
+				// length -3 to discard first 3, + 2 for holding object 
+				// and method name
+				Object[] arguments = new Object[args.length - 1];
+				arguments[0] = c;
+				arguments[1] = methodName;
+                for (int i = 0; i < args.length - 3; i++) {
+                    arguments[i+2] = store.getObject(parseCall(args[3 + i], null, Integer.class));
+                    PluginDebug.debug("GOT ARG: " + arguments[i]);
+                }
 
-				final Object[] fArguments = arguments;
+                Object[] matchingMethodAndArgs = MethodOverloadResolver.getMatchingMethod(arguments);
+                
+                if (matchingMethodAndArgs == null) {
+                    write(reference, "Error: No suitable method with matching args found");
+                    return;
+                }
+
+				final Method m = (Method) matchingMethodAndArgs[0];
+				Object[] castedArgs = new Object[matchingMethodAndArgs.length - 1];
+				for (int i=0; i < castedArgs.length; i++) {
+				    castedArgs[i] = matchingMethodAndArgs[i+1];
+				}
+
+				String collapsedArgs = "";
+				for (Object arg : castedArgs) {
+					collapsedArgs += " " + arg.toString();
+				}
+
+				PluginDebug.debug("Calling method " + m + " on object " + o
+						+ " (" + c + ") with " + collapsedArgs);
+
 				AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
-				Class c = (Class) store.getObject(classID);
 				checkPermission(src, c, acc);
 
+				final Object[] fArguments = castedArgs;
+				final Object callableObject = o;
 				Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
 					public Object run() {
 						try {
-							return m.invoke(null, fArguments);
-						} catch (Throwable t) {
-							return t;
-						}
-					}
-				}, acc);
-
-				if (ret instanceof Throwable)
-					throw (Throwable) ret;
-
-				// if (ret != null)
-				// System.out.println ("RETURN VALUE: " + ret + " " +
-				// ret.getClass());
-				// else
-				// System.out.println ("RETURN VALUE: " + ret);
-				if (ret == null) {
-					write(reference, "CallStaticMethod void");
-				} else if (m.getReturnType() == Boolean.TYPE
-						|| m.getReturnType() == Byte.TYPE
-						|| m.getReturnType() == Short.TYPE
-						|| m.getReturnType() == Integer.TYPE
-						|| m.getReturnType() == Long.TYPE
-						|| m.getReturnType() == Float.TYPE
-						|| m.getReturnType() == Double.TYPE) {
-					write(reference, "CallStaticMethod " + ret);
-				} else if (m.getReturnType() == Character.TYPE) {
-					char ch = (Character) ret;
-					int high = (((int) ch) >> 8) & 0x0ff;
-					int low = ((int) ch) & 0x0ff;
-					write(reference, "CallStaticMethod " + low + "_" + high);
-				} else {
-					// Track returned object.
-					store.reference(ret);
-					write(reference, "CallStaticMethod "
-							+ store.getIdentifier(ret));
-				}
-			} else if (message.startsWith("CallMethod")) {
-				String[] args = message.split(" ");
-				Integer objectID = parseCall(args[1], null, Integer.class);
-				Integer methodID = parseCall(args[2], null, Integer.class);
-
-				final Object o = (Object) store.getObject(objectID);
-				final Method m = (Method) store.getObject(methodID);
-				Class[] argTypes = m.getParameterTypes();
-
-				Object[] arguments = new Object[argTypes.length];
-				for (int i = 0; i < argTypes.length; i++) {
-					arguments[i] = parseArgs(args[3 + i], argTypes[i]);
-					PluginDebug.debug("GOT ARG: " + argTypes[i] + " "
-							+ arguments[i]);
-				}
-
-				String collapsedArgs = "";
-				for (String s : args) {
-					collapsedArgs += " " + s;
-				}
-
-				PluginDebug.debug("Calling method " + m + " on object " + o
-						+ " with " + arguments);
-
-				AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
-				checkPermission(src, o.getClass(), acc);
-
-				final Object[] fArguments = arguments;
-				Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
-					public Object run() {
-						try {
-							return m.invoke(o, fArguments);
+							return m.invoke(callableObject, fArguments);
 						} catch (Throwable t) {
 							return t;
 						}
@@ -691,20 +664,36 @@
 						+ " of type " + retO);
 
 				if (ret == null) {
-					write(reference, "CallMethod void");
+					write(reference, "CallMethod literalreturn void");
 				} else if (m.getReturnType() == Boolean.TYPE
 						|| m.getReturnType() == Byte.TYPE
 						|| m.getReturnType() == Short.TYPE
 						|| m.getReturnType() == Integer.TYPE
 						|| m.getReturnType() == Long.TYPE
 						|| m.getReturnType() == Float.TYPE
-						|| m.getReturnType() == Double.TYPE) {
-					write(reference, "CallMethod " + ret);
-				} else if (m.getReturnType() == Character.TYPE) {
-					char ch = (Character) ret;
-					int high = (((int) ch) >> 8) & 0x0ff;
-					int low = ((int) ch) & 0x0ff;
-					write(reference, "CallMethod " + low + "_" + high);
+						|| m.getReturnType() == Double.TYPE
+						|| m.getReturnType() == Boolean.class
+                        || m.getReturnType() == Byte.class
+                        || m.getReturnType() == Short.class
+                        || m.getReturnType() == Integer.class
+                        || m.getReturnType() == Long.class
+                        || m.getReturnType() == Float.class
+                        || m.getReturnType() == Double.class) {
+					write(reference, "CallMethod literalreturn " + ret);
+				} else if (m.getReturnType() == Character.TYPE
+				        || m.getReturnType() == Character.class) {
+				    String s = new String(new char[] {(Character) ret});
+				    byte[] b = null;
+				    b = s.getBytes("UTF-8");
+				    StringBuffer 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, "CallMethod literalreturn " + buf);
 				} else {
 					// Track returned object.
 					store.reference(ret);
@@ -844,7 +833,57 @@
 
 				store.reference(newArray);
 				write(reference, "NewArray " + store.getIdentifier(newArray));
-			} else if (message.startsWith("NewObjectArray")) {
+			} else if (message.startsWith("HasMethod")) {
+                String[] args = message.split(" ");
+                Integer classNameID = parseCall(args[1], null, Integer.class);
+                Integer methodNameID = parseCall(args[2], null, Integer.class);
+                
+                Class c = (Class) store.getObject(classNameID);
+                String methodName = (String) store.getObject(methodNameID);
+
+                Method method = null;
+                Method[] classMethods = c.getMethods();
+                for (Method m: classMethods) {
+                	if (m.getName().equals(methodName)) {
+                		method = m;
+                		break;
+                	}
+                }
+                
+                int hasMethod = (method != null) ? 1 : 0; 
+
+                write(reference, "HasMethod " + hasMethod);
+            } else if (message.startsWith("HasPackage")) {
+                String[] args = message.split(" ");
+                Integer nameID = parseCall(args[1], null, Integer.class);
+                String pkgName = (String) store.getObject(nameID);
+
+                Package pkg = Package.getPackage(pkgName);
+                int hasPkg = (pkg != null) ? 1 : 0; 
+
+                write(reference, "HasPackage " + hasPkg);
+
+            } else if (message.startsWith("HasField")) {
+                String[] args = message.split(" ");
+                Integer classNameID = parseCall(args[1], null, Integer.class);
+                Integer fieldNameID = parseCall(args[2], null, Integer.class);
+                
+                Class c = (Class) store.getObject(classNameID);
+                String fieldName = (String) store.getObject(fieldNameID);
+
+                Field field = null;
+                Field[] classFields = c.getFields();
+                for (Field f: classFields) {
+                	if (f.getName().equals(fieldName)) {
+                		field = f;
+                		break;
+                	}
+                }
+
+                int hasField = (field != null) ? 1 : 0; 
+
+                write(reference, "HasField " + hasField);
+            } else if (message.startsWith("NewObjectArray")) {
 				String[] args = message.split(" ");
 				Integer length = parseCall(args[1], null, Integer.class);
 				Integer classID = parseCall(args[2], null, Integer.class);
@@ -907,16 +946,16 @@
                 PluginDebug.debug("MESSAGE: " + message);
                 String[] args = message.split(" ");
                 int length = new Integer(args[1]);
-                byte[] byteArray = new byte[length + 1];
+                byte[] byteArray = new byte[length];
                 String ret = null;
-                int i = 2;
-                int c = Integer.parseInt(args[i++], 16);
+                int i = 0;
+                int j = 2;
+                int c;
                 while (i < length) {
-                    byteArray[i-2] = (byte) c;
-                    c = Integer.parseInt(args[i++], 16);
+                    c = Integer.parseInt(args[j++], 16);
+                    byteArray[i++] = (byte) c;
                 }
 
-                byteArray[i] = (byte) 0;
                 ret = new String(byteArray, "UTF-8");
                 PluginDebug.debug("NEWSTRINGUTF: " + ret);
 
@@ -977,7 +1016,12 @@
 				Integer objectID = parseCall(args[1], null, Integer.class);
 				Object o = (Object) store.getObject(objectID);
 				write(reference, "GetClassName " + o.getClass().getName());
-			} 
+			} else if (message.startsWith("GetClassID")) {
+                String[] args = message.split(" ");
+                Integer objectID = parseCall(args[1], null, Integer.class);
+                store.reference(store.getObject(objectID).getClass());
+                write(reference, "GetClassID " + store.getIdentifier(store.getObject(objectID).getClass()));
+            }
 		} catch (Throwable t) {
 			t.printStackTrace();
 			String msg = t.getCause() != null ? t.getCause().getMessage() : t.getMessage();
@@ -988,7 +1032,7 @@
 				msg = "LiveConnectPermissionNeeded " + msg;
 			}
 
-			this.streamhandler.write("instance " + identifier + " reference " + reference + " Error " + msg);
+			write(reference, " Error " + msg);
 
 			// ExceptionOccured is only called after Callmethod() by mozilla. So
 			// for exceptions that are not related to CallMethod, we need a way