Back to index

lightning-sunbird  0.9+nobinonly
nsCLiveconnect.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code, released
00017  * March 31, 1998.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 /*
00040  * This file is part of the Java-vendor-neutral implementation of LiveConnect
00041  *
00042  * It contains the implementation providing nsIFactory XP-COM interface.
00043  *
00044  */
00045 
00046 
00047 #include <stdlib.h>
00048 #include <string.h>
00049 #include "prtypes.h"
00050 #include "prprf.h"
00051 #include "prlog.h"
00052 
00053 #include "jsj_private.h"
00054 #include "jsjava.h"
00055 
00056 #include "jscntxt.h"        /* For js_ReportErrorAgain().*/
00057 
00058 #include "netscape_javascript_JSObject.h"   /* javah-generated headers */
00059 #include "nsISecurityContext.h"
00060 #include "nsIServiceManager.h"
00061 #include "nsIJSContextStack.h"
00062 
00063 PR_BEGIN_EXTERN_C
00064 
00065 /* A captured JavaScript error, created when JS_ReportError() is called while
00066    running JavaScript code that is itself called from Java. */
00067 struct CapturedJSError {
00068     char *              message;
00069     JSErrorReport       report;         /* Line # of error, etc. */
00070     jthrowable          java_exception; /* Java exception, error, or null */
00071     CapturedJSError *   next;                   /* Next oldest captured JS error */
00072 };
00073 PR_END_EXTERN_C
00074 
00075 #include "nsCLiveconnect.h"
00076 
00077 #include "jsinterp.h"  // XXX private API so we can auto-push a JSStackFrame
00078 #include "nsIScriptSecurityManager.h"
00079 #include "nsIPrincipal.h"
00080 #include "nsNetUtil.h"
00081 #include "nsISecurityContext.h"
00082 #include "prmem.h"
00083 
00084 /***************************************************************************/
00085 // A class to put on the stack to manage JS contexts when we are entering JS.
00086 // This pushes and pops the given context
00087 // with the nsThreadJSContextStack service as this object goes into and out
00088 // of scope. It is optimized to not push/pop the cx if it is already on top
00089 // of the stack. We need to push the JSContext when we enter JS because the
00090 // JS security manager looks on the context stack for permissions information.
00091 
00092 class AutoPushJSContext
00093 {
00094 public:
00095     AutoPushJSContext(nsISupports* aSecuritySupports,
00096                       JSContext *cx);
00097 
00098     ~AutoPushJSContext();
00099 
00100     nsresult ResultOfPush() { return mPushResult; };
00101 
00102 private:
00103     nsCOMPtr<nsIJSContextStack> mContextStack;
00104     JSContext*                  mContext;
00105     JSStackFrame                mFrame;
00106     nsresult                    mPushResult;
00107 };
00108 
00109 AutoPushJSContext::AutoPushJSContext(nsISupports* aSecuritySupports,
00110                                      JSContext *cx) 
00111                                      : mContext(cx), mPushResult(NS_OK)
00112 {
00113     nsCOMPtr<nsIJSContextStack> contextStack =
00114         do_GetService("@mozilla.org/js/xpc/ContextStack;1");
00115 
00116     JSContext* currentCX;
00117     if(contextStack &&
00118        // Don't push if the current context is already on the stack.
00119        (NS_FAILED(contextStack->Peek(&currentCX)) ||
00120         cx != currentCX) )
00121     {
00122         if (NS_SUCCEEDED(contextStack->Push(cx)))
00123         {
00124             // Leave the reference in mContextStack to
00125             // indicate that we need to pop it in our dtor.
00126             mContextStack.swap(contextStack);
00127         }
00128     }
00129 
00130     nsCOMPtr<nsIScriptSecurityManager> secMan(
00131         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &mPushResult));
00132 
00133     if (NS_FAILED(mPushResult))
00134         return;
00135 
00136     nsCOMPtr<nsIPrincipal> principal;
00137     mPushResult = secMan->GetPrincipalFromContext(cx, getter_AddRefs(principal));
00138 
00139     if (NS_FAILED(mPushResult))
00140     {
00141         JS_ReportError(cx, "failed to get a principal");
00142         return;
00143     }
00144 
00145     // See if JavaScript is enabled for the current window
00146     PRBool jsEnabled = PR_FALSE;
00147     mPushResult = secMan->CanExecuteScripts(cx, principal, &jsEnabled);
00148     if (!jsEnabled)
00149         mPushResult = NS_ERROR_FAILURE;
00150 
00151     memset(&mFrame, 0, sizeof(mFrame));
00152 
00153     if (NS_SUCCEEDED(mPushResult))
00154     {
00155         // See if there are any scripts on the stack.
00156         // If not, we need to add a dummy frame with a principal.
00157 
00158         PRBool hasScript = PR_FALSE;
00159         JSStackFrame* tempFP = cx->fp;
00160         while (tempFP)
00161         {
00162             if (tempFP->script)
00163             {
00164                 hasScript = PR_TRUE;
00165                 break;
00166             }
00167             tempFP = tempFP->down;
00168         };
00169 
00170         if (!hasScript)
00171         {
00172             JSPrincipals* jsprinc;
00173             principal->GetJSPrincipals(cx, &jsprinc);
00174 
00175             mFrame.script = JS_CompileScriptForPrincipals(cx, JS_GetGlobalObject(cx),
00176                                                           jsprinc, "", 0, "", 1);
00177             JSPRINCIPALS_DROP(cx, jsprinc);
00178 
00179             if (mFrame.script)
00180             {
00181                 mFrame.down = cx->fp;
00182                 cx->fp = &mFrame;
00183             }
00184             else
00185                 mPushResult = NS_ERROR_OUT_OF_MEMORY;
00186         }
00187     }
00188 }
00189 
00190 AutoPushJSContext::~AutoPushJSContext()
00191 {
00192     if (mContextStack)
00193         mContextStack->Pop(nsnull);
00194 
00195     if (mFrame.script)
00196         mContext->fp = mFrame.down;
00197 
00198 }
00199 
00200 
00202 // from nsISupports and AggregatedQueryInterface:
00203 
00204 // Thes macro expands to the aggregated query interface scheme.
00205 
00206 NS_IMPL_AGGREGATED(nsCLiveconnect)
00207 
00208 NS_METHOD
00209 nsCLiveconnect::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr)
00210 {
00211         NS_ENSURE_ARG_POINTER(aInstancePtr);
00212 
00213     if (aIID.Equals(NS_GET_IID(nsISupports))) {
00214       *aInstancePtr = GetInner();
00215     }
00216     else if (aIID.Equals(NS_GET_IID(nsILiveconnect))) {
00217         *aInstancePtr = NS_STATIC_CAST(nsILiveconnect*, this);
00218     }
00219         else  {
00220                 *aInstancePtr = nsnull;
00221                 return NS_NOINTERFACE;
00222         }
00223         NS_ADDREF((nsISupports*) *aInstancePtr);
00224         return NS_OK;
00225 }
00226 
00227 
00228 
00230 // from nsILiveconnect:
00231 
00243 NS_METHOD     
00244 nsCLiveconnect::GetMember(JNIEnv *jEnv, lcjsobject obj, const jchar *name, jsize length, void* principalsArray[], 
00245                      int numPrincipals, nsISupports *securitySupports, jobject *pjobj)
00246 {
00247     if(jEnv == NULL || obj == 0)
00248     {
00249        return NS_ERROR_FAILURE;
00250     }
00251 
00252     JSJavaThreadState *jsj_env        = NULL;
00253     JSObjectHandle    *handle         = (JSObjectHandle*)obj;
00254     JSObject          *js_obj         = handle->js_obj;
00255     JSContext         *cx             = NULL;
00256     jobject            member         = NULL;
00257     jsval              js_val;
00258     int                dummy_cost     = 0;
00259     JSBool             dummy_bool     = PR_FALSE;
00260     JSErrorReporter    saved_state    = NULL;
00261 
00262     jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, principalsArray, numPrincipals, securitySupports);
00263     if (!jsj_env)
00264         return NS_ERROR_FAILURE;
00265 
00266     AutoPushJSContext autopush(securitySupports, cx);
00267     if (NS_FAILED(autopush.ResultOfPush()))
00268         goto done;
00269 
00270     if (!name) {
00271         JS_ReportError(cx, "illegal null member name");
00272         member = NULL;
00273         goto done;
00274     }
00275     
00276     if (!JS_GetUCProperty(cx, js_obj, name, length, &js_val))
00277         goto done;
00278 
00279     jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
00280                                    &dummy_cost, &member, &dummy_bool);
00281 
00282 done:
00283     if (!jsj_exit_js(cx, jsj_env, saved_state))
00284         return NS_ERROR_FAILURE;
00285     
00286     *pjobj = member;
00287 
00288     return NS_OK;
00289 }
00290 
00291 
00301 NS_METHOD     
00302 nsCLiveconnect::GetSlot(JNIEnv *jEnv, lcjsobject obj, jint slot, void* principalsArray[], 
00303                      int numPrincipals, nsISupports *securitySupports,  jobject *pjobj)
00304 {
00305     if(jEnv == NULL || obj == 0)
00306     {
00307        return NS_ERROR_FAILURE;
00308     }
00309 
00310     JSJavaThreadState *jsj_env        = NULL;
00311     JSObjectHandle    *handle         = (JSObjectHandle*)obj;
00312     JSObject          *js_obj         = handle->js_obj;
00313     JSContext         *cx             = NULL;
00314     jobject            member         = NULL;
00315     jsval              js_val;
00316     int                dummy_cost     = 0;
00317     JSBool             dummy_bool     = PR_FALSE;
00318     JSErrorReporter    saved_state    = NULL;
00319 
00320     jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, principalsArray, numPrincipals, securitySupports);
00321     if (!jsj_env)
00322        return NS_ERROR_FAILURE;
00323 
00324     AutoPushJSContext autopush(securitySupports, cx);
00325     if (NS_FAILED(autopush.ResultOfPush()))
00326         goto done;
00327     
00328     // =-= sudu: check to see if slot can be passed in as is.
00329     //           Should it be converted to a jsint?
00330     if (!JS_GetElement(cx, js_obj, slot, &js_val))
00331         goto done;
00332     if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
00333                                         &dummy_cost, &member, &dummy_bool))
00334         goto done;
00335 
00336 done:
00337     if (!jsj_exit_js(cx, jsj_env, saved_state))
00338        return NS_ERROR_FAILURE;
00339     
00340     *pjobj = member;
00341     return NS_OK;
00342 }
00343 
00354 NS_METHOD     
00355 nsCLiveconnect::SetMember(JNIEnv *jEnv, lcjsobject obj, const jchar *name, jsize length, jobject java_obj, void* principalsArray[], 
00356                      int numPrincipals, nsISupports *securitySupports)
00357 {
00358     if(jEnv == NULL || obj == 0)
00359     {
00360        return NS_ERROR_FAILURE;
00361     }
00362 
00363     JSJavaThreadState *jsj_env        = NULL;
00364     JSObjectHandle    *handle         = (JSObjectHandle*)obj;
00365     JSObject          *js_obj         = handle->js_obj;
00366     JSContext         *cx             = NULL;
00367     jsval              js_val;
00368     JSErrorReporter    saved_state    = NULL;
00369 
00370     jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, principalsArray, numPrincipals, securitySupports);
00371     if (!jsj_env)
00372         return NS_ERROR_FAILURE;
00373 
00374     AutoPushJSContext autopush(securitySupports, cx);
00375     if (NS_FAILED(autopush.ResultOfPush()))
00376         goto done;
00377     
00378     if (!name) {
00379         JS_ReportError(cx, "illegal null member name");
00380         goto done;
00381     }
00382 
00383     if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_val))
00384         goto done;
00385 
00386     JS_SetUCProperty(cx, js_obj, name, length, &js_val);
00387 
00388 done:
00389     jsj_exit_js(cx, jsj_env, saved_state);
00390    return NS_OK;
00391 }
00392 
00393 
00404 NS_METHOD     
00405 nsCLiveconnect::SetSlot(JNIEnv *jEnv, lcjsobject obj, jint slot, jobject java_obj,  void* principalsArray[], 
00406                      int numPrincipals, nsISupports *securitySupports)
00407 {
00408     if(jEnv == NULL || obj == 0)
00409     {
00410        return NS_ERROR_FAILURE;
00411     }
00412 
00413     JSJavaThreadState *jsj_env        = NULL;
00414     JSObjectHandle    *handle         = (JSObjectHandle*)obj;
00415     JSObject          *js_obj         = handle->js_obj;
00416     JSContext         *cx             = NULL;
00417     jsval              js_val;
00418     JSErrorReporter    saved_state    = NULL;
00419 
00420     jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, principalsArray, numPrincipals, securitySupports);
00421     if (!jsj_env)
00422         return NS_ERROR_FAILURE;
00423 
00424     AutoPushJSContext autopush(securitySupports, cx);
00425     if (NS_FAILED(autopush.ResultOfPush()))
00426         goto done;
00427     
00428     if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_val))
00429         goto done;
00430     JS_SetElement(cx, js_obj, slot, &js_val);
00431 
00432 done:
00433     jsj_exit_js(cx, jsj_env, saved_state);
00434     return NS_OK;
00435 }
00436 
00437 
00445 NS_METHOD     
00446 nsCLiveconnect::RemoveMember(JNIEnv *jEnv, lcjsobject obj, const jchar *name, jsize length,  void* principalsArray[], 
00447                              int numPrincipals, nsISupports *securitySupports)
00448 {
00449     if(jEnv == NULL || obj == 0)
00450     {
00451        return NS_ERROR_FAILURE;
00452     }
00453 
00454     JSJavaThreadState *jsj_env        = NULL;
00455     JSObjectHandle    *handle         = (JSObjectHandle*)obj;
00456     JSObject          *js_obj         = handle->js_obj;
00457     JSContext         *cx             = NULL;
00458     jsval              js_val;
00459     JSErrorReporter    saved_state    = NULL;
00460 
00461     jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, principalsArray, numPrincipals, securitySupports);
00462     if (!jsj_env)
00463         return NS_ERROR_FAILURE;
00464 
00465     AutoPushJSContext autopush(securitySupports, cx);
00466     if (NS_FAILED(autopush.ResultOfPush()))
00467         goto done;
00468     
00469     if (!name) {
00470         JS_ReportError(cx, "illegal null member name");
00471         goto done;
00472     }
00473 
00474     JS_DeleteUCProperty2(cx, js_obj, name, length, &js_val);
00475 
00476 done:
00477     jsj_exit_js(cx, jsj_env, saved_state);
00478     return NS_OK;
00479 }
00480 
00481 
00491 NS_METHOD     
00492 nsCLiveconnect::Call(JNIEnv *jEnv, lcjsobject obj, const jchar *name, jsize length, jobjectArray java_args, void* principalsArray[], 
00493                      int numPrincipals, nsISupports *securitySupports, jobject *pjobj)
00494 {
00495     if(jEnv == NULL || obj == 0)
00496     {
00497        return NS_ERROR_FAILURE;
00498     }
00499 
00500     int                i              = 0;
00501     int                argc           = 0;
00502     int                arg_num        = 0;
00503     jsval             *argv           = 0;
00504     JSJavaThreadState *jsj_env        = NULL;
00505     JSObjectHandle    *handle         = (JSObjectHandle*)obj;
00506     JSObject          *js_obj         = handle->js_obj;
00507     JSContext         *cx             = NULL;
00508     jsval              js_val;
00509     jsval              function_val   = 0;
00510     int                dummy_cost     = 0;
00511     JSBool             dummy_bool     = PR_FALSE;
00512     JSErrorReporter    saved_state    = NULL;
00513     jobject            result         = NULL;
00514 
00515     jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, principalsArray, numPrincipals, securitySupports);
00516     if (!jsj_env)
00517         return NS_ERROR_FAILURE;
00518 
00519     result = NULL;
00520     AutoPushJSContext autopush(securitySupports, cx);
00521     if (NS_FAILED(autopush.ResultOfPush()))
00522         goto done;
00523     
00524     if (!name) {
00525         JS_ReportError(cx, "illegal null JavaScript function name");
00526         goto done;
00527     }
00528 
00529     /* Allocate space for JS arguments */
00530     argc = java_args ? jEnv->GetArrayLength(java_args) : 0;
00531     if (argc) {
00532         argv = (jsval*)JS_malloc(cx, argc * sizeof(jsval));
00533         if (!argv)
00534             goto done;
00535     } else {
00536         argv = 0;
00537     }
00538 
00539     /* Convert arguments from Java to JS values */
00540     for (arg_num = 0; arg_num < argc; arg_num++) {
00541         jobject arg = jEnv->GetObjectArrayElement(java_args, arg_num);
00542         JSBool ret = jsj_ConvertJavaObjectToJSValue(cx, jEnv, arg, &argv[arg_num]);
00543               
00544         jEnv->DeleteLocalRef(arg);
00545         if (!ret)
00546             goto cleanup_argv;
00547         JS_AddRoot(cx, &argv[arg_num]);
00548     }
00549 
00550     if (!JS_GetUCProperty(cx, js_obj, name, length, &function_val))
00551         goto cleanup_argv;
00552 
00553     if (!JS_CallFunctionValue(cx, js_obj, function_val, argc, argv, &js_val))
00554         goto cleanup_argv;
00555 
00556     jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
00557                                    &dummy_cost, &result, &dummy_bool);
00558 
00559 cleanup_argv:
00560     if (argv) {
00561         for (i = 0; i < arg_num; i++)
00562             JS_RemoveRoot(cx, &argv[i]);
00563         JS_free(cx, argv);
00564     }
00565 
00566 done:
00567     if (!jsj_exit_js(cx, jsj_env, saved_state))
00568         return NS_ERROR_FAILURE;
00569     
00570     *pjobj = result;
00571 
00572     return NS_OK;
00573 }
00574 
00575 NS_METHOD     
00576 nsCLiveconnect::Eval(JNIEnv *jEnv, lcjsobject obj, const jchar *script, jsize length, void* principalsArray[], 
00577                      int numPrincipals, nsISupports *securitySupports, jobject *pjobj)
00578 {
00579     if(jEnv == NULL || obj == 0)
00580     {
00581        return NS_ERROR_FAILURE;
00582     }
00583 
00584     JSJavaThreadState *jsj_env        = NULL;
00585     JSObjectHandle    *handle         = (JSObjectHandle*)obj;
00586     JSObject          *js_obj         = handle->js_obj;
00587     JSContext         *cx             = NULL;
00588     jsval              js_val;
00589     int                dummy_cost     = 0;
00590     JSBool             dummy_bool     = PR_FALSE;
00591     JSErrorReporter    saved_state    = NULL;
00592     jobject            result         = NULL;
00593        const char             *codebase       = NULL;
00594     JSPrincipals      *principals     = NULL;
00595     JSBool             eval_succeeded = PR_FALSE;
00596 
00597     jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, principalsArray, numPrincipals, securitySupports);
00598     if (!jsj_env)
00599        return NS_ERROR_FAILURE;
00600 
00601     result = NULL;
00602     AutoPushJSContext autopush(securitySupports, cx);
00603     if (NS_FAILED(autopush.ResultOfPush()))
00604         goto done;
00605     
00606     if (!script) {
00607         JS_ReportError(cx, "illegal null string eval argument");
00608         goto done;
00609     }
00610 
00611     /* Set up security stuff */
00612     if (JSJ_callbacks && JSJ_callbacks->get_JSPrincipals_from_java_caller)
00613         principals = JSJ_callbacks->get_JSPrincipals_from_java_caller(jEnv, cx, principalsArray, numPrincipals, securitySupports);
00614     codebase = principals ? principals->codebase : NULL;
00615 
00616     /* Have the JS engine evaluate the unicode string */
00617     eval_succeeded = JS_EvaluateUCScriptForPrincipals(cx, js_obj, principals,
00618                                                       script, length,
00619                                                       codebase, 0, &js_val);
00620 
00621     if (!eval_succeeded)
00622         goto done;
00623 
00624     /* Convert result to a subclass of java.lang.Object */
00625     jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
00626                                    &dummy_cost, &result, &dummy_bool);
00627 
00628 done:
00629     if (principals)
00630         JSPRINCIPALS_DROP(cx, principals);
00631     if (!jsj_exit_js(cx, jsj_env, saved_state))
00632        return NS_ERROR_FAILURE;
00633     
00634     *pjobj = result;
00635     return NS_OK;
00636 }
00637 
00638 
00649 NS_METHOD     
00650 nsCLiveconnect::GetWindow(JNIEnv *jEnv, void *pJavaObject,  void* principalsArray[], 
00651                      int numPrincipals, nsISupports *securitySupports, lcjsobject *pobj)
00652 {
00653     if(jEnv == NULL || JSJ_callbacks == NULL)
00654     {
00655        return NS_ERROR_FAILURE;
00656     }
00657 
00658     // associate this Java client with this LiveConnect connection.
00659     mJavaClient = pJavaObject;
00660 
00661     char              *err_msg        = NULL;
00662     JSContext         *cx             = NULL;
00663     JSObject          *js_obj         = NULL;
00664     JSErrorReporter    saved_state    = NULL;
00665     JSJavaThreadState *jsj_env        = NULL;
00666     JSObjectHandle    *handle         = NULL;
00667 
00668     jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, principalsArray, numPrincipals, securitySupports);
00669     if (!jsj_env)
00670        return NS_ERROR_FAILURE;
00671 
00672     err_msg = NULL;
00673     AutoPushJSContext autopush(securitySupports, cx);
00674     if (NS_FAILED(autopush.ResultOfPush()))
00675         goto done;
00676     
00677     js_obj = JSJ_callbacks->map_java_object_to_js_object(jEnv, mJavaClient, &err_msg);
00678     if (!js_obj) {
00679         if (err_msg) {
00680             JS_ReportError(cx, err_msg);
00681             free(err_msg);
00682         }
00683         goto done;
00684     }
00685 #ifdef PRESERVE_JSOBJECT_IDENTITY
00686     *pobj = (jint)js_obj;
00687 #else
00688        /* FIXME:  to handle PRESERVE_JSOBJECT_IDENTITY case, this needs to
00689     just return a raw JSObject reference. FIXME !!! */
00690     /* Create a tiny stub object to act as the GC root that points to the
00691        JSObject from its netscape.javascript.JSObject counterpart. */
00692     handle = (JSObjectHandle*)JS_malloc(cx, sizeof(JSObjectHandle));
00693     if (handle != NULL)
00694     {
00695       handle->js_obj = js_obj;
00696       handle->rt = JS_GetRuntime(cx);
00697     }
00698     *pobj = (lcjsobject)handle;
00699     /* FIXME:  what if the window is explicitly disposed of, how do we
00700        notify Java? */
00701 #endif
00702 done:
00703     if (!jsj_exit_js(cx, jsj_env, saved_state))
00704        return NS_ERROR_FAILURE;
00705 
00706     return NS_OK;
00707 }
00708 
00715 NS_METHOD     
00716 nsCLiveconnect::FinalizeJSObject(JNIEnv *jEnv, lcjsobject obj)
00717 {
00718     if(jEnv == NULL || obj == 0)
00719     {
00720        return NS_ERROR_FAILURE;
00721     }
00722 
00723     JSObjectHandle    *handle         = (JSObjectHandle *)obj;
00724     
00725     if (!handle)
00726         return NS_ERROR_NULL_POINTER;
00727     JS_RemoveRootRT(handle->rt, &handle->js_obj);
00728     free(handle);
00729     return NS_OK;
00730 }
00731 
00732 
00733 NS_METHOD     
00734 nsCLiveconnect::ToString(JNIEnv *jEnv, lcjsobject obj, jstring *pjstring)
00735 {
00736     if(jEnv == NULL || obj == 0)
00737     {
00738        return NS_ERROR_FAILURE;
00739     }
00740 
00741     JSJavaThreadState *jsj_env        = NULL;
00742     JSObjectHandle    *handle         = (JSObjectHandle*)obj;
00743     JSObject          *js_obj         = handle->js_obj;
00744     JSContext         *cx             = NULL;
00745     JSErrorReporter    saved_state    = NULL;
00746     jstring            result         = NULL;
00747     JSString          *jsstr          = NULL;
00748 
00749     jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, NULL, 0, NULL );
00750     if (!jsj_env)
00751        return NS_ERROR_FAILURE;
00752 
00753     result = NULL;
00754     AutoPushJSContext autopush(nsnull, cx);
00755     if (NS_FAILED(autopush.ResultOfPush()))
00756         return NS_ERROR_FAILURE;
00757 
00758     jsstr = JS_ValueToString(cx, OBJECT_TO_JSVAL(js_obj));
00759     if (jsstr)
00760         result = jsj_ConvertJSStringToJavaString(cx, jEnv, jsstr);
00761     if (!result)
00762         result = jEnv->NewStringUTF("*JavaObject*");
00763 
00764     if (!jsj_exit_js(cx, jsj_env, saved_state))
00765         return NS_ERROR_FAILURE;
00766     *pjstring = result;     
00767     return NS_OK;
00768 }
00769 
00770 
00772 // from nsCLiveconnect:
00773 
00774 nsCLiveconnect::nsCLiveconnect(nsISupports *aOuter)
00775     :   mJavaClient(NULL)
00776 {
00777     NS_INIT_AGGREGATED(aOuter);
00778 #ifdef PRESERVE_JSOBJECT_IDENTITY
00779     jsj_init_js_obj_reflections_table();
00780 #endif
00781 }
00782 
00783 nsCLiveconnect::~nsCLiveconnect()
00784 {
00785 }