From 4b2e00383888bf15243e131cf9511c0f4eab90a2 Mon Sep 17 00:00:00 2001 From: "pedemont%us.ibm.com" Date: Fri, 17 Dec 2004 22:25:12 +0000 Subject: [PATCH] Bug 270889 - Change params for initEmbedding() to use java.io.File and custom class. Backout lazy discovery of interface info (no longer needed). Better distribute methods in XPCOM and GeckoEmbed classes. r=darin. git-svn-id: svn://10.0.0.236/trunk@166838 18797224-902f-48f8-a5cc-f745e15eee43 --- .../java/xpcom/nsAppFileLocProviderProxy.cpp | 3 +- .../java/xpcom/nsAppFileLocProviderProxy.h | 60 ++++++ .../java/xpcom/nsJavaInterfaces.cpp | 189 +++++++++++++----- .../extensions/java/xpcom/nsJavaWrapper.cpp | 45 ++--- .../java/xpcom/nsJavaXPCOMBindingUtils.cpp | 107 ++++++---- .../java/xpcom/nsJavaXPCOMBindingUtils.h | 14 +- .../java/xpcom/tests/TestArray.java | 5 +- 7 files changed, 298 insertions(+), 125 deletions(-) create mode 100644 mozilla/extensions/java/xpcom/nsAppFileLocProviderProxy.h diff --git a/mozilla/extensions/java/xpcom/nsAppFileLocProviderProxy.cpp b/mozilla/extensions/java/xpcom/nsAppFileLocProviderProxy.cpp index 12706608c78..63a33ae8cef 100644 --- a/mozilla/extensions/java/xpcom/nsAppFileLocProviderProxy.cpp +++ b/mozilla/extensions/java/xpcom/nsAppFileLocProviderProxy.cpp @@ -74,7 +74,8 @@ nsAppFileLocProviderProxy::GetFile(const char* aProp, PRBool* aIsPersistant, // Call Java function jobject javaFile = nsnull; if (mid) { - javaFile = mJavaEnv->CallObjectMethod(mJavaLocProvider, mid, prop, persistant); + javaFile = mJavaEnv->CallObjectMethod(mJavaLocProvider, mid, prop, + persistant); } if (javaFile == nsnull) { return NS_ERROR_FAILURE; diff --git a/mozilla/extensions/java/xpcom/nsAppFileLocProviderProxy.h b/mozilla/extensions/java/xpcom/nsAppFileLocProviderProxy.h new file mode 100644 index 00000000000..edbcf204d80 --- /dev/null +++ b/mozilla/extensions/java/xpcom/nsAppFileLocProviderProxy.h @@ -0,0 +1,60 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _nsAppFileLocProviderProxy_h_ +#define _nsAppFileLocProviderProxy_h_ + +#include "nsIDirectoryService.h" +#include "jni.h" + + +class nsAppFileLocProviderProxy : public nsIDirectoryServiceProvider +{ +public: + nsAppFileLocProviderProxy(JNIEnv* env, jobject aJavaLocProvider); + ~nsAppFileLocProviderProxy(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + +private: + JNIEnv* mJavaEnv; + jobject mJavaLocProvider; +}; + +#endif //_nsAppFileLocProviderProxy_h_ + diff --git a/mozilla/extensions/java/xpcom/nsJavaInterfaces.cpp b/mozilla/extensions/java/xpcom/nsJavaInterfaces.cpp index addcf559cab..c8715ec629f 100644 --- a/mozilla/extensions/java/xpcom/nsJavaInterfaces.cpp +++ b/mozilla/extensions/java/xpcom/nsJavaInterfaces.cpp @@ -39,89 +39,142 @@ #include "nsJavaXPCOMBindingUtils.h" #include "nsJavaXPTCStub.h" #include "nsEmbedAPI.h" +#include "nsIComponentRegistrar.h" #include "nsString.h" #include "nsISimpleEnumerator.h" #include "nsIInterfaceInfoManager.h" #include "nsIInputStream.h" #include "nsEnumeratorUtils.h" #include "nsArray.h" +#include "nsAppFileLocProviderProxy.h" #define GECKO_NATIVE(func) Java_org_mozilla_xpcom_GeckoEmbed_##func #define XPCOM_NATIVE(func) Java_org_mozilla_xpcom_XPCOM_##func -PRBool gEmbeddingInitialized = PR_FALSE; - extern "C" JNIEXPORT void JNICALL GECKO_NATIVE(initEmbedding) (JNIEnv* env, jclass, jobject aMozBinDirectory, jobject aAppFileLocProvider) { - if (!InitializeJavaGlobals(env)) { - FreeJavaGlobals(env); - ThrowXPCOMException(env, 0); - return; - } - - nsresult rv; - nsCOMPtr directory; - if (aMozBinDirectory) + nsresult rv = NS_OK; + if (InitializeJavaGlobals(env)) { - // Find corresponding XPCOM object - void* xpcomObj = GetMatchingXPCOMObject(env, aMozBinDirectory); - NS_ASSERTION(xpcomObj != nsnull, "Failed to get matching XPCOM object"); - if (xpcomObj == nsnull) { - ThrowXPCOMException(env, 0); - return; + // Create an nsILocalFile from given java.io.File + nsCOMPtr directory; + if (aMozBinDirectory) { + rv = File_to_nsILocalFile(env, aMozBinDirectory, getter_AddRefs(directory)); } - NS_ASSERTION(!IsXPTCStub(xpcomObj), "Expected JavaXPCOMInstance, but got nsJavaXPTCStub"); - directory = do_QueryInterface(((JavaXPCOMInstance*) xpcomObj)->GetInstance()); + if (NS_SUCCEEDED(rv)) { + nsAppFileLocProviderProxy* provider = nsnull; + if (aAppFileLocProvider) { + provider = new nsAppFileLocProviderProxy(env, aAppFileLocProvider); + } + + rv = NS_InitEmbedding(directory, provider); + if (provider) { + delete provider; + } + if (NS_SUCCEEDED(rv)) { + return; + } + } } - /* XXX How do we handle AppFileLocProvider, if we can't create any of the - * Java<->XPCOM mappings before NS_InitEmbedding has been called? - */ - nsIDirectoryServiceProvider* provider = nsnull; -/* if (aAppFileLocProvider) - { - JavaXPCOMInstance* inst = (JavaXPCOMInstance*) aMozBinDirectory; - provider = (nsIDirectoryServiceProvider*) inst->GetInstance(); - } */ - - rv = NS_InitEmbedding(directory, provider); - if (NS_FAILED(rv)) - ThrowXPCOMException(env, rv); - - gEmbeddingInitialized = PR_TRUE; + FreeJavaGlobals(env); + ThrowXPCOMException(env, NS_FAILED(rv) ? rv : NS_ERROR_FAILURE); } extern "C" JNIEXPORT void JNICALL GECKO_NATIVE(termEmbedding) (JNIEnv *env, jclass) { - FreeJavaGlobals(env); - nsresult rv = NS_TermEmbedding(); if (NS_FAILED(rv)) ThrowXPCOMException(env, rv); + + FreeJavaGlobals(env); } -/* XXX This can be called before XPCOM is init'd. So we need to find a way - * to create an appropriate Java class for this, such that if it is passed - * through the JNI code (or if we make NS_InitEmbedding take it as a param), - * then we can deal with it accordingly, since it won't yet have an - * InterfaceInfo attached to it. Perhaps we can set its InterfaceInfo to - * NULL and just create it lazily. - */ extern "C" JNIEXPORT jobject JNICALL -GECKO_NATIVE(newLocalFile) (JNIEnv *env, jclass, jstring aPath, - jboolean aFollowLinks) +XPCOM_NATIVE(initXPCOM) (JNIEnv* env, jclass, jobject aMozBinDirectory, + jobject aAppFileLocProvider) { - if (!InitializeJavaGlobals(env)) { - FreeJavaGlobals(env); - ThrowXPCOMException(env, 0); - return nsnull; + nsresult rv = NS_OK; + if (InitializeJavaGlobals(env)) + { + // Create an nsILocalFile from given java.io.File + nsCOMPtr directory; + if (aMozBinDirectory) { + rv = File_to_nsILocalFile(env, aMozBinDirectory, getter_AddRefs(directory)); + } + + if (NS_SUCCEEDED(rv)) { + nsAppFileLocProviderProxy* provider = nsnull; + if (aAppFileLocProvider) { + provider = new nsAppFileLocProviderProxy(env, aAppFileLocProvider); + } + + nsIServiceManager* servMan = nsnull; + rv = NS_InitXPCOM2(&servMan, directory, provider); + if (provider) { + delete provider; + } + + jobject java_stub = nsnull; + if (NS_SUCCEEDED(rv)) { + // wrap xpcom instance + JavaXPCOMInstance* inst; + inst = CreateJavaXPCOMInstance(servMan, &NS_GET_IID(nsIServiceManager)); + NS_RELEASE(servMan); // JavaXPCOMInstance has owning ref + + if (inst) { + // create java stub + java_stub = CreateJavaWrapper(env, "nsIServiceManager"); + + if (java_stub) { + // Associate XPCOM object w/ Java stub + AddJavaXPCOMBinding(env, java_stub, inst); + return java_stub; + } + } + } + } } + FreeJavaGlobals(env); + ThrowXPCOMException(env, NS_FAILED(rv) ? rv : NS_ERROR_FAILURE); + return nsnull; +} + +extern "C" JNIEXPORT void JNICALL +XPCOM_NATIVE(shutdownXPCOM) (JNIEnv *env, jclass, jobject aServMgr) +{ + nsCOMPtr servMgr; + if (aServMgr) { + // Find corresponding XPCOM object + void* xpcomObj = GetMatchingXPCOMObject(env, aServMgr); + NS_ASSERTION(xpcomObj != nsnull, "Failed to get matching XPCOM object"); + if (xpcomObj == nsnull) { + ThrowXPCOMException(env, NS_ERROR_FAILURE); + return; + } + + NS_ASSERTION(!IsXPTCStub(xpcomObj), + "Expected JavaXPCOMInstance, but got nsJavaXPTCStub"); + servMgr = do_QueryInterface(((JavaXPCOMInstance*) xpcomObj)->GetInstance()); + } + + nsresult rv = NS_ShutdownXPCOM(servMgr); + if (NS_FAILED(rv)) + ThrowXPCOMException(env, rv); + + FreeJavaGlobals(env); +} + +extern "C" JNIEXPORT jobject JNICALL +XPCOM_NATIVE(newLocalFile) (JNIEnv *env, jclass, jstring aPath, + jboolean aFollowLinks) +{ jobject java_stub = nsnull; // Create a Mozilla string from the jstring @@ -143,7 +196,7 @@ GECKO_NATIVE(newLocalFile) (JNIEnv *env, jclass, jstring aPath, if (NS_SUCCEEDED(rv)) { // wrap xpcom instance JavaXPCOMInstance* inst; - inst = CreateJavaXPCOMInstance(file, nsnull); + inst = CreateJavaXPCOMInstance(file, &NS_GET_IID(nsILocalFile)); NS_RELEASE(file); // JavaXPCOMInstance has owning ref if (inst) { @@ -164,7 +217,7 @@ GECKO_NATIVE(newLocalFile) (JNIEnv *env, jclass, jstring aPath, } extern "C" JNIEXPORT jobject JNICALL -GECKO_NATIVE(getComponentManager) (JNIEnv *env, jclass) +XPCOM_NATIVE(getComponentManager) (JNIEnv *env, jclass) { jobject java_stub = nsnull; @@ -196,7 +249,39 @@ GECKO_NATIVE(getComponentManager) (JNIEnv *env, jclass) } extern "C" JNIEXPORT jobject JNICALL -GECKO_NATIVE(getServiceManager) (JNIEnv *env, jclass) +XPCOM_NATIVE(getComponentRegistrar) (JNIEnv *env, jclass) +{ + jobject java_stub = nsnull; + + // Call XPCOM method + nsIComponentRegistrar* cr = nsnull; + nsresult rv = NS_GetComponentRegistrar(&cr); + + if (NS_SUCCEEDED(rv)) { + // wrap xpcom instance + JavaXPCOMInstance* inst; + inst = CreateJavaXPCOMInstance(cr, &NS_GET_IID(nsIComponentRegistrar)); + NS_RELEASE(cr); // JavaXPCOMInstance has owning ref + + if (inst) { + // create java stub + java_stub = CreateJavaWrapper(env, "nsIComponentRegistrar"); + + if (java_stub) { + // Associate XPCOM object w/ Java stub + AddJavaXPCOMBinding(env, java_stub, inst); + } + } + } + + if (java_stub == nsnull) + ThrowXPCOMException(env, 0); + + return java_stub; +} + +extern "C" JNIEXPORT jobject JNICALL +XPCOM_NATIVE(getServiceManager) (JNIEnv *env, jclass) { jobject java_stub = nsnull; diff --git a/mozilla/extensions/java/xpcom/nsJavaWrapper.cpp b/mozilla/extensions/java/xpcom/nsJavaWrapper.cpp index 62fafc9fa8f..72b06a1fc37 100644 --- a/mozilla/extensions/java/xpcom/nsJavaWrapper.cpp +++ b/mozilla/extensions/java/xpcom/nsJavaWrapper.cpp @@ -42,7 +42,6 @@ #include "xptcall.h" #include "nsIInterfaceInfoManager.h" #include "nsString.h" -#include "nsString.h" #include "nsCRT.h" #include "prmem.h" @@ -382,16 +381,7 @@ SetupParams(JNIEnv *env, const jobject aParam, const nsXPTParamInfo &aParamInfo, data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, 0); } - jboolean isCopy = JNI_FALSE; - const PRUnichar* buf = nsnull; - if (data) { - buf = env->GetStringChars(data, &isCopy); - } - - nsString* str = new nsString(buf); - if (isCopy) { - env->ReleaseStringChars((jstring)data, buf); - } + nsAString* str = jstring_to_nsAString(env, data); aVariant.val.p = aVariant.ptr = str; aVariant.flags = nsXPTCVariant::PTR_IS_DATA | nsXPTCVariant::VAL_IS_DOMSTR; @@ -410,16 +400,7 @@ SetupParams(JNIEnv *env, const jobject aParam, const nsXPTParamInfo &aParamInfo, data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, 0); } - jboolean isCopy = JNI_FALSE; - const char* buf = nsnull; - if (data) { - buf = env->GetStringUTFChars(data, &isCopy); - } - - nsCString* str = new nsCString(buf); - if (isCopy) { - env->ReleaseStringUTFChars((jstring)aParam, buf); - } + nsACString* str = jstring_to_nsACString(env, data); aVariant.val.p = aVariant.ptr = str; aVariant.flags = nsXPTCVariant::PTR_IS_DATA; @@ -685,12 +666,13 @@ FinalizeParams(JNIEnv *env, const jobject aParam, { nsString* str = (nsString*) aVariant.val.p; - if (str && aParamInfo.IsOut()) { - jstring jstr = env->NewString((const jchar*) str->get(), str->Length()); - env->SetObjectArrayElement((jobjectArray) aParam, 0, jstr); + if (str) { + if (aParamInfo.IsOut()) { + jstring jstr = env->NewString((const jchar*) str->get(), str->Length()); + env->SetObjectArrayElement((jobjectArray) aParam, 0, jstr); + } + delete str; } - - delete str; } break; @@ -699,12 +681,13 @@ FinalizeParams(JNIEnv *env, const jobject aParam, { nsCString* str = (nsCString*) aVariant.val.p; - if (str && aParamInfo.IsOut()) { - jstring jstr = env->NewStringUTF((const char*) str->get()); - env->SetObjectArrayElement((jobjectArray) aParam, 0, jstr); + if (str) { + if (aParamInfo.IsOut()) { + jstring jstr = env->NewStringUTF((const char*) str->get()); + env->SetObjectArrayElement((jobjectArray) aParam, 0, jstr); + } + delete str; } - - delete str; } break; diff --git a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp index 534b295e6ba..7b7971b88d9 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp +++ b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp @@ -46,10 +46,6 @@ #include "nsProxyRelease.h" -#ifdef DEBUG -extern PRBool gEmbeddingInitialized; -#endif - /* Java JNI globals */ jclass intClass = nsnull; jclass intArrayClass = nsnull; @@ -438,46 +434,20 @@ JavaXPCOMInstance::~JavaXPCOMInstance() NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get MainEventQ"); } -nsIInterfaceInfo* -JavaXPCOMInstance::InterfaceInfo() -{ - // We lazily create the interfaceInfo for nsILocalFile. - if (!mIInfo) { - NS_ASSERTION(gEmbeddingInitialized, "Trying to create interface info, but XPCOM not inited"); - - // Get interface info for class - nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); - NS_ASSERTION(iim != nsnull, "Failed to get InterfaceInfoManager"); - if (iim) { - iim->GetInfoForIID(&NS_GET_IID(nsILocalFile), getter_AddRefs(mIInfo)); - } - } - - NS_ASSERTION(mIInfo, "No interfaceInfo for JavaXPCOMInstance"); - return mIInfo; -} - JavaXPCOMInstance* CreateJavaXPCOMInstance(nsISupports* aXPCOMObject, const nsIID* aIID) { JavaXPCOMInstance* inst = nsnull; - // We can't call XPTI_GetInterfaceInfoManager() before NS_InitEmbedding(), - // so for NS_NewLocalFile (which can be called before NS_InitEmbedding), we - // pass in a null aIID, and create the interface info lazily later. - if (!aIID) { - inst = new JavaXPCOMInstance(aXPCOMObject, nsnull); - } else { - // Get interface info for class - nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); - NS_ASSERTION(iim != nsnull, "Failed to get InterfaceInfoManager"); - if (iim) { - nsCOMPtr info; - iim->GetInfoForIID(aIID, getter_AddRefs(info)); + // Get interface info for class + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + NS_ASSERTION(iim != nsnull, "Failed to get InterfaceInfoManager"); + if (iim) { + nsCOMPtr info; + iim->GetInfoForIID(aIID, getter_AddRefs(info)); - // Wrap XPCOM object - inst = new JavaXPCOMInstance(aXPCOMObject, info); - } + // Wrap XPCOM object + inst = new JavaXPCOMInstance(aXPCOMObject, info); } return inst; @@ -548,3 +518,64 @@ GetIIDForMethodParam(nsIInterfaceInfo *iinfo, return rv; } + +/******************************* + * JNI helper functions + *******************************/ +nsAString* +jstring_to_nsAString(JNIEnv* env, jstring aString) +{ + jboolean isCopy = JNI_FALSE; + const PRUnichar* buf = nsnull; + if (aString) { + buf = env->GetStringChars(aString, &isCopy); + } + + nsString* str = new nsString(buf); + if (isCopy) { + env->ReleaseStringChars(aString, buf); + } + + return str; +} + +nsACString* +jstring_to_nsACString(JNIEnv* env, jstring aString) +{ + jboolean isCopy = JNI_FALSE; + const char* buf = nsnull; + if (aString) { + buf = env->GetStringUTFChars(aString, &isCopy); + } + + nsCString* str = new nsCString(buf); + if (isCopy) { + env->ReleaseStringUTFChars(aString, buf); + } + + return str; +} + +nsresult +File_to_nsILocalFile(JNIEnv* env, jobject aFile, nsILocalFile** aLocalFile) +{ + jstring pathName = nsnull; + jclass clazz = env->FindClass("java/io/File"); + if (clazz) { + jmethodID pathMID = env->GetMethodID(clazz, "getCanonicalPath", + "()Ljava/lang/String;"); + if (pathMID) { + pathName = (jstring) env->CallObjectMethod(aFile, pathMID); + } + } + + if (pathName) { + nsAString* path = jstring_to_nsAString(env, pathName); + nsresult rv = NS_NewLocalFile(*path, false, aLocalFile); + delete path; + return rv; + } + + return NS_ERROR_FAILURE; +} + diff --git a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h index 9f98b977b5c..a4638eee058 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h +++ b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h @@ -41,6 +41,7 @@ #include "jni.h" #include "xptcall.h" #include "nsCOMPtr.h" +#include "nsString.h" #ifdef DEBUG_pedemonte #define LOG(x) printf x @@ -86,7 +87,7 @@ public: ~JavaXPCOMInstance(); nsISupports* GetInstance() { return mInstance; } - nsIInterfaceInfo* InterfaceInfo(); + nsIInterfaceInfo* InterfaceInfo() { return mIInfo; } private: nsISupports* mInstance; @@ -118,4 +119,15 @@ nsresult GetIIDForMethodParam(nsIInterfaceInfo *iinfo, PRBool isFullVariantArray, nsID &result); +/******************************* + * JNI helper functions + *******************************/ +// java.lang.String to nsAString/nsACString +nsAString* jstring_to_nsAString(JNIEnv* env, jstring aString); +nsACString* jstring_to_nsACString(JNIEnv* env, jstring aString); + +// java.io.File to nsILocalFile +nsresult File_to_nsILocalFile(JNIEnv* env, jobject aFile, + nsILocalFile** aLocalFile); + #endif // _nsJavaXPCOMBindingUtils_h_ diff --git a/mozilla/extensions/java/xpcom/tests/TestArray.java b/mozilla/extensions/java/xpcom/tests/TestArray.java index c95b1f05311..e50e44b0acb 100644 --- a/mozilla/extensions/java/xpcom/tests/TestArray.java +++ b/mozilla/extensions/java/xpcom/tests/TestArray.java @@ -36,6 +36,7 @@ * ***** END LICENSE BLOCK ***** */ import org.mozilla.xpcom.*; +import java.io.*; /** * Adapted from xpcom/tests/TestArray.cpp @@ -70,10 +71,10 @@ public class TestArray { throw new RuntimeException("MOZILLA_FIVE_HOME system property not set."); } - nsILocalFile localFile = GeckoEmbed.newLocalFile(mozillaPath, true); + File localFile = new File(mozillaPath); GeckoEmbed.initEmbedding(localFile, null); - nsIComponentManager componentManager = GeckoEmbed.getComponentManager(); + nsIComponentManager componentManager = XPCOM.getComponentManager(); nsIMutableArray array = (nsIMutableArray) componentManager.createInstanceByContractID(NS_ARRAY_CID, null, nsIMutableArray.NS_IMUTABLEARRAY_IID); if (array == null) { throw new RuntimeException("Failed to create nsIMutableArray.");