Back to index

lightning-sunbird  0.9+nobinonly
LiveConnectNativeMethods.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the MRJ Carbon OJI Plugin.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corp.
00018  * Portions created by the Initial Developer are Copyright (C) 2001
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Patrick C. Beard <beard@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039     LiveConnectNativeMethods.cpp
00040  */
00041 
00042 #include <memory>
00043 
00044 #include "LiveConnectNativeMethods.h"
00045 
00046 #include "nsIComponentManagerObsolete.h"
00047 #include "nsIPluginManager.h"
00048 #include "nsIJVMManager.h"
00049 #include "nsILiveconnect.h"
00050 #include "nsIPluginInstancePeer2.h"
00051 
00052 #include "MRJPlugin.h"
00053 #include "MRJContext.h"
00054 #include "MRJSession.h"
00055 #include "MRJSecurityContext.h"
00056 #include "CSecureEnv.h"
00057 #include "JavaMessageQueue.h"
00058 #include "MRJMonitor.h"
00059 #include "NativeMonitor.h"
00060 #include "RunnableMixin.h"
00061 #include "StringUtils.h"
00062 
00063 #include "netscape_javascript_JSObject.h"   /* javah-generated headers */
00064 
00065 extern nsIPluginManager* thePluginManager;
00066 
00067 static MRJPlugin* theJVMPlugin = NULL;
00068 static nsILiveconnect* theLiveConnectManager = NULL;
00069 static nsIComponentManagerObsolete* theComponentManager = NULL;
00070 
00071 static jclass netscape_javascript_JSObject = NULL;
00072 static jmethodID netscape_javascript_JSObject_JSObject;
00073 static jfieldID netscape_javascript_JSObject_internal;
00074 
00075 static jclass netscape_oji_JNIUtils = NULL;
00076 static jmethodID netscape_oji_JNIUtils_NewLocalRef = NULL;
00077 static jmethodID netscape_oji_JNIUtils_GetCurrentThread = NULL;
00078 static jmethodID netscape_oji_JNIUtils_GetCurrentClassLoader = NULL;
00079 static jmethodID netscape_oji_JNIUtils_GetObjectClassLoader = NULL;
00080 
00081 static NS_DEFINE_IID(kLiveConnectCID, NS_CLIVECONNECT_CID);
00082 static NS_DEFINE_IID(kComponentManagerCID, NS_COMPONENTMANAGER_CID);
00083 
00084 static nsresult getGlobalComponentManager(nsIComponentManagerObsolete* *result)
00085 {
00086     return MRJPlugin::GetService(kComponentManagerCID, NS_GET_IID(nsIComponentManagerObsolete), (void**)result);
00087 }
00088 
00089 nsresult InitLiveConnectSupport(MRJPlugin* jvmPlugin)
00090 {
00091     theJVMPlugin = jvmPlugin;
00092 
00093     getGlobalComponentManager(&theComponentManager);
00094 
00095     nsresult result = MRJPlugin::GetService(kLiveConnectCID, NS_GET_IID(nsILiveconnect),
00096                                             (void**)&theLiveConnectManager);
00097     if (result != NS_OK)
00098         return result;
00099     
00100     // Manually load the required native methods.
00101     static JNINativeMethod nativeMethods[] = {
00102         "getMember", "(Ljava/lang/String;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_getMember,
00103         "getSlot", "(I)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_getSlot,
00104         "setMember", "(Ljava/lang/String;Ljava/lang/Object;)V", (void*)&Java_netscape_javascript_JSObject_setMember,
00105         "setSlot", "(ILjava/lang/Object;)V", (void*)&Java_netscape_javascript_JSObject_setSlot,
00106         "removeMember", "(Ljava/lang/String;)V", (void*)&Java_netscape_javascript_JSObject_removeMember,
00107         "call", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_call,
00108         "eval", "(Ljava/lang/String;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_eval,
00109         "toString", "()Ljava/lang/String;", (void*)&Java_netscape_javascript_JSObject_toString,
00110         "getWindow", "(Ljava/applet/Applet;)Lnetscape/javascript/JSObject;", (void*)&Java_netscape_javascript_JSObject_getWindow,
00111         "finalize", "()V", (void*)&Java_netscape_javascript_JSObject_finalize,
00112     };
00113     
00114     MRJSession* session = jvmPlugin->getSession();
00115     JNIEnv* env = session->getCurrentEnv();
00116     if (env != NULL) {
00117         jclass classJSObject = env->FindClass("netscape/javascript/JSObject");
00118         if (classJSObject != NULL) {
00119             // register LiveConnect native methods.
00120             netscape_javascript_JSObject = (jclass) env->NewGlobalRef(classJSObject);
00121             env->DeleteLocalRef(classJSObject);
00122             
00123             netscape_javascript_JSObject_JSObject = env->GetMethodID(netscape_javascript_JSObject, "<init>", "(I)V");
00124             if (env->ExceptionCheck()) {
00125                 env->ExceptionClear();
00126                 result = NS_ERROR_FAILURE;
00127             }
00128 
00129             netscape_javascript_JSObject_internal = env->GetFieldID(netscape_javascript_JSObject, "internal", "I");
00130             if (env->ExceptionCheck()) {
00131                 env->ExceptionClear();
00132                 result = NS_ERROR_FAILURE;
00133             }
00134 
00135             env->RegisterNatives(netscape_javascript_JSObject, nativeMethods, sizeof(nativeMethods) / sizeof(JNINativeMethod));
00136             if (env->ExceptionCheck()) {
00137                 env->ExceptionClear();
00138                 result = NS_ERROR_FAILURE;
00139             }
00140         }
00141         
00142         // load netscape.oji.JNIUtils class.
00143         jclass classJNIUtils = env->FindClass("netscape/oji/JNIUtils");
00144         if (classJNIUtils != NULL) {
00145             netscape_oji_JNIUtils = (jclass) env->NewGlobalRef(classJNIUtils);
00146             env->DeleteLocalRef(classJNIUtils);
00147             netscape_oji_JNIUtils_NewLocalRef = env->GetStaticMethodID(netscape_oji_JNIUtils, "NewLocalRef", "(Ljava/lang/Object;)Ljava/lang/Object;");
00148             netscape_oji_JNIUtils_GetCurrentThread = env->GetStaticMethodID(netscape_oji_JNIUtils, "GetCurrentThread", "()Ljava/lang/Object;");
00149             netscape_oji_JNIUtils_GetCurrentClassLoader = env->GetStaticMethodID(netscape_oji_JNIUtils, "GetCurrentClassLoader", "()Ljava/lang/Object;");
00150             netscape_oji_JNIUtils_GetObjectClassLoader = env->GetStaticMethodID(netscape_oji_JNIUtils, "GetObjectClassLoader", "(Ljava/lang/Object;)Ljava/lang/Object;");
00151         }
00152     }
00153     
00154     return result;
00155 }
00156 
00157 nsresult ShutdownLiveConnectSupport()
00158 {
00159     NS_IF_RELEASE(theLiveConnectManager);
00160     NS_IF_RELEASE(theComponentManager);
00161     
00162     if (theJVMPlugin != NULL) {
00163         theJVMPlugin = NULL;
00164     }
00165     
00166     return NS_OK;
00167 }
00168 
00169 jobject Wrap_JSObject(JNIEnv* env, jsobject js_obj)
00170 {
00171     jmethodID constructorID = env->GetMethodID(netscape_javascript_JSObject, "<init>", "(I)V");
00172     return env->NewObject(netscape_javascript_JSObject, constructorID, js_obj);
00173 }
00174 
00175 jsobject Unwrap_JSObject(JNIEnv* env, jobject java_wrapper_obj)
00176 {
00177     return env->GetIntField(java_wrapper_obj, netscape_javascript_JSObject_internal);
00178 }
00179 
00180 static jobject NewLocalRef(JNIEnv* env, jobject global_ref)
00181 {
00182     return env->CallStaticObjectMethod(netscape_oji_JNIUtils, netscape_oji_JNIUtils_NewLocalRef, global_ref);
00183 }
00184 
00185 static jobject ToGlobalRef(JNIEnv* env, jobject localRef)
00186 {
00187     jobject globalRef = env->NewGlobalRef(localRef);
00188     env->DeleteLocalRef(localRef);
00189     return globalRef;
00190 }
00191 
00192 static jobject ToLocalRef(JNIEnv* env, jobject globalRef)
00193 {
00194     jobject localRef = NewLocalRef(env, globalRef);
00195     env->DeleteGlobalRef(globalRef);
00196     return localRef;
00197 }
00198 
00199 static jobject GetCurrentThread(JNIEnv* env)
00200 {
00201     return env->CallStaticObjectMethod(netscape_oji_JNIUtils, netscape_oji_JNIUtils_GetCurrentThread);
00202 }
00203 
00208 MRJSecurityContext::MRJSecurityContext(const char* location)
00209     :   mLocation(nsnull), mConnection(nsnull)
00210 {
00211     mLocation = ::strdup(location);
00212     if (mLocation) {
00213         // find the 3rd slash of the URL, hopefully it's in canonical form.
00214         char* colon = ::strchr(mLocation, ':');
00215         if (colon) {
00216             if (colon[1] == '/' && colon[2] == '/') {
00217                 char* slash = ::strchr(colon + 3, '/');
00218                 if (slash) *slash = '\0';
00219             }
00220         }
00221     }
00222 
00223     if (theComponentManager) {
00224         theComponentManager->CreateInstance(kLiveConnectCID, nsnull, NS_GET_IID(nsILiveconnect),
00225                                             (void**)&mConnection);
00226     } else {
00227         mConnection = theLiveConnectManager;
00228         NS_IF_ADDREF(mConnection);
00229     }
00230 }
00231 
00232 MRJSecurityContext::~MRJSecurityContext()
00233 {
00234     delete[] mLocation;
00235     NS_IF_RELEASE(mConnection);
00236 }
00237 
00238 // work around a bug in Metrowerks pre-processor.
00239 NS_IMPL_ISUPPORTS1(MRJSecurityContext, nsISecurityContext)
00240 
00241 NS_METHOD MRJSecurityContext::Implies(const char* target, const char* action, PRBool *bAllowedAccess)
00242 {
00243     *bAllowedAccess = (target != NULL && action == NULL);
00244     return NS_OK;
00245 }
00246 
00247 NS_METHOD 
00248 MRJSecurityContext::GetOrigin(char* buf, int len)
00249 {
00250     char* origin = nsnull;
00251     if (mLocation) {
00252         ::strncpy(buf, mLocation, len);
00253         return NS_OK;
00254     }
00255     return NS_ERROR_FAILURE;
00256 }
00257 
00258 NS_METHOD 
00259 MRJSecurityContext::GetCertificateID(char* buf, int len)
00260 {
00261     // ACTION: Implement me.
00262     return NS_ERROR_NOT_IMPLEMENTED;
00263 }
00264 
00265 // NOTE:  this a weak reference to the MRJSecurityContext associated with this
00266 // plugin instance. The MRJSecurityContext is owned by the MRJContext.
00267 
00268 static MRJSecurityContext* getSecurityContext(MRJPluginInstance* pluginInstance)
00269 {
00270     if (pluginInstance != NULL) {
00271         MRJContext* context = pluginInstance->getContext();
00272         MRJSecurityContext* securityContext = context->getSecurityContext();
00273         if (securityContext == NULL) {
00274             securityContext = new MRJSecurityContext(context->getDocumentBase());
00275             context->setSecurityContext(securityContext);
00276         }
00277         return securityContext;
00278     }
00279     return NULL;
00280 }
00281 
00282 inline nsILiveconnect* getLiveconnectInstance(MRJSecurityContext* securityContext)
00283 {
00284     return (securityContext ? securityContext->getConnection() : theLiveConnectManager);
00285 }
00286 
00287 static jobject GetCurrentClassLoader(JNIEnv* env)
00288 {
00289     return env->CallStaticObjectMethod(netscape_oji_JNIUtils, netscape_oji_JNIUtils_GetCurrentClassLoader);
00290 }
00291 
00292 static jobject GetObjectClassLoader(JNIEnv* env, jobject object)
00293 {
00294     return env->CallStaticObjectMethod(netscape_oji_JNIUtils, netscape_oji_JNIUtils_GetObjectClassLoader, object);
00295 }
00296 
00303 static MRJPluginInstance* GetCurrentInstance(JNIEnv* env)
00304 {
00305     MRJPluginInstance* pluginInstance = NULL;
00306     jobject classLoader = GetCurrentClassLoader(env);
00307     if (classLoader != NULL) {
00308         pluginInstance = MRJPluginInstance::getInstances();
00309         while (pluginInstance != NULL) {
00310             jobject applet;
00311             pluginInstance->GetJavaObject(&applet);
00312             jobject appletClassLoader = GetObjectClassLoader(env, applet);
00313             jboolean sameClassLoader = env->IsSameObject(appletClassLoader, classLoader);
00314             env->DeleteLocalRef(appletClassLoader);
00315             if (sameClassLoader)
00316                 break;
00317             pluginInstance = pluginInstance->getNextInstance();
00318         }
00319         env->DeleteLocalRef(classLoader);
00320     }
00321     return pluginInstance;
00322 }
00323 
00329 static MRJPluginInstance* GetCurrentInstance(JNIEnv* env, jobject applet)
00330 {
00331     MRJPluginInstance* pluginInstance = MRJPluginInstance::getInstances();
00332     while (pluginInstance != NULL) {
00333         jobject object = NULL;
00334         if (pluginInstance->GetJavaObject(&object) == NS_OK && env->IsSameObject(applet, object)) {
00335             return pluginInstance;
00336         }
00337         pluginInstance = pluginInstance->getNextInstance();
00338     }
00339     return NULL;
00340 }
00341 
00345 class MessageRunnable : public JavaMessage, public RunnableMixin {
00346 public:
00347     MessageRunnable(PRUint32 threadID, JavaMessage* msg);
00348     
00349     virtual void execute(JNIEnv* env);
00350     
00351     NS_IMETHOD Run();
00352 
00353 private:
00354     PRUint32 mThreadID;
00355     JavaMessage* mMessage;
00356 };
00357 
00358 MessageRunnable::MessageRunnable(PRUint32 threadID, JavaMessage* msg)
00359     : mThreadID(threadID), mMessage(msg)
00360 {
00361 }
00362 
00363 void MessageRunnable::execute(JNIEnv* env)
00364 {
00365     // because a spontaneous Java thread called us, we have to switch to the JavaScript thread
00366     // to handle this request.
00367     nsIThreadManager* threadManager = NULL;
00368     if (MRJPlugin::GetService(nsIJVMManager::GetCID(), NS_GET_IID(nsIThreadManager), (void**)&threadManager) == NS_OK) {
00369         threadManager->PostEvent(mThreadID, this, PR_FALSE);
00370         NS_RELEASE(threadManager);
00371     }
00372 }
00373 
00374 NS_IMETHODIMP MessageRunnable::Run()
00375 {
00376     nsIJVMManager* javaManager = NULL;
00377     if (MRJPlugin::GetService(nsIJVMManager::GetCID(), NS_GET_IID(nsIJVMManager), (void**)&javaManager) == NS_OK) {
00378         JNIEnv* proxyEnv = NULL;
00379         if (javaManager->GetProxyJNI(&proxyEnv) == NS_OK && proxyEnv != NULL)
00380             mMessage->execute(proxyEnv);
00381         NS_RELEASE(javaManager);
00382     }
00383     return NS_OK;
00384 }
00385 
00386 static PRUint32 getJavaScriptThread(JNIEnv* env)
00387 {
00388     PRUint32 threadID = 0;
00389     MRJPluginInstance* pluginInstance = GetCurrentInstance(env);
00390     if (pluginInstance != NULL) {
00391         nsIPluginInstancePeer* peer;
00392         if (pluginInstance->GetPeer(&peer) == NS_OK) {
00393             nsIPluginInstancePeer2* peer2 = NULL;
00394             if (peer->QueryInterface(NS_GET_IID(nsIPluginInstancePeer2), (void**)&peer2) == NS_OK) {
00395                 if (peer2->GetJSThread(&threadID) != NS_OK)
00396                     threadID = 0;
00397                 NS_RELEASE(peer2);
00398             }
00399             NS_RELEASE(peer);
00400         }
00401     }
00402     return threadID;
00403 }
00404 
00409 static void sendMessage(JNIEnv* env, JavaMessage* msg)
00410 {
00411     // the main thread gets its own secure env, so it won't contend with other threads. this
00412     // is needed to handle finalization, which seems to get called from the main thread sometimes.
00413     if (env == theJVMPlugin->getSession()->getMainEnv()) {
00414         static CSecureEnv* mainEnv = NULL;
00415         if (mainEnv == NULL) {
00416             mainEnv = new CSecureEnv(theJVMPlugin, NULL, env);
00417             mainEnv->AddRef();
00418         }
00419         mainEnv->setJavaEnv(env);
00420         mainEnv->sendMessageFromJava(env, msg, true);
00421         return;
00422     }
00423     
00424     // If this is a call back into JavaScript from Java, there will be a secureEnv associated with this thread.
00425     jobject thread = GetCurrentThread(env);
00426     CSecureEnv* secureEnv = GetSecureJNI(env, thread);
00427     env->DeleteLocalRef(thread);
00428     if (secureEnv != NULL) {
00429         secureEnv->sendMessageFromJava(env, msg);
00430     } else {
00431         // spontaneous call in from Java. this communicates with a shared server thread. this is *VERY* slow right now.
00432         static MRJMonitor sharedMonitor(theJVMPlugin->getSession());
00433         // only 1 Java thread can use this at a time.
00434         sharedMonitor.enter();
00435         {
00436             static CSecureEnv* sharedEnv = NULL;
00437             if (sharedEnv == NULL) {
00438                 sharedEnv = new CSecureEnv(theJVMPlugin, NULL, env);
00439                 sharedEnv->AddRef();
00440             }
00441             sharedEnv->setJavaEnv(env);
00442 
00443             // In the current Seamonkey architecture, there's really only one thread that JavaScript
00444             // can execute in. We take advantage of that fact here. When we have a more multithreaded
00445             // system, this will have to be revisited.
00446             static PRUint32 theJavaScriptThread = getJavaScriptThread(env);
00447             
00448             // if the JavaScript thread is known, wrap the message in a MessageRunnable to handle
00449             // the message in the JavaScript thread.
00450             if (theJavaScriptThread != 0) {
00451                 MessageRunnable* runnableMsg = new MessageRunnable(theJavaScriptThread, msg);
00452                 NS_ADDREF(runnableMsg);
00453                 sharedEnv->sendMessageFromJava(env, runnableMsg);
00454                 NS_IF_RELEASE(runnableMsg);
00455             }
00456         }
00457         sharedMonitor.exit();
00458     }
00459 }
00460 
00461 static nsIPrincipal* newCodebasePrincipal(const char* codebaseURL)
00462 {
00463     nsIPrincipal* principal = NULL;
00464 #if 0
00465     nsICapsManager* capsManager = NULL;
00466     static NS_DEFINE_IID(kICapsManagerIID, NS_ICAPSMANAGER_IID);
00467     if (thePluginManager->QueryInterface(kICapsManagerIID, &capsManager) == NS_OK) {
00468         if (capsManager->CreateCodebasePrincipal(codebaseURL, &principal) != NS_OK)
00469             principal = NULL;
00470         capsManager->Release();
00471     }
00472 #endif
00473     return principal;
00474 }
00475 
00476 /****************** Implementation of methods of JSObject *******************/
00477 
00478 /*
00479  * Class:     netscape_javascript_JSObject
00480  * Method:    getMember
00481  * Signature: (Ljava/lang/String;)Ljava/lang/Object;
00482  */
00483 
00484 class GetMemberMessage : public JavaMessage {
00485     MRJPluginInstance* mPluginInstance;
00486     jsobject mObject;
00487     const jchar* mPropertyName;
00488     jsize mLength;
00489     jobject* mResultObject;
00490 public:
00491     GetMemberMessage(MRJPluginInstance* pluginInstance, jsobject js_obj,
00492                      const jchar* propertyName, jsize nameLength, jobject* member)
00493         :   mPluginInstance(pluginInstance), mObject(js_obj), mPropertyName(propertyName),
00494             mLength(nameLength), mResultObject(member)
00495     {
00496     }
00497 
00498     virtual void execute(JNIEnv* env)
00499     {
00500         MRJSecurityContext* securityContext = getSecurityContext(mPluginInstance);
00501         nsILiveconnect* connection = getLiveconnectInstance(securityContext);
00502         jobject member;
00503         nsresult result = connection->GetMember(env, mObject, mPropertyName, mLength, NULL, 0, securityContext, &member);
00504         if (result == NS_OK) {
00505             // convert reference to a global reference, in case we're switching threads.
00506             *mResultObject = ToGlobalRef(env, member);
00507         }
00508     }
00509 };
00510 
00511 JNIEXPORT jobject JNICALL
00512 Java_netscape_javascript_JSObject_getMember(JNIEnv* env,
00513                                             jobject java_wrapper_obj,
00514                                             jstring property_name_jstr)
00515 {
00516     if (property_name_jstr == NULL) {
00517         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal null member name");
00518         return NULL;
00519     }
00520 
00521     MRJPluginInstance* pluginInstance = GetCurrentInstance(env);
00522     if (pluginInstance == NULL) {
00523         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal JNIEnv (can't find plugin)");
00524         return NULL;
00525     }
00526 
00527     /* Get the Unicode string for the JS property name */
00528     jboolean is_copy;
00529     const jchar* property_name_ucs2 = env->GetStringChars(property_name_jstr, &is_copy);
00530     jsize property_name_len = env->GetStringLength(property_name_jstr);
00531 
00532     jsobject js_obj = Unwrap_JSObject(env, java_wrapper_obj);
00533     jobject member = NULL;
00534 
00535     GetMemberMessage msg(pluginInstance, js_obj, property_name_ucs2, property_name_len, &member);
00536     sendMessage(env, &msg);
00537 
00538     // convert the resulting reference back to a local reference.
00539     if (member != NULL)
00540         member = ToLocalRef(env, member);
00541     
00542     env->ReleaseStringChars(property_name_jstr, property_name_ucs2);
00543 
00544     return member;
00545 }
00546 
00547 /*
00548  * Class:     netscape_javascript_JSObject
00549  * Method:    getSlot
00550  * Signature: (I)Ljava/lang/Object;
00551  */
00552 
00553 class GetSlotMessage : public JavaMessage {
00554     MRJPluginInstance* mPluginInstance;
00555     jsobject mObject;
00556     jint mSlot;
00557     jobject* mResultObject;
00558 public:
00559     GetSlotMessage(MRJPluginInstance* pluginInstance, jsobject js_obj,
00560                    jint slot, jobject* member)
00561         :   mPluginInstance(pluginInstance), mObject(js_obj), mSlot(slot), mResultObject(member)
00562     {
00563     }
00564 
00565     virtual void execute(JNIEnv* env)
00566     {
00567         MRJSecurityContext* securityContext = getSecurityContext(mPluginInstance);
00568         nsILiveconnect* connection = getLiveconnectInstance(securityContext);
00569         jobject member;
00570         nsresult result = connection->GetSlot(env, mObject, mSlot, NULL, 0, securityContext, &member);
00571         if (result == NS_OK) {
00572             // convert reference to a global reference, in case we're switching threads.
00573             *mResultObject = ToGlobalRef(env, member);
00574         }
00575     }
00576 };
00577 
00578 JNIEXPORT jobject JNICALL
00579 Java_netscape_javascript_JSObject_getSlot(JNIEnv* env,
00580                                           jobject java_wrapper_obj,
00581                                           jint slot)
00582 {
00583     MRJPluginInstance* pluginInstance = GetCurrentInstance(env);
00584 
00585     if (pluginInstance == NULL) {
00586         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal JNIEnv (can't find plugin)");
00587         return NULL;
00588     }
00589 
00590     jsobject js_obj = Unwrap_JSObject(env, java_wrapper_obj);
00591     jobject member = NULL;
00592     
00593     GetSlotMessage msg(pluginInstance, js_obj, slot, &member);
00594     sendMessage(env, &msg);
00595     
00596     // convert the resulting reference back to a local reference.
00597     if (member != NULL)
00598         member = ToLocalRef(env, member);
00599     return member;
00600 }
00601 
00602 /*
00603  * Class:     netscape_javascript_JSObject
00604  * Method:    setMember
00605  * Signature: (Ljava/lang/String;Ljava/lang/Object;)V
00606  */
00607 
00608 class SetMemberMessage : public JavaMessage {
00609     MRJPluginInstance* mPluginInstance;
00610     jsobject mObject;
00611     const jchar* mPropertyName;
00612     jsize mLength;
00613     jobject mJavaObject;
00614 public:
00615     SetMemberMessage(MRJPluginInstance* pluginInstance, jsobject js_obj, const jchar* propertyName,
00616                      jsize nameLength, jobject java_obj)
00617         :   mPluginInstance(pluginInstance), mObject(js_obj), mPropertyName(propertyName), mLength(nameLength), mJavaObject(java_obj)
00618     {
00619     }
00620 
00621     virtual void execute(JNIEnv* env)
00622     {
00623         MRJSecurityContext* securityContext = getSecurityContext(mPluginInstance);
00624         nsILiveconnect* connection = getLiveconnectInstance(securityContext);
00625         nsresult result = connection->SetMember(env, mObject, mPropertyName, mLength, mJavaObject, 0, NULL, securityContext);
00626     }
00627 };
00628 
00629 JNIEXPORT void JNICALL
00630 Java_netscape_javascript_JSObject_setMember(JNIEnv* env,
00631                                             jobject java_wrapper_obj,
00632                                             jstring property_name_jstr,
00633                                             jobject java_obj)
00634 {
00635     if (property_name_jstr == NULL) {
00636         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal null member name");
00637         return;
00638     }
00639 
00640     MRJPluginInstance* pluginInstance = GetCurrentInstance(env);
00641     if (pluginInstance == NULL) {
00642         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal JNIEnv (can't find plugin)");
00643         return;
00644     }
00645 
00646     /* Get the Unicode string for the JS property name */
00647     jboolean is_copy;
00648     const jchar* property_name_ucs2 = env->GetStringChars(property_name_jstr, &is_copy);
00649     jsize property_name_len = env->GetStringLength(property_name_jstr);
00650     
00651     jsobject js_obj = Unwrap_JSObject(env, java_wrapper_obj);
00652     java_obj = ToGlobalRef(env, java_obj);
00653 
00654     SetMemberMessage msg(pluginInstance, js_obj, property_name_ucs2, property_name_len, java_obj);
00655     sendMessage(env, &msg);
00656     
00657     env->DeleteGlobalRef(java_obj);
00658     env->ReleaseStringChars(property_name_jstr, property_name_ucs2);
00659 }
00660 
00661 /*
00662  * Class:     netscape_javascript_JSObject
00663  * Method:    setSlot
00664  * Signature: (ILjava/lang/Object;)V
00665  */
00666 
00667 class SetSlotMessage : public JavaMessage {
00668     MRJPluginInstance* mPluginInstance;
00669     jsobject mObject;
00670     jint mSlot;
00671     jobject mJavaObject;
00672 public:
00673     SetSlotMessage(MRJPluginInstance* pluginInstance, jsobject js_obj, jint slot, jobject java_obj)
00674         :   mPluginInstance(pluginInstance), mObject(js_obj), mSlot(slot), mJavaObject(java_obj)
00675     {
00676     }
00677 
00678     virtual void execute(JNIEnv* env)
00679     {
00680         MRJSecurityContext* securityContext = getSecurityContext(mPluginInstance);
00681         nsILiveconnect* connection = getLiveconnectInstance(securityContext);
00682         nsresult result = connection->SetSlot(env, mObject, mSlot, mJavaObject, 0, NULL, securityContext);
00683     }
00684 };
00685 
00686 JNIEXPORT void JNICALL
00687 Java_netscape_javascript_JSObject_setSlot(JNIEnv* env,
00688                                           jobject java_wrapper_obj,
00689                                           jint slot,
00690                                           jobject java_obj)
00691 {
00692     MRJPluginInstance* pluginInstance = GetCurrentInstance(env);
00693 
00694     if (pluginInstance == NULL) {
00695         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal JNIEnv (can't find plugin)");
00696         return;
00697     }
00698 
00699     jsobject js_obj = Unwrap_JSObject(env, java_wrapper_obj);
00700     java_obj = ToGlobalRef(env, java_obj);
00701     
00702     SetSlotMessage msg(pluginInstance, js_obj, slot, java_obj);
00703     sendMessage(env, &msg);
00704     env->DeleteGlobalRef(java_obj);
00705 }
00706 
00707 /*
00708  * Class:     netscape_javascript_JSObject
00709  * Method:    removeMember
00710  * Signature: (Ljava/lang/String;)V
00711  */
00712 
00713 class RemoveMemberMessage : public JavaMessage {
00714     MRJPluginInstance* mPluginInstance;
00715     jsobject mObject;
00716     const jchar* mPropertyName;
00717     jsize mLength;
00718 public:
00719     RemoveMemberMessage(MRJPluginInstance* pluginInstance, jsobject obj,
00720                         const jchar* propertyName, jsize length)
00721         :   mPluginInstance(pluginInstance), mObject(obj),
00722             mPropertyName(propertyName), mLength(length)
00723     {
00724     }
00725 
00726     virtual void execute(JNIEnv* env)
00727     {
00728         MRJSecurityContext* securityContext = getSecurityContext(mPluginInstance);
00729         nsILiveconnect* connection = getLiveconnectInstance(securityContext);
00730         nsresult result = connection->RemoveMember(env, mObject, mPropertyName, mLength, NULL, 0, securityContext);
00731     }
00732 };
00733 
00734 JNIEXPORT void JNICALL
00735 Java_netscape_javascript_JSObject_removeMember(JNIEnv* env,
00736                                                jobject java_wrapper_obj,
00737                                                jstring property_name_jstr)
00738 {
00739     if (property_name_jstr == NULL) {
00740         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal null member name");
00741         return;
00742     }
00743 
00744     MRJPluginInstance* pluginInstance = GetCurrentInstance(env);
00745     if (pluginInstance == NULL) {
00746         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal JNIEnv (can't find plugin)");
00747         return;
00748     }
00749 
00750     /* Get the Unicode string for the JS property name */
00751     jboolean is_copy;
00752     const jchar* property_name_ucs2 = env->GetStringChars(property_name_jstr, &is_copy);
00753     jsize property_name_len = env->GetStringLength(property_name_jstr);
00754 
00755     jsobject js_obj = Unwrap_JSObject(env, java_wrapper_obj);
00756     RemoveMemberMessage msg(pluginInstance, js_obj, property_name_ucs2, property_name_len);
00757     
00758     sendMessage(env, &msg);
00759     
00760     env->ReleaseStringChars(property_name_jstr, property_name_ucs2);
00761 }
00762 
00763 /*
00764  * Class:     netscape_javascript_JSObject
00765  * Method:    call
00766  * Signature: (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;
00767  */
00768 class CallMessage : public JavaMessage {
00769     MRJPluginInstance* mPluginInstance;
00770     jsobject mObject;
00771     const jchar* mFunctionName;
00772     jsize mLength;
00773     jobjectArray mJavaArgs;
00774     jobject* mJavaResult;
00775 public:
00776     CallMessage(MRJPluginInstance* pluginInstance, jsobject obj, const jchar* functionName,
00777                 jsize length, jobjectArray javaArgs, jobject* javaResult)
00778         :   mPluginInstance(pluginInstance), mObject(obj), mFunctionName(functionName),
00779             mLength(length), mJavaArgs(javaArgs), mJavaResult(javaResult)
00780     {
00781     }
00782 
00783     virtual void execute(JNIEnv* env)
00784     {
00785         /* If we have an applet, try to create a codebase principle. */
00786         MRJSecurityContext* securityContext = getSecurityContext(mPluginInstance);
00787         nsILiveconnect* connection = getLiveconnectInstance(securityContext);
00788         jobject jresult = NULL;
00789         nsresult result = connection->Call(env, mObject, mFunctionName, mLength, mJavaArgs, NULL, 0, securityContext, &jresult);
00790         if (result == NS_OK)
00791             *mJavaResult = ToGlobalRef(env, jresult);
00792     }
00793 };
00794 
00795 JNIEXPORT jobject JNICALL
00796 Java_netscape_javascript_JSObject_call(JNIEnv* env, jobject java_wrapper_obj,
00797                                        jstring function_name_jstr, jobjectArray java_args)
00798 {
00799     if (function_name_jstr == NULL) {
00800         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal null function name");
00801         return NULL;
00802     }
00803 
00804     /* Try to determine which plugin instance is responsible for this thread. This is done by checking class loaders. */
00805     MRJPluginInstance* pluginInstance = GetCurrentInstance(env);
00806     if (pluginInstance == NULL) {
00807         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal JNIEnv (can't find plugin)");
00808         return NULL;
00809     }
00810 
00811     /* Get the Unicode string for the JS function name */
00812     jboolean is_copy;
00813     const jchar* function_name_ucs2 = env->GetStringChars(function_name_jstr, &is_copy);
00814     jsize function_name_len = env->GetStringLength(function_name_jstr);
00815 
00816     jsobject js_obj = Unwrap_JSObject(env, java_wrapper_obj);
00817     jobject jresult = NULL;
00818 
00819     CallMessage msg(pluginInstance, js_obj, function_name_ucs2, function_name_len, java_args, &jresult);
00820     sendMessage(env, &msg);
00821 
00822     env->ReleaseStringChars(function_name_jstr, function_name_ucs2);
00823 
00824     if (jresult != NULL)
00825         jresult = ToLocalRef(env, jresult);
00826 
00827     return jresult;
00828 }
00829 
00830 /*
00831  * Class:     netscape_javascript_JSObject
00832  * Method:    eval
00833  * Signature: (Ljava/lang/String;)Ljava/lang/Object;
00834  */
00835 class EvalMessage : public JavaMessage {
00836     MRJPluginInstance* mPluginInstance;
00837     jsobject mObject;
00838     const jchar* mScript;
00839     jsize mLength;
00840     jobject* mJavaResult;
00841 public:
00842     EvalMessage(MRJPluginInstance* pluginInstance, jsobject obj, const jchar* script, jsize length, jobject* javaResult)
00843         :   mPluginInstance(pluginInstance), mObject(obj), mScript(script), mLength(length), mJavaResult(javaResult)
00844     {
00845     }
00846 
00847     virtual void execute(JNIEnv* env)
00848     {
00849         jobject jresult = NULL;
00850         MRJSecurityContext* securityContext = getSecurityContext(mPluginInstance);
00851         nsILiveconnect* connection = getLiveconnectInstance(securityContext);
00852         nsresult result = connection->Eval(env, mObject, mScript, mLength, NULL, 0, securityContext, &jresult);
00853         if (result == NS_OK && jresult != NULL)
00854             *mJavaResult = ToGlobalRef(env, jresult);
00855     }
00856 };
00857 
00858 JNIEXPORT jobject JNICALL
00859 Java_netscape_javascript_JSObject_eval(JNIEnv* env,
00860                                        jobject java_wrapper_obj,
00861                                        jstring script_jstr)
00862 {
00863     /* Get the Unicode string for the JS function name */
00864     if (script_jstr == NULL) {
00865         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal null script string");
00866         return NULL;
00867     }
00868     jboolean is_copy;
00869     const jchar* script_ucs2 = env->GetStringChars(script_jstr, &is_copy);
00870     jsize script_len = env->GetStringLength(script_jstr);
00871 
00872     /* unwrap the JS object from the Java object. */
00873     jsobject js_obj = Unwrap_JSObject(env, java_wrapper_obj);
00874     jobject jresult = NULL;
00875     
00876     /* determine the plugin instance so we can obtain its codebase. */
00877     // beard: should file a bug with Apple that JMJNIToAWTContext doesn't work.
00878     MRJPluginInstance* pluginInstance = GetCurrentInstance(env);
00879     if (pluginInstance == NULL) {
00880         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal JNIEnv (can't find plugin)");
00881         return NULL;
00882     }
00883 
00884     EvalMessage msg(pluginInstance, js_obj, script_ucs2, script_len, &jresult);
00885     sendMessage(env, &msg);
00886     
00887     if (jresult != NULL)
00888         jresult = ToLocalRef(env, jresult);
00889 
00890     env->ReleaseStringChars(script_jstr, script_ucs2);
00891 
00892     return jresult;
00893 }
00894 
00895 /*
00896  * Class:     netscape_javascript_JSObject
00897  * Method:    toString
00898  * Signature: ()Ljava/lang/String;
00899  */
00900 class ToStringMessage : public JavaMessage {
00901     MRJPluginInstance* mPluginInstance;
00902     jsobject mObject;
00903     jstring* mStringResult;
00904 public:
00905     ToStringMessage(MRJPluginInstance* pluginInstance, jsobject js_obj, jstring* stringResult)
00906         :   mPluginInstance(pluginInstance), mObject(js_obj), mStringResult(stringResult)
00907     {
00908     }
00909 
00910     virtual void execute(JNIEnv* env)
00911     {
00912         MRJSecurityContext* securityContext = getSecurityContext(mPluginInstance);
00913         nsILiveconnect* connection = getLiveconnectInstance(securityContext);
00914         jstring jresult = NULL;
00915         nsresult status = connection->ToString(env, mObject, &jresult);
00916         if (status == NS_OK && jresult != NULL)
00917             *mStringResult = (jstring) ToGlobalRef(env, jresult);
00918     }
00919 };
00920 
00921 JNIEXPORT jstring JNICALL
00922 Java_netscape_javascript_JSObject_toString(JNIEnv* env, jobject java_wrapper_obj)
00923 {
00924     /* unwrap the JS object from the Java object. */
00925     jstring jresult = NULL;
00926     jsobject js_obj = Unwrap_JSObject(env, java_wrapper_obj);
00927 
00928     MRJPluginInstance* pluginInstance = GetCurrentInstance(env);
00929     if (pluginInstance == NULL) {
00930         env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "illegal JNIEnv (can't find plugin)");
00931         return NULL;
00932     }
00933 
00934     ToStringMessage msg(pluginInstance, js_obj, &jresult);
00935     sendMessage(env, &msg);
00936     
00937     if (jresult != NULL)
00938         jresult = (jstring) ToLocalRef(env, jresult);
00939     
00940     return jresult;
00941 }
00942 
00943 /*
00944  * Class:     netscape_javascript_JSObject
00945  * Method:    getWindow
00946  * Signature: (Ljava/applet/Applet;)Lnetscape/javascript/JSObject;
00947  */
00948 class GetWindowMessage : public JavaMessage {
00949     MRJPluginInstance* mPluginInstance;
00950     jsobject* mWindowResult;
00951 public:
00952     GetWindowMessage(MRJPluginInstance* pluginInstance, jsobject* windowResult)
00953         :   mPluginInstance(pluginInstance), mWindowResult(windowResult)
00954     {
00955     }
00956     
00957     virtual void execute(JNIEnv* env)
00958     {
00959         MRJSecurityContext* securityContext = getSecurityContext(mPluginInstance);
00960         nsILiveconnect* connection = getLiveconnectInstance(securityContext);
00961         nsresult status = connection->GetWindow(env, mPluginInstance, NULL, 0, securityContext, mWindowResult);
00962     }
00963 };
00964 
00965 JNIEXPORT jobject JNICALL
00966 Java_netscape_javascript_JSObject_getWindow(JNIEnv* env,
00967                                             jclass js_object_class,
00968                                             jobject java_applet_obj)
00969 {
00970     MRJPluginInstance* pluginInstance = GetCurrentInstance(env, java_applet_obj);
00971     if (pluginInstance != NULL) {
00972         jsobject jswindow = NULL;
00973         GetWindowMessage msg(pluginInstance, &jswindow);
00974         sendMessage(env, &msg);
00975         
00976         if (jswindow != NULL)
00977             return Wrap_JSObject(env, jswindow);
00978     }
00979     return NULL;
00980 }
00981 
00982 /*
00983  * Class:     netscape_javascript_JSObject
00984  * Method:    finalize
00985  * Signature: ()V
00986  */
00987 class FinalizeMessage : public JavaMessage {
00988     jsobject m_jsobj;
00989 public:
00990     FinalizeMessage(jsobject jsobj)
00991         :   m_jsobj(jsobj)
00992     {
00993     }
00994 
00995     virtual void execute(JNIEnv* env)
00996     {
00997         nsresult result = theLiveConnectManager->FinalizeJSObject(env, m_jsobj);
00998     }
00999 };
01000 
01001 JNIEXPORT void JNICALL
01002 Java_netscape_javascript_JSObject_finalize(JNIEnv* env, jobject java_wrapper_obj)
01003 {
01004     jsobject jsobj = Unwrap_JSObject(env, java_wrapper_obj);
01005 
01006     FinalizeMessage msg(jsobj);
01007     sendMessage(env, &msg);
01008 }