Mercurial > hg > release > icedtea7-2.6
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