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