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