Back to index

lightning-sunbird  0.9+nobinonly
nsJVMManager.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.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK *****
00038  *
00039  *
00040  * This Original Code has been modified by IBM Corporation.
00041  * Modifications made by IBM described herein are
00042  * Copyright (c) International Business Machines
00043  * Corporation, 2000
00044  *
00045  * Modifications to Mozilla code or documentation
00046  * identified per MPL Section 3.3
00047  *
00048  * Date         Modified by     Description of modification
00049  * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
00050  *                               use in OS2
00051  */
00052 
00054 // Plugin Manager Methods to support the JVM Plugin API
00056 
00057 #include "nscore.h"
00058 #include "nsJVMManager.h"
00059 #include "nspr.h"
00060 #include "ProxyJNI.h"
00061 #include "nsIPluginHost.h"
00062 #include "nsIServiceManager.h"
00063 #include "nsIEventQueueService.h"
00064 
00065 // All these interfaces are necessary just to get the damn
00066 // nsIWebBrowserChrome to send the "Starting Java" message to the status
00067 // bar.
00068 #include "nsIWindowWatcher.h"
00069 #include "nsIDOMWindow.h"
00070 #include "nsIScriptGlobalObject.h"
00071 #include "nsPresContext.h"
00072 #include "nsIDocShell.h"
00073 #include "nsIDocShellTreeItem.h"
00074 #include "nsIDocShellTreeOwner.h"
00075 #include "nsIWebBrowserChrome.h"
00076 #include "nsIInterfaceRequestor.h"
00077 #include "nsIInterfaceRequestorUtils.h"
00078 
00079 #include "nsIStringBundle.h"
00080 
00081 #include "nsIObserver.h"
00082 #include "nsIPrefBranch.h"
00083 #include "nsIPrefBranch2.h"
00084 #include "nsIPrefService.h"
00085 #include "lcglue.h"
00086 
00087 #include "nspr.h"
00088 #include "plstr.h"
00089 #include "nsCOMPtr.h"
00090 #include "nsIPrincipal.h"
00091 #include "nsIScriptSecurityManager.h"
00092 #include "nsISignatureVerifier.h"
00093 
00094 
00095 extern "C" int XP_PROGRESS_STARTING_JAVA;
00096 extern "C" int XP_PROGRESS_STARTING_JAVA_DONE;
00097 extern "C" int XP_JAVA_NO_CLASSES;
00098 extern "C" int XP_JAVA_GENERAL_FAILURE;
00099 extern "C" int XP_JAVA_STARTUP_FAILED;
00100 extern "C" int XP_JAVA_DEBUGGER_FAILED;
00101 
00102 static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
00103 
00104 static NS_DEFINE_CID(kJVMManagerCID, NS_JVMMANAGER_CID);
00105 
00106 static NS_DEFINE_CID(kPluginManagerCID, NS_PLUGINMANAGER_CID);
00107 
00108 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00109 
00110 // FIXME -- need prototypes for these functions!!! XXX
00111 #ifdef XP_MAC
00112 extern "C" {
00113 OSErr ConvertUnixPathToMacPath(const char *, char **);
00114 void startAsyncCursors(void);
00115 void stopAsyncCursors(void);
00116 }
00117 #endif // XP_MAC
00118 
00119 static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
00120 static NS_DEFINE_IID(kIJVMManagerIID, NS_IJVMMANAGER_IID);
00121 static NS_DEFINE_IID(kIThreadManagerIID, NS_ITHREADMANAGER_IID);
00122 static NS_DEFINE_IID(kILiveConnectManagerIID, NS_ILIVECONNECTMANAGER_IID);
00123 static NS_DEFINE_IID(kIJVMPluginIID, NS_IJVMPLUGIN_IID);
00124 
00125 #define PLUGIN_REGIONAL_URL "chrome://global-region/locale/region.properties"
00126 
00128 
00129 NS_IMPL_AGGREGATED(nsJVMManager)
00130 
00131 extern "C" {
00132 static nsIJVMPlugin* GetRunningJVM(void);
00133 static nsIJVMPlugin*
00134 GetRunningJVM()
00135 {
00136     nsIJVMPlugin* jvm = NULL;
00137     nsresult rv;
00138     nsCOMPtr<nsIJVMManager> managerService = do_GetService(kJVMManagerCID, &rv);
00139     if (NS_FAILED(rv)) return jvm;
00140     nsJVMManager* jvmMgr = (nsJVMManager *)managerService.get();
00141     if (jvmMgr) {
00142         nsJVMStatus status = jvmMgr->GetJVMStatus();
00143         if (status == nsJVMStatus_Enabled)
00144             status = jvmMgr->StartupJVM();
00145         if (status == nsJVMStatus_Running) {
00146             jvm = jvmMgr->GetJVMPlugin();
00147         }
00148     }
00149     return jvm;
00150 }
00151 }
00152 
00153 NS_METHOD
00154 nsJVMManager::CreateProxyJNI(nsISecureEnv* inSecureEnv, JNIEnv** outProxyEnv)
00155 {
00156        JVMContext* context = GetJVMContext();
00157        if (context->proxyEnv != NULL) {
00158               *outProxyEnv = context->proxyEnv;
00159               return NS_OK;
00160        }
00161     nsIJVMPlugin* jvmPlugin = GetRunningJVM();
00162        if (jvmPlugin != NULL) {
00163               *outProxyEnv = context->proxyEnv = ::CreateProxyJNI(jvmPlugin, inSecureEnv);
00164               return NS_OK;
00165        }
00166        return NS_ERROR_FAILURE;
00167 }
00168 
00169 NS_METHOD
00170 nsJVMManager::GetProxyJNI(JNIEnv** outProxyEnv)
00171 {
00172         // Get proxy JNI, if not created yet, create it.
00173         *outProxyEnv = JVM_GetJNIEnv();
00174        return NS_OK;
00175 }
00176 
00177 NS_METHOD
00178 nsJVMManager::GetJavaEnabled(PRBool* outEnabled)
00179 {
00180        nsJVMStatus status = GetJVMStatus();
00181        *outEnabled = (status == nsJVMStatus_Enabled || status == nsJVMStatus_Running);
00182        return NS_OK;
00183 }
00184 
00185 NS_METHOD
00186 nsJVMManager::ShowJavaConsole(void)
00187 {
00188     nsresult rv;
00189     nsCOMPtr<nsIWebBrowserChrome> chrome;
00190     nsAutoString  msg; 
00191     
00192     if (!fStartupMessagePosted) {
00193         PRUnichar *messageUni;
00194         nsCOMPtr<nsIStringBundleService> strings(do_GetService(kStringBundleServiceCID));
00195         nsCOMPtr<nsIStringBundle> regionalBundle;
00196         
00197         rv = this->GetChrome(getter_AddRefs(chrome));
00198         if (NS_SUCCEEDED(rv) && chrome && strings) {
00199             rv = strings->CreateBundle(PLUGIN_REGIONAL_URL, 
00200                                        getter_AddRefs(regionalBundle));
00201             if (NS_SUCCEEDED(rv) && regionalBundle) {
00202                 // pluginStartupMessage is something like "Starting
00203                 // plugin for type"
00204                 rv = regionalBundle->GetStringFromName(NS_LITERAL_STRING("pluginStartupMessage").get(), 
00205                                                        &messageUni);
00206                 if (NS_SUCCEEDED(rv) && messageUni) {
00207                     msg = messageUni;
00208                     nsMemory::Free((void *)messageUni);
00209                     
00210                     msg.Append(PRUnichar(' '));
00211                     msg.AppendLiteral("application/x-java-vm");
00212                     chrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT, 
00213                                       msg.get());
00214                 }
00215             }
00216         }
00217     } // !fStartupMessagePosted
00218 
00219     JVM_ShowConsole();
00220     // clear the startup message, if one was posted
00221     if (!fStartupMessagePosted && chrome) {
00222         msg.Truncate();
00223         chrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT, 
00224                           msg.get());
00225         fStartupMessagePosted = PR_TRUE;
00226     }
00227         
00228     return NS_OK;
00229 }
00230     
00231 // nsIThreadManager:
00232 
00233 NS_METHOD
00234 nsJVMManager::GetCurrentThread(PRThread* *threadID)
00235 {
00236        *threadID = PR_GetCurrentThread();
00237        return NS_OK;
00238 }
00239 
00240 NS_METHOD
00241 nsJVMManager::Sleep(PRUint32 milli)
00242 {
00243        PRIntervalTime ticks = (milli > 0 ? PR_MillisecondsToInterval(milli) : PR_INTERVAL_NO_WAIT);
00244        return (PR_Sleep(ticks) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE);
00245 }
00246 
00247 NS_METHOD
00248 nsJVMManager::EnterMonitor(void* address)
00249 {
00250        return (PR_CEnterMonitor(address) != NULL ? NS_OK : NS_ERROR_FAILURE);
00251 }
00252 
00253 NS_METHOD
00254 nsJVMManager::ExitMonitor(void* address)
00255 {
00256        return (PR_CExitMonitor(address) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE);
00257 }
00258 
00259 NS_METHOD
00260 nsJVMManager::Wait(void* address, PRUint32 milli)
00261 {
00262        PRIntervalTime timeout = (milli > 0 ? PR_MillisecondsToInterval(milli) : PR_INTERVAL_NO_TIMEOUT);
00263        return (PR_CWait(address, timeout) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE);
00264 }
00265 
00266 NS_METHOD
00267 nsJVMManager::Notify(void* address)
00268 {
00269        return (PR_CNotify(address) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE);
00270 }
00271 
00272 NS_METHOD
00273 nsJVMManager::NotifyAll(void* address)
00274 {
00275        return (PR_CNotifyAll(address) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE);
00276 }
00277 
00278 static void PR_CALLBACK thread_starter(void* arg)
00279 {
00280        nsIRunnable* runnable = (nsIRunnable*) arg;
00281        if (runnable != NULL) {
00282               runnable->Run();
00283        }
00284 }
00285 
00286 NS_METHOD
00287 nsJVMManager::CreateThread(PRThread **outThread, nsIRunnable* runnable)
00288 {
00289        PRThread* thread = PR_CreateThread(PR_USER_THREAD, &thread_starter, (void*) runnable,
00290                                                                PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
00291        *outThread = thread;
00292        return (thread != NULL ?  NS_OK : NS_ERROR_FAILURE);
00293 }
00294 
00295 struct JVMRunnableEvent : PLEvent {
00296        JVMRunnableEvent(nsIRunnable* runnable);
00297        ~JVMRunnableEvent();
00298 
00299        nsIRunnable* mRunnable;     
00300 };
00301 
00302 static void PR_CALLBACK
00303 handleRunnableEvent(JVMRunnableEvent* aEvent)
00304 {
00305        aEvent->mRunnable->Run();
00306 }
00307 
00308 static void PR_CALLBACK
00309 destroyRunnableEvent(JVMRunnableEvent* aEvent)
00310 {
00311        delete aEvent;
00312 }
00313 
00314 JVMRunnableEvent::JVMRunnableEvent(nsIRunnable* runnable)
00315        :      mRunnable(runnable)
00316 {
00317        NS_ADDREF(mRunnable);
00318        PL_InitEvent(this, nsnull, PLHandleEventProc(handleRunnableEvent), PLDestroyEventProc(&destroyRunnableEvent));
00319 }
00320 
00321 JVMRunnableEvent::~JVMRunnableEvent()
00322 {
00323        NS_RELEASE(mRunnable);
00324 }
00325 
00326 NS_METHOD
00327 nsJVMManager::PostEvent(PRThread* thread, nsIRunnable* runnable, PRBool async)
00328 {
00329     nsresult rv;
00330     nsCOMPtr<nsIEventQueueService> eventService = 
00331              do_GetService(kEventQueueServiceCID, &rv);
00332     if (NS_FAILED(rv)) return rv;
00333 
00334     nsCOMPtr<nsIEventQueue> eventQueue = NULL;
00335     rv = eventService->GetThreadEventQueue(thread, getter_AddRefs(eventQueue));
00336     if (NS_FAILED(rv)) return rv;
00337 
00338     JVMRunnableEvent* runnableEvent = new JVMRunnableEvent(runnable);
00339     if (runnableEvent == nsnull)
00340         return NS_ERROR_OUT_OF_MEMORY;
00341     if (async)
00342         eventQueue->PostEvent(runnableEvent);
00343     else
00344         eventQueue->PostSynchronousEvent(runnableEvent, nsnull);
00345     return rv;
00346 }
00347 
00348 NS_METHOD
00349 nsJVMManager::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
00350 {
00351         if (!aInstancePtr)
00352                 return NS_ERROR_INVALID_POINTER;
00353         *aInstancePtr = nsnull;
00354 
00355     if (outer && !aIID.Equals(kISupportsIID))
00356         return NS_ERROR_INVALID_ARG; 
00357     nsJVMManager* jvmmgr = new nsJVMManager(outer);
00358     if (jvmmgr == NULL)
00359         return NS_ERROR_OUT_OF_MEMORY;
00360 
00361         nsresult rv = jvmmgr->AggregatedQueryInterface(aIID, aInstancePtr);
00362         if(NS_FAILED(rv))
00363                 delete jvmmgr;
00364 
00365         return rv;
00366 }
00367 
00368 nsJVMManager::nsJVMManager(nsISupports* outer)
00369     : fJVM(NULL), fStatus(nsJVMStatus_Enabled),
00370       fDebugManager(NULL), fJSJavaVM(NULL),
00371       fClassPathAdditions(new nsVoidArray()), fClassPathAdditionsString(NULL),
00372       fStartupMessagePosted(PR_FALSE)
00373 {
00374     NS_INIT_AGGREGATED(outer);
00375 
00376     nsCOMPtr<nsIPrefBranch2> branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
00377     if (branch) {
00378         branch->AddObserver("security.enable_java", this, PR_FALSE);
00379         PRBool prefBool = PR_TRUE;
00380         nsresult rv = branch->GetBoolPref("security.enable_java", &prefBool);
00381         if (NS_SUCCEEDED(rv)) {
00382             SetJVMEnabled(prefBool);
00383         }
00384     }
00385 }
00386 
00387 nsJVMManager::~nsJVMManager()
00388 {
00389     int count = fClassPathAdditions->Count();
00390     for (int i = 0; i < count; i++) {
00391         PR_Free((*fClassPathAdditions)[i]);
00392     }
00393     delete fClassPathAdditions;
00394     if (fClassPathAdditionsString)
00395         PR_Free(fClassPathAdditionsString);
00396     if (fJVM) {
00397         /*nsrefcnt c =*/ fJVM->Release();   // Release for QueryInterface in GetJVM
00398         // XXX unload plugin if c == 1 ? (should this be done inside Release?)
00399     }
00400 }
00401 
00402 NS_METHOD
00403 nsJVMManager::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr)
00404 {
00405     if (aIID.Equals(kIJVMManagerIID)) {
00406         *aInstancePtr = this;
00407         NS_ADDREF_THIS();
00408         return NS_OK;
00409     }
00410     if (aIID.Equals(kIThreadManagerIID)) {
00411         *aInstancePtr = (void*) NS_STATIC_CAST(nsIThreadManager*, this);
00412         NS_ADDREF_THIS();
00413         return NS_OK;
00414     }
00415     if (aIID.Equals(kILiveConnectManagerIID)) {
00416         *aInstancePtr = (void*) NS_STATIC_CAST(nsILiveConnectManager*, this);
00417         NS_ADDREF_THIS();
00418         return NS_OK;
00419     }
00420     if (aIID.Equals(kISupportsIID)) {
00421         *aInstancePtr = GetInner();
00422         NS_ADDREF((nsISupports*)*aInstancePtr);
00423         return NS_OK;
00424     }
00425     if (aIID.Equals(NS_GET_IID(nsIObserver))) {
00426         *aInstancePtr = (void*) NS_STATIC_CAST(nsIObserver*, this);
00427         NS_ADDREF_THIS();
00428         return NS_OK;
00429     }
00430 #if defined(XP_WIN) || defined(XP_OS2)
00431     // Aggregates...
00432     if (fDebugManager == NULL) {
00433         nsresult rslt =
00434             nsSymantecDebugManager::Create((nsIJVMManager *)this, kISupportsIID,
00435                                            (void**)&fDebugManager, this);
00436         if (rslt != NS_OK) return rslt;
00437     }
00438     return fDebugManager->QueryInterface(aIID, aInstancePtr);
00439 #else
00440     return NS_NOINTERFACE;
00441 #endif
00442 }
00443 
00445 
00446 NS_METHOD
00447 nsJVMManager::InitLiveConnectClasses(JSContext* context, JSObject* globalObject)
00448 {
00449        return (JSJ_InitJSContext(context, globalObject, NULL) ? NS_OK : NS_ERROR_FAILURE);
00450 }
00451 
00453 
00454 NS_METHOD
00455 nsJVMManager::WrapJavaObject(JSContext* context, jobject javaObject, JSObject* *outJSObject)
00456 {
00457        if (NULL == outJSObject) {
00458               return NS_ERROR_NULL_POINTER; 
00459        }
00460        jsval val;
00461        if (JSJ_ConvertJavaObjectToJSValue(context, javaObject, &val)) {
00462               *outJSObject = JSVAL_TO_OBJECT(val);
00463               return NS_OK;
00464        }
00465        return NS_ERROR_FAILURE;
00466 }
00467 
00469 
00470 NS_METHOD
00471 nsJVMManager::GetClasspathAdditions(const char* *result)
00472 {
00473     if (fClassPathAdditionsString != NULL)
00474         PR_Free(fClassPathAdditionsString);
00475     int count = fClassPathAdditions->Count();
00476     char* classpathAdditions = NULL;
00477     for (int i = 0; i < count; i++) {
00478         const char* path = (const char*)(*fClassPathAdditions)[i];
00479         char* oldPath = classpathAdditions;
00480         if (oldPath) {
00481             char sep = PR_GetPathSeparator();
00482             classpathAdditions = PR_smprintf("%s%c%s", oldPath, sep, path);
00483             PR_Free(oldPath);
00484         }
00485         else
00486             classpathAdditions = PL_strdup(path);
00487     }
00488     fClassPathAdditionsString = classpathAdditions;
00489     *result = classpathAdditions;  // XXX need to convert to PRUnichar*
00490     return classpathAdditions ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00491 }
00492 
00494 
00495 #if 0
00496 static const char*
00497 ConvertToPlatformPathList(const char* cp)
00498 {
00499     const char* c = strdup(cp);
00500     if (c == NULL)
00501         return NULL;
00502 #ifdef XP_MAC
00503     {
00504         const char* path;
00505         const char* strtok_path;
00506               
00507         char* result = (char*) malloc(1);
00508         if (result == NULL)
00509             return NULL;
00510         result[0] = '\0';
00511         path = c;
00512         strtok_path = path;
00513         while ((path = XP_STRTOK(strtok_path, PR_PATH_SEPARATOR_STR)))
00514         {
00515             const char* macPath;
00516             OSErr err = ConvertUnixPathToMacPath(path, &macPath);
00517             char* r = PR_smprintf("%s\r%s", result, macPath);
00518                      
00519             strtok_path = NULL;
00520 
00521             if (r == NULL)
00522                 return result;     /* return what we could come up with */
00523             free(result);
00524             result = r;
00525         }
00526         free(c);
00527         return result;
00528     }
00529 #else
00530     return c;
00531 #endif
00532 }
00533 
00534 void
00535 nsJVMManager::ReportJVMError(nsresult err)
00536 {
00537     MWContext* cx = XP_FindSomeContext();
00538     char *s = NULL;
00539     switch (err) {
00540       case NS_JVM_ERROR_NO_CLASSES: {
00541           s = PR_smprintf(XP_GetString(XP_JAVA_NO_CLASSES));
00542           break;
00543       }
00544 
00545       case NS_JVM_ERROR_JAVA_ERROR: {
00546           nsIJVMPlugin* plugin = GetJVMPlugin();
00547           PR_ASSERT(plugin != NULL);
00548           if (plugin == NULL) break;
00549           JNIEnv* env;
00550           plugin->GetJNIEnv(&env);
00551           const char* msg = GetJavaErrorString(env);
00552           plugin->ReleaseJNIEnv(env);
00553 #ifdef DEBUG
00554                 env->ExceptionDescribe();
00555 #endif
00556           s = PR_smprintf(XP_GetString(XP_JAVA_STARTUP_FAILED), 
00557                           (msg ? msg : ""));
00558           if (msg) free((void*)msg);
00559           break;
00560       }
00561 
00562       case NS_JVM_ERROR_NO_DEBUGGER: {
00563           s = PR_smprintf(XP_GetString(XP_JAVA_DEBUGGER_FAILED));
00564           break;
00565       }
00566 
00567       default: {
00568           s = PR_smprintf(XP_GetString(XP_JAVA_GENERAL_FAILURE), err);
00569           break;
00570       }
00571     }
00572     if (s) {
00573         FE_Alert(cx, s);
00574         free(s);
00575     }
00576 }
00577 /* stolen from java_lang_Object.h (jri version) */
00578 #define classname_java_lang_Object "java/lang/Object"
00579 #define name_java_lang_Object_toString    "toString"
00580 #define sig_java_lang_Object_toString     "()Ljava/lang/String;"
00581 
00582 const char*
00583 nsJVMManager::GetJavaErrorString(JNIEnv* env)
00584 {
00585     jthrowable exc = env->ExceptionOccurred();
00586     if (exc == NULL) {
00587         return strdup("");  /* XXX better "no error" message? */
00588     }
00589 
00590     /* Got to do this before trying to find a class (like Object). 
00591        This is because the runtime refuses to do this with a pending 
00592        exception! I think it's broken. */
00593 
00594     env->ExceptionClear();
00595 
00596     jclass classObject = env->FindClass(classname_java_lang_Object);
00597     jmethodID toString = env->GetMethodID(classObject, name_java_lang_Object_toString, sig_java_lang_Object_toString);
00598     jstring excString = (jstring) env->CallObjectMethod(exc, toString);
00599 
00600        jboolean isCopy;
00601     const char* msg = env->GetStringUTFChars(excString, &isCopy);
00602     if (msg != NULL) {
00603         const char* dupmsg = (msg == NULL ? (const char*)NULL : strdup(msg));
00604        env->ReleaseStringUTFChars(excString, msg);
00605        msg = dupmsg;
00606     }
00607     return msg;
00608 }
00609 #endif // 0
00610 
00612 
00613 PRLogModuleInfo* NSJAVA = NULL;
00614 
00615 nsJVMStatus
00616 nsJVMManager::StartupJVM(void)
00617 {
00618     // Be sure to check the prefs first before asking java to startup.
00619     switch (GetJVMStatus()) {
00620       case nsJVMStatus_Disabled:
00621         return nsJVMStatus_Disabled;
00622       case nsJVMStatus_Running:
00623         return nsJVMStatus_Running;
00624       default:
00625         break;
00626     }
00627 
00628 #ifdef DEBUG
00629     PRIntervalTime start = PR_IntervalNow();
00630     if (NSJAVA == NULL)
00631         NSJAVA = PR_NewLogModule("NSJAVA");
00632     PR_LOG(NSJAVA, PR_LOG_ALWAYS, ("Starting java..."));
00633 #endif
00634 
00635  /* TODO: Show the progress bar.
00636        MWContext* someRandomContext = XP_FindSomeContext();
00637        if (someRandomContext) {
00638               FE_Progress(someRandomContext, XP_GetString(XP_PROGRESS_STARTING_JAVA));
00639        }
00640  */
00641 
00642 #ifdef MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00643     PRUintn uStatus=0;
00644     EnterMonitor(&uStatus);
00645 #endif // MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00646 
00647     PR_ASSERT(fJVM == NULL);
00648     /*
00649     **TODO: amusil. Load the plugin by getting into Service manager.
00650     **              Right now there is no API to do this stuff. We need to
00651     **              add this to nsIPluginHost. We need a case where we just 
00652     **              load the plugin but do not instantiate any instance. 
00653     **              The code in there right now always creates a new instance.
00654     **              But for Java we may not create any instances and may need to
00655     **              do JNI calls via liveconnect.
00656     */
00657 
00658        // beard:  Now uses the nsIPluginHost to load the plugin factory for NS_JVM_MIME_TYPE.
00659     nsresult err;
00660     nsCOMPtr<nsIPluginHost> pluginHost = 
00661              do_GetService(kPluginManagerCID, &err);
00662     if (NS_FAILED(err)) {
00663         fStatus = nsJVMStatus_Failed;
00664 
00665 #ifdef MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00666         ExitMonitor(&uStatus);
00667 #endif // MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00668 
00669         return fStatus;
00670     }
00671 
00672     if (!pluginHost) {
00673         fStatus = nsJVMStatus_Failed;
00674 
00675 #ifdef MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00676         ExitMonitor(&uStatus);
00677 #endif // MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00678 
00679         return fStatus;
00680     }
00681 
00682     nsIPlugin* pluginFactory = NULL;
00683      // this code is the correct way to obtain pluggable JVM
00684     nsCOMPtr<nsIPlugin> f = 
00685              do_GetService(NS_INLINE_PLUGIN_CONTRACTID_PREFIX NS_JVM_MIME_TYPE, &err);
00686     if (NS_FAILED(err) || !f) {
00687         err = pluginHost->GetPluginFactory(NS_JVM_MIME_TYPE, &pluginFactory);
00688     } 
00689     else {
00690         pluginFactory  = f;
00691     }
00692     
00693     if (pluginFactory == NULL) {
00694         fStatus = nsJVMStatus_Failed;
00695 
00696 #ifdef MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00697         ExitMonitor(&uStatus);
00698 #endif // MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00699 
00700         return fStatus;
00701     }
00702 
00703     nsresult rslt = pluginFactory->QueryInterface(kIJVMPluginIID, (void**)&fJVM);
00704     if (rslt != NS_OK) {
00705         PR_ASSERT(fJVM == NULL);
00706         fStatus = nsJVMStatus_Failed;
00707 
00708 #ifdef MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00709         ExitMonitor(&uStatus);
00710 #endif // MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00711 
00712         return fStatus;
00713     }
00714 
00715     // beard: do we really need an explicit startup mechanim for the JVM?
00716     // since we obtained a working JVM plugin, assume it is running.
00717     fStatus = nsJVMStatus_Running;
00718 
00719 #if 0
00720     JSContext* crippledContext = LM_GetCrippledContext();
00721     MaybeStartupLiveConnect(crippledContext, JS_GetGlobalObject(crippledContext));
00722 #endif
00723 
00724     fJVM->Release();
00725 
00726 #ifdef DEBUG
00727     PRIntervalTime end = PR_IntervalNow();
00728     PRInt32 d = PR_IntervalToMilliseconds(end - start);
00729     PR_LOG(NSJAVA, PR_LOG_ALWAYS,
00730            ("Starting java...%s (%ld ms)",
00731             (fStatus == nsJVMStatus_Running ? "done" : "failed"), d));
00732 #endif
00733 
00734 #ifdef MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00735         ExitMonitor(&uStatus);
00736 #endif // MOZ_OJI_REQUIRE_THREAD_SAFE_ON_STARTUP    
00737 
00738  /* TODO:
00739 
00740     if (someRandomContext) {
00741         FE_Progress(someRandomContext, XP_GetString(XP_PROGRESS_STARTING_JAVA_DONE));
00742     }
00743  */
00744     return fStatus;
00745 }
00746 
00747 nsJVMStatus
00748 nsJVMManager::ShutdownJVM(PRBool fullShutdown)
00749 {
00750     if (fStatus == nsJVMStatus_Running) {
00751         PR_ASSERT(fJVM != NULL);
00752         // XXX need to shutdown JVM via ServiceManager
00753 //        nsresult err = fJVM->ShutdownJVM(fullShutdown);
00754 //        if (err == NS_OK)
00755             fStatus = nsJVMStatus_Enabled;
00756 //        else {
00757 //            ReportJVMError(err);
00758 //            fStatus = nsJVMStatus_Disabled;
00759 //        }
00760         fJVM = NULL;
00761     }
00762     PR_ASSERT(fJVM == NULL);
00763     return fStatus;
00764 }
00765 
00767 
00768 void
00769 nsJVMManager::SetJVMEnabled(PRBool enabled)
00770 {
00771     if (enabled) {
00772         if (fStatus != nsJVMStatus_Running) 
00773             fStatus = nsJVMStatus_Enabled;
00774         // don't start the JVM here, do it lazily
00775     }
00776     else {
00777         if (fStatus == nsJVMStatus_Running) 
00778             (void)ShutdownJVM();
00779         fStatus = nsJVMStatus_Disabled;
00780     }
00781 }
00782 
00783 nsresult
00784 nsJVMManager::GetChrome(nsIWebBrowserChrome **theChrome)
00785 {
00786     *theChrome = nsnull;
00787 
00788     nsresult rv;
00789     nsCOMPtr<nsIWindowWatcher> windowWatcher =
00790         do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
00791     if (NS_FAILED(rv)) {
00792         return rv;
00793     }
00794     nsCOMPtr<nsIDOMWindow> domWindow;
00795     windowWatcher->GetActiveWindow(getter_AddRefs(domWindow));
00796     nsCOMPtr<nsIScriptGlobalObject> scriptObject =
00797         do_QueryInterface(domWindow, &rv);
00798     if (!scriptObject) {
00799         return rv;
00800     }
00801     nsIDocShell *docShell = scriptObject->GetDocShell();
00802     if (!docShell) {
00803         return NS_OK;
00804     }
00805     nsCOMPtr<nsPresContext> presContext;
00806     rv = docShell->GetPresContext(getter_AddRefs(presContext));
00807     if (!presContext) {
00808         return rv;
00809     }
00810     nsCOMPtr<nsISupports> container(presContext->GetContainer());
00811     nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container, &rv);
00812     if (!treeItem) {
00813         return rv;
00814     }
00815     nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
00816     treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
00817 
00818     nsCOMPtr<nsIWebBrowserChrome> chrome = do_GetInterface(treeOwner, &rv);
00819     *theChrome = (nsIWebBrowserChrome *) chrome.get();
00820     NS_IF_ADDREF(*theChrome);
00821     return rv;
00822 }
00823 
00824 NS_IMETHODIMP
00825 nsJVMManager::Observe(nsISupports*     subject,
00826                       const char*      topic,
00827                       const PRUnichar* data_unicode)
00828 {
00829     nsresult rv;
00830     nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(subject, &rv);
00831     if (NS_FAILED(rv)) return rv;
00832 
00833     PRBool prefBool = PR_TRUE;
00834     rv = branch->GetBoolPref("security.enable_java", &prefBool);
00835     if (NS_SUCCEEDED(rv)) {
00836         SetJVMEnabled(prefBool);
00837     }
00838 
00839     return rv;
00840 }
00841 
00842 nsJVMStatus
00843 nsJVMManager::GetJVMStatus(void)
00844 {
00845     return fStatus;
00846 }
00847 
00848 extern "C" NS_VISIBILITY_DEFAULT nsresult JSJ_RegisterLiveConnectFactory(void);
00849 
00850 PRBool
00851 nsJVMManager::MaybeStartupLiveConnect(void)
00852 {
00853     if (fJSJavaVM)
00854         return PR_TRUE;
00855 
00856        do {
00857               static PRBool registeredLiveConnectFactory = NS_SUCCEEDED(JSJ_RegisterLiveConnectFactory());
00858         if (IsLiveConnectEnabled()) {
00859             JVM_InitLCGlue();
00860 #if 0
00861             nsIJVMPlugin* plugin = GetJVMPlugin();
00862             if (plugin) {
00863                    const char* classpath = NULL;
00864                    nsresult err = plugin->GetClassPath(&classpath);
00865                    if (err != NS_OK) break;
00866 
00867                    JavaVM* javaVM = NULL;
00868                    err = plugin->GetJavaVM(&javaVM);
00869                    if (err != NS_OK) break;
00870 #endif
00871                    fJSJavaVM = JSJ_ConnectToJavaVM(NULL, NULL);
00872                    if (fJSJavaVM != NULL)
00873                        return PR_TRUE;
00874                    // plugin->Release(); // GetJVMPlugin no longer calls AddRef
00875                //}
00876            }
00877        } while (0);
00878     return PR_FALSE;
00879 }
00880 
00881 PRBool
00882 nsJVMManager::MaybeShutdownLiveConnect(void)
00883 {
00884     if (fJSJavaVM) {
00885         JSJ_DisconnectFromJavaVM(fJSJavaVM);
00886         fJSJavaVM = NULL;
00887         return PR_TRUE; 
00888     }
00889     return PR_FALSE;
00890 }
00891 
00892 PRBool
00893 nsJVMManager::IsLiveConnectEnabled(void)
00894 {
00895 #if 0
00896 // TODO: Get a replacement for LM_GetMochaEnabled. This is on Tom's list.
00897        if (LM_GetMochaEnabled()) {
00898               nsJVMStatus status = GetJVMStatus();
00899               return (status == nsJVMStatus_Enabled || status == nsJVMStatus_Running);
00900        }
00901 #endif
00902        return PR_TRUE;
00903 }
00904 
00905 /*
00906  * Find out if a given signer has been granted all permissions. This
00907  * is a precondition to loading a signed applet in trusted mode.
00908  * The certificate from which the fingerprint and commonname have
00909  * be derived, should have been verified before this method is 
00910  * called.
00911  */
00912 // XXXbz this function has been deprecated for 4.5 years.  We have no
00913 // callers in the tree.  Is it time to remove it?  It's returning
00914 // PRBools for a NS_METHOD, and NS_METHOD for an interface method, for
00915 // goodness' sake!
00916 NS_METHOD
00917 nsJVMManager::IsAllPermissionGranted(
00918     const char * lastFP,
00919     const char * lastCN, 
00920     const char * rootFP,
00921     const char * rootCN, 
00922     PRBool * isGranted)
00923 {
00924     if (!lastFP || !lastCN) {
00925         return PR_FALSE;
00926     }
00927     
00928     nsresult rv      = NS_OK;
00929 
00930     nsCOMPtr<nsIPrincipal> pIPrincipal;
00931   
00932     // Get the Script Security Manager.
00933 
00934     nsCOMPtr<nsIScriptSecurityManager> secMan = 
00935              do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
00936     if (NS_FAILED(rv) || !secMan) return PR_FALSE;
00937 
00938     // Ask the Script Security Manager to make a Certificate Principal.
00939     // The fingerprint is a one way hash of this certificate. It is used
00940     // as the key to store the principal in the principal database.
00941 
00942     // XXXbz using the |lastCN| for the subjectName for lack of
00943     // anything better.  Also not passing in a pointer to a cert,
00944     // since we don't have one.
00945     rv = secMan->GetCertificatePrincipal(nsDependentCString(lastFP),
00946                                          nsDependentCString(lastCN),
00947                                          nsDependentCString(lastCN),
00948                                          nsnull, nsnull,
00949                                          getter_AddRefs(pIPrincipal));
00950     if (NS_FAILED(rv)) return PR_FALSE;
00951 
00952     PRInt16 ret;
00953 
00954     secMan->RequestCapability(pIPrincipal,"AllPermission",&ret);
00955 
00956     PR_ASSERT(isGranted);
00957     *isGranted = (ret!=0);
00958 
00959     return PR_TRUE;
00960 }
00961 
00962 NS_METHOD
00963 nsJVMManager::IsAppletTrusted(
00964     const char* aRSABuf, 
00965     PRUint32    aRSABufLen, 
00966     const char* aPlaintext, 
00967     PRUint32    aPlaintextLen,    
00968     PRBool*     isTrusted,
00969     nsIPrincipal** pIPrincipal)
00970 {
00971     nsresult rv      = NS_OK;
00972 
00973     //-- Get the signature verifier service
00974     nsCOMPtr<nsISignatureVerifier> verifier = 
00975              do_GetService(SIGNATURE_VERIFIER_CONTRACTID, &rv);
00976     if (NS_FAILED(rv)) // No signature verifier available
00977         return NS_OK;
00978 
00979     // Get the Script Security Manager.
00980 
00981     nsCOMPtr<nsIScriptSecurityManager> secMan = 
00982              do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
00983     if (NS_FAILED(rv) || !secMan) return PR_FALSE;
00984 
00985 
00986     // Ask the Script Security Manager to make a Certificate Principal.
00987     // The fingerprint is a one way hash of this certificate. It is used
00988     // as the key to store the principal in the principal database.
00989 
00990     {
00991         PRInt32 ret;
00992         PR_ASSERT(pIPrincipal);
00993         rv = verifier->VerifySignature(aRSABuf,aRSABufLen,aPlaintext,aPlaintextLen,&ret,pIPrincipal);
00994         if (NS_FAILED(rv)) return PR_FALSE;
00995     }
00996 
00997     {
00998         PRInt16 ret = 0;
00999         secMan->RequestCapability(*pIPrincipal,"UniversalBrowserRead",&ret);
01000         PR_ASSERT(isTrusted);
01001         *isTrusted = (ret!=0);
01002     }
01003 
01004     return PR_TRUE;
01005 }
01006 
01007 
01009 
01010 nsresult
01011 nsJVMManager::AddToClassPath(const char* dirPath)
01012 {
01013     nsIJVMPlugin* jvm = GetJVMPlugin();
01014 
01015     /* Add any zip or jar files in this directory to the classpath: */
01016     PRDir* dir = PR_OpenDir(dirPath);
01017     if (dir != NULL) {
01018         PRDirEntry* dirent;
01019         while ((dirent = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
01020             PRFileInfo info;
01021             char sep = PR_GetDirectorySeparator();
01022             char* path = PR_smprintf("%s%c%s", dirPath, sep, PR_DirName(dirent));
01023                      if (path != NULL) {
01024                      PRBool freePath = PR_TRUE;
01025                    if ((PR_GetFileInfo(path, &info) == PR_SUCCESS)
01026                        && (info.type == PR_FILE_FILE)) {
01027                        int len = PL_strlen(path);
01028 
01029                        /* Is it a zip or jar file? */
01030                        if ((len > 4) && 
01031                            ((PL_strcasecmp(path+len-4, ".zip") == 0) || 
01032                             (PL_strcasecmp(path+len-4, ".jar") == 0))) {
01033                            fClassPathAdditions->AppendElement((void*)path);
01034                            if (jvm) {
01035                                /* Add this path to the classpath: */
01036                                jvm->AddToClassPath(path);
01037                            }
01038                            freePath = PR_FALSE;
01039                        }
01040                    }
01041                    
01042                    // Don't leak the path!
01043                    if (freePath)
01044                           PR_smprintf_free(path);
01045                }
01046         }
01047         PR_CloseDir(dir);
01048     }
01049 
01050     /* Also add the directory to the classpath: */
01051     fClassPathAdditions->AppendElement((void*)dirPath);
01052     if (jvm) {
01053         jvm->AddToClassPath(dirPath);
01054         // jvm->Release(); // GetJVMPlugin no longer calls AddRef
01055     }
01056     return NS_OK;
01057 }
01058