Back to index

lightning-sunbird  0.9+nobinonly
nsJavaInterfaces.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 Java XPCOM Bindings.
00015  *
00016  * The Initial Developer of the Original Code is IBM Corporation.
00017  * Portions created by the Initial Developer are Copyright (C) 2007
00018  * IBM Corporation. All Rights Reserved.
00019  *
00020  * Contributor(s):
00021  *   Javier Pedemonte (jhpedemonte@gmail.com)
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * 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 #include "nsJavaInterfaces.h"
00038 #include "nsJavaWrapper.h"
00039 #include "nsJavaXPCOMBindingUtils.h"
00040 #include "nsJavaXPTCStub.h"
00041 #include "nsIComponentRegistrar.h"
00042 #include "nsString.h"
00043 #include "nsISimpleEnumerator.h"
00044 #include "nsIInterfaceInfoManager.h"
00045 #include "nsIInputStream.h"
00046 #include "nsEnumeratorUtils.h"
00047 #include "nsArray.h"
00048 #include "nsAppFileLocProviderProxy.h"
00049 #include "nsIEventQueueService.h"
00050 #include "nsXULAppAPI.h"
00051 #include "nsILocalFile.h"
00052 
00053 #ifdef XP_MACOSX
00054 #include "jawt.h"
00055 #endif
00056 
00057 // profile support
00058 #include "nsIObserverService.h"
00059 #include "nsIProfileChangeStatus.h"
00060 #include "jsapi.h"
00061 #include "nsIJSContextStack.h"
00062 #include "nsIToolkitProfile.h"
00063 
00064 PRBool profileNotified = PR_FALSE;
00065 
00066 extern nsresult
00067 NS_LockProfilePath(nsILocalFile* aPath, nsILocalFile* aTempPath,
00068                    nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult);
00069 
00070 class ProfileChangeStatusImpl : public nsIProfileChangeStatus
00071 {
00072 public:
00073   NS_DECL_ISUPPORTS
00074   NS_DECL_NSIPROFILECHANGESTATUS
00075   ProfileChangeStatusImpl() { }
00076 private:
00077   ~ProfileChangeStatusImpl() { }
00078 };
00079 
00080 
00081 extern "C" NS_EXPORT void JNICALL
00082 MOZILLA_NATIVE(initialize) (JNIEnv* env, jobject)
00083 {
00084   if (!InitializeJavaGlobals(env)) {
00085     jclass clazz =
00086         env->FindClass("org/mozilla/xpcom/XPCOMInitializationException");
00087     if (clazz) {
00088       env->ThrowNew(clazz, "Failed to initialize JavaXPCOM");
00089     }
00090   }
00091 }
00092 
00093 nsresult
00094 InitEmbedding_Impl(JNIEnv* env, jobject aLibXULDirectory,
00095                    jobject aAppDirectory, jobject aAppDirProvider)
00096 {
00097   nsresult rv;
00098 
00099   // create an nsILocalFile from given java.io.File
00100   nsCOMPtr<nsILocalFile> libXULDir;
00101   if (aLibXULDirectory) {
00102     rv = File_to_nsILocalFile(env, aLibXULDirectory, getter_AddRefs(libXULDir));
00103     NS_ENSURE_SUCCESS(rv, rv);
00104   }
00105   nsCOMPtr<nsILocalFile> appDir;
00106   if (aAppDirectory) {
00107     rv = File_to_nsILocalFile(env, aAppDirectory, getter_AddRefs(appDir));
00108     NS_ENSURE_SUCCESS(rv, rv);
00109   }
00110 
00111   // create nsAppFileLocProviderProxy from given Java object
00112   nsCOMPtr<nsIDirectoryServiceProvider> provider;
00113   if (aAppDirProvider) {
00114     rv = NS_NewAppFileLocProviderProxy(aAppDirProvider,
00115                                        getter_AddRefs(provider));
00116     NS_ENSURE_SUCCESS(rv, rv);
00117   }
00118 
00119   // init libXUL
00120   return XRE_InitEmbedding(libXULDir, appDir, provider, nsnull, 0);
00121 }
00122 
00123 extern "C" NS_EXPORT void JNICALL
00124 GRE_NATIVE(initEmbedding) (JNIEnv* env, jobject, jobject aLibXULDirectory,
00125                            jobject aAppDirectory, jobject aAppDirProvider)
00126 {
00127   nsresult rv = InitEmbedding_Impl(env, aLibXULDirectory, aAppDirectory,
00128                                    aAppDirProvider);
00129 
00130   if (NS_FAILED(rv)) {
00131     ThrowException(env, rv, "Failure in initEmbedding");
00132     FreeJavaGlobals(env);
00133   }
00134 }
00135 
00136 extern "C" NS_EXPORT void JNICALL
00137 GRE_NATIVE(termEmbedding) (JNIEnv *env, jobject)
00138 {
00139   if (profileNotified) {
00140     nsCOMPtr<nsIObserverService> obssvc
00141       (do_GetService("@mozilla.org/observer-service;1"));
00142     NS_ASSERTION(obssvc, "No observer service?");
00143     if (obssvc) {
00144       nsCOMPtr<nsIProfileChangeStatus> cs = new ProfileChangeStatusImpl();
00145       static const PRUnichar kShutdownPersist[] =
00146         {'s','h','u','t','d','o','w','n','-','p','e','r','s','i','s','t','\0'};
00147       obssvc->NotifyObservers(cs, "profile-change-net-teardown",
00148                               kShutdownPersist);
00149       obssvc->NotifyObservers(cs, "profile-change-teardown", kShutdownPersist);
00150 
00151       // Now that things are torn down, force JS GC so that things
00152       // which depend on resources which are about to go away in
00153       // "profile-before-change" are destroyed first.
00154       nsCOMPtr<nsIThreadJSContextStack> stack
00155         (do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
00156       if (stack)
00157       {
00158         JSContext *cx = nsnull;
00159         stack->GetSafeJSContext(&cx);
00160         if (cx)
00161           ::JS_GC(cx);
00162       }
00163 
00164       // Notify observers of a profile change
00165       obssvc->NotifyObservers(cs, "profile-before-change", kShutdownPersist);
00166     }
00167     profileNotified = PR_FALSE;
00168   }
00169 
00170   // Free globals before calling XRE_TermEmbedding(), since we need some
00171   // XPCOM services.
00172   FreeJavaGlobals(env);
00173 
00174   XRE_TermEmbedding();
00175 }
00176 
00177 extern "C" NS_EXPORT jobject JNICALL
00178 GRE_NATIVE(lockProfileDirectory) (JNIEnv* env, jobject, jobject aDirectory)
00179 {
00180   nsresult rv = NS_ERROR_FAILURE;
00181 
00182   if (aDirectory) {
00183     nsCOMPtr<nsILocalFile> profileDir;
00184     rv = File_to_nsILocalFile(env, aDirectory, getter_AddRefs(profileDir));
00185 
00186     if (NS_SUCCEEDED(rv)) {
00187       nsIProfileLock* lock;
00188       rv = NS_LockProfilePath(profileDir, nsnull, nsnull, &lock);
00189 
00190       if (NS_SUCCEEDED(rv)) {
00191         jclass clazz =
00192             env->FindClass("org/mozilla/xpcom/ProfileLock");
00193         if (clazz) {
00194           jmethodID mid = env->GetMethodID(clazz, "<init>", "(J)V");
00195           if (mid) {
00196             return env->NewObject(clazz, mid, NS_REINTERPRET_CAST(jlong, lock));
00197           }
00198         }
00199 
00200         // if we get here, then something failed
00201         rv = NS_ERROR_FAILURE;
00202       }
00203     }
00204   }
00205 
00206   ThrowException(env, rv, "Failure in lockProfileDirectory");
00207   return nsnull;
00208 }
00209 
00210 extern "C" NS_EXPORT void JNICALL
00211 GRE_NATIVE(notifyProfile) (JNIEnv *env, jobject)
00212 {
00213   if (!profileNotified) {
00214     nsCOMPtr<nsIObserverService> obsSvc
00215       (do_GetService("@mozilla.org/observer-service;1"));
00216 
00217     if (obsSvc) {
00218       profileNotified = PR_TRUE;
00219 
00220       static const PRUnichar kStartup[] = {'s','t','a','r','t','u','p','\0'};
00221       obsSvc->NotifyObservers(nsnull, "profile-do-change", kStartup);
00222       obsSvc->NotifyObservers(nsnull, "profile-after-change", kStartup);
00223     }
00224   }
00225 }
00226 
00227 nsresult
00228 InitXPCOM_Impl(JNIEnv* env, jobject aMozBinDirectory,
00229                jobject aAppFileLocProvider, jobject* aResult)
00230 {
00231   nsresult rv;
00232 
00233   // create an nsILocalFile from given java.io.File
00234   nsCOMPtr<nsILocalFile> directory;
00235   if (aMozBinDirectory) {
00236     rv = File_to_nsILocalFile(env, aMozBinDirectory, getter_AddRefs(directory));
00237     NS_ENSURE_SUCCESS(rv, rv);
00238   }
00239 
00240   // create nsAppFileLocProviderProxy from given Java object
00241   nsCOMPtr<nsIDirectoryServiceProvider> provider;
00242   if (aAppFileLocProvider) {
00243     rv = NS_NewAppFileLocProviderProxy(aAppFileLocProvider,
00244                                        getter_AddRefs(provider));
00245     NS_ENSURE_SUCCESS(rv, rv);
00246   }
00247 
00248   // init XPCOM
00249   nsCOMPtr<nsIServiceManager> servMan;
00250   rv = NS_InitXPCOM2(getter_AddRefs(servMan), directory, provider);
00251   NS_ENSURE_SUCCESS(rv, rv);
00252 
00253   // init Event Queue
00254   nsCOMPtr<nsIEventQueueService> eventQService =
00255             do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
00256   NS_ENSURE_SUCCESS(rv, rv);
00257   rv = eventQService->CreateThreadEventQueue();
00258   NS_ENSURE_SUCCESS(rv, rv);
00259 
00260   // create Java proxy for service manager returned by NS_InitXPCOM2
00261   return GetNewOrUsedJavaObject(env, servMan, NS_GET_IID(nsIServiceManager),
00262                                 nsnull, aResult);
00263 }
00264 
00265 extern "C" NS_EXPORT jobject JNICALL
00266 XPCOM_NATIVE(initXPCOM) (JNIEnv* env, jobject, jobject aMozBinDirectory,
00267                          jobject aAppFileLocProvider)
00268 {
00269   jobject servMan;
00270   nsresult rv = InitXPCOM_Impl(env, aMozBinDirectory, aAppFileLocProvider,
00271                                &servMan);
00272   if (NS_SUCCEEDED(rv))
00273     return servMan;
00274 
00275   ThrowException(env, rv, "Failure in initXPCOM");
00276   FreeJavaGlobals(env);
00277   return nsnull;
00278 }
00279 
00280 extern "C" NS_EXPORT void JNICALL
00281 XPCOM_NATIVE(shutdownXPCOM) (JNIEnv *env, jobject, jobject aServMgr)
00282 {
00283   nsresult rv;
00284   nsIServiceManager* servMgr = nsnull;
00285   if (aServMgr) {
00286     // Get native XPCOM instance
00287     rv = GetNewOrUsedXPCOMObject(env, aServMgr, NS_GET_IID(nsIServiceManager),
00288                                  (nsISupports**) &servMgr);
00289     NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get XPCOM obj for ServiceMgr.");
00290 
00291     // Even if we failed to get the matching xpcom object, we don't abort this
00292     // function.  Just call NS_ShutdownXPCOM with a null service manager.
00293   }
00294 
00295   // Free globals before calling NS_ShutdownXPCOM(), since we need some
00296   // XPCOM services.
00297   FreeJavaGlobals(env);
00298 
00299   rv = NS_ShutdownXPCOM(servMgr);
00300   if (NS_FAILED(rv))
00301     ThrowException(env, rv, "NS_ShutdownXPCOM failed");
00302 }
00303 
00304 extern "C" NS_EXPORT jobject JNICALL
00305 XPCOM_NATIVE(newLocalFile) (JNIEnv *env, jobject, jstring aPath,
00306                             jboolean aFollowLinks)
00307 {
00308   // Create a Mozilla string from the jstring
00309   const PRUnichar* buf = nsnull;
00310   if (aPath) {
00311     buf = env->GetStringChars(aPath, nsnull);
00312     if (!buf)
00313       return nsnull;  // exception already thrown
00314   }
00315 
00316   nsAutoString path_str(buf);
00317   env->ReleaseStringChars(aPath, buf);
00318 
00319   // Make call to given function
00320   nsCOMPtr<nsILocalFile> file;
00321   nsresult rv = NS_NewLocalFile(path_str, aFollowLinks, getter_AddRefs(file));
00322 
00323   if (NS_SUCCEEDED(rv)) {
00324     jobject javaProxy;
00325     rv = GetNewOrUsedJavaObject(env, file, NS_GET_IID(nsILocalFile),
00326                                 nsnull, &javaProxy);
00327     if (NS_SUCCEEDED(rv))
00328       return javaProxy;
00329   }
00330 
00331   ThrowException(env, rv, "Failure in newLocalFile");
00332   return nsnull;
00333 }
00334 
00335 extern "C" NS_EXPORT jobject JNICALL
00336 XPCOM_NATIVE(getComponentManager) (JNIEnv *env, jobject)
00337 {
00338   // Call XPCOM method
00339   nsCOMPtr<nsIComponentManager> cm;
00340   nsresult rv = NS_GetComponentManager(getter_AddRefs(cm));
00341 
00342   if (NS_SUCCEEDED(rv)) {
00343     jobject javaProxy;
00344     rv = GetNewOrUsedJavaObject(env, cm, NS_GET_IID(nsIComponentManager),
00345                                 nsnull, &javaProxy);
00346     if (NS_SUCCEEDED(rv))
00347       return javaProxy;
00348   }
00349 
00350   ThrowException(env, rv, "Failure in getComponentManager");
00351   return nsnull;
00352 }
00353 
00354 extern "C" NS_EXPORT jobject JNICALL
00355 XPCOM_NATIVE(getComponentRegistrar) (JNIEnv *env, jobject)
00356 {
00357   // Call XPCOM method
00358   nsCOMPtr<nsIComponentRegistrar> cr;
00359   nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(cr));
00360 
00361   if (NS_SUCCEEDED(rv)) {
00362     jobject javaProxy;
00363     rv = GetNewOrUsedJavaObject(env, cr, NS_GET_IID(nsIComponentRegistrar),
00364                                 nsnull, &javaProxy);
00365     if (NS_SUCCEEDED(rv))
00366       return javaProxy;
00367   }
00368 
00369   ThrowException(env, rv, "Failure in getComponentRegistrar");
00370   return nsnull;
00371 }
00372 
00373 extern "C" NS_EXPORT jobject JNICALL
00374 XPCOM_NATIVE(getServiceManager) (JNIEnv *env, jobject)
00375 {
00376   // Call XPCOM method
00377   nsCOMPtr<nsIServiceManager> sm;
00378   nsresult rv = NS_GetServiceManager(getter_AddRefs(sm));
00379 
00380   if (NS_SUCCEEDED(rv)) {
00381     jobject javaProxy;
00382     rv = GetNewOrUsedJavaObject(env, sm, NS_GET_IID(nsIServiceManager),
00383                                 nsnull, &javaProxy);
00384     if (NS_SUCCEEDED(rv))
00385       return javaProxy;
00386   }
00387 
00388   ThrowException(env, rv, "Failure in getServiceManager");
00389   return nsnull;
00390 }
00391 
00392 #ifdef XP_MACOSX
00393 extern PRUint64 GetPlatformHandle(JAWT_DrawingSurfaceInfo* dsi);
00394 #endif
00395 
00396 extern "C" NS_EXPORT jlong JNICALL
00397 MOZILLA_NATIVE(getNativeHandleFromAWT) (JNIEnv* env, jobject clazz,
00398                                         jobject widget)
00399 {
00400   PRUint64 handle = 0;
00401 
00402 #ifdef XP_MACOSX
00403   JAWT awt;
00404   awt.version = JAWT_VERSION_1_4;
00405   jboolean result = JAWT_GetAWT(env, &awt);
00406   if (result == JNI_FALSE)
00407     return 0;
00408     
00409   JAWT_DrawingSurface* ds = awt.GetDrawingSurface(env, widget);
00410   if (ds != nsnull) {
00411     jint lock = ds->Lock(ds);
00412     if (!(lock & JAWT_LOCK_ERROR)) {
00413       JAWT_DrawingSurfaceInfo* dsi = ds->GetDrawingSurfaceInfo(ds);
00414       if (dsi) {
00415         handle = GetPlatformHandle(dsi);
00416         ds->FreeDrawingSurfaceInfo(dsi);
00417       }
00418 
00419       ds->Unlock(ds);
00420     }
00421 
00422     awt.FreeDrawingSurface(ds);
00423   }
00424 #else
00425   NS_WARNING("getNativeHandleFromAWT JNI method not implemented");
00426 #endif
00427 
00428   return handle;
00429 }
00430 
00431 extern "C" NS_EXPORT jlong JNICALL
00432 JXUTILS_NATIVE(wrapJavaObject) (JNIEnv* env, jobject, jobject aJavaObject,
00433                                 jstring aIID)
00434 {
00435   nsresult rv;
00436   nsISupports* xpcomObject = nsnull;
00437 
00438   if (!aJavaObject || !aIID) {
00439     rv = NS_ERROR_NULL_POINTER;
00440   } else {
00441     const char* str = env->GetStringUTFChars(aIID, nsnull);
00442     if (!str) {
00443       rv = NS_ERROR_OUT_OF_MEMORY;
00444     } else {
00445       nsID iid;
00446       if (iid.Parse(str)) {
00447         rv = GetNewOrUsedXPCOMObject(env, aJavaObject, iid, &xpcomObject);
00448       } else {
00449         rv = NS_ERROR_INVALID_ARG;
00450       }
00451 
00452       env->ReleaseStringUTFChars(aIID, str);
00453     }
00454   }
00455 
00456   if (NS_FAILED(rv)) {
00457     ThrowException(env, rv, "Failed to create XPCOM proxy for Java object");
00458   }
00459   return NS_REINTERPRET_CAST(jlong, xpcomObject);
00460 }
00461 
00462 extern "C" NS_EXPORT jobject JNICALL
00463 JXUTILS_NATIVE(wrapXPCOMObject) (JNIEnv* env, jobject, jlong aXPCOMObject,
00464                                  jstring aIID)
00465 {
00466   nsresult rv;
00467   jobject javaObject = nsnull;
00468   nsISupports* xpcomObject = NS_REINTERPRET_CAST(nsISupports*, aXPCOMObject);
00469 
00470   if (!xpcomObject || !aIID) {
00471     rv = NS_ERROR_NULL_POINTER;
00472   } else {
00473     const char* str = env->GetStringUTFChars(aIID, nsnull);
00474     if (!str) {
00475       rv = NS_ERROR_OUT_OF_MEMORY;
00476     } else {
00477       nsID iid;
00478       if (iid.Parse(str)) {
00479         // XXX Should we be passing something other than NULL for aObjectLoader?
00480         rv = GetNewOrUsedJavaObject(env, xpcomObject, iid, nsnull, &javaObject);
00481       } else {
00482         rv = NS_ERROR_INVALID_ARG;
00483       }
00484 
00485       env->ReleaseStringUTFChars(aIID, str);
00486     }
00487   }
00488 
00489   if (NS_FAILED(rv)) {
00490     ThrowException(env, rv, "Failed to create XPCOM proxy for Java object");
00491   }
00492   return javaObject;
00493 }