diff --git a/extensions/java/xpcom/GeckoEmbed.java b/extensions/java/xpcom/GeckoEmbed.java new file mode 100644 index 000000000000..f8b0faf77700 --- /dev/null +++ b/extensions/java/xpcom/GeckoEmbed.java @@ -0,0 +1,74 @@ +/* ***** 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 ***** */ + +package org.mozilla.xpcom; + +public final class GeckoEmbed { + + // XPCOM Utility functions + public static native void NS_InitEmbedding(String aMozBinDirectory, int aAppFileLocProvider); + public static native void NS_TermEmbedding(); + public static native nsILocalFile NS_NewLocalFile(String aPath, boolean followLinks); + public static native nsIComponentManager NS_GetComponentManager(); + public static native nsIServiceManager NS_GetServiceManager(); + public static native nsISimpleEnumerator NS_NewSingletonEnumerator(nsISupports aSingleton); + + // Calling functions used by Java stub classes + public static native void CallXPCOMMethodVoid(Object thisObj, int fnNumber, Object[] params); + public static native boolean CallXPCOMMethodBool(Object thisObj, int fnNumber, Object[] params); + public static native boolean[] CallXPCOMMethodBoolA(Object thisObj, int fnNumber, Object[] params); + public static native byte CallXPCOMMethodByte(Object thisObj, int fnNumber, Object[] params); + public static native byte[] CallXPCOMMethodByteA(Object thisObj, int fnNumber, Object[] params); + public static native char CallXPCOMMethodChar(Object thisObj, int fnNumber, Object[] params); + public static native char[] CallXPCOMMethodCharA(Object thisObj, int fnNumber, Object[] params); + public static native short CallXPCOMMethodShort(Object thisObj, int fnNumber, Object[] params); + public static native short[] CallXPCOMMethodShortA(Object thisObj, int fnNumber, Object[] params); + public static native int CallXPCOMMethodInt(Object thisObj, int fnNumber, Object[] params); + public static native int[] CallXPCOMMethodIntA(Object thisObj, int fnNumber, Object[] params); + public static native long CallXPCOMMethodLong(Object thisObj, int fnNumber, Object[] params); + public static native long[] CallXPCOMMethodLongA(Object thisObj, int fnNumber, Object[] params); + public static native float CallXPCOMMethodFloat(Object thisObj, int fnNumber, Object[] params); + public static native float[] CallXPCOMMethodFloatA(Object thisObj, int fnNumber, Object[] params); + public static native double CallXPCOMMethodDouble(Object thisObj, int fnNumber, Object[] params); + public static native double[] CallXPCOMMethodDoubleA(Object thisObj, int fnNumber, Object[] params); + public static native Object CallXPCOMMethodObj(Object thisObj, int fnNumber, Object[] params); + public static native Object[] CallXPCOMMethodObjA(Object thisObj, int fnNumber, Object[] params); + + public static native void FinalizeStub(Object thisObj); + + public static native int nsWriteSegmentFun(int ptr, Object aInStream, int aClosure, byte[] aFromSegment, int aToOffset, int aCount); +} \ No newline at end of file diff --git a/extensions/java/xpcom/Makefile.in b/extensions/java/xpcom/Makefile.in new file mode 100644 index 000000000000..974e34b5e322 --- /dev/null +++ b/extensions/java/xpcom/Makefile.in @@ -0,0 +1,169 @@ +# ***** 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/config.mk + +MODULE = javaembed +LIBRARY_NAME = javaembed +EXPORT_LIBRARY = 1 + +EMBED_JAR = mozembed.jar +EMBED_JAR_SRC = $(patsubst %.jar,%-src.jar,$(EMBED_JAR)) + +REQUIRES = xpcom \ + string \ + embed_base \ + nspr \ + gfx \ + $(NULL) + +CPPSRCS = \ + nsJavaInterfaces.cpp \ + nsJavaWrapper.cpp \ + nsJavaXPTCStub.cpp \ + nsJavaXPCOMBindingUtils.cpp \ + $(NULL) + +JAVA_LOC = /opt/IBMJava2-141 + +LOCAL_INCLUDES = \ + -I$(JAVA_LOC)/include \ + $(NULL) + +EXTRA_DSO_LIBS = \ + embed_base_s \ + xpcomglue_s \ + xpcom \ + $(NULL) + +EXTRA_DSO_LDOPTS = \ + $(LIBS_DIR) \ + $(EXTRA_DSO_LIBS) \ + $(NULL) + +IDL_FILES := $(filter-out nsrootidl.idl,$(wildcard $(DIST)/idl/*)) + +JAVA_IFACES = $(addprefix $(XPIDL_GEN_DIR)/org/mozilla/xpcom/,$($(notdir $(IDL_FILES)):.idl=.java)) +JAVA_STUBS = $(patsubst %.idl,$(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/%_Stub.java,$(notdir $(IDL_FILES))) + +_JAVA_IFACE_CLASSES = $(patsubst %.idl,org/mozilla/xpcom/%.class,$(notdir $(IDL_FILES))) +_JAVA_STUB_CLASSES = $(patsubst %.idl,org/mozilla/xpcom/stubs/%_Stub.class,$(notdir $(IDL_FILES))) + +_IGNORE_IFACES = domstubs +IGNORE_IFACES = $(patsubst %,org/mozilla/xpcom/%.class,$(_IGNORE_IFACES)) +JAVA_IFACE_CLASSES = $(filter-out $(IGNORE_IFACES),$(_JAVA_IFACE_CLASSES)) + +_IGNORE_STUBS = domstubs gfxIFormats +IGNORE_STUBS = $(patsubst %,org/mozilla/xpcom/stubs/%_Stub.class,$(_IGNORE_STUBS)) +JAVA_STUB_CLASSES = $(filter-out $(IGNORE_STUBS),$(_JAVA_STUB_CLASSES)) + +GARBAGE = $(EMBED_JAR) $(EMBED_JAR_SRC) +GARBAGE_DIRS += $(XPIDL_GEN_DIR) org + +include $(topsrcdir)/config/rules.mk + +$(XPIDL_GEN_DIR)/.done: + @if test ! -d $(XPIDL_GEN_DIR); then echo Creating $(XPIDL_GEN_DIR)/.done; rm -rf $(XPIDL_GEN_DIR); mkdir $(XPIDL_GEN_DIR); fi + @touch $@ + +$(XPIDL_GEN_DIR)/org/mozilla/xpcom/.done: $(XPIDL_GEN_DIR)/.done + @if test ! -d $(XPIDL_GEN_DIR)/org/mozilla/xpcom; then echo Creating $(XPIDL_GEN_DIR)/org/mozilla/xpcom/.done; rm -rf $(XPIDL_GEN_DIR)/org; mkdir $(XPIDL_GEN_DIR)/org; mkdir $(XPIDL_GEN_DIR)/org/mozilla; mkdir $(XPIDL_GEN_DIR)/org/mozilla/xpcom; fi + @touch $@ + +$(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/.done: $(XPIDL_GEN_DIR)/org/mozilla/xpcom/.done + @if test ! -d $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs; then echo Creating $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/.done; rm -rf $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs; mkdir $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs; fi + @touch $@ + +org/mozilla/xpcom/.done: + @if test ! -d org/mozilla/xpcom; then echo Creating org/mozilla/xpcom/.done; rm -rf org; mkdir org; mkdir org/mozilla; mkdir org/mozilla/xpcom; fi + @touch $@ + +org/mozilla/xpcom/stubs/.done: org/mozilla/xpcom/.done + @if test ! -d org/mozilla/xpcom/stubs; then echo Creating org/mozilla/xpcom/stubs/.done; rm -rf org/mozilla/xpcom/stubs; mkdir org/mozilla/xpcom/stubs; fi + @touch $@ + +#$(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/%.java: $(XPIDL_COMPILE) $(XPIDL_GEN_DIR)/.done +# $(ELOG) $(XPIDL_COMPILE) -m javastub -w -I$(srcdir) -I$(IDL_DIR) -o $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/$* $(_VPATH_SRCS) +$(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/.java_done: $(XPIDL_COMPILE) $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/.done + @echo Making Java stub files + @for idl in $(IDL_FILES); do \ + $(XPIDL_COMPILE) -m javastub -w -I$(srcdir) -I$(IDL_DIR) -o $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/`basename $$idl`_Stub $$idl; \ + done + @touch $@ + +#$(XPIDL_GEN_DIR)/org/mozilla/xpcom/%.java: $(XPIDL_COMPILE) $(XPIDL_GEN_DIR)/.done +# $(ELOG) $(XPIDL_COMPILE) -m java -w -I$(srcdir) -I$(IDL_DIR) -o $(XPIDL_GEN_DIR)/org/mozilla/xpcom/$* $(_VPATH_SRCS) +$(XPIDL_GEN_DIR)/org/mozilla/xpcom/.java_done: $(XPIDL_COMPILE) $(XPIDL_GEN_DIR)/org/mozilla/xpcom/.done + @echo Making Java interface files + @for idl in $(IDL_FILES); do \ + $(XPIDL_COMPILE) -m java -w -I$(srcdir) -I$(IDL_DIR) -o $(XPIDL_GEN_DIR)/org/mozilla/xpcom/`basename $$idl` $$idl; \ + done + @$(INSTALL) -m 644 $(srcdir)/GeckoEmbed.java $(XPIDL_GEN_DIR)/org/mozilla/xpcom + @touch $@ + +#org/mozilla/xpcom/stubs/%.class: $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/.java_done org/mozilla/xpcom/stubs/.done +# @javac -classpath org/mozilla/xpcom:org/mozilla/xpcom/stubs -sourcepath $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs -d org/mozilla/xpcom/stubs $(XPIDL_GEN_DIR)/$(patsubst %.class,%.java,$@) + +#org/mozilla/xpcom/%.class: $(XPIDL_GEN_DIR)/org/mozilla/xpcom/.java_done org/mozilla/xpcom/.done +# @javac -classpath org/mozilla/xpcom -sourcepath $(XPIDL_GEN_DIR)/org/mozilla/xpcom -d org/mozilla/xpcom $(XPIDL_GEN_DIR)/$(patsubst %.class,%.java,$@) + +org/mozilla/xpcom/.class_done: $(XPIDL_GEN_DIR)/org/mozilla/xpcom/.java_done + @echo Compiling Java interface classes + @javac -classpath . -d . $(filter-out $(addprefix $(XPIDL_GEN_DIR)/,$(IGNORE_STUBS:.class=.java)),$(wildcard $(XPIDL_GEN_DIR)/org/mozilla/xpcom/*.java)) + @touch $@ + +org/mozilla/xpcom/stubs/.class_done: org/mozilla/xpcom/.class_done $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/.java_done + @echo Compiling Java stub classes + @javac -classpath . -d . $(filter-out $(addprefix $(XPIDL_GEN_DIR)/,$(IGNORE_STUBS:.class=.java)),$(wildcard $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/*.java)) + @touch $@ + +#$(EMBED_JAR): $(JAVA_IFACE_CLASSES) $(JAVA_STUB_CLASSES) +$(EMBED_JAR): org/mozilla/xpcom/.class_done org/mozilla/xpcom/stubs/.class_done + $(ZIP) $(EMBED_JAR) -qq -r org + +$(EMBED_JAR_SRC): $(XPIDL_GEN_DIR)/org/mozilla/xpcom/.java_done $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/.java_done + @cd $(XPIDL_GEN_DIR); $(ZIP) ../$(EMBED_JAR_SRC) -qq -r org + +jar:: $(EMBED_JAR) $(EMBED_JAR_SRC) + $(INSTALL) $(IFLAGS1) $^ $(DIST)/bin + diff --git a/extensions/java/xpcom/nsJavaInterfaces.cpp b/extensions/java/xpcom/nsJavaInterfaces.cpp new file mode 100644 index 000000000000..134373200482 --- /dev/null +++ b/extensions/java/xpcom/nsJavaInterfaces.cpp @@ -0,0 +1,522 @@ +/* ***** 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 ***** */ + +#include "nsJavaWrapper.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "nsJavaXPTCStub.h" +#include "nsEmbedAPI.h" +#include "nsString.h" +#include "nsISimpleEnumerator.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIInputStream.h" +#include "nsEnumeratorUtils.h" + +#define XPCOM_NATIVE(func) Java_org_mozilla_xpcom_GeckoEmbed_##func + +PRBool gEmbeddingInitialized = PR_FALSE; + + +extern "C" JNIEXPORT void JNICALL +XPCOM_NATIVE(NS_1InitEmbedding) (JNIEnv* env, jclass, jstring aMozBinDirectory, + jint aAppFileLocProvider) +{ + if (!InitializeJavaGlobals(env)) { + FreeJavaGlobals(env); + ThrowXPCOMException(env, 0); + return; + } + + nsresult rv; + nsCOMPtr directory; + if (aMozBinDirectory) + { + jboolean isCopy; + const PRUnichar* buf = env->GetStringChars(aMozBinDirectory, &isCopy); + nsAutoString path(buf); + rv = NS_NewLocalFile(path, PR_TRUE, getter_AddRefs(directory)); + if (NS_FAILED(rv)) { + ThrowXPCOMException(env, 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; +} + +extern "C" JNIEXPORT void JNICALL +XPCOM_NATIVE(NS_1TermEmbedding) (JNIEnv *env, jclass) +{ + FreeJavaGlobals(env); + + nsresult rv = NS_TermEmbedding(); + if (NS_FAILED(rv)) + ThrowXPCOMException(env, rv); +} + +/* 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 +XPCOM_NATIVE(NS_1NewLocalFile) (JNIEnv *env, jclass, jstring aPath, + jboolean aFollowLinks) +{ + jobject java_stub = nsnull; + + // XXX For now, return if we haven't called NS_InitEmbedding yet + if (!gEmbeddingInitialized) { + ThrowXPCOMException(env, 0); + return nsnull; + } + + // Create a Mozilla string from the jstring + jboolean isCopy; + const PRUnichar* buf = nsnull; + if (aPath) { + buf = env->GetStringChars(aPath, &isCopy); + } + + nsAutoString path_str(buf); + if (isCopy) { + env->ReleaseStringChars(aPath, buf); + } + + // Make call to given function + nsCOMPtr file; + nsresult rv = NS_NewLocalFile(path_str, aFollowLinks, getter_AddRefs(file)); + + if (NS_SUCCEEDED(rv)) { + // wrap xpcom instance + JavaXPCOMInstance* inst; + inst = CreateJavaXPCOMInstance(file, &NS_GET_IID(nsILocalFile)); + + if (inst) { + // create java stub + java_stub = CreateJavaWrapper(env, "nsILocalFile"); + + 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(NS_1NewSingletonEnumerator) (JNIEnv *env, jclass, jobject aSingleton) +{ + void* inst = GetMatchingXPCOMObject(env, aSingleton); + if (inst == nsnull) { + // If there is not corresponding XPCOM object, then that means that the + // parameter is non-generated class (that is, it is not one of our + // Java stubs that represent an exising XPCOM object). So we need to + // create an XPCOM stub, that can route any method calls to the class. + + // Get interface info for class + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + nsCOMPtr iinfo; + iim->GetInfoForIID(&NS_GET_IID(nsISupports), getter_AddRefs(iinfo)); + + // Create XPCOM stub + nsJavaXPTCStub* xpcomStub = new nsJavaXPTCStub(env, aSingleton, iinfo); + NS_ADDREF(xpcomStub); + inst = SetAsXPTCStub(xpcomStub); + AddJavaXPCOMBinding(env, aSingleton, inst); + } + + nsISupports* singleton; + if (IsXPTCStub(inst)) + singleton = (nsISupports*) GetXPTCStubAddr(inst); + else { + JavaXPCOMInstance* xpcomInst = (JavaXPCOMInstance*) inst; + singleton = xpcomInst->GetInstance(); + } + + // Call XPCOM method + jobject java_stub = nsnull; + nsISimpleEnumerator *enumerator = nsnull; + nsresult rv = NS_NewSingletonEnumerator(&enumerator, singleton); + + if (NS_SUCCEEDED(rv)) { + // wrap xpcom instance + JavaXPCOMInstance* inst; + inst = CreateJavaXPCOMInstance(enumerator, &NS_GET_IID(nsISimpleEnumerator)); + + if (inst) { + // create java stub + java_stub = CreateJavaWrapper(env, "nsISimpleEnumerator"); + + 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(NS_1GetComponentManager) (JNIEnv *env, jclass) +{ + jobject java_stub = nsnull; + + // Call XPCOM method + nsCOMPtr cm; + nsresult rv = NS_GetComponentManager(getter_AddRefs(cm)); + + if (NS_SUCCEEDED(rv)) { + // wrap xpcom instance + JavaXPCOMInstance* inst; + inst = CreateJavaXPCOMInstance(cm, &NS_GET_IID(nsIComponentManager)); + + if (inst) { + // create java stub + java_stub = CreateJavaWrapper(env, "nsIComponentManager"); + + 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(NS_1GetServiceManager) (JNIEnv *env, jclass) +{ + jobject java_stub = nsnull; + + // Call XPCOM method + nsCOMPtr sm; + nsresult rv = NS_GetServiceManager(getter_AddRefs(sm)); + + if (NS_SUCCEEDED(rv)) { + // wrap xpcom instance + JavaXPCOMInstance* inst; + inst = CreateJavaXPCOMInstance(sm, &NS_GET_IID(nsIServiceManager)); + + if (inst) { + // create java stub + java_stub = CreateJavaWrapper(env, "nsIServiceManager"); + + if (java_stub) { + // Associate XPCOM object w/ Java stub + AddJavaXPCOMBinding(env, java_stub, inst); + } + } + } + + if (java_stub == nsnull) + ThrowXPCOMException(env, 0); + + return java_stub; +} + +// JNI wrapper for calling an nsWriteSegmentFun function +extern "C" JNIEXPORT jint JNICALL +XPCOM_NATIVE(nsWriteSegmentFun) (JNIEnv *env, jclass that, jint aWriterFunc, + jobject aInStream, jint aClosure, + jbyteArray aFromSegment, jint aToOffset, + jint aCount) +{ + nsresult rc; + + void* inst = GetMatchingXPCOMObject(env, aInStream); + if (inst == nsnull) { + // If there is not corresponding XPCOM object, then that means that the + // parameter is non-generated class (that is, it is not one of our + // Java stubs that represent an exising XPCOM object). So we need to + // create an XPCOM stub, that can route any method calls to the class. + + // Get interface info for class + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + nsCOMPtr iinfo; + iim->GetInfoForIID(&NS_GET_IID(nsIInputStream), getter_AddRefs(iinfo)); + + // Create XPCOM stub + nsJavaXPTCStub* xpcomStub = new nsJavaXPTCStub(env, aInStream, iinfo); + NS_ADDREF(xpcomStub); + inst = SetAsXPTCStub(xpcomStub); + AddJavaXPCOMBinding(env, aInStream, inst); + } + + nsIInputStream* instream; + if (IsXPTCStub(inst)) + instream = (nsIInputStream*) GetXPTCStubAddr(inst); + else { + JavaXPCOMInstance* xpcomInst = (JavaXPCOMInstance*) inst; + instream = (nsIInputStream*) xpcomInst->GetInstance(); + } + + jbyte* fromSegment = nsnull; + jboolean isCopy = JNI_FALSE; + if (aFromSegment) { + fromSegment = env->GetByteArrayElements(aFromSegment, &isCopy); + } + + PRUint32 write_count; + nsWriteSegmentFun writer = (nsWriteSegmentFun) aWriterFunc; + rc = writer(instream, (void*) aClosure, (const char*) fromSegment, aToOffset, + aCount, &write_count); + if (NS_FAILED(rc)) { + ThrowXPCOMException(env, rc); + return 0; + } + + if (isCopy) { + env->ReleaseByteArrayElements(aFromSegment, fromSegment, 0); + } + return write_count; +} + +extern "C" JNIEXPORT void JNICALL +XPCOM_NATIVE(CallXPCOMMethodVoid) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); +} + +extern "C" JNIEXPORT jboolean JNICALL +XPCOM_NATIVE(CallXPCOMMethodBool) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return rc.z; +} + +extern "C" JNIEXPORT jbooleanArray JNICALL +XPCOM_NATIVE(CallXPCOMMethodBoolA) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return (jbooleanArray) rc.l; +} + +extern "C" JNIEXPORT jbyte JNICALL +XPCOM_NATIVE(CallXPCOMMethodByte) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return rc.b; +} + +extern "C" JNIEXPORT jbyteArray JNICALL +XPCOM_NATIVE(CallXPCOMMethodByteA) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return (jbyteArray) rc.l; +} + +extern "C" JNIEXPORT jchar JNICALL +XPCOM_NATIVE(CallXPCOMMethodChar) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return rc.c; +} + +extern "C" JNIEXPORT jcharArray JNICALL +XPCOM_NATIVE(CallXPCOMMethodCharA) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return (jcharArray) rc.l; +} + +extern "C" JNIEXPORT jshort JNICALL +XPCOM_NATIVE(CallXPCOMMethodShort) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return rc.s; +} + +extern "C" JNIEXPORT jshortArray JNICALL +XPCOM_NATIVE(CallXPCOMMethodShortA) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return (jshortArray) rc.l; +} + +extern "C" JNIEXPORT jint JNICALL +XPCOM_NATIVE(CallXPCOMMethodInt) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return rc.i; +} + +extern "C" JNIEXPORT jintArray JNICALL +XPCOM_NATIVE(CallXPCOMMethodIntA) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return (jintArray) rc.l; +} + +extern "C" JNIEXPORT jlong JNICALL +XPCOM_NATIVE(CallXPCOMMethodLong) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return rc.j; +} + +extern "C" JNIEXPORT jlongArray JNICALL +XPCOM_NATIVE(CallXPCOMMethodLongA) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return (jlongArray) rc.l; +} + +extern "C" JNIEXPORT jfloat JNICALL +XPCOM_NATIVE(CallXPCOMMethodFloat) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return rc.f; +} + +extern "C" JNIEXPORT jfloatArray JNICALL +XPCOM_NATIVE(CallXPCOMMethodFloatA) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return (jfloatArray) rc.l; +} + +extern "C" JNIEXPORT jdouble JNICALL +XPCOM_NATIVE(CallXPCOMMethodDouble) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return rc.d; +} + +extern "C" JNIEXPORT jdoubleArray JNICALL +XPCOM_NATIVE(CallXPCOMMethodDoubleA) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return (jdoubleArray) rc.l; +} + +extern "C" JNIEXPORT jobject JNICALL +XPCOM_NATIVE(CallXPCOMMethodObj) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return rc.l; +} + +extern "C" JNIEXPORT jobjectArray JNICALL +XPCOM_NATIVE(CallXPCOMMethodObjA) (JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams) +{ + jvalue rc; + CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc); + return (jobjectArray) rc.l; +} + +extern "C" JNIEXPORT void JNICALL +XPCOM_NATIVE(FinalizeStub) (JNIEnv *env, jclass that, jobject aJavaObject) +{ +#ifdef DEBUG + jboolean isCopy; + jclass clazz = env->GetObjectClass(aJavaObject); + jstring name = (jstring) env->CallObjectMethod(clazz, getNameMID); + const char* javaObjectName = env->GetStringUTFChars(name, &isCopy); + fprintf(stderr, "*** Finalize(java_obj=%s)\n", javaObjectName); + if (isCopy) + env->ReleaseStringUTFChars(name, javaObjectName); +#endif + nsISupports* xpcomObj = RemoveXPCOMBinding(env, aJavaObject); + NS_RELEASE(xpcomObj); +} + diff --git a/extensions/java/xpcom/nsJavaWrapper.cpp b/extensions/java/xpcom/nsJavaWrapper.cpp new file mode 100644 index 000000000000..a5a0ee8cd80c --- /dev/null +++ b/extensions/java/xpcom/nsJavaWrapper.cpp @@ -0,0 +1,1061 @@ +/* ***** 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 ***** */ + +#include "nsJavaWrapper.h" +#include "nsJavaXPTCStub.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "jni.h" +#include "xptcall.h" +#include "nsIInterfaceInfoManager.h" +#include "nsString.h" +#include "nsString.h" +#include "nsCRT.h" +#include "prmem.h" + +static nsID nullID = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; + + +nsresult +SetupParams(JNIEnv *env, const jobject aParam, + const nsXPTParamInfo &aParamInfo, + const nsXPTMethodInfo* aMethodInfo, + nsIInterfaceInfo* aIInfo, + PRUint16 aMethodIndex, + nsXPTCVariant* aDispatchParams, + nsXPTCVariant &aVariant) +{ + nsresult rv = NS_OK; + const nsXPTType &type = aParamInfo.GetType(); + + // defaults + aVariant.ptr = nsnull; + aVariant.type = type; + aVariant.flags = 0; + + PRUint8 tag = type.TagPart(); + switch (tag) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + { + LOG("byte"); + if (!aParamInfo.IsOut()) { + aVariant.val.u8 = env->CallByteMethod(aParam, byteValueMID); + } else { + jboolean isCopy = JNI_FALSE; + jbyte* buf = nsnull; + if (aParam) { + buf = env->GetByteArrayElements((jbyteArray) aParam, &isCopy); + } + + aVariant.ptr = buf; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (isCopy) { + aVariant.flags |= nsXPTCVariant::VAL_IS_ALLOCD; + } + } + } + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + { + LOG("short"); + if (!aParamInfo.IsOut()) { + aVariant.val.u16 = env->CallShortMethod(aParam, shortValueMID); + } else { + jboolean isCopy = JNI_FALSE; + jshort* buf = nsnull; + if (aParam) { + buf = env->GetShortArrayElements((jshortArray) aParam, &isCopy); + } + + aVariant.ptr = buf; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (isCopy) { + aVariant.flags |= nsXPTCVariant::VAL_IS_ALLOCD; + } + } + } + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + { + LOG("int"); + if (!aParamInfo.IsOut()) { + aVariant.val.u32 = env->CallIntMethod(aParam, intValueMID); + } else { + jboolean isCopy = JNI_FALSE; + jint* buf = nsnull; + if (aParam) { + buf = env->GetIntArrayElements((jintArray) aParam, &isCopy); + } + + aVariant.ptr = buf; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (isCopy) { + aVariant.flags |= nsXPTCVariant::VAL_IS_ALLOCD; + } + } + } + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + { + LOG("long"); + if (!aParamInfo.IsOut()) { + aVariant.val.u64 = env->CallLongMethod(aParam, longValueMID); + } else { + jboolean isCopy = JNI_FALSE; + jlong* buf = nsnull; + if (aParam) { + buf = env->GetLongArrayElements((jlongArray) aParam, &isCopy); + } + + aVariant.ptr = buf; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (isCopy) { + aVariant.flags |= nsXPTCVariant::VAL_IS_ALLOCD; + } + } + } + break; + + case nsXPTType::T_FLOAT: + { + LOG("float"); + if (!aParamInfo.IsOut()) { + aVariant.val.f = env->CallFloatMethod(aParam, floatValueMID); + } else { + jboolean isCopy = JNI_FALSE; + jfloat* buf = nsnull; + if (aParam) { + buf = env->GetFloatArrayElements((jfloatArray) aParam, &isCopy); + } + + aVariant.ptr = buf; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (isCopy) { + aVariant.flags |= nsXPTCVariant::VAL_IS_ALLOCD; + } + } + } + break; + + case nsXPTType::T_DOUBLE: + { + LOG("double"); + if (!aParamInfo.IsOut()) { + aVariant.val.d = env->CallDoubleMethod(aParam, doubleValueMID); + } else { + jboolean isCopy = JNI_FALSE; + jdouble* buf = nsnull; + if (aParam) { + buf = env->GetDoubleArrayElements((jdoubleArray) aParam, &isCopy); + } + + aVariant.ptr = buf; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (isCopy) { + aVariant.flags |= nsXPTCVariant::VAL_IS_ALLOCD; + } + } + } + break; + + case nsXPTType::T_BOOL: + { + LOG("boolean"); + if (!aParamInfo.IsOut()) { + aVariant.val.b = env->CallBooleanMethod(aParam, booleanValueMID); + } else { + jboolean isCopy = JNI_FALSE; + jboolean* buf = nsnull; + if (aParam) { + buf = env->GetBooleanArrayElements((jbooleanArray) aParam, &isCopy); + } + + aVariant.ptr = buf; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (isCopy) { + aVariant.flags |= nsXPTCVariant::VAL_IS_ALLOCD; + } + } + } + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + { + LOG("char"); + if (!aParamInfo.IsOut()) { + if (tag == nsXPTType::T_CHAR) + aVariant.val.c = env->CallCharMethod(aParam, charValueMID); + else + aVariant.val.wc = env->CallCharMethod(aParam, charValueMID); + } else { + jboolean isCopy = JNI_FALSE; + jchar* buf = nsnull; + if (aParam) { + buf = env->GetCharArrayElements((jcharArray) aParam, &isCopy); + } + + aVariant.ptr = buf; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (isCopy) { + aVariant.flags |= nsXPTCVariant::VAL_IS_ALLOCD; + } + } + } + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + { + LOG("String"); + jstring data = nsnull; + if (!aParamInfo.IsOut()) { + data = (jstring) aParam; + } else { + if (aParam) + data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, 0); + } + + jboolean isCopy = JNI_FALSE; + const void* buf = nsnull; + if (data) { + if (tag == nsXPTType::T_CHAR_STR) { + buf = env->GetStringUTFChars(data, &isCopy); + } else { + buf = env->GetStringChars(data, &isCopy); + } + } + + aVariant.val.p = aVariant.ptr = NS_CONST_CAST(void*, buf); + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (isCopy) { + aVariant.flags |= nsXPTCVariant::VAL_IS_ALLOCD; + } + } + break; + + case nsXPTType::T_IID: + { + LOG("String(IID)"); + jstring data = nsnull; + if (!aParamInfo.IsOut()) { + data = (jstring) aParam; + } else { + if (aParam) + data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, 0); + } + + nsID* iid = new nsID; + if (data) { + jboolean isCopy; + const char* str = nsnull; + str = env->GetStringUTFChars(data, &isCopy); + iid->Parse(str); + if (isCopy) { + env->ReleaseStringUTFChars(data, str); + } + } else { + *iid = nullID; + } + + aVariant.val.p = aVariant.ptr = iid; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + LOG("nsISupports"); + jobject data = nsnull; + if (!aParamInfo.IsOut()) { + data = (jobject) aParam; + } else { + if (aParam) + data = (jobject) env->GetObjectArrayElement((jobjectArray) aParam, 0); + } + + if (data) { + // Check if we already have a corresponding XPCOM object + void* inst = GetMatchingXPCOMObject(env, data); + + if (inst == nsnull) { + // If there is not corresponding XPCOM object, then that means that the + // parameter is non-generated class (that is, it is not one of our + // Java stubs that represent an exising XPCOM object). So we need to + // create an XPCOM stub, that can route any method calls to the class. + + // Get IID for this param + nsID iid; + rv = GetIIDForMethodParam(aIInfo, aMethodInfo, aParamInfo, + aMethodIndex, aDispatchParams, PR_TRUE, iid); + if (NS_FAILED(rv)) + return rv; + + // Get interface info for class + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + nsCOMPtr iinfo; + iim->GetInfoForIID(&iid, getter_AddRefs(iinfo)); + + // Create XPCOM stub + nsJavaXPTCStub* xpcomStub = new nsJavaXPTCStub(env, data, iinfo); + NS_ADDREF(xpcomStub); + inst = SetAsXPTCStub(xpcomStub); + AddJavaXPCOMBinding(env, data, inst); + } +#if 1 + // XXX This code is here to make sure that the nsJavaXPTCStub that is + // used has the correct (asked for) interface info. For example, in + // the Java code, the nsIWeakReference functions return the current + // Java object ('this'); so when we call GetMatchingXPCOMObject on + // that Java object, we get back a nsJavaXPTCStub that has the interface + // info for something other than nsIWeakReference. This will cause + // problems later when we try to call one of the nsIWeakReference + // functions on that Java object, but the nsJavaXPTCStub object doesn't + // know anything about nsIWeakReference. + else { + if (IsXPTCStub(inst)) { + // Get IID for this param + nsID iid; + rv = GetIIDForMethodParam(aIInfo, aMethodInfo, aParamInfo, + aMethodIndex, aDispatchParams, PR_TRUE, iid); + if (NS_FAILED(rv)) + return rv; + + void* temp; + rv = GetXPTCStubAddr(inst)->QueryInterface(iid, &temp); + if (NS_SUCCEEDED(rv) && temp != GetXPTCStubAddr(inst)) + inst = SetAsXPTCStub((nsJavaXPTCStub*) temp); + } + } +#endif + + if (IsXPTCStub(inst)) + aVariant.val.p = aVariant.ptr = (void*) GetXPTCStubAddr(inst); + else { + JavaXPCOMInstance* xpcomInst = (JavaXPCOMInstance*) inst; + aVariant.val.p = aVariant.ptr = (void*) xpcomInst->GetInstance(); + } + } else { + aVariant.val.p = aVariant.ptr = nsnull; + } + + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + aVariant.SetValIsInterface(); + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + LOG("String"); + jstring data = nsnull; + if (!aParamInfo.IsOut()) { + data = (jstring) aParam; + } else { + if (aParam) + 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); + } + + aVariant.val.p = aVariant.ptr = str; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA | nsXPTCVariant::VAL_IS_DOMSTR; + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + LOG("StringUTF"); + jstring data = nsnull; + if (!aParamInfo.IsOut()) { + data = (jstring) aParam; + } else { + if (aParam) + 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); + } + + aVariant.val.p = aVariant.ptr = str; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (tag == nsXPTType::T_CSTRING) { + aVariant.flags |= nsXPTCVariant::VAL_IS_CSTR; + } else { + aVariant.flags |= nsXPTCVariant::VAL_IS_UTF8STR; + } + } + break; + + // XXX How should this be handled? + case nsXPTType::T_VOID: + { + if (env->IsInstanceOf(aParam, intClass)) + { + if (env->IsInstanceOf(aParam, intArrayClass)) + { + LOG("int[] (void)"); + jboolean isCopy = JNI_FALSE; + jint* buf = nsnull; + if (aParam) { + buf = env->GetIntArrayElements((jintArray) aParam, &isCopy); + } + + aVariant.ptr = buf; + aVariant.flags = nsXPTCVariant::PTR_IS_DATA; + if (isCopy) { + aVariant.flags |= nsXPTCVariant::VAL_IS_ALLOCD; + } + } else { + LOG("int (void)"); + NS_ASSERTION(type.IsPointer(), "T_VOID 'int' handler received non-pointer type"); + aVariant.val.p = (void*) env->CallIntMethod(aParam, intValueMID); + } + } else { + NS_WARNING("Unhandled T_VOID"); + return NS_ERROR_UNEXPECTED; + } + } + break; + + case nsXPTType::T_ARRAY: + NS_WARNING("array types are not yet supported"); + return NS_ERROR_NOT_IMPLEMENTED; + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return rv; +} + +nsresult +FinalizeParams(JNIEnv *env, const jobject aParam, + const nsXPTParamInfo &aParamInfo, + const nsXPTMethodInfo* aMethodInfo, + nsIInterfaceInfo* aIInfo, + PRUint16 aMethodIndex, + nsXPTCVariant* aDispatchParams, + nsXPTCVariant &aVariant) +{ + nsresult rv = NS_OK; + const nsXPTType &type = aParamInfo.GetType(); + + // XXX Not sure if this is necessary + // Only write the array elements back if the parameter is an output param + jint mode = 0; + if (!aParamInfo.IsOut() && !aParamInfo.IsRetval()) + mode = JNI_ABORT; + + switch (type.TagPart()) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + { + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + env->ReleaseByteArrayElements((jbyteArray) aParam, + (jbyte*) aVariant.val.p, mode); + } + } + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + { + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + env->ReleaseShortArrayElements((jshortArray) aParam, + (jshort*) aVariant.val.p, mode); + } + } + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + { + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + env->ReleaseIntArrayElements((jintArray) aParam, + (jint*) aVariant.val.p, mode); + } + } + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + { + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + env->ReleaseLongArrayElements((jlongArray) aParam, + (jlong*) aVariant.val.p, mode); + } + } + break; + + case nsXPTType::T_FLOAT: + { + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + env->ReleaseFloatArrayElements((jfloatArray) aParam, + (jfloat*) aVariant.val.p, mode); + } + } + break; + + case nsXPTType::T_DOUBLE: + { + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + env->ReleaseDoubleArrayElements((jdoubleArray) aParam, + (jdouble*) aVariant.val.p, mode); + } + } + break; + + case nsXPTType::T_BOOL: + { + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + env->ReleaseBooleanArrayElements((jbooleanArray) aParam, + (jboolean*) aVariant.val.p, mode); + } + } + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + { + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + env->ReleaseCharArrayElements((jcharArray) aParam, + (jchar*) aVariant.val.p, mode); + } + } + break; + + case nsXPTType::T_CHAR_STR: + { + // release Java string buffer + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + jstring data = nsnull; + if (!aParamInfo.IsOut()) { + data = (jstring) aParam; + } else { + data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, 0); + } + env->ReleaseStringUTFChars(data, (const char*) aVariant.val.p); + } + + // If this is an output parameter, then create the string to return + if (aParam && aParamInfo.IsOut()) { + jstring str = env->NewStringUTF((const char*) aVariant.val.p); + env->SetObjectArrayElement((jobjectArray) aParam, 0, str); + } + } + break; + + case nsXPTType::T_WCHAR_STR: + { + // release Java string buffer + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + jstring data = nsnull; + if (!aParamInfo.IsOut()) { + data = (jstring) aParam; + } else { + data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, 0); + } + env->ReleaseStringChars(data, (const jchar*) aVariant.val.p); + } + + // If this is an output parameter, then create the string to return + if (aParam && aParamInfo.IsOut()) { + PRUint32 length = nsCRT::strlen((const PRUnichar*) aVariant.val.p); + jstring str = env->NewString((const jchar*) aVariant.val.p, length); + env->SetObjectArrayElement((jobjectArray) aParam, 0, str); + } + } + break; + + case nsXPTType::T_IID: + { + nsID* iid = (nsID*) aVariant.val.p; + + // If this is an output parameter, then create the string to return + if (iid && aParamInfo.IsOut()) { + char* iid_str = iid->ToString(); + jstring str = env->NewStringUTF(iid_str); + PR_Free(iid_str); + env->SetObjectArrayElement((jobjectArray) aParam, 0, str); + } + + // XXX Cannot delete this until we've handled all of the params. See + // comment in CallXPCOMMethod +// delete iid; + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + if (aVariant.val.p && aParamInfo.IsOut()) { + jobject java_obj = GetMatchingJavaObject(aVariant.val.p); + + if (java_obj == nsnull) { + // wrap xpcom instance + nsID iid; + JavaXPCOMInstance* inst; + rv = GetIIDForMethodParam(aIInfo, aMethodInfo, aParamInfo, + aMethodIndex, aDispatchParams, PR_TRUE, iid); + if (NS_FAILED(rv)) + return rv; + + inst = CreateJavaXPCOMInstance((nsISupports*) aVariant.val.p, &iid); + + if (inst) { + // create java stub + char* iface_name; + inst->InterfaceInfo()->GetName(&iface_name); + java_obj = CreateJavaWrapper(env, iface_name); + + if (java_obj) { + // Associate XPCOM object w/ Java stub + AddJavaXPCOMBinding(env, java_obj, inst); + } + } + } + + env->SetObjectArrayElement((jobjectArray) aParam, 0, java_obj); + } + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + 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); + } + + delete str; + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + nsCString* str = (nsCString*) aVariant.val.p; + + if (str && aParamInfo.IsOut()) { + jstring jstr = env->NewStringUTF((const char*) str->get()); + env->SetObjectArrayElement((jobjectArray) aParam, 0, jstr); + } + + delete str; + } + break; + + case nsXPTType::T_VOID: + { + if (aVariant.flags & nsXPTCVariant::VAL_IS_ALLOCD) { + env->ReleaseIntArrayElements((jintArray) aParam, + (jint*) aVariant.val.p, mode); + } + } + break; + } + + return rv; +} + +nsresult +SetRetval(JNIEnv *env, + const nsXPTParamInfo &aParamInfo, + const nsXPTMethodInfo* aMethodInfo, + nsIInterfaceInfo* aIInfo, + PRUint16 aMethodIndex, + nsXPTCVariant* aDispatchParams, + nsXPTCVariant &aVariant, + jvalue &aResult) +{ + nsresult rv = NS_OK; + const nsXPTType &type = aParamInfo.GetType(); + + switch (type.TagPart()) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + aResult.b = aVariant.val.u8; + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + aResult.s = aVariant.val.u16; + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + aResult.i = aVariant.val.u32; + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + aResult.j = aVariant.val.u64; + break; + + case nsXPTType::T_FLOAT: + aResult.f = aVariant.val.f; + break; + + case nsXPTType::T_DOUBLE: + aResult.d = aVariant.val.d; + break; + + case nsXPTType::T_BOOL: + aResult.z = aVariant.val.b; + break; + + case nsXPTType::T_CHAR: + aResult.c = aVariant.val.c; + break; + + case nsXPTType::T_WCHAR: + aResult.c = aVariant.val.wc; + break; + + case nsXPTType::T_CHAR_STR: + { + if (aVariant.ptr) + aResult.l = env->NewStringUTF((const char*) aVariant.ptr); + else + aResult.l = nsnull; + } + break; + + case nsXPTType::T_WCHAR_STR: + { + if (aVariant.ptr) { + PRUint32 length = nsCRT::strlen((const PRUnichar*) aVariant.ptr); + aResult.l = env->NewString((const jchar*) aVariant.ptr, length); + } else { + aResult.l = nsnull; + } + } + break; + + case nsXPTType::T_IID: + { + if (aVariant.ptr) { + nsID* iid = (nsID*) aVariant.ptr; + char* iid_str = iid->ToString(); + aResult.l = env->NewStringUTF(iid_str); + PR_Free(iid_str); + } else { + aResult.l = nsnull; + } + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + if (aVariant.val.p) { + nsID iid; + rv = GetIIDForMethodParam(aIInfo, aMethodInfo, aParamInfo, + aMethodIndex, aDispatchParams, PR_TRUE, iid); + if (NS_FAILED(rv)) + return rv; + + jobject java_stub = nsnull; + + // wrap XPCOM object + nsCOMPtr info; + JavaXPCOMInstance* inst = nsnull; + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + NS_ASSERTION(iim != nsnull, "Failed to get InterfaceInfoManager"); + if (iim) { + iim->GetInfoForIID(&iid, getter_AddRefs(info)); + + inst = new JavaXPCOMInstance((nsISupports*)aVariant.val.p, info); + NS_ADDREF((nsISupports*)aVariant.val.p); + } + + if (inst) { + // create java stub + char* iface_name; + info->GetName(&iface_name); + java_stub = CreateJavaWrapper(env, iface_name); + + if (java_stub) { + AddJavaXPCOMBinding(env, java_stub, inst); + + aResult.l = java_stub; + } + } + } else { + aResult.l = nsnull; + } + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + if (aVariant.ptr) { + nsString* str = (nsString*) aVariant.ptr; + aResult.l = env->NewString(str->get(), str->Length()); + } else { + aResult.l = nsnull; + } + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + if (aVariant.ptr) { + nsCString* str = (nsCString*) aVariant.ptr; + aResult.l = env->NewStringUTF(str->get()); + } else { + aResult.l = nsnull; + } + } + break; + + // XXX not sure about this one + case nsXPTType::T_VOID: + aResult.l = (jobject) aVariant.ptr; + + case nsXPTType::T_ARRAY: + NS_WARNING("array types are not yet supported"); + return NS_ERROR_NOT_IMPLEMENTED; + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return rv; +} + +void +CallXPCOMMethod(JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams, jvalue &aResult) +{ + // Find corresponding XPCOM object + void* xpcomObj = GetMatchingXPCOMObject(env, aJavaObject); + NS_ASSERTION(xpcomObj != nsnull, "Failed to get matching XPCOM object"); + if (xpcomObj == nsnull) { + ThrowXPCOMException(env, 0); + return; + } + + NS_ASSERTION(!IsXPTCStub(xpcomObj), "Expected JavaXPCOMInstance, but got nsJavaXPTCStub"); + JavaXPCOMInstance* inst = (JavaXPCOMInstance*) xpcomObj; + + // Get method info + const nsXPTMethodInfo* methodInfo; + nsIInterfaceInfo* iinfo = inst->InterfaceInfo(); + nsresult rv = iinfo->GetMethodInfo(aMethodIndex, &methodInfo); + NS_ASSERTION(NS_SUCCEEDED(rv), "GetMethodInfo failed"); + +#ifdef DEBUG + const char* ifaceName; + iinfo->GetNameShared(&ifaceName); + LOG("=> Calling %s::%s(", ifaceName, methodInfo->GetName()); +#endif + + PRUint8 paramCount = methodInfo->GetParamCount(); + nsXPTCVariant* params = nsnull; + if (paramCount) + { + params = new nsXPTCVariant[paramCount]; + + for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) + { +#ifdef DEBUG + if (i > 0) + LOG(", "); +#endif + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(i); + + NS_ASSERTION(!paramInfo.IsDipper(), "Dipper!"); + + if (!paramInfo.IsRetval() && !paramInfo.IsDipper()) { + rv = SetupParams(env, env->GetObjectArrayElement(aParams, i), paramInfo, + methodInfo, iinfo, aMethodIndex, params, params[i]); + } else if (paramInfo.IsDipper()) { + LOG("dipper"); + const nsXPTType &type = paramInfo.GetType(); + switch (type.TagPart()) + { + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + params[i].val.p = params[i].ptr = new nsString(); + params[i].type = type; + params[i].flags = nsXPTCVariant::PTR_IS_DATA | + nsXPTCVariant::VAL_IS_DOMSTR; + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + params[i].val.p = params[i].ptr = new nsCString(); + params[i].type = type; + params[i].flags = nsXPTCVariant::PTR_IS_DATA | + nsXPTCVariant::VAL_IS_CSTR; + break; + + default: + LOG("unhandled dipper type\n"); + rv = NS_ERROR_UNEXPECTED; + } + } else { + LOG("retval"); + params[i].ptr = &(params[i].val); + params[i].type = paramInfo.GetType(); + params[i].flags = nsXPTCVariant::PTR_IS_DATA; + } + } + if (NS_FAILED(rv)) { + NS_WARNING("SetupParams failed"); + ThrowXPCOMException(env, rv); + return; + } + } + LOG(")\n"); + + nsresult invokeResult; + invokeResult = XPTC_InvokeByIndex(inst->GetInstance(), aMethodIndex, + paramCount, params); + + if (NS_FAILED(invokeResult)) { + ThrowXPCOMException(env, invokeResult); + return; + } + + for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) + { + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(i); + + if (!paramInfo.IsRetval()) { + rv = FinalizeParams(env, env->GetObjectArrayElement(aParams, i), + paramInfo, methodInfo, iinfo, aMethodIndex, + params, params[i]); + } else { + rv = SetRetval(env, + paramInfo, methodInfo, iinfo, aMethodIndex, + params, params[i], aResult); + } + } + if (NS_FAILED(rv)) { + NS_WARNING("SetupParams failed"); + ThrowXPCOMException(env, rv); + return; + } + + // XXX Normally, we would delete any created nsID object in the above loop. + // However, GetIIDForMethodParam may need some of the nsID params when it's + // looking for the IID of an INTERFACE_IS. Therefore, we can't delete it + // until we've gone through the 'Finalize' loop once and created the result. + for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) + { + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(i); + const nsXPTType &type = paramInfo.GetType(); + if (type.TagPart() == nsXPTType::T_IID) { + nsID* iid = (nsID*) params[i].ptr; + delete iid; + } + } + + if (params) + delete params; + + return; +} + +// XXX Use org.mozilla.classfile.ClassFileWriter for stubs? +jobject +CreateJavaWrapper(JNIEnv* env, const char* aClassName) +{ + jobject java_stub = nsnull; + + // Create stub class name + nsCAutoString class_name("org/mozilla/xpcom/stubs/"); + class_name.Append(aClassName); + class_name.Append("_Stub"); + + // Create Java stub for XPCOM object + jclass clazz; + clazz = env->FindClass(class_name.get()); + + if (clazz) { + jmethodID constructor = env->GetMethodID(clazz, "", "()V"); + if (constructor) { + java_stub = env->NewObject(clazz, constructor); + } + } + + return java_stub; +// return env->NewGlobalRef(java_stub); +} + diff --git a/extensions/java/xpcom/nsJavaWrapper.h b/extensions/java/xpcom/nsJavaWrapper.h new file mode 100644 index 000000000000..515eb4e9520b --- /dev/null +++ b/extensions/java/xpcom/nsJavaWrapper.h @@ -0,0 +1,50 @@ +/* ***** 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 _nsJavaWrapper_h_ +#define _nsJavaWrapper_h_ + +#include "jni.h" + + +void CallXPCOMMethod(JNIEnv *env, jclass that, jobject aJavaObject, + jint aMethodIndex, jobjectArray aParams, jvalue &aResult); + +// Creates a Java stub for an XPCOM object of type aClassName +jobject CreateJavaWrapper(JNIEnv* env, const char* aClassName); + +#endif // _nsJavaWrapper_h_ diff --git a/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp b/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp new file mode 100644 index 000000000000..2fa42b05ed39 --- /dev/null +++ b/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp @@ -0,0 +1,521 @@ +/* ***** 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 ***** */ + + +#include "nsJavaXPCOMBindingUtils.h" +#include "nsJavaXPTCStub.h" +#include "jni.h" +#include "nsIInterfaceInfoManager.h" +#include "pldhash.h" + + +/* Java JNI globals */ +jclass classClass = nsnull; +jmethodID getNameMID = nsnull; + +jclass objectClass = nsnull; +jmethodID hashCodeMID = nsnull; + +jclass booleanClass = nsnull; +jclass booleanArrayClass = nsnull; +jmethodID booleanInitMID = nsnull; +jmethodID booleanValueMID = nsnull; + +jclass charClass = nsnull; +jclass charArrayClass = nsnull; +jmethodID charInitMID = nsnull; +jmethodID charValueMID = nsnull; + +jclass byteClass = nsnull; +jclass byteArrayClass = nsnull; +jmethodID byteInitMID = nsnull; +jmethodID byteValueMID = nsnull; + +jclass shortClass = nsnull; +jclass shortArrayClass = nsnull; +jmethodID shortInitMID = nsnull; +jmethodID shortValueMID = nsnull; + +jclass intClass = nsnull; +jclass intArrayClass = nsnull; +jmethodID intInitMID = nsnull; +jmethodID intValueMID = nsnull; + +jclass longClass = nsnull; +jclass longArrayClass = nsnull; +jmethodID longInitMID = nsnull; +jmethodID longValueMID = nsnull; + +jclass floatClass = nsnull; +jclass floatArrayClass = nsnull; +jmethodID floatInitMID = nsnull; +jmethodID floatValueMID = nsnull; + +jclass doubleClass = nsnull; +jclass doubleArrayClass = nsnull; +jmethodID doubleInitMID = nsnull; +jmethodID doubleValueMID = nsnull; + +jclass stringClass = nsnull; +jclass stringArrayClass = nsnull; + +jclass nsISupportsClass = nsnull; + +jclass exceptionClass = nsnull; + +/************************************** + * Java<->XPCOM binding stores + **************************************/ +class JavaXPCOMBindingEntry : public PLDHashEntryHdr +{ +public: + jobject mJavaObject; + void* mXPCOMInstance; +}; + +static PLDHashTable *gJAVAtoXPCOMBindings = nsnull; +static PLDHashTable *gXPCOMtoJAVABindings = nsnull; + +PR_STATIC_CALLBACK(PRBool) +InitJAVAtoXPCOMBindingEntry(PLDHashTable *table, PLDHashEntryHdr *entry, + const void *key) +{ + JavaXPCOMBindingEntry *e = + NS_CONST_CAST(JavaXPCOMBindingEntry *, + NS_STATIC_CAST(const JavaXPCOMBindingEntry *, entry)); + + e->mJavaObject = NS_CONST_CAST(jobject, + NS_STATIC_CAST(const __jobject*, key)); + e->mXPCOMInstance = nsnull; + + return PR_TRUE; +} + +PR_STATIC_CALLBACK(PRBool) +InitXPCOMtoJAVABindingEntry(PLDHashTable *table, PLDHashEntryHdr *entry, + const void *key) +{ + JavaXPCOMBindingEntry *e = + NS_CONST_CAST(JavaXPCOMBindingEntry *, + NS_STATIC_CAST(const JavaXPCOMBindingEntry *, entry)); + + e->mXPCOMInstance = NS_CONST_CAST(void*, key); + e->mJavaObject = nsnull; + + return PR_TRUE; +} + +void +AddJavaXPCOMBinding(JNIEnv* env, jobject aJavaObject, void* aXPCOMObject) +{ + jint hash = env->CallIntMethod(aJavaObject, hashCodeMID); + + JavaXPCOMBindingEntry *entry = + NS_STATIC_CAST(JavaXPCOMBindingEntry*, + PL_DHashTableOperate(gJAVAtoXPCOMBindings, + NS_INT32_TO_PTR(hash), + PL_DHASH_ADD)); + entry->mXPCOMInstance = aXPCOMObject; + + entry = + NS_STATIC_CAST(JavaXPCOMBindingEntry*, + PL_DHashTableOperate(gXPCOMtoJAVABindings, aXPCOMObject, + PL_DHASH_ADD)); + entry->mJavaObject = aJavaObject; + +// LOG("+ Adding Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x)\n", +// hash, (int) aXPCOMObject); +} + +nsISupports* +RemoveXPCOMBinding(JNIEnv* env, jobject aJavaObject) +{ + void* xpcomObj = GetMatchingXPCOMObject(env, aJavaObject); + + // Remove both instances from stores + jint hash = env->CallIntMethod(aJavaObject, hashCodeMID); + PL_DHashTableOperate(gJAVAtoXPCOMBindings, NS_INT32_TO_PTR(hash), + PL_DHASH_REMOVE); + PL_DHashTableOperate(gXPCOMtoJAVABindings, xpcomObj, PL_DHASH_REMOVE); + + if (IsXPTCStub(xpcomObj)) { + return (nsISupports*) GetXPTCStubAddr(xpcomObj); + } else { + JavaXPCOMInstance* xpcomInst = (JavaXPCOMInstance*) xpcomObj; + nsISupports* inst = xpcomInst->GetInstance(); + // XXX Getting some odd thread issues when calling this. Addreffing for + // now to work around the errors. + NS_ADDREF(inst); + delete xpcomInst; + return inst; + } +} + +void* +GetMatchingXPCOMObject(JNIEnv* env, jobject aJavaObject) +{ + jint hash = env->CallIntMethod(aJavaObject, hashCodeMID); + + JavaXPCOMBindingEntry *entry = + NS_STATIC_CAST(JavaXPCOMBindingEntry*, + PL_DHashTableOperate(gJAVAtoXPCOMBindings, + NS_INT32_TO_PTR(hash), + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(entry)) { +// LOG("< Get Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x)\n", +// (int) aJavaObject, (int) entry->mXPCOMInstance); + return entry->mXPCOMInstance; + } + + return nsnull; +} + +jobject +GetMatchingJavaObject(void* aXPCOMObject) +{ + JavaXPCOMBindingEntry *entry = + NS_STATIC_CAST(JavaXPCOMBindingEntry*, + PL_DHashTableOperate(gXPCOMtoJAVABindings, aXPCOMObject, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(entry)) { +// LOG("< Get Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x)\n", +// (int) entry->mJavaObject, (int) aXPCOMObject); + return entry->mJavaObject; + } + + return nsnull; +} + + +/****************************** + * InitializeJavaGlobals + ******************************/ +PRBool +InitializeJavaGlobals(JNIEnv *env) +{ + jclass clazz; + if (!(clazz = env->FindClass("java/lang/Class")) || + !(classClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + + if (!(clazz = env->FindClass("java/lang/Object")) || + !(objectClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + + if (!(clazz = env->FindClass("java/lang/Boolean")) || + !(booleanClass = (jclass) env->NewGlobalRef(clazz)) || + !(clazz = env->FindClass("[Z")) || + !(booleanArrayClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + + if (!(clazz = env->FindClass("java/lang/Character")) || + !(charClass = (jclass) env->NewGlobalRef(clazz)) || + !(clazz = env->FindClass("[C")) || + !(charArrayClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + if (!(clazz = env->FindClass("java/lang/Byte")) || + !(byteClass = (jclass) env->NewGlobalRef(clazz)) || + !(clazz = env->FindClass("[B")) || + !(byteArrayClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + if (!(clazz = env->FindClass("java/lang/Short")) || + !(shortClass = (jclass) env->NewGlobalRef(clazz)) || + !(clazz = env->FindClass("[[S")) || + !(shortArrayClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + if (!(clazz = env->FindClass("java/lang/Integer")) || + !(intClass = (jclass) env->NewGlobalRef(clazz)) || + !(clazz = env->FindClass("[I")) || + !(intArrayClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + if (!(clazz = env->FindClass("java/lang/Long")) || + !(longClass = (jclass) env->NewGlobalRef(clazz)) || + !(clazz = env->FindClass("[J"))) + { + return PR_FALSE; + } + if (!(clazz = env->FindClass("java/lang/Float")) || + !(floatClass = (jclass) env->NewGlobalRef(clazz)) || + !(clazz = env->FindClass("[F")) || + !(floatArrayClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + if (!(clazz = env->FindClass("java/lang/Double")) || + !(doubleClass = (jclass) env->NewGlobalRef(clazz)) || + !(clazz = env->FindClass("[D")) || + !(doubleArrayClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + + if (!(clazz = env->FindClass("java/lang/String")) || + !(stringClass = (jclass) env->NewGlobalRef(clazz)) || + !(clazz = env->FindClass("[Ljava/lang/String;")) || + !(stringArrayClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + + if (!(clazz = env->FindClass("org/mozilla/xpcom/nsISupports")) || + !(nsISupportsClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + + if (!(clazz = env->FindClass("java/lang/Exception")) || + !(exceptionClass = (jclass) env->NewGlobalRef(clazz))) + { + return PR_FALSE; + } + + if (!(hashCodeMID = env->GetMethodID(objectClass, "hashCode","()I"))) { + return PR_FALSE; + } + + if (!(booleanInitMID = env->GetMethodID(booleanClass,"","(Z)V"))) { + return PR_FALSE; + } + if (!(booleanValueMID = env->GetMethodID(booleanClass,"booleanValue","()Z"))) { + return PR_FALSE; + } + + if (!(charInitMID = env->GetMethodID(charClass,"","(C)V"))) { + return PR_FALSE; + } + if (!(charValueMID = env->GetMethodID(charClass,"charValue","()C"))) { + return PR_FALSE; + } + + if (!(byteInitMID = env->GetMethodID(byteClass,"","(B)V"))) { + return PR_FALSE; + } + if (!(byteValueMID = env->GetMethodID(byteClass,"byteValue","()B"))) { + return PR_FALSE; + } + if (!(shortInitMID = env->GetMethodID(shortClass,"","(S)V"))) { + return PR_FALSE; + } + if (!(shortValueMID = env->GetMethodID(shortClass,"shortValue","()S"))) { + return PR_FALSE; + } + + if (!(intInitMID = env->GetMethodID(intClass,"","(I)V"))) { + return PR_FALSE; + } + if (!(intValueMID = env->GetMethodID(intClass,"intValue","()I"))) { + return PR_FALSE; + } + + if (!(longInitMID = env->GetMethodID(longClass,"","(J)V"))) { + return PR_FALSE; + } + if (!(longValueMID = env->GetMethodID(longClass,"longValue","()J"))) { + return PR_FALSE; + } + + if (!(floatInitMID = env->GetMethodID(floatClass,"","(F)V"))) { + return PR_FALSE; + } + if (!(floatValueMID = env->GetMethodID(floatClass,"floatValue","()F"))) { + return PR_FALSE; + } + + if (!(doubleInitMID = env->GetMethodID(doubleClass,"","(D)V"))) { + return PR_FALSE; + } + if (!(doubleValueMID = env->GetMethodID(doubleClass,"doubleValue","()D"))) { + return PR_FALSE; + } + + if (!(getNameMID = env->GetMethodID(classClass, "getName","()Ljava/lang/String;"))) { + return PR_FALSE; + } + + static PLDHashTableOps java_to_xpcom_hash_ops = + { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashVoidPtrKeyStub, + PL_DHashMatchEntryStub, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + InitJAVAtoXPCOMBindingEntry + }; + + gJAVAtoXPCOMBindings = PL_NewDHashTable(&java_to_xpcom_hash_ops, nsnull, + sizeof(JavaXPCOMBindingEntry), 16); + if (!gJAVAtoXPCOMBindings) { + return PR_FALSE; + } + + static PLDHashTableOps xpcom_to_java_hash_ops = + { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashVoidPtrKeyStub, + PL_DHashMatchEntryStub, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + InitXPCOMtoJAVABindingEntry + }; + + gXPCOMtoJAVABindings = PL_NewDHashTable(&xpcom_to_java_hash_ops, nsnull, + sizeof(JavaXPCOMBindingEntry), 16); + if (!gXPCOMtoJAVABindings) { + return PR_FALSE; + } + + return PR_TRUE; +} + +/************************* + * FreeJavaGlobals + *************************/ +void +FreeJavaGlobals(JNIEnv* env) +{ + // XXX Need to write +} + + +/********************************************************** + * JavaXPCOMInstance + *********************************************************/ +JavaXPCOMInstance* +CreateJavaXPCOMInstance(nsISupports* aXPCOMObject, const nsIID* aIID) +{ + JavaXPCOMInstance* inst = nsnull; + + // 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); + NS_ADDREF(aXPCOMObject); + } + + return inst; +} + + +void +ThrowXPCOMException(JNIEnv* env, int aFailureCode) +{ + // only throw this exception if one hasn't already been thrown + jthrowable throwObj = env->ExceptionOccurred(); + if (throwObj != nsnull) { + char exp_msg[32]; + sprintf(exp_msg, "\nInternal Gecko Error: %x", aFailureCode); + env->ThrowNew(exceptionClass, exp_msg); + } +} + +nsresult +GetIIDForMethodParam(nsIInterfaceInfo *iinfo, + const nsXPTMethodInfo *methodInfo, + const nsXPTParamInfo ¶mInfo, + PRUint16 methodIndex, + nsXPTCMiniVariant *dispatchParams, + PRBool isFullVariantArray, + nsID &result) +{ + nsresult rv; + + switch (paramInfo.GetType().TagPart()) + { + case nsXPTType::T_INTERFACE: + rv = iinfo->GetIIDForParamNoAlloc(methodIndex, ¶mInfo, &result); + break; + + case nsXPTType::T_INTERFACE_IS: + { + PRUint8 argnum; + rv = iinfo->GetInterfaceIsArgNumberForParam(methodIndex, ¶mInfo, &argnum); + if (NS_FAILED(rv)) + return rv; + + const nsXPTParamInfo& arg_param = methodInfo->GetParam(argnum); + const nsXPTType& arg_type = arg_param.GetType(); + + // The xpidl compiler ensures this. We reaffirm it for safety. + if (!arg_type.IsPointer() || arg_type.TagPart() != nsXPTType::T_IID) + return NS_ERROR_UNEXPECTED; + + nsID *p = nsnull; + if (isFullVariantArray) { + p = (nsID *) ((nsXPTCVariant*) dispatchParams)[argnum].val.p; + } else { + p = (nsID *) dispatchParams[argnum].val.p; + } + if (!p) + return NS_ERROR_UNEXPECTED; + + result = *p; + break; + } + + default: + rv = NS_ERROR_UNEXPECTED; + } + return rv; +} + diff --git a/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h b/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h new file mode 100644 index 000000000000..d47c51cc3069 --- /dev/null +++ b/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h @@ -0,0 +1,153 @@ +/* ***** 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 _nsJavaXPCOMBindingUtils_h_ +#define _nsJavaXPCOMBindingUtils_h_ + +#include "jni.h" +#include "xptcall.h" +#include "nsCOMPtr.h" + +#ifdef DEBUG +#define LOG(...) printf(__VA_ARGS__) +#else +#define LOG(format, ...) +#endif + + +/********************* + * Java JNI globals + *********************/ +extern jclass classClass; +extern jmethodID getNameMID; + +extern jclass objectClass; +extern jmethodID hashCodeMID; + +extern jclass booleanClass; +extern jclass booleanArrayClass; +extern jmethodID booleanInitMID; +extern jmethodID booleanValueMID; + +extern jclass charClass; +extern jclass charArrayClass; +extern jmethodID charInitMID; +extern jmethodID charValueMID; + +extern jclass byteClass; +extern jclass byteArrayClass; +extern jmethodID byteInitMID; +extern jmethodID byteValueMID; + +extern jclass shortClass; +extern jclass shortArrayClass; +extern jmethodID shortInitMID; +extern jmethodID shortValueMID; + +extern jclass intClass; +extern jclass intArrayClass; +extern jmethodID intInitMID; +extern jmethodID intValueMID; + +extern jclass longClass; +extern jclass longArrayClass; +extern jmethodID longInitMID; +extern jmethodID longValueMID; + +extern jclass floatClass; +extern jclass floatArrayClass; +extern jmethodID floatInitMID; +extern jmethodID floatValueMID; + +extern jclass doubleClass; +extern jclass doubleArrayClass; +extern jmethodID doubleInitMID; +extern jmethodID doubleValueMID; + +extern jclass stringClass; +extern jclass stringArrayClass; + +extern jclass nsISupportsClass; + +extern jclass exceptionClass; + +PRBool InitializeJavaGlobals(JNIEnv *env); +void FreeJavaGlobals(JNIEnv* env); + + +/************************* + * JavaXPCOMInstance + *************************/ +class JavaXPCOMInstance +{ +public: + JavaXPCOMInstance(nsISupports* aInstance, nsIInterfaceInfo* aIInfo) + : mInstance(aInstance), + mIInfo(aIInfo) + {} + + nsISupports* GetInstance() { return mInstance; } + nsIInterfaceInfo* InterfaceInfo() { return mIInfo; } + +private: + nsCOMPtr mInstance; + nsCOMPtr mIInfo; +}; + +JavaXPCOMInstance* CreateJavaXPCOMInstance(nsISupports* aXPCOMObject, + const nsIID* aIID); + +/************************************** + * Java<->XPCOM binding stores + **************************************/ +void AddJavaXPCOMBinding(JNIEnv* env, jobject aJavaStub, void* aXPCOMObject); +nsISupports* RemoveXPCOMBinding(JNIEnv* env, jobject aJavaObject); +void* GetMatchingXPCOMObject(JNIEnv* env, jobject aJavaObject); +jobject GetMatchingJavaObject(void* aXPCOMObject); + + +void ThrowXPCOMException(JNIEnv* env, int aFailureCode); + +nsresult GetIIDForMethodParam(nsIInterfaceInfo *iinfo, + const nsXPTMethodInfo *methodInfo, + const nsXPTParamInfo ¶mInfo, + PRUint16 methodIndex, + nsXPTCMiniVariant *dispatchParams, + PRBool isFullVariantArray, + nsID &result); + +#endif // _nsJavaXPCOMBindingUtils_h_ diff --git a/extensions/java/xpcom/nsJavaXPTCStub.cpp b/extensions/java/xpcom/nsJavaXPTCStub.cpp new file mode 100644 index 000000000000..2640861ef96d --- /dev/null +++ b/extensions/java/xpcom/nsJavaXPTCStub.cpp @@ -0,0 +1,1111 @@ +/* ***** 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 ***** */ + +#include "nsJavaXPTCStub.h" +#include "nsJavaWrapper.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "prmem.h" +#include "nsIInterfaceInfoManager.h" +#include "nsString.h" +#include "nsString.h" +#include "nsCRT.h" + + +nsJavaXPTCStub::nsJavaXPTCStub(JNIEnv* aJavaEnv, jobject aJavaObject, + nsIInterfaceInfo *aIInfo) + : mJavaEnv(aJavaEnv) + , mIInfo(aIInfo) + , mMaster(nsnull) +{ + mJavaObject = aJavaEnv->NewGlobalRef(aJavaObject); +} + +nsJavaXPTCStub::~nsJavaXPTCStub() +{ +#ifdef DEBUG + jboolean isCopy; + jclass clazz = mJavaEnv->GetObjectClass(mJavaObject); + jstring name = (jstring) mJavaEnv->CallObjectMethod(clazz, getNameMID); + const char* javaObjectName = mJavaEnv->GetStringUTFChars(name, &isCopy); + fprintf(stderr, "*** ~nsJavaXPTCStub(java_obj=%s)\n", javaObjectName); + if (isCopy) + mJavaEnv->ReleaseStringUTFChars(name, javaObjectName); +#endif + if (mMaster) + { + mMaster->mChildren.RemoveElement(this); + NS_RELEASE(mMaster); + } + + mJavaEnv->DeleteGlobalRef(mJavaObject); +} + +NS_IMPL_ADDREF(nsJavaXPTCStub) +NS_IMPL_RELEASE(nsJavaXPTCStub) + +NS_IMETHODIMP +nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr) +{ + LOG("JavaStub::QueryInterface()\n"); + nsJavaXPTCStub *master = mMaster ? mMaster : this; + + // always return the master stub for nsISupports + if (aIID.Equals(NS_GET_IID(nsISupports))) + { + *aInstancePtr = master; + NS_ADDREF(master); + return NS_OK; + } + + // does any existing stub support the requested IID? + nsJavaXPTCStub *stub = master->FindStubSupportingIID(aIID); + if (stub) + { + *aInstancePtr = stub; + NS_ADDREF(stub); + return NS_OK; + } + + // Query Java object + LOG("\tCalling Java object queryInterface\n"); + jclass clazz = mJavaEnv->GetObjectClass(mJavaObject); + char* sig = "(Ljava/lang/String;)Lorg/mozilla/xpcom/nsISupports;"; + jmethodID qiMID = mJavaEnv->GetMethodID(clazz, "queryInterface", sig); + NS_ASSERTION(qiMID, "Failed to get queryInterface method ID"); + + char* iid_str = aIID.ToString(); + jstring iid_jstr = mJavaEnv->NewStringUTF(iid_str); + PR_Free(iid_str); + jobject obj = mJavaEnv->CallObjectMethod(mJavaObject, qiMID, iid_jstr); + + // XXX Should we check here if the jobject we got back is the same as + // mJavaObject? Or to see if it already has a nsJavaXPTCStub associated + // with it? + + if (obj) { + // Get interface info for new java object + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + nsCOMPtr iinfo; + iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo)); + + nsJavaXPTCStub* stub = new nsJavaXPTCStub(mJavaEnv, obj, iinfo); + + // add stub to the master's list of children, so we can preserve + // symmetry in future QI calls. each child owns his master, but + // the master only keeps weak references to its children. the + // children are responsible for removing themselves as they die. + NS_ADDREF(master); + stub->mMaster = master; + master->mChildren.AppendElement(stub); + + *aInstancePtr = stub; + NS_ADDREF(stub); + return NS_OK; + } + + *aInstancePtr = nsnull; + return NS_OK; +} + +PRBool +nsJavaXPTCStub::SupportsIID(const nsID &iid) +{ + PRBool match; + nsCOMPtr iter = mIInfo; + do + { + if (NS_SUCCEEDED(iter->IsIID(&iid, &match)) && match) + return PR_TRUE; + + nsCOMPtr parent; + iter->GetParent(getter_AddRefs(parent)); + iter = parent; + } + while (iter != nsnull); + + return PR_FALSE; +} + +nsJavaXPTCStub * +nsJavaXPTCStub::FindStubSupportingIID(const nsID &iid) +{ + NS_ASSERTION(mMaster == nsnull, "this is not a master stub"); + + if (SupportsIID(iid)) + return this; + + for (PRInt32 i = 0; i < mChildren.Count(); i++) + { + nsJavaXPTCStub *child = (nsJavaXPTCStub *) mChildren[i]; + if (child->SupportsIID(iid)) + return child; + } + return nsnull; +} + +NS_IMETHODIMP +nsJavaXPTCStub::GetInterfaceInfo(nsIInterfaceInfo **aInfo) +{ + NS_ADDREF(*aInfo = mIInfo); + return NS_OK; +} + +NS_IMETHODIMP +nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex, + const nsXPTMethodInfo *aMethodInfo, + nsXPTCMiniVariant *aParams) +{ + LOG("nsJavaXPTCStub::CallMethod [%s]\n", aMethodInfo->GetName()); + + nsresult rv = NS_OK; + + nsCAutoString methodSig("("); + + // Create jvalue array to hold Java params + PRUint8 paramCount = aMethodInfo->GetParamCount(); + jvalue* java_params = nsnull; + const nsXPTParamInfo* retvalInfo = nsnull; + if (paramCount) { + java_params = new jvalue[paramCount]; + + for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) + { + const nsXPTParamInfo ¶mInfo = aMethodInfo->GetParam(i); + if (!paramInfo.IsRetval()) { + rv = SetupJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, + aParams[i], java_params[i], methodSig); + } else { + retvalInfo = ¶mInfo; + } + } + NS_ASSERTION(NS_SUCCEEDED(rv), "SetupJavaParams failed"); + } + + // Finish method signature + if (NS_SUCCEEDED(rv)) { + methodSig.Append(")"); + if (retvalInfo) { + nsCAutoString retvalSig; + rv = GetRetvalSig(retvalInfo, retvalSig); + methodSig.Append(retvalSig); + } else { + methodSig.Append("V"); + } + NS_ASSERTION(NS_SUCCEEDED(rv), "GetRetvalSig failed"); + } + + // Get Java method to call + jmethodID mid = nsnull; + if (NS_SUCCEEDED(rv)) { + nsCAutoString methodName(aMethodInfo->GetName()); + methodName.SetCharAt(tolower(methodName[0]), 0); + + jclass clazz = mJavaEnv->GetObjectClass(mJavaObject); + if (clazz) + mid = mJavaEnv->GetMethodID(clazz, methodName.get(), methodSig.get()); + NS_ASSERTION(mid, "Failed to get requested method for Java object"); + } + + // Call method + jvalue retval; + if (mid) { + if (!retvalInfo) { + mJavaEnv->CallVoidMethodA(mJavaObject, mid, java_params); + } else { + switch (retvalInfo->GetType().TagPart()) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + retval.b = mJavaEnv->CallByteMethodA(mJavaObject, mid, java_params); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + retval.s = mJavaEnv->CallShortMethodA(mJavaObject, mid, java_params); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + retval.i = mJavaEnv->CallIntMethodA(mJavaObject, mid, java_params); + break; + + case nsXPTType::T_FLOAT: + retval.f = mJavaEnv->CallFloatMethodA(mJavaObject, mid, java_params); + break; + + case nsXPTType::T_DOUBLE: + retval.d = mJavaEnv->CallDoubleMethodA(mJavaObject, mid, java_params); + break; + + case nsXPTType::T_BOOL: + retval.z = mJavaEnv->CallBooleanMethodA(mJavaObject, mid, java_params); + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + retval.c = mJavaEnv->CallCharMethodA(mJavaObject, mid, java_params); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + retval.l = mJavaEnv->CallObjectMethodA(mJavaObject, mid, java_params); + break; + + default: + NS_WARNING("Unhandled retval type"); + break; + } + } + + // Check for exception from called Java function + jthrowable exp = mJavaEnv->ExceptionOccurred(); + if (exp) { +#ifdef DEBUG + mJavaEnv->ExceptionDescribe(); +#endif + mJavaEnv->ExceptionClear(); + rv = NS_ERROR_FAILURE; + } + } + + // Handle any inout params + if (NS_SUCCEEDED(rv)) { + for (PRUint8 i = 0; i < paramCount; i++) + { + const nsXPTParamInfo ¶mInfo = aMethodInfo->GetParam(i); + if (!paramInfo.IsRetval()) { + rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, + aParams[i], java_params[i]); + } else { + rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, + aParams[i], retval); + } + } + NS_ASSERTION(NS_SUCCEEDED(rv), "FinalizeJavaParams/SetXPCOMRetval failed"); + } + + if (java_params) + delete [] java_params; + + return rv; +} + +nsresult +nsJavaXPTCStub::SetupJavaParams(const nsXPTParamInfo &aParamInfo, + const nsXPTMethodInfo* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, jvalue &aJValue, + nsACString &aMethodSig) +{ + nsresult rv; + const nsXPTType &type = aParamInfo.GetType(); + PRUint8 tag = type.TagPart(); + switch (tag) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + { + if (!aParamInfo.IsOut()) { + aJValue.b = aVariant.val.u8; + aMethodSig.Append("B"); + } else { + jbyteArray array = mJavaEnv->NewByteArray(1); + mJavaEnv->SetByteArrayRegion(array, 0, 1, (jbyte*) &(aVariant.val.u8)); + aJValue.l = array; + aMethodSig.Append("[B"); + } + } + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + { + if (!aParamInfo.IsOut()) { + aJValue.s = aVariant.val.u16; + aMethodSig.Append("S"); + } else { + jshortArray array = mJavaEnv->NewShortArray(1); + mJavaEnv->SetShortArrayRegion(array, 0, 1, + (jshort*) &(aVariant.val.u16)); + aJValue.l = array; + aMethodSig.Append("[S"); + } + } + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + { + if (!aParamInfo.IsOut()) { + aJValue.i = aVariant.val.u32; + aMethodSig.Append("I"); + } else { + jintArray array = mJavaEnv->NewIntArray(1); + mJavaEnv->SetIntArrayRegion(array, 0, 1, (jint*) &(aVariant.val.u32)); + aJValue.l = array; + aMethodSig.Append("[I"); + } + } + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + { + if (!aParamInfo.IsOut()) { + aJValue.j = aVariant.val.u64; + aMethodSig.Append("J"); + } else { + jlongArray array = mJavaEnv->NewLongArray(1); + mJavaEnv->SetLongArrayRegion(array, 0, 1, (jlong*) &(aVariant.val.u64)); + aJValue.l = array; + aMethodSig.Append("[J"); + } + } + break; + + case nsXPTType::T_FLOAT: + { + if (!aParamInfo.IsOut()) { + aJValue.f = aVariant.val.f; + aMethodSig.Append("F"); + } else { + jfloatArray array = mJavaEnv->NewFloatArray(1); + mJavaEnv->SetFloatArrayRegion(array, 0, 1, (jfloat*) &(aVariant.val.f)); + aJValue.l = array; + aMethodSig.Append("[F"); + } + } + break; + + case nsXPTType::T_DOUBLE: + { + if (!aParamInfo.IsOut()) { + aJValue.d = aVariant.val.d; + aMethodSig.Append("D"); + } else { + jdoubleArray array = mJavaEnv->NewDoubleArray(1); + mJavaEnv->SetDoubleArrayRegion(array, 0, 1, + (jdouble*) &(aVariant.val.d)); + aJValue.l = array; + aMethodSig.Append("[D"); + } + } + break; + + case nsXPTType::T_BOOL: + { + if (!aParamInfo.IsOut()) { + aJValue.z = aVariant.val.b; + aMethodSig.Append("Z"); + } else { + jbooleanArray array = mJavaEnv->NewBooleanArray(1); + mJavaEnv->SetBooleanArrayRegion(array, 0, 1, + (jboolean*) &(aVariant.val.b)); + aJValue.l = array; + aMethodSig.Append("[Z"); + } + } + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + { + if (!aParamInfo.IsOut()) { + aJValue.c = aVariant.val.wc; + aMethodSig.Append("C"); + } else { + jcharArray array = mJavaEnv->NewCharArray(1); + mJavaEnv->SetCharArrayRegion(array, 0, 1, (jchar*) &(aVariant.val.wc)); + aJValue.l = array; + aMethodSig.Append("[C"); + } + } + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + { + jobject str; + if (aVariant.val.p) { + if (tag == nsXPTType::T_CHAR_STR) { + str = mJavaEnv->NewStringUTF((const char*) aVariant.val.p); + } else { + const PRUnichar* buf = (const PRUnichar*) aVariant.val.p; + str = mJavaEnv->NewString(buf, nsCRT::strlen(buf)); + } + } else { + str = nsnull; + } + + if (!aParamInfo.IsOut()) { + aJValue.l = str; + aMethodSig.Append("Ljava/lang/String;"); + } else { + aJValue.l = mJavaEnv->NewObjectArray(1, stringClass, str); + aMethodSig.Append("[Ljava/lang/String;"); + } + } + break; + + case nsXPTType::T_IID: + { + jstring str = nsnull; + nsID* iid = (nsID*) aVariant.val.p; + if (iid) { + char* iid_str = iid->ToString(); + str = mJavaEnv->NewStringUTF(iid_str); + PR_Free(iid_str); + } + + if (!aParamInfo.IsOut()) { + aJValue.l = str; + aMethodSig.Append("Ljava/lang/String;"); + } else { + aJValue.l = mJavaEnv->NewObjectArray(1, stringClass, str); + aMethodSig.Append("[Ljava/lang/String;"); + } + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + jobject java_stub; + if (aVariant.val.p) { + java_stub = GetMatchingJavaObject(aVariant.val.p); + + if (java_stub == nsnull) { + // wrap xpcom instance + nsID iid; + JavaXPCOMInstance* inst; + rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo, + aMethodIndex, aDispatchParams, PR_FALSE, iid); + if (NS_FAILED(rv)) + return rv; + + inst = CreateJavaXPCOMInstance((nsISupports*) aVariant.val.p, &iid); + + if (inst) { + // create java stub + char* iface_name; + inst->InterfaceInfo()->GetName(&iface_name); + java_stub = CreateJavaWrapper(mJavaEnv, iface_name); + + if (java_stub) { + // Associate XPCOM object w/ Java stub + AddJavaXPCOMBinding(mJavaEnv, java_stub, inst); + } + } + } + } else { + java_stub = nsnull; + } + + if (!aParamInfo.IsOut()) { + aJValue.l = java_stub; + aMethodSig.Append("Lorg/mozilla/xpcom/nsISupports;"); + } else { + aJValue.l = mJavaEnv->NewObjectArray(1, nsISupportsClass, java_stub); + aMethodSig.Append("[Lorg/mozilla/xpcom/nsISupports;"); + } + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + jstring jstr = nsnull; + nsString* str = (nsString*) aVariant.val.p; + if (str) { + jstr = mJavaEnv->NewString(str->get(), str->Length()); + } + + if (!aParamInfo.IsOut()) { + aJValue.l = jstr; + aMethodSig.Append("Ljava/lang/String;"); + } else { + aJValue.l = mJavaEnv->NewObjectArray(1, stringClass, jstr); + aMethodSig.Append("[Ljava/lang/String;"); + } + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + jstring jstr = nsnull; + nsCString* str = (nsCString*) aVariant.val.p; + if (str) { + jstr = mJavaEnv->NewStringUTF(str->get()); + } + + if (!aParamInfo.IsOut()) { + aJValue.l = jstr; + aMethodSig.Append("Ljava/lang/String;"); + } else { + aJValue.l = mJavaEnv->NewObjectArray(1, stringClass, jstr); + aMethodSig.Append("[Ljava/lang/String;"); + } + } + break; + + // XXX How should this be handled? + case nsXPTType::T_VOID: + NS_WARNING("Unhandled T_VOID"); + return NS_ERROR_NOT_IMPLEMENTED; + break; + + case nsXPTType::T_ARRAY: + NS_WARNING("array types are not yet supported"); + return NS_ERROR_NOT_IMPLEMENTED; + break; + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +nsresult +nsJavaXPTCStub::GetRetvalSig(const nsXPTParamInfo* aParamInfo, + nsACString &aRetvalSig) +{ + const nsXPTType &type = aParamInfo->GetType(); + PRUint8 tag = type.TagPart(); + switch (tag) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + aRetvalSig.Append("B"); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + aRetvalSig.Append("S"); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + aRetvalSig.Append("I"); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + aRetvalSig.Append("J"); + break; + + case nsXPTType::T_FLOAT: + aRetvalSig.Append("F"); + break; + + case nsXPTType::T_DOUBLE: + aRetvalSig.Append("D"); + break; + + case nsXPTType::T_BOOL: + aRetvalSig.Append("Z"); + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + aRetvalSig.Append("C"); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + aRetvalSig.Append("Ljava/lang/String;"); + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + aRetvalSig.Append("Lorg/mozilla/xpcom/nsISupports;"); + break; + + // XXX How should this be handled? + case nsXPTType::T_VOID: + NS_WARNING("Unhandled T_VOID"); + return NS_ERROR_NOT_IMPLEMENTED; + break; + + case nsXPTType::T_ARRAY: + NS_WARNING("array types are not yet supported"); + return NS_ERROR_NOT_IMPLEMENTED; + break; + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +nsresult +nsJavaXPTCStub::FinalizeJavaParams(const nsXPTParamInfo &aParamInfo, + const nsXPTMethodInfo* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, jvalue &aJValue) +{ + nsresult rv; + const nsXPTType &type = aParamInfo.GetType(); + + switch (type.TagPart()) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + { + if (aJValue.l) { + if (aParamInfo.IsRetval()) { + *((PRUint8 *) aVariant.val.p) = aJValue.b; + } else if (aParamInfo.IsOut()) { + jboolean isCopy = PR_FALSE; + jbyte* array = mJavaEnv->GetByteArrayElements((jbyteArray) aJValue.l, + &isCopy); + *((PRUint8 *) aVariant.val.p) = array[0]; + if (isCopy) { + mJavaEnv->ReleaseByteArrayElements((jbyteArray) aJValue.l, array, + JNI_ABORT); + } + } + } + } + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + { + if (aJValue.l) { + if (aParamInfo.IsRetval()) { + *((PRUint16 *) aVariant.val.p) = aJValue.s; + } else if (aParamInfo.IsOut()) { + jboolean isCopy = PR_FALSE; + jshort* array = + mJavaEnv->GetShortArrayElements((jshortArray) aJValue.l, + &isCopy); + *((PRUint16 *) aVariant.val.p) = array[0]; + if (isCopy) { + mJavaEnv->ReleaseShortArrayElements((jshortArray) aJValue.l, array, + JNI_ABORT); + } + } + } + } + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + { + if (aJValue.l) { + if (aParamInfo.IsRetval()) { + *((PRUint32 *) aVariant.val.p) = aJValue.i; + } else if (aParamInfo.IsOut()) { + jboolean isCopy = PR_FALSE; + jint* array = mJavaEnv->GetIntArrayElements((jintArray) aJValue.l, + &isCopy); + *((PRUint32 *) aVariant.val.p) = array[0]; + if (isCopy) { + mJavaEnv->ReleaseIntArrayElements((jintArray) aJValue.l, array, + JNI_ABORT); + } + } + } + } + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + { + if (aJValue.l) { + if (aParamInfo.IsRetval()) { + *((PRUint64 *) aVariant.val.p) = aJValue.j; + } else if (aParamInfo.IsOut()) { + jboolean isCopy = PR_FALSE; + jlong* array = mJavaEnv->GetLongArrayElements((jlongArray) aJValue.l, + &isCopy); + *((PRUint64 *) aVariant.val.p) = array[0]; + if (isCopy) { + mJavaEnv->ReleaseLongArrayElements((jlongArray) aJValue.l, array, + JNI_ABORT); + } + } + } + } + break; + + case nsXPTType::T_FLOAT: + { + if (aJValue.l) { + if (aParamInfo.IsRetval()) { + *((float *) aVariant.val.p) = aJValue.f; + } else if (aParamInfo.IsOut()) { + jboolean isCopy = PR_FALSE; + jfloat* array = + mJavaEnv->GetFloatArrayElements((jfloatArray) aJValue.l, + &isCopy); + *((float *) aVariant.val.p) = array[0]; + if (isCopy) { + mJavaEnv->ReleaseFloatArrayElements((jfloatArray) aJValue.l, array, + JNI_ABORT); + } + } + } + } + break; + + case nsXPTType::T_DOUBLE: + { + if (aJValue.l) { + if (aParamInfo.IsRetval()) { + *((double *) aVariant.val.p) = aJValue.d; + } else if (aParamInfo.IsOut()) { + jboolean isCopy = PR_FALSE; + jdouble* array = + mJavaEnv->GetDoubleArrayElements((jdoubleArray) aJValue.l, + &isCopy); + *((double *) aVariant.val.p) = array[0]; + if (isCopy) { + mJavaEnv->ReleaseDoubleArrayElements((jdoubleArray) aJValue.l, + array, JNI_ABORT); + } + } + } + } + break; + + case nsXPTType::T_BOOL: + { + if (aJValue.l) { + if (aParamInfo.IsRetval()) { + *((PRBool *) aVariant.val.p) = aJValue.z; + } else if (aParamInfo.IsOut()) { + jboolean isCopy = PR_FALSE; + jboolean* array = + mJavaEnv->GetBooleanArrayElements((jbooleanArray) aJValue.l, + &isCopy); + *((PRBool *) aVariant.val.p) = array[0]; + if (isCopy) { + mJavaEnv->ReleaseBooleanArrayElements((jbooleanArray) aJValue.l, + array, JNI_ABORT); + } + } + } + } + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + { + if (aJValue.l) { + if (aParamInfo.IsRetval()) { + if (type.TagPart() == nsXPTType::T_CHAR) + *((char *) aVariant.val.p) = aJValue.c; + else + *((PRUnichar *) aVariant.val.p) = aJValue.c; + } else if (aParamInfo.IsOut()) { + jboolean isCopy = PR_FALSE; + jchar* array = mJavaEnv->GetCharArrayElements((jcharArray) aJValue.l, + &isCopy); + if (type.TagPart() == nsXPTType::T_CHAR) + *((char *) aVariant.val.p) = array[0]; + else + *((PRUnichar *) aVariant.val.p) = array[0]; + if (isCopy) { + mJavaEnv->ReleaseCharArrayElements((jcharArray) aJValue.l, array, + JNI_ABORT); + } + } + } + } + break; + + case nsXPTType::T_CHAR_STR: + { + // XXX not sure how this should be handled + if (aJValue.l && aParamInfo.IsOut()) { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { + str = (jstring) aJValue.l; + } else if (aParamInfo.IsOut()) { + str = (jstring) + mJavaEnv->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + if (str) { + jboolean isCopy; + const char* char_ptr = mJavaEnv->GetStringUTFChars(str, &isCopy); + *((char **) aVariant.val.p) = strdup(char_ptr); + if (isCopy) { + mJavaEnv->ReleaseStringUTFChars(str, char_ptr); + } + } + } + } + break; + + case nsXPTType::T_WCHAR_STR: + { + // XXX not sure how this should be handled + if (aJValue.l && aParamInfo.IsOut()) { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { + str = (jstring) aJValue.l; + } else if (aParamInfo.IsOut()) { + str = (jstring) + mJavaEnv->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + if (str) { + jboolean isCopy; + const jchar* wchar_ptr = mJavaEnv->GetStringChars(str, &isCopy); + + PRUint32 length = nsCRT::strlen(wchar_ptr); + PRUnichar* string = (PRUnichar*) malloc(length + 1); // add one for null + memcpy(string, wchar_ptr, length * sizeof(PRUnichar)); + string[length] = 0; + *((PRUnichar **) aVariant.val.p) = string; + + if (isCopy) { + mJavaEnv->ReleaseStringChars(str, wchar_ptr); + } + } + } + } + break; + + case nsXPTType::T_IID: + { + if (aJValue.l && aParamInfo.IsOut()) { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { + str = (jstring) aJValue.l; + } else { + str = (jstring) + mJavaEnv->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + if (str) { + jboolean isCopy; + const char* char_ptr = mJavaEnv->GetStringUTFChars(str, &isCopy); + + if (aVariant.val.p) { + // If not null, then we just put in the new value. + nsID* iid = *((nsID**) aVariant.val.p); + iid->Parse(char_ptr); + } else { + // If the argument that was passed in was null, then we need to + // create a new nsID. + nsID* iid = new nsID; + iid->Parse(char_ptr); + *((nsID **) aVariant.val.p) = iid; + } + + if (isCopy) { + mJavaEnv->ReleaseStringUTFChars(str, char_ptr); + } + } + } + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + if (aJValue.l && aParamInfo.IsOut()) { + jobject java_obj = nsnull; + if (aParamInfo.IsRetval()) { + java_obj = aJValue.l; + } else { + java_obj = mJavaEnv->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + if (java_obj) { + void* inst = GetMatchingXPCOMObject(mJavaEnv, java_obj); + if (inst == nsnull) { + // Get IID for this param + nsID iid; + rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo, + aMethodIndex, aDispatchParams, PR_TRUE, + iid); + if (NS_FAILED(rv)) + return rv; + + // Get interface info for class + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + nsCOMPtr iinfo; + iim->GetInfoForIID(&iid, getter_AddRefs(iinfo)); + + // Create XPCOM stub + nsJavaXPTCStub* xpcomStub = new nsJavaXPTCStub(mJavaEnv, java_obj, + iinfo); + NS_ADDREF(xpcomStub); + inst = SetAsXPTCStub(xpcomStub); + AddJavaXPCOMBinding(mJavaEnv, java_obj, inst); + } +#if 1 + // XXX This code is here to make sure that the nsJavaXPTCStub that is + // used has the correct (asked for) interface info. For example, in + // the Java code, the nsIWeakReference functions return the current + // Java object ('this'); so when we call GetMatchingXPCOMObject on + // that Java object, we get back a nsJavaXPTCStub that has the interface + // info for something other than nsIWeakReference. This will cause + // problems later when we try to call one of the nsIWeakReference + // functions on that Java object, but the nsJavaXPTCStub object doesn't + // know anything about nsIWeakReference. + else { + if (IsXPTCStub(inst)) { + // Get IID for this param + nsID iid; + rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo, + aMethodIndex, aDispatchParams, PR_TRUE, + iid); + if (NS_FAILED(rv)) + return rv; + + void* temp; + rv = GetXPTCStubAddr(inst)->QueryInterface(iid, &temp); + if (NS_SUCCEEDED(rv) && temp != GetXPTCStubAddr(inst)) + inst = SetAsXPTCStub((nsJavaXPTCStub*) temp); + } + } +#endif + + if (IsXPTCStub(inst)) + *((void **) aVariant.val.p) = (void*) GetXPTCStubAddr(inst); + else { + JavaXPCOMInstance* xpcomInst = (JavaXPCOMInstance*) inst; + *((void **) aVariant.val.p) = (void*) xpcomInst->GetInstance(); + } + } + } + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + if (aJValue.l && aParamInfo.IsOut()) { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { + str = (jstring) aJValue.l; + } else { + str = (jstring) + mJavaEnv->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + if (str) { + jboolean isCopy; + const jchar* wchar_ptr = mJavaEnv->GetStringChars(str, &isCopy); + + if (aVariant.val.p) { + ((nsString*) aVariant.val.p)->Assign(wchar_ptr); + } else { + nsString* embedStr = new nsString(wchar_ptr); + aVariant.val.p = embedStr; + } + + if (isCopy) { + mJavaEnv->ReleaseStringChars(str, wchar_ptr); + } + } + } + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + if (aJValue.l && aParamInfo.IsOut()) { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { + str = (jstring) aJValue.l; + } else { + str = (jstring) + mJavaEnv->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + if (str) { + jboolean isCopy; + const char* char_ptr = mJavaEnv->GetStringUTFChars(str, &isCopy); + + if (aVariant.val.p) { + ((nsCString*) aVariant.val.p)->Assign(char_ptr); + } else { + nsCString* embedStr = new nsCString(char_ptr); + aVariant.val.p = embedStr; + } + + if (isCopy) { + mJavaEnv->ReleaseStringUTFChars(str, char_ptr); + } + } + } + } + break; + + case nsXPTType::T_VOID: + NS_WARNING("Unhandled T_VOID"); + return NS_ERROR_NOT_IMPLEMENTED; + break; + + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + diff --git a/extensions/java/xpcom/nsJavaXPTCStub.h b/extensions/java/xpcom/nsJavaXPTCStub.h new file mode 100644 index 000000000000..81759e1bf803 --- /dev/null +++ b/extensions/java/xpcom/nsJavaXPTCStub.h @@ -0,0 +1,110 @@ +/* ***** 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 _nsJavaXPTCStub_h_ +#define _nsJavaXPTCStub_h_ + +#include "xptcall.h" +#include "jni.h" +#include "nsVoidArray.h" +#include "nsIInterfaceInfo.h" +#include "nsCOMPtr.h" + + +class nsJavaXPTCStub : public nsXPTCStubBase +{ +public: + NS_DECL_ISUPPORTS + + nsJavaXPTCStub(JNIEnv* aJavaEnv, jobject aJavaObject, nsIInterfaceInfo *aIInfo); + + virtual ~nsJavaXPTCStub(); + + // return a refcounted pointer to the InterfaceInfo for this object + // NOTE: on some platforms this MUST not fail or we crash! + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo **aInfo); + + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 aMethodIndex, + const nsXPTMethodInfo *aInfo, + nsXPTCMiniVariant *aParams); + +private: +// NS_HIDDEN ~JavaStub(); + + // returns a weak reference to a child supporting the specified interface +// NS_HIDDEN_(JavaStub *) FindStubSupportingIID(const nsID &aIID); + nsJavaXPTCStub * FindStubSupportingIID(const nsID &aIID); + + // returns true if this stub supports the specified interface +// NS_HIDDEN_(PRBool) SupportsIID(const nsID &aIID); + PRBool SupportsIID(const nsID &aIID); + + nsresult SetupJavaParams(const nsXPTParamInfo &aParamInfo, + const nsXPTMethodInfo* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, + jvalue &aJValue, nsACString &aMethodSig); + nsresult GetRetvalSig(const nsXPTParamInfo* aParamInfo, + nsACString &aRetvalSig); + nsresult FinalizeJavaParams(const nsXPTParamInfo &aParamInfo, + const nsXPTMethodInfo* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, + jvalue &aJValue); + nsresult SetXPCOMRetval(); + + JNIEnv* mJavaEnv; + jobject mJavaObject; + nsCOMPtr mIInfo; + + nsVoidArray mChildren; // weak references (cleared by the children) + nsJavaXPTCStub *mMaster; // strong reference +}; + +inline void* SetAsXPTCStub(nsJavaXPTCStub* ptr) + { return (void*) (((unsigned long) ptr) | 0x1); } + +inline PRBool IsXPTCStub(void* ptr) + { return ((unsigned long) ptr) & 0x1; } + +inline nsJavaXPTCStub* GetXPTCStubAddr(void* ptr) + { return (nsJavaXPTCStub*) (((unsigned long) ptr) & ~0x1); } + +#endif // _nsJavaXPTCStub_h_