Back to index

lightning-sunbird  0.9+nobinonly
nsJavaXPCOMGlue.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) 2006
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 "jni.h"
00038 #include "nsXPCOMPrivate.h" // for XPCOM_DLL defines.
00039 #include "nsXPCOMGlue.h"
00040 #include <stdlib.h>
00041 
00042 #if defined(XP_WIN) || defined(XP_OS2)
00043 #define JX_EXPORT   JNIEXPORT
00044 #else
00045 #define JX_EXPORT   JNIEXPORT NS_EXPORT
00046 #endif
00047 
00048 
00049 /***********************
00050  *  JNI Load & Unload
00051  ***********************/
00052 
00053 extern "C" JX_EXPORT jint JNICALL
00054 JNI_OnLoad(JavaVM* vm, void* reserved)
00055 {
00056   // Let the JVM know that we are using JDK 1.2 JNI features.
00057   return JNI_VERSION_1_2;
00058 }
00059 
00060 extern "C" JX_EXPORT void JNICALL
00061 JNI_OnUnload(JavaVM* vm, void* reserved)
00062 {
00063 }
00064 
00065 /********************************
00066  *  JavaXPCOM JNI interfaces
00067  ********************************/
00068 
00069 #define JXM_NATIVE(func) Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_##func
00070 
00071 enum {
00072   kFunc_Initialize,
00073   kFunc_InitEmbedding,
00074   kFunc_TermEmbedding,
00075   kFunc_LockProfileDirectory,
00076   kFunc_NotifyProfile,
00077   kFunc_InitXPCOM,
00078   kFunc_ShutdownXPCOM,
00079   kFunc_GetComponentManager,
00080   kFunc_GetComponentRegistrar,
00081   kFunc_GetServiceManager,
00082   kFunc_NewLocalFile,
00083   kFunc_CallXPCOMMethod,
00084   kFunc_FinalizeProxy,
00085   kFunc_IsSameXPCOMObject,
00086   kFunc_ReleaseProfileLock,
00087   kFunc_GetNativeHandleFromAWT,
00088   kFunc_WrapJavaObject,
00089   kFunc_WrapXPCOMObject
00090 };
00091 
00092 #define JX_NUM_FUNCS 18
00093 
00094 
00095 // Get path string from java.io.File object.
00096 jstring
00097 GetJavaFilePath(JNIEnv* env, jobject aFile)
00098 {
00099   jclass clazz = env->FindClass("java/io/File");
00100   if (clazz) {
00101     jmethodID pathMID = env->GetMethodID(clazz, "getCanonicalPath",
00102                                          "()Ljava/lang/String;");
00103     if (pathMID) {
00104       return (jstring) env->CallObjectMethod(aFile, pathMID);
00105     }
00106   }
00107 
00108   return nsnull;
00109 }
00110 
00111 // Calls XPCOMGlueStartup using the given java.io.File object, and loads
00112 // the JavaXPCOM methods from the XUL shared library.
00113 nsresult
00114 LoadXULMethods(JNIEnv* env, jobject aXPCOMPath, void** aFunctions)
00115 {
00116   jstring pathString = GetJavaFilePath(env, aXPCOMPath);
00117   if (!pathString)
00118     return NS_ERROR_FAILURE;
00119   const char* path = env->GetStringUTFChars(pathString, nsnull);
00120   if (!path)
00121     return NS_ERROR_OUT_OF_MEMORY;
00122 
00123   int len = strlen(path);
00124   char* xpcomPath = (char*) malloc(len + sizeof(XPCOM_DLL) +
00125                                    sizeof(XPCOM_FILE_PATH_SEPARATOR) + 1);
00126   if (!xpcomPath)
00127     return NS_ERROR_OUT_OF_MEMORY;
00128   sprintf(xpcomPath, "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, path);
00129 
00130   nsresult rv = XPCOMGlueStartup(xpcomPath);
00131   free(xpcomPath);
00132   if (NS_FAILED(rv))
00133     return rv;
00134 
00135 #ifdef XP_WIN32
00136   // The JNICALL calling convention defines to "__stdcall" on Win32, which
00137   // mangles the name.
00138   nsDynamicFunctionLoad funcs[] = {
00139     { "_Java_org_mozilla_xpcom_internal_MozillaImpl_initialize@8",
00140             (NSFuncPtr*) &aFunctions[kFunc_Initialize] },
00141     { "_Java_org_mozilla_xpcom_internal_GREImpl_initEmbedding@20",
00142             (NSFuncPtr*) &aFunctions[kFunc_InitEmbedding] },
00143     { "_Java_org_mozilla_xpcom_internal_GREImpl_termEmbedding@8",
00144             (NSFuncPtr*) &aFunctions[kFunc_TermEmbedding] },
00145     { "_Java_org_mozilla_xpcom_internal_GREImpl_lockProfileDirectory@12",
00146             (NSFuncPtr*) &aFunctions[kFunc_LockProfileDirectory] },
00147     { "_Java_org_mozilla_xpcom_internal_GREImpl_notifyProfile@8",
00148             (NSFuncPtr*) &aFunctions[kFunc_NotifyProfile] },
00149     { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_initXPCOM@16",
00150             (NSFuncPtr*) &aFunctions[kFunc_InitXPCOM] },
00151     { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_shutdownXPCOM@12",
00152             (NSFuncPtr*) &aFunctions[kFunc_ShutdownXPCOM] },
00153     { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentManager@8",
00154             (NSFuncPtr*) &aFunctions[kFunc_GetComponentManager] },
00155     { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentRegistrar@8",
00156             (NSFuncPtr*) &aFunctions[kFunc_GetComponentRegistrar] },
00157     { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_getServiceManager@8",
00158             (NSFuncPtr*) &aFunctions[kFunc_GetServiceManager] },
00159     { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_newLocalFile@16",
00160             (NSFuncPtr*) &aFunctions[kFunc_NewLocalFile] },
00161     { "_Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_callXPCOMMethod@20",
00162             (NSFuncPtr*) &aFunctions[kFunc_CallXPCOMMethod] },
00163     { "_Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_finalizeProxy@12",
00164             (NSFuncPtr*) &aFunctions[kFunc_FinalizeProxy] },
00165     { "_Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_isSameXPCOMObject@16",
00166             (NSFuncPtr*) &aFunctions[kFunc_IsSameXPCOMObject] },
00167     { "_Java_org_mozilla_xpcom_ProfileLock_release@16",
00168             (NSFuncPtr*) &aFunctions[kFunc_ReleaseProfileLock] },
00169     { "_Java_org_mozilla_xpcom_internal_MozillaImpl_getNativeHandleFromAWT@12",
00170             (NSFuncPtr*) &aFunctions[kFunc_GetNativeHandleFromAWT] },
00171     { "_Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapJavaObject@16",
00172             (NSFuncPtr*) &aFunctions[kFunc_WrapJavaObject] },
00173     { "_Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapXPCOMObject@20",
00174             (NSFuncPtr*) &aFunctions[kFunc_WrapXPCOMObject] },
00175     { nsnull, nsnull }
00176   };
00177 #else
00178   nsDynamicFunctionLoad funcs[] = {
00179     { "Java_org_mozilla_xpcom_internal_MozillaImpl_initialize",
00180             (NSFuncPtr*) &aFunctions[kFunc_Initialize] },
00181     { "Java_org_mozilla_xpcom_internal_GREImpl_initEmbedding",
00182             (NSFuncPtr*) &aFunctions[kFunc_InitEmbedding] },
00183     { "Java_org_mozilla_xpcom_internal_GREImpl_termEmbedding",
00184             (NSFuncPtr*) &aFunctions[kFunc_TermEmbedding] },
00185     { "Java_org_mozilla_xpcom_internal_GREImpl_lockProfileDirectory",
00186             (NSFuncPtr*) &aFunctions[kFunc_LockProfileDirectory] },
00187     { "Java_org_mozilla_xpcom_internal_GREImpl_notifyProfile",
00188             (NSFuncPtr*) &aFunctions[kFunc_NotifyProfile] },
00189     { "Java_org_mozilla_xpcom_internal_XPCOMImpl_initXPCOM",
00190             (NSFuncPtr*) &aFunctions[kFunc_InitXPCOM] },
00191     { "Java_org_mozilla_xpcom_internal_XPCOMImpl_shutdownXPCOM",
00192             (NSFuncPtr*) &aFunctions[kFunc_ShutdownXPCOM] },
00193     { "Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentManager",
00194             (NSFuncPtr*) &aFunctions[kFunc_GetComponentManager] },
00195     { "Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentRegistrar",
00196             (NSFuncPtr*) &aFunctions[kFunc_GetComponentRegistrar] },
00197     { "Java_org_mozilla_xpcom_internal_XPCOMImpl_getServiceManager",
00198             (NSFuncPtr*) &aFunctions[kFunc_GetServiceManager] },
00199     { "Java_org_mozilla_xpcom_internal_XPCOMImpl_newLocalFile",
00200             (NSFuncPtr*) &aFunctions[kFunc_NewLocalFile] },
00201     { "Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_callXPCOMMethod",
00202             (NSFuncPtr*) &aFunctions[kFunc_CallXPCOMMethod] },
00203     { "Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_finalizeProxy",
00204             (NSFuncPtr*) &aFunctions[kFunc_FinalizeProxy] },
00205     { "Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_isSameXPCOMObject",
00206             (NSFuncPtr*) &aFunctions[kFunc_IsSameXPCOMObject] },
00207     { "Java_org_mozilla_xpcom_ProfileLock_release",
00208             (NSFuncPtr*) &aFunctions[kFunc_ReleaseProfileLock] },
00209     { "Java_org_mozilla_xpcom_internal_MozillaImpl_getNativeHandleFromAWT",
00210             (NSFuncPtr*) &aFunctions[kFunc_GetNativeHandleFromAWT] },
00211     { "Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapJavaObject",
00212             (NSFuncPtr*) &aFunctions[kFunc_WrapJavaObject] },
00213     { "Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapXPCOMObject",
00214             (NSFuncPtr*) &aFunctions[kFunc_WrapXPCOMObject] },
00215     { nsnull, nsnull }
00216   };
00217 #endif
00218 
00219   rv = XPCOMGlueLoadXULFunctions(funcs);
00220   if (NS_FAILED(rv))
00221     return rv;
00222 
00223   return NS_OK;
00224 }
00225 
00226 void
00227 ThrowException(JNIEnv* env, const nsresult aErrorCode, const char* aMessage)
00228 {
00229   // Only throw this exception if one hasn't already been thrown, so we don't
00230   // mask a previous exception/error.
00231   if (env->ExceptionCheck())
00232     return;
00233 
00234   // If the error code we get is for an Out Of Memory error, try to throw an
00235   // OutOfMemoryError.  The JVM may have enough memory to create this error.
00236   if (aErrorCode == NS_ERROR_OUT_OF_MEMORY) {
00237     jclass clazz = env->FindClass("java/lang/OutOfMemoryError");
00238     if (clazz) {
00239       env->ThrowNew(clazz, aMessage);
00240     }
00241     env->DeleteLocalRef(clazz);
00242     return;
00243   }
00244 
00245   // If the error was not handled above, then create an XPCOMException with the
00246   // given error code.
00247   jthrowable throwObj = nsnull;
00248   jclass exceptionClass = env->FindClass("org/mozilla/xpcom/XPCOMException");
00249   if (exceptionClass) {
00250     jmethodID mid = env->GetMethodID(exceptionClass, "<init>",
00251                                      "(JLjava/lang/String;)V");
00252     if (mid) {
00253       throwObj = (jthrowable) env->NewObject(exceptionClass, mid,
00254                                              (PRInt64) aErrorCode,
00255                                              env->NewStringUTF(aMessage));
00256     }
00257   }
00258   NS_ASSERTION(throwObj, "Failed to create XPCOMException object");
00259 
00260   // throw exception
00261   if (throwObj) {
00262     env->Throw(throwObj);
00263   }
00264 }
00265 
00266 // Register the JavaXPCOM native methods.  This associates a native Java
00267 // method with its C implementation.
00268 nsresult
00269 RegisterNativeMethods(JNIEnv* env, void** aFunctions)
00270 {
00271   JNINativeMethod mozilla_methods[] = {
00272     { "initializeNative", "()V",
00273       (void*) aFunctions[kFunc_Initialize] },
00274     { "getNativeHandleFromAWT", "(Ljava/lang/Object;)J",
00275       (void*) aFunctions[kFunc_GetNativeHandleFromAWT] }
00276   };
00277 
00278   JNINativeMethod gre_methods[] = {
00279     { "initEmbeddingNative",
00280       "(Ljava/io/File;Ljava/io/File;Lorg/mozilla/xpcom/IAppFileLocProvider;)V",
00281       (void*) aFunctions[kFunc_InitEmbedding] },
00282     { "termEmbedding", "()V",
00283       (void*) aFunctions[kFunc_TermEmbedding] },
00284     { "lockProfileDirectory", "(Ljava/io/File;)Lorg/mozilla/xpcom/ProfileLock;",
00285       (void*) aFunctions[kFunc_LockProfileDirectory] },
00286     { "notifyProfile", "()V",
00287       (void*) aFunctions[kFunc_NotifyProfile] },
00288   };
00289 
00290   JNINativeMethod xpcom_methods[] = {
00291     { "initXPCOMNative",
00292       "(Ljava/io/File;Lorg/mozilla/xpcom/IAppFileLocProvider;)Lorg/mozilla/interfaces/nsIServiceManager;",
00293       (void*) aFunctions[kFunc_InitXPCOM] },
00294     { "shutdownXPCOM", "(Lorg/mozilla/interfaces/nsIServiceManager;)V",
00295       (void*) aFunctions[kFunc_ShutdownXPCOM] },
00296     { "getComponentManager", "()Lorg/mozilla/interfaces/nsIComponentManager;",
00297       (void*) aFunctions[kFunc_GetComponentManager] },
00298     { "getComponentRegistrar", "()Lorg/mozilla/interfaces/nsIComponentRegistrar;",
00299       (void*) aFunctions[kFunc_GetComponentRegistrar] },
00300     { "getServiceManager", "()Lorg/mozilla/interfaces/nsIServiceManager;",
00301       (void*) aFunctions[kFunc_GetServiceManager] },
00302     { "newLocalFile", "(Ljava/lang/String;Z)Lorg/mozilla/interfaces/nsILocalFile;",
00303       (void*) aFunctions[kFunc_NewLocalFile] }
00304   };
00305 
00306   JNINativeMethod proxy_methods[] = {
00307     { "callXPCOMMethod",
00308       "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;",
00309       (void*) aFunctions[kFunc_CallXPCOMMethod] },
00310     { "finalizeProxyNative", "(Ljava/lang/Object;)V",
00311       (void*) aFunctions[kFunc_FinalizeProxy] },
00312     { "isSameXPCOMObject", "(Ljava/lang/Object;Ljava/lang/Object;)Z",
00313       (void*) aFunctions[kFunc_IsSameXPCOMObject] }
00314   };
00315 
00316   JNINativeMethod lockProxy_methods[] = {
00317     { "releaseNative", "(J)V",
00318       (void*) aFunctions[kFunc_ReleaseProfileLock] }
00319   };
00320 
00321   JNINativeMethod util_methods[] = {
00322     { "wrapJavaObject", "(Ljava/lang/Object;Ljava/lang/String;)J",
00323       (void*) aFunctions[kFunc_WrapJavaObject] },
00324     { "wrapXPCOMObject", "(JLjava/lang/String;)Ljava/lang/Object;",
00325       (void*) aFunctions[kFunc_WrapXPCOMObject] }
00326   };
00327 
00328   jint rc = -1;
00329   jclass clazz = env->FindClass("org/mozilla/xpcom/internal/MozillaImpl");
00330   if (clazz) {
00331     rc = env->RegisterNatives(clazz, mozilla_methods,
00332                           sizeof(mozilla_methods) / sizeof(mozilla_methods[0]));
00333   }
00334   NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE);
00335 
00336   rc = -1;
00337   clazz = env->FindClass("org/mozilla/xpcom/internal/GREImpl");
00338   if (clazz) {
00339     rc = env->RegisterNatives(clazz, gre_methods,
00340                               sizeof(gre_methods) / sizeof(gre_methods[0]));
00341   }
00342   NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE);
00343 
00344   rc = -1;
00345   clazz = env->FindClass("org/mozilla/xpcom/internal/XPCOMImpl");
00346   if (clazz) {
00347     rc = env->RegisterNatives(clazz, xpcom_methods,
00348                               sizeof(xpcom_methods) / sizeof(xpcom_methods[0]));
00349   }
00350   NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE);
00351 
00352   rc = -1;
00353   clazz = env->FindClass("org/mozilla/xpcom/internal/XPCOMJavaProxy");
00354   if (clazz) {
00355     rc = env->RegisterNatives(clazz, proxy_methods,
00356                               sizeof(proxy_methods) / sizeof(proxy_methods[0]));
00357   }
00358   NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE);
00359 
00360   rc = -1;
00361   clazz = env->FindClass("org/mozilla/xpcom/ProfileLock");
00362   if (clazz) {
00363     rc = env->RegisterNatives(clazz, lockProxy_methods,
00364                       sizeof(lockProxy_methods) / sizeof(lockProxy_methods[0]));
00365   }
00366   NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE);
00367 
00368   rc = -1;
00369   clazz = env->FindClass("org/mozilla/xpcom/internal/JavaXPCOMMethods");
00370   if (clazz) {
00371     rc = env->RegisterNatives(clazz, util_methods,
00372                               sizeof(util_methods) / sizeof(util_methods[0]));
00373   }
00374   NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE);
00375 
00376   return NS_OK;
00377 }
00378 
00379 // Load the JavaXPCOM methods from the XUL shared library, and registers them
00380 // as Java native methods.
00381 extern "C" JX_EXPORT void JNICALL
00382 JXM_NATIVE(registerJavaXPCOMMethodsNative) (JNIEnv *env, jclass that,
00383                                             jobject aXPCOMPath)
00384 {
00385   void* functions[JX_NUM_FUNCS];
00386   memset(functions, 0, JX_NUM_FUNCS * sizeof(void*));
00387 
00388   nsresult rv = LoadXULMethods(env, aXPCOMPath, functions);
00389   if (NS_SUCCEEDED(rv)) {
00390     rv = RegisterNativeMethods(env, functions);
00391   }
00392 
00393   if (NS_FAILED(rv)) {
00394     ThrowException(env, rv, "Failed to register JavaXPCOM methods");
00395   }
00396 }
00397