diff options
Diffstat (limited to 'plugin/icedteanp/IcedTeaJavaRequestProcessor.cc')
-rw-r--r-- | plugin/icedteanp/IcedTeaJavaRequestProcessor.cc | 1392 |
1 files changed, 1392 insertions, 0 deletions
diff --git a/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc b/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc new file mode 100644 index 0000000..8b5b8a3 --- /dev/null +++ b/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc @@ -0,0 +1,1392 @@ +/* IcedTeaJavaRequestProcessor.cc + + Copyright (C) 2009, 2010 Red Hat + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +IcedTea is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +#include <typeinfo> + +#include "IcedTeaJavaRequestProcessor.h" +#include "IcedTeaScriptablePluginObject.h" + +/* + * This class processes LiveConnect requests from JavaScript to Java. + * + * It sends the requests to Java, gets the return information, and sends it + * back to the browser/JavaScript + */ + +/** + * Processes return information from JavaSide (return messages of requests) + * + * @param message The message request to process + * @return boolean indicating whether the message is serviceable by this object + */ + +bool +JavaRequestProcessor::newMessageOnBus(const char* message) +{ + + // Anything we are waiting for _MUST_ have and instance id and reference # + std::vector<std::string*>* message_parts = IcedTeaPluginUtilities::strSplit(message, " "); + + IcedTeaPluginUtilities::printStringPtrVector("JavaRequest::newMessageOnBus:", message_parts); + + if (*(message_parts->at(0)) == "context" && *(message_parts->at(2)) == "reference") + if (atoi(message_parts->at(1)->c_str()) == this->instance && atoi(message_parts->at(3)->c_str()) == this->reference) + { + // Gather the results + + // Let's get errors out of the way first + if (!message_parts->at(4)->find("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)->find("GetStringUTFChars") || + !message_parts->at(4)->find("GetToStringValue")) + { + // first item is length, and it is radix 10 + int length = strtol(message_parts->at(5)->c_str(), NULL, 10); + + IcedTeaPluginUtilities::getUTF8String(length, 6 /* start at */, message_parts, result->return_string); + result_ready = true; + } + else if (!message_parts->at(4)->find("GetStringChars")) // GetStringChars (UTF-16LE/UCS-2) + { + // first item is length, and it is radix 10 + int length = strtol(message_parts->at(5)->c_str(), NULL, 10); + + IcedTeaPluginUtilities::getUTF16LEString(length, 6 /* start at */, message_parts, result->return_wstring); + result_ready = true; + } else if (!message_parts->at(4)->find("FindClass") || + !message_parts->at(4)->find("GetClassName") || + !message_parts->at(4)->find("GetClassID") || + !message_parts->at(4)->find("GetMethodID") || + !message_parts->at(4)->find("GetStaticMethodID") || + !message_parts->at(4)->find("GetObjectClass") || + !message_parts->at(4)->find("NewObject") || + !message_parts->at(4)->find("NewStringUTF") || + !message_parts->at(4)->find("HasPackage") || + !message_parts->at(4)->find("HasMethod") || + !message_parts->at(4)->find("HasField") || + !message_parts->at(4)->find("GetStaticFieldID") || + !message_parts->at(4)->find("GetFieldID") || + !message_parts->at(4)->find("GetJavaObject") || + !message_parts->at(4)->find("IsInstanceOf") || + !message_parts->at(4)->find("NewArray")) + { + 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)->find("DeleteLocalRef") || + !message_parts->at(4)->find("NewGlobalRef")) + { + result_ready = true; // nothing else to do + } else if (!message_parts->at(4)->find("CallMethod") || + !message_parts->at(4)->find("CallStaticMethod") || + !message_parts->at(4)->find("GetField") || + !message_parts->at(4)->find("GetStaticField") || + !message_parts->at(4)->find("GetValue") || + !message_parts->at(4)->find("GetObjectArrayElement")) + { + + if (!message_parts->at(5)->find("literalreturn")) + { + // literal returns don't have a corresponding jni id + result->return_identifier = 0; + result->return_string->append(*(message_parts->at(5))); + result->return_string->append(" "); + 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; + } else if (!message_parts->at(4)->find("GetArrayLength")) + { + result->return_identifier = 0; // length is not an "identifier" + result->return_string->append(*(message_parts->at(5))); + result_ready = true; + } else if (!message_parts->at(4)->find("SetField") || + !message_parts->at(4)->find("SetObjectArrayElement")) + { + + // nothing to do + + result->return_identifier = 0; + result_ready = true; + } + + IcedTeaPluginUtilities::freeStringPtrVector(message_parts); + return true; + } + + IcedTeaPluginUtilities::freeStringPtrVector(message_parts); + return false; +} + +/** + * Constructor. + * + * Initializes the result data structure (heap) + */ + +JavaRequestProcessor::JavaRequestProcessor() +{ + PLUGIN_DEBUG("JavaRequestProcessor constructor\n"); + + // 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_occurred = false; + + result_ready = false; +} + +/** + * Destructor + * + * Frees memory used by the result struct + */ + +JavaRequestProcessor::~JavaRequestProcessor() +{ + PLUGIN_DEBUG("JavaRequestProcessor::~JavaRequestProcessor\n"); + + if (result) + { + if (result->error_msg) + delete result->error_msg; + + if (result->return_string) + delete result->return_string; + + if (result->return_wstring) + delete result->return_wstring; + + delete result; + } +} + +/** + * 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) +{ + struct timespec t; + clock_gettime(CLOCK_REALTIME, &t); + t.tv_sec += REQUESTTIMEOUT; // 1 minute timeout + + // Clear the result + resetResult(); + + java_to_plugin_bus->subscribe(this); + plugin_to_java_bus->post(message.c_str()); + + // Wait for result to be filled in. + struct timespec curr_t; + + do + { + clock_gettime(CLOCK_REALTIME, &curr_t); + + if (!result_ready && (curr_t.tv_sec < t.tv_sec)) + { + if (g_main_context_pending(NULL)) + g_main_context_iteration(NULL, false); + else + usleep(200); + } + else + break; + + } while (1); + + 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("Error: Timed out when waiting for response to %s\n", message.c_str()); + } + + java_to_plugin_bus->unSubscribe(this); +} + +/** + * Given an object id, fetches the toString() value from Java + * + * @param object_id The ID of the object + * @return A JavaResultData struct containing the result of the request + */ + +JavaResultData* +JavaRequestProcessor::getToStringValue(std::string object_id) +{ + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" GetToStringValue "); // get it in UTF8 + message.append(object_id); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +/** + * Given an object id, fetches the value of that ID from Java + * + * @param object_id The ID of the object + * @return A JavaResultData struct containing the result of the request + */ + +JavaResultData* +JavaRequestProcessor::getValue(std::string object_id) +{ + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" GetValue "); // get it in UTF8 + message.append(object_id); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +/** + * Given a string id, fetches the actual string from Java side + * + * @param string_id The ID of the string + * @return A JavaResultData struct containing the result of the request + */ + +JavaResultData* +JavaRequestProcessor::getString(std::string string_id) +{ + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" GetStringUTFChars "); // get it in UTF8 + message.append(string_id); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + 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 = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" DeleteLocalRef "); + message.append(object_id); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); +} + +/** + * Increments reference count by 1 + * + * @param object_id The ID of the object + */ + +void +JavaRequestProcessor::addReference(std::string object_id) +{ + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" NewGlobalRef "); + message.append(object_id); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + +} + +JavaResultData* +JavaRequestProcessor::findClass(int plugin_instance_id, + std::string name) +{ + std::string message = std::string(); + std::string plugin_instance_id_str = std::string(); + + IcedTeaPluginUtilities::itoa(plugin_instance_id, &plugin_instance_id_str); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" FindClass "); + message.append(plugin_instance_id_str); + message.append(" "); + message.append(name); + + postAndWaitForResponse(message); + + return result; +} + +JavaResultData* +JavaRequestProcessor::getClassName(std::string objectID) +{ + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" GetClassName "); + message.append(objectID); + + postAndWaitForResponse(message); + + return result; +} + +JavaResultData* +JavaRequestProcessor::getClassID(std::string objectID) +{ + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" GetClassID "); + message.append(objectID); + + postAndWaitForResponse(message); + + return result; +} + +JavaResultData* +JavaRequestProcessor::getArrayLength(std::string objectID) +{ + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" GetArrayLength "); + message.append(objectID); + + postAndWaitForResponse(message); + + return result; +} + +JavaResultData* +JavaRequestProcessor::getSlot(std::string objectID, std::string index) +{ + std::string message = std::string(); + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" GetObjectArrayElement "); + message.append(objectID); + message.append(" "); + message.append(index); + + postAndWaitForResponse(message); + + return result; +} + +JavaResultData* +JavaRequestProcessor::setSlot(std::string objectID, + std::string index, + std::string value_id) +{ + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" SetObjectArrayElement "); + message.append(objectID); + message.append(" "); + message.append(index); + message.append(" "); + message.append(value_id); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +JavaResultData* +JavaRequestProcessor::newArray(std::string array_class, + std::string length) +{ + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + + message.append(" NewArray "); + message.append(array_class); + message.append(" "); + message.append(length); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +JavaResultData* +JavaRequestProcessor::getFieldID(std::string classID, std::string fieldName) +{ + JavaResultData* java_result; + JavaRequestProcessor* java_request = new JavaRequestProcessor(); + std::string message = std::string(); + + java_result = java_request->newString(fieldName); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + message.append(" GetFieldID "); + message.append(classID); + message.append(" "); + message.append(java_result->return_string->c_str()); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + delete java_request; + + return result; +} + +JavaResultData* +JavaRequestProcessor::getStaticFieldID(std::string classID, std::string fieldName) +{ + JavaResultData* java_result; + JavaRequestProcessor* java_request = new JavaRequestProcessor(); + std::string message = std::string(); + + java_result = java_request->newString(fieldName); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + message.append(" GetStaticFieldID "); + message.append(classID); + message.append(" "); + message.append(java_result->return_string->c_str()); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + delete java_request; + + return result; +} + +JavaResultData* +JavaRequestProcessor::getField(std::string source, + std::string classID, + std::string objectID, + std::string fieldName) +{ + JavaResultData* java_result; + JavaRequestProcessor* java_request = new JavaRequestProcessor(); + std::string message = std::string(); + + java_result = java_request->getFieldID(classID, fieldName); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message); + message.append(" GetField "); + message.append(objectID); + message.append(" "); + message.append(java_result->return_string->c_str()); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + delete java_request; + + return result; +} + +JavaResultData* +JavaRequestProcessor::getStaticField(std::string source, std::string classID, + std::string fieldName) +{ + JavaResultData* java_result; + JavaRequestProcessor* java_request = new JavaRequestProcessor(); + std::string message = std::string(); + + java_result = java_request->getStaticFieldID(classID, fieldName); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message); + message.append(" GetStaticField "); + message.append(classID); + message.append(" "); + message.append(java_result->return_string->c_str()); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + delete java_request; + + return result; +} + + +JavaResultData* +JavaRequestProcessor::set(std::string source, + bool isStatic, + std::string classID, + std::string objectID, + std::string fieldName, + std::string value_id) +{ + JavaResultData* java_result; + JavaRequestProcessor java_request = JavaRequestProcessor(); + std::string message = std::string(); + + java_result = java_request.getFieldID(classID, fieldName); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message); + + if (isStatic) + { + message.append(" SetStaticField "); + message.append(classID); + } else + { + message.append(" SetField "); + message.append(objectID); + } + + message.append(" "); + message.append(java_result->return_string->c_str()); + message.append(" "); + message.append(value_id); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +JavaResultData* +JavaRequestProcessor::setStaticField(std::string source, + std::string classID, + std::string fieldName, + std::string value_id) +{ + return set(source, true, classID, "", fieldName, value_id); +} + +JavaResultData* +JavaRequestProcessor::setField(std::string source, + std::string classID, + std::string objectID, + std::string fieldName, + std::string value_id) +{ + return set(source, false, classID, objectID, fieldName, value_id); +} + +JavaResultData* +JavaRequestProcessor::getMethodID(std::string classID, NPIdentifier methodName, + std::vector<std::string> args) +{ + JavaRequestProcessor* java_request; + std::string message = std::string(); + 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(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + message += " GetMethodID "; + message += classID; + message += " "; + message += browser_functions.utf8fromidentifier(methodName); + message += " "; + message += *signature; + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + delete signature; + + return result; +} + +JavaResultData* +JavaRequestProcessor::getStaticMethodID(std::string classID, NPIdentifier methodName, + std::vector<std::string> args) +{ + JavaRequestProcessor* java_request; + std::string message = std::string(); + 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(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + message += " GetStaticMethodID "; + message += classID; + message += " "; + message += browser_functions.utf8fromidentifier(methodName); + message += " "; + message += *signature; + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + delete signature; + + return result; +} + +void +getArrayTypeForJava(NPP instance, NPVariant element, std::string* type) +{ + + if (NPVARIANT_IS_BOOLEAN(element)) { + type->append("string"); + } else if (NPVARIANT_IS_INT32(element)) { + type->append("string"); + } else if (NPVARIANT_IS_DOUBLE(element)) { + type->append("string"); + } else if (NPVARIANT_IS_STRING(element)) { + type->append("string"); + } else if (NPVARIANT_IS_OBJECT(element)) { + + NPObject* first_element_obj = NPVARIANT_TO_OBJECT(element); + if (IcedTeaScriptableJavaPackageObject::is_valid_java_object(first_element_obj)) + { + std::string class_id = std::string(((IcedTeaScriptableJavaObject*) first_element_obj)->getClassID()); + type->append(class_id); + } else + { + type->append("jsobject"); + } + } else { + type->append("jsobject"); // Else it is a string + } +} + +void +createJavaObjectFromVariant(NPP instance, NPVariant variant, std::string* id) +{ + 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("VOID %d\n", variant); + id->append("0"); + return; // no need to go further + } else if (NPVARIANT_IS_NULL(variant)) + { + PLUGIN_DEBUG("NULL\n", variant); + id->append("0"); + return; // no need to go further + } 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, "%f", NPVARIANT_TO_DOUBLE(variant)); + stringArg += valueStr; + free(valueStr); + } else if (NPVARIANT_IS_STRING(variant)) + { + className = "java.lang.String"; +#if MOZILLA_VERSION_COLLAPSED < 1090200 + stringArg += NPVARIANT_TO_STRING(variant).utf8characters; +#else + stringArg += NPVARIANT_TO_STRING(variant).UTF8Characters; +#endif + } else if (NPVARIANT_IS_OBJECT(variant)) + { + + NPObject* obj = NPVARIANT_TO_OBJECT(variant); + if (IcedTeaScriptableJavaPackageObject::is_valid_java_object(obj)) + { + PLUGIN_DEBUG("NPObject is a Java object\n"); + alreadyCreated = true; + } else + { + PLUGIN_DEBUG("NPObject is not a Java object\n"); + NPIdentifier length_id = browser_functions.getstringidentifier("length"); + + // FIXME: We currently only handle <= 2 dim arrays. Do we really need more though? + + // Is it an array? + if (IcedTeaPluginUtilities::isObjectJSArray(instance, obj)) { + PLUGIN_DEBUG("NPObject is an array\n"); + + std::string array_id = std::string(); + std::string java_array_type = std::string(); + NPVariant length = NPVariant(); + browser_functions.getproperty(instance, obj, length_id, &length); + + std::string length_str = std::string(); + IcedTeaPluginUtilities::itoa(NPVARIANT_TO_INT32(length), &length_str); + + if (NPVARIANT_TO_INT32(length) > 0) + { + NPIdentifier id_0 = browser_functions.getintidentifier(0); + NPVariant first_element = NPVariant(); + browser_functions.getproperty(instance, obj, id_0, &first_element); + + // Check for multi-dim array + if (NPVARIANT_IS_OBJECT(first_element) && + IcedTeaPluginUtilities::isObjectJSArray(instance, NPVARIANT_TO_OBJECT(first_element))) { + + NPVariant first_nested_element = NPVariant(); + browser_functions.getproperty(instance, NPVARIANT_TO_OBJECT(first_element), id_0, &first_nested_element); + + getArrayTypeForJava(instance, first_nested_element, &java_array_type); + + length_str.append(" 0"); // secondary array is created on the fly + } else + { + getArrayTypeForJava(instance, first_element, &java_array_type); + } + } else + java_array_type.append("jsobject"); + + java_result = java_request.newArray(java_array_type, length_str); + + if (java_result->error_occurred) { + printf("Unable to create array\n"); + id->append("-1"); + return; + } + + id->append(*(java_result->return_string)); + + NPIdentifier index_id = NPIdentifier(); + for (int i=0; i < NPVARIANT_TO_INT32(length); i++) + { + NPVariant value = NPVariant(); + + index_id = browser_functions.getintidentifier(i); + browser_functions.getproperty(instance, obj, index_id, &value); + + std::string value_id = std::string(); + createJavaObjectFromVariant(instance, value, &value_id); + + if (value_id == "-1") { + printf("Unable to populate array\n"); + id->clear(); + id->append("-1"); + return; + } + + std::string value_str = std::string(); + IcedTeaPluginUtilities::itoa(i, &value_str); + java_result = java_request.setSlot(*id, value_str, value_id); + + } + + // Got here => no errors above. We're good to return! + return; + } else // Else it is not an array + { + + NPVariant* variant_copy = new NPVariant(); + OBJECT_TO_NPVARIANT(NPVARIANT_TO_OBJECT(variant), *variant_copy); + + className = "netscape.javascript.JSObject"; + IcedTeaPluginUtilities::JSIDToString(variant_copy, &stringArg); + browser_functions.retainobject(NPVARIANT_TO_OBJECT(variant)); + + std::string jsObjectClassID = std::string(); + std::string jsObjectConstructorID = std::string(); + std::vector<std::string> args = std::vector<std::string>(); + + java_result = java_request.findClass(0, "netscape.javascript.JSObject"); + + // the result we want is in result_string (assuming there was no error) + if (java_result->error_occurred) + { + printf("Unable to get JSObject class id\n"); + id->clear(); + id->append("-1"); + return; + } + + jsObjectClassID.append(*(java_result->return_string)); + args.push_back("J"); + + 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 get JSObject constructor id\n"); + id->clear(); + id->append("-1"); + return; + } + + jsObjectConstructorID.append(*(java_result->return_string)); + + // We have the method id. Now create a new object. + + args.clear(); + args.push_back(stringArg); + java_result = java_request.newObjectWithConstructor("", + jsObjectClassID, + jsObjectConstructorID, + args); + + // Store the instance ID for future reference + IcedTeaPluginUtilities::storeInstanceID(variant_copy, instance); + + // the result we want is in result_string (assuming there was no error) + // the result we want is in result_string (assuming there was no error) + if (java_result->error_occurred) + { + printf("Unable to create JSObject\n"); + id->clear(); + id->append("-1"); + return; + } + + id->append(*(java_result->return_string)); + return; + } + } + } + + if (!alreadyCreated) { + java_result = java_request.findClass(0, className); + + // 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()); + id->append("-1"); + return; + } + + jsObjectClassID.append(*(java_result->return_string)); + + 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()); + id->append("-1"); + return; + } + + jsObjectConstructorID.append(*(java_result->return_string)); + + // We have class id and constructor ID. So we know we can create the + // object.. now create the string that will be provided as the arg + java_result = java_request.newString(stringArg); + + if (java_result->error_occurred) { + printf("Unable to create requested object\n"); + id->append("-1"); + return; + } + + // Create the object + args.clear(); + std::string arg = std::string(); + arg.append(*(java_result->return_string)); + args.push_back(arg); + java_result = java_request.newObjectWithConstructor("[System]", jsObjectClassID, jsObjectConstructorID, args); + + if (java_result->error_occurred) { + printf("Unable to create requested object\n"); + id->append("-1"); + return; + } + + + id->append(*(java_result->return_string)); + + } else { + // Else already created + + 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) + id->append(classId.c_str()); + else + id->append(instanceId.c_str()); + } + +} + +JavaResultData* +JavaRequestProcessor::callStaticMethod(std::string source, std::string classID, + std::string methodName, + std::vector<std::string> args) +{ + return call(source, true, classID, methodName, args); +} + +JavaResultData* +JavaRequestProcessor::callMethod(std::string source, + std::string objectID, std::string methodName, + std::vector<std::string> args) +{ + return call(source, false, objectID, methodName, args); +} + +JavaResultData* +JavaRequestProcessor::call(std::string source, + bool isStatic, std::string objectID, + std::string methodName, + std::vector<std::string> args) +{ + std::string message = std::string(); + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message); + + if (isStatic) + message += " CallStaticMethod "; + else + message += " CallMethod "; + + message += objectID; + message += " "; + message += methodName; + message += " "; + + for (int i=0; i < args.size(); i++) + { + message += args[i]; + message += " "; + } + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +JavaResultData* +JavaRequestProcessor::getObjectClass(std::string objectID) +{ + JavaRequestProcessor* java_request; + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + message += " GetObjectClass "; + message += objectID; + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +JavaResultData* +JavaRequestProcessor::newObject(std::string source, std::string classID, + std::vector<std::string> args) +{ + JavaRequestProcessor* java_request; + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message); + message += " NewObject "; + message += classID; + message += " "; + + for (int i=0; i < args.size(); i++) + { + message += args[i]; + message += " "; + } + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +JavaResultData* +JavaRequestProcessor::newObjectWithConstructor(std::string source, std::string classID, + std::string methodID, + std::vector<std::string> args) +{ + JavaRequestProcessor* java_request; + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message); + message += " NewObjectWithConstructor "; + message += classID; + message += " "; + message += methodID; + message += " "; + + for (int i=0; i < args.size(); i++) + { + message += args[i]; + message += " "; + } + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +JavaResultData* +JavaRequestProcessor::newString(std::string str) +{ + std::string utf_string = std::string(); + std::string message = std::string(); + + IcedTeaPluginUtilities::convertStringToUTF8(&str, &utf_string); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + message.append(" NewStringUTF "); + message.append(utf_string); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +JavaResultData* +JavaRequestProcessor::hasPackage(int plugin_instance_id, + std::string package_name) +{ + JavaResultData* java_result; + JavaRequestProcessor* java_request = new JavaRequestProcessor(); + std::string message = std::string(); + std::string plugin_instance_id_str = std::string(); + IcedTeaPluginUtilities::itoa(plugin_instance_id, &plugin_instance_id_str); + + java_result = java_request->newString(package_name); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + message.append(" HasPackage "); + message.append(plugin_instance_id_str); + message.append(" "); + message.append(java_result->return_string->c_str()); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + delete java_request; + + return result; +} + +JavaResultData* +JavaRequestProcessor::hasMethod(std::string classID, std::string method_name) +{ + JavaResultData* java_result; + JavaRequestProcessor* java_request = new JavaRequestProcessor(); + std::string message = std::string(); + + java_result = java_request->newString(method_name); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + message.append(" HasMethod "); + message.append(classID); + message.append(" "); + message.append(java_result->return_string->c_str()); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + delete java_request; + + return result; +} + +JavaResultData* +JavaRequestProcessor::hasField(std::string classID, std::string method_name) +{ + JavaResultData* java_result; + JavaRequestProcessor java_request = JavaRequestProcessor(); + std::string message = std::string(); + + java_result = java_request.newString(method_name); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + message.append(" HasField "); + message.append(classID); + message.append(" "); + message.append(java_result->return_string->c_str()); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +JavaResultData* +JavaRequestProcessor::isInstanceOf(std::string objectID, std::string classID) +{ + std::string message = std::string(); + + this->instance = 0; // context is always 0 (needed for java-side backwards compat.) + this->reference = IcedTeaPluginUtilities::getReference(); + + IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message); + message.append(" IsInstanceOf "); + message.append(objectID); + message.append(" "); + message.append(classID); + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + +JavaResultData* +JavaRequestProcessor::getAppletObjectInstance(std::string instanceID) +{ + std::string message = std::string(); + std::string ref_str = std::string(); + + this->instance = 0; + this->reference = IcedTeaPluginUtilities::getReference(); + IcedTeaPluginUtilities::itoa(reference, &ref_str); + + message = "instance "; + message += instanceID; + message += " reference "; + message += ref_str; + message += " GetJavaObject"; + + postAndWaitForResponse(message); + + IcedTeaPluginUtilities::releaseReference(); + + return result; +} + |