Bug 279649 - Dynamically create Java proxies. r=darin.

git-svn-id: svn://10.0.0.236/trunk@169666 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
pedemont%us.ibm.com 2005-02-23 20:19:55 +00:00
parent 7fa761ebfe
commit c9c27d63d5
15 changed files with 843 additions and 442 deletions

View File

@ -1513,14 +1513,9 @@ $(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 $@
$(XPIDL_GEN_DIR)/org/mozilla/xpcom/.%.java.pp: %.idl $(JAVA_IDL_COMPILE) $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/.done
$(XPIDL_GEN_DIR)/org/mozilla/xpcom/.%.java.pp: %.idl $(JAVA_IDL_COMPILE) $(XPIDL_GEN_DIR)/org/mozilla/xpcom/.done
$(REPORT_BUILD)
$(ELOG) $(JAVA_IDL_COMPILE) -m java -p org.mozilla.xpcom -w -I$(srcdir) -I$(IDL_DIR) -o $(XPIDL_GEN_DIR)/org/mozilla/xpcom/$* $(_VPATH_SRCS)
$(ELOG) $(JAVA_IDL_COMPILE) -m javastub -p org.mozilla.xpcom -w -I$(srcdir) -I$(IDL_DIR) -o $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/$*_Stub $(_VPATH_SRCS)
@touch $@
@ -1532,7 +1527,6 @@ export:: $(JAVA_DIST_DIR)
export:: $(JAVADEPFILES)
ifndef NO_DIST_INSTALL
$(INSTALL) $(IFLAGS1) $(XPIDL_GEN_DIR)/org/mozilla/xpcom/*.java $(JAVA_DIST_DIR)/org/mozilla/xpcom/
$(INSTALL) $(IFLAGS1) $(XPIDL_GEN_DIR)/org/mozilla/xpcom/stubs/*.java $(JAVA_DIST_DIR)/org/mozilla/xpcom/stubs/
endif
endif # JAVA_XPIDLSRCS

View File

@ -69,7 +69,8 @@ CPPSRCS = \
JAVA_SRCS = \
XPCOM.java \
XPCOMPrivate.java \
XPCOMJavaProxy.java \
XPCOMJavaProxyBase.java \
XPCOMException.java \
GeckoEmbed.java \
AppFileLocProvider.java \

View File

@ -0,0 +1,230 @@
/* ***** 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;
import java.lang.reflect.*;
/**
* This class is used to pass XPCOM objects to Java functions. A
* <code>java.lang.reflect.Proxy</code> instance is created using the expected
* interface, and all calls to the proxy are forwarded to the XPCOM object.
*/
public final class XPCOMJavaProxy implements InvocationHandler {
/**
* Pointer to the XPCOM object for which we are a proxy.
*/
protected long nativeXPCOMPtr;
/**
* Default constructor.
*
* @param aXPCOMInstance address of XPCOM object as a long
*/
public XPCOMJavaProxy(long aXPCOMInstance)
{
nativeXPCOMPtr = aXPCOMInstance;
}
/**
* Creates a Proxy for the given XPCOM object.
*
* @param aInterface interface from which to create Proxy
* @param aXPCOMInstance address of XPCOM object as a long
*
* @return Proxy of given XPCOM object
*/
protected static Object createProxy(Class aInterface, long aXPCOMInstance)
{
return Proxy.newProxyInstance(aInterface.getClassLoader(),
new Class[] { aInterface,
XPCOMJavaProxyBase.class },
new XPCOMJavaProxy(aXPCOMInstance));
}
/**
* All calls to the Java proxy are forwarded to this method. This method
* takes care of a few of the <code>Object</code> method calls; all other
* calls are forwarded to the XPCOM object.
*
* @param aProxy Proxy created by <code>createProxy</code>
* @param aMethod object that describes the called method
* @param aParams array of the arguments passed to the method
*
* @return return value as defined by given <code>aMethod</code>
*/
public Object invoke(Object aProxy, Method aMethod, Object[] aParams)
throws Throwable
{
String methodName = aMethod.getName();
// Handle the three java.lang.Object methods that are passed to us.
if (aMethod.getDeclaringClass() == Object.class) {
if (methodName.equals("hashCode")) {
return proxyHashCode(aProxy);
}
if (methodName.equals("equals")) {
return proxyEquals(aProxy, aParams[0]);
}
if (methodName.equals("toString")) {
return proxyToString(aProxy);
}
System.err.println("WARNING: Unhandled Object method [" +
methodName + "]");
return null;
}
// Handle the 'finalize' method called during garbage collection
if (aMethod.getDeclaringClass() == XPCOMJavaProxyBase.class) {
if (methodName.equals("finalize")) {
finalizeProxy(aProxy);
} else {
System.err.println("WARNING: Unhandled XPCOMJavaProxyBase method [" +
methodName + "]");
}
return null;
}
// If not already handled, pass method calls to XPCOM object.
return callXPCOMMethod(aProxy, methodName, aParams);
}
/**
* Handles method calls of <code>java.lang.Object.hashCode</code>
*
* @param aProxy Proxy created by <code>createProxy</code>
*
* @return Integer object representing hash code of given object
*
* @see Object#hashCode()
*/
protected static Integer proxyHashCode(Object aProxy)
{
return new Integer(System.identityHashCode(aProxy));
}
/**
* Handles method calls of <code>java.lang.Object.equals</code>
*
* @param aProxy Proxy created by <code>createProxy</code>
* @param aOther another object
*
* @return <code>true</code> if the given objects are the same;
* <code>false</code> otherwise
*
* @see Object#equals(Object)
*/
protected static Boolean proxyEquals(Object aProxy, Object aOther)
{
return (aProxy == aOther ? Boolean.TRUE : Boolean.FALSE);
}
/**
* Handles method calls of <code>java.lang.Object.toString</code>
*
* @param aProxy Proxy created by <code>createProxy</code>
*
* @return String representation of given object
*
* @see Object#toString()
*/
protected static String proxyToString(Object aProxy)
{
return aProxy.getClass().getInterfaces()[0].getName() + '@' +
Integer.toHexString(aProxy.hashCode());
}
/**
* Indicates whether the given object is an XPCOMJavaProxy.
*
* @param aObject object to check
*
* @return <code>true</code> if the given object is an XPCOMJavaProxy;
* <code>false</code> otherwise
*/
protected static boolean isXPCOMJavaProxy(Object aObject)
{
Class objectClass = aObject.getClass();
if (Proxy.isProxyClass(objectClass)) {
Class[] interfaces = objectClass.getInterfaces();
if (interfaces[interfaces.length-1] == XPCOMJavaProxyBase.class) {
return true;
}
}
return false;
}
/**
* Returns the XPCOM object that the given proxy references.
*
* @param aProxy Proxy created by <code>createProxy</code>
*
* @return address of XPCOM object as a long
*/
protected static long getNativeXPCOMInstance(Object aProxy)
{
XPCOMJavaProxy proxy = (XPCOMJavaProxy) Proxy.getInvocationHandler(aProxy);
return proxy.nativeXPCOMPtr;
}
/**
* Calls the XPCOM object referenced by the proxy with the given method.
*
* @param aProxy Proxy created by <code>createProxy</code>
* @param aMethodName name of method that we want to call
* @param aParams array of params passed to method
*
* @return return value as defined by given method
*
* @exception XPCOMException if XPCOM method failed. Values of XPCOMException
* are defined by the method called.
*/
protected static native
Object callXPCOMMethod(Object aProxy, String aMethodName, Object[] aParams);
/**
* Called when the proxy is garbage collected by the JVM. Allows us to clean
* up any references to the XPCOM object.
*
* @param aProxy reference to Proxy that is being garbage collected
*/
protected static native
void finalizeProxy(Object aProxy);
}

View File

@ -0,0 +1,53 @@
/* ***** 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;
/**
* This interface forms the foundation of any XPCOMJavaProxy that is created.
* It allows us to handle any JVM calls to <code>finalize</code> when the Proxy
* is garbage collected.
*/
public interface XPCOMJavaProxyBase {
/**
* @see java.lang.Object#finalize()
*/
void finalize() throws Throwable;
}

View File

@ -51,20 +51,19 @@ GARBAGE_DIRS += org
include $(topsrcdir)/config/rules.mk
ifdef MOZ_DEBUG
JAVAC_FLAGS = -g
endif
org/mozilla/xpcom/.class_done:
@echo Compiling Java interface classes
@$(JAVAC) -classpath . -d . $(JAVA_DIST_DIR)/org/mozilla/xpcom/*.java
@$(JAVAC) $(JAVAC_FLAGS) -classpath . -d . $(JAVA_DIST_DIR)/org/mozilla/xpcom/*.java
@touch $@
org/mozilla/xpcom/stubs/.class_done:
@echo Compiling Java stub classes
@$(JAVAC) -classpath . -d . $(JAVA_DIST_DIR)/org/mozilla/xpcom/stubs/*.java
@touch $@
$(JARFILE): org/mozilla/xpcom/.class_done org/mozilla/xpcom/stubs/.class_done
$(JARFILE): org/mozilla/xpcom/.class_done Makefile
$(JAR) cf $@ org
$(JARFILE_SRC):
$(JARFILE_SRC): $(JARFILE)
$(JAR) cf $@ -C $(JAVA_DIST_DIR) org
libs:: $(JARFILE) $(JARFILE_SRC)

View File

@ -47,48 +47,61 @@
#include "nsEnumeratorUtils.h"
#include "nsArray.h"
#include "nsAppFileLocProviderProxy.h"
#include "nsIEventQueueService.h"
#define GECKO_NATIVE(func) Java_org_mozilla_xpcom_GeckoEmbed_##func
#define XPCOM_NATIVE(func) Java_org_mozilla_xpcom_XPCOM_##func
#define XPCOMPRIVATE_NATIVE(func) Java_org_mozilla_xpcom_XPCOMPrivate_##func
nsresult
InitEmbedding_Impl(JNIEnv* env, jobject aMozBinDirectory,
jobject aAppFileLocProvider)
{
nsresult rv;
if (!InitializeJavaGlobals(env))
return NS_ERROR_FAILURE;
// create an nsILocalFile from given java.io.File
nsCOMPtr<nsILocalFile> directory;
if (aMozBinDirectory) {
rv = File_to_nsILocalFile(env, aMozBinDirectory, getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv);
}
// create nsAppFileLocProviderProxy from given Java object
nsAppFileLocProviderProxy* provider = nsnull;
if (aAppFileLocProvider) {
provider = new nsAppFileLocProviderProxy(env, aAppFileLocProvider);
if (!provider)
return NS_ERROR_OUT_OF_MEMORY;
}
// init Gecko
rv = NS_InitEmbedding(directory, provider);
if (provider) {
delete provider;
}
NS_ENSURE_SUCCESS(rv, rv);
// init Event Queue
nsCOMPtr<nsIEventQueueService>
eventQService(do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = eventQService->CreateThreadEventQueue();
return rv;
}
extern "C" JX_EXPORT void JNICALL
GECKO_NATIVE(initEmbedding) (JNIEnv* env, jclass, jobject aMozBinDirectory,
jobject aAppFileLocProvider)
{
nsresult rv = NS_OK;
if (!InitializeJavaGlobals(env)) {
rv = NS_ERROR_FAILURE;
} else {
// Create an nsILocalFile from given java.io.File
nsCOMPtr<nsILocalFile> directory;
if (aMozBinDirectory) {
rv = File_to_nsILocalFile(env, aMozBinDirectory, getter_AddRefs(directory));
}
nsresult rv = InitEmbedding_Impl(env, aMozBinDirectory, aAppFileLocProvider);
if (NS_SUCCEEDED(rv)) {
nsAppFileLocProviderProxy* provider = nsnull;
if (aAppFileLocProvider) {
provider = new nsAppFileLocProviderProxy(env, aAppFileLocProvider);
if (!provider)
rv = NS_ERROR_OUT_OF_MEMORY;
}
if (NS_SUCCEEDED(rv)) {
rv = NS_InitEmbedding(directory, provider);
if (provider) {
delete provider;
}
if (NS_SUCCEEDED(rv)) {
return;
}
}
}
if (NS_FAILED(rv)) {
ThrowException(env, rv, "Failure in initEmbedding");
FreeJavaGlobals(env);
}
ThrowException(env, rv, "Failure in initEmbedding");
FreeJavaGlobals(env);
}
extern "C" JX_EXPORT void JNICALL
@ -101,46 +114,61 @@ GECKO_NATIVE(termEmbedding) (JNIEnv *env, jclass)
FreeJavaGlobals(env);
}
nsresult
InitXPCOM_Impl(JNIEnv* env, jobject aMozBinDirectory,
jobject aAppFileLocProvider, jobject* aResult)
{
nsresult rv;
if (!InitializeJavaGlobals(env))
return NS_ERROR_FAILURE;
// create an nsILocalFile from given java.io.File
nsCOMPtr<nsILocalFile> directory;
if (aMozBinDirectory) {
rv = File_to_nsILocalFile(env, aMozBinDirectory, getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv);
}
// create nsAppFileLocProviderProxy from given Java object
nsAppFileLocProviderProxy* provider = nsnull;
if (aAppFileLocProvider) {
provider = new nsAppFileLocProviderProxy(env, aAppFileLocProvider);
if (!provider)
return NS_ERROR_OUT_OF_MEMORY;
}
// init XPCOM
nsIServiceManager* servMan = nsnull;
rv = NS_InitXPCOM2(&servMan, directory, provider);
if (provider) {
delete provider;
}
NS_ENSURE_SUCCESS(rv, rv);
// init Event Queue
nsCOMPtr<nsIEventQueueService>
eventQService(do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = eventQService->CreateThreadEventQueue();
NS_ENSURE_SUCCESS(rv, rv);
// create Java proxy for service manager returned by NS_InitXPCOM2
rv = CreateJavaProxy(env, servMan, NS_GET_IID(nsIServiceManager),
aResult);
NS_RELEASE(servMan); // Java proxy has owning ref
return rv;
}
extern "C" JX_EXPORT jobject JNICALL
XPCOM_NATIVE(initXPCOM) (JNIEnv* env, jclass, jobject aMozBinDirectory,
jobject aAppFileLocProvider)
{
nsresult rv = NS_OK;
if (!InitializeJavaGlobals(env)) {
rv = NS_ERROR_FAILURE;
} else {
// Create an nsILocalFile from given java.io.File
nsCOMPtr<nsILocalFile> directory;
if (aMozBinDirectory) {
rv = File_to_nsILocalFile(env, aMozBinDirectory, getter_AddRefs(directory));
}
if (NS_SUCCEEDED(rv)) {
nsAppFileLocProviderProxy* provider = nsnull;
if (aAppFileLocProvider) {
provider = new nsAppFileLocProviderProxy(env, aAppFileLocProvider);
if (!provider)
rv = NS_ERROR_OUT_OF_MEMORY;
}
if (NS_SUCCEEDED(rv)) {
nsIServiceManager* servMan = nsnull;
rv = NS_InitXPCOM2(&servMan, directory, provider);
if (provider) {
delete provider;
}
if (NS_SUCCEEDED(rv)) {
jobject javaProxy;
rv = CreateJavaProxy(env, servMan, NS_GET_IID(nsIServiceManager),
&javaProxy);
NS_RELEASE(servMan); // JavaXPCOMInstance has owning ref
if (NS_SUCCEEDED(rv))
return javaProxy;
}
}
}
}
jobject servMan;
nsresult rv = InitXPCOM_Impl(env, aMozBinDirectory, aAppFileLocProvider,
&servMan);
if (NS_SUCCEEDED(rv))
return servMan;
ThrowException(env, rv, "Failure in initXPCOM");
FreeJavaGlobals(env);
@ -150,23 +178,24 @@ XPCOM_NATIVE(initXPCOM) (JNIEnv* env, jclass, jobject aMozBinDirectory,
extern "C" JX_EXPORT void JNICALL
XPCOM_NATIVE(shutdownXPCOM) (JNIEnv *env, jclass, jobject aServMgr)
{
nsresult rv;
nsCOMPtr<nsIServiceManager> servMgr;
if (aServMgr) {
// Find corresponding XPCOM object
void* xpcomObj = gBindings->GetXPCOMObject(env, aServMgr);
NS_ASSERTION(xpcomObj != nsnull, "Failed to get XPCOM obj for ServiceMgr.");
// Get native XPCOM instance
void* xpcom_obj;
rv = GetXPCOMInstFromProxy(env, aServMgr, &xpcom_obj);
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get XPCOM obj for ServiceMgr.");
// Even if we failed to get the matching xpcom object, we don't abort this
// function. Just call NS_ShutdownXPCOM with a null service manager.
if (xpcomObj) {
NS_ASSERTION(!IsXPTCStub(xpcomObj),
"Expected JavaXPCOMInstance, but got nsJavaXPTCStub");
servMgr = do_QueryInterface(((JavaXPCOMInstance*) xpcomObj)->GetInstance());
if (NS_SUCCEEDED(rv)) {
JavaXPCOMInstance* inst = NS_STATIC_CAST(JavaXPCOMInstance*, xpcom_obj);
servMgr = do_QueryInterface(inst->GetInstance());
}
}
nsresult rv = NS_ShutdownXPCOM(servMgr);
rv = NS_ShutdownXPCOM(servMgr);
if (NS_FAILED(rv))
ThrowException(env, rv, "NS_ShutdownXPCOM failed");
@ -261,239 +290,3 @@ XPCOM_NATIVE(getServiceManager) (JNIEnv *env, jclass)
return nsnull;
}
extern "C" JX_EXPORT void JNICALL
XPCOMPRIVATE_NATIVE(CallXPCOMMethodVoid) (JNIEnv *env, jclass that,
jobject aJavaObject,
jint aMethodIndex,
jobjectArray aParams)
{
jvalue rc;
CallXPCOMMethod(env, that, aJavaObject, aMethodIndex, aParams, rc);
}
extern "C" JX_EXPORT jboolean JNICALL
XPCOMPRIVATE_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" JX_EXPORT jbooleanArray JNICALL
XPCOMPRIVATE_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" JX_EXPORT jbyte JNICALL
XPCOMPRIVATE_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" JX_EXPORT jbyteArray JNICALL
XPCOMPRIVATE_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" JX_EXPORT jchar JNICALL
XPCOMPRIVATE_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" JX_EXPORT jcharArray JNICALL
XPCOMPRIVATE_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" JX_EXPORT jshort JNICALL
XPCOMPRIVATE_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" JX_EXPORT jshortArray JNICALL
XPCOMPRIVATE_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" JX_EXPORT jint JNICALL
XPCOMPRIVATE_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" JX_EXPORT jintArray JNICALL
XPCOMPRIVATE_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" JX_EXPORT jlong JNICALL
XPCOMPRIVATE_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" JX_EXPORT jlongArray JNICALL
XPCOMPRIVATE_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" JX_EXPORT jfloat JNICALL
XPCOMPRIVATE_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" JX_EXPORT jfloatArray JNICALL
XPCOMPRIVATE_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" JX_EXPORT jdouble JNICALL
XPCOMPRIVATE_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" JX_EXPORT jdoubleArray JNICALL
XPCOMPRIVATE_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" JX_EXPORT jobject JNICALL
XPCOMPRIVATE_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" JX_EXPORT jobjectArray JNICALL
XPCOMPRIVATE_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" JX_EXPORT void JNICALL
XPCOMPRIVATE_NATIVE(FinalizeStub) (JNIEnv *env, jclass that,
jobject aJavaObject)
{
#ifdef DEBUG_pedemonte
jclass clazz = env->GetObjectClass(aJavaObject);
jstring name = (jstring) env->CallObjectMethod(clazz, getNameMID);
const char* javaObjectName = env->GetStringUTFChars(name, nsnull);
LOG(("*** Finalize(java_obj=%s)\n", javaObjectName));
env->ReleaseStringUTFChars(name, javaObjectName);
#endif
// Due to Java's garbage collection, this finalize statement may get called
// after FreeJavaGlobals(). So check to make sure that everything is still
// initialized.
if (gJavaXPCOMInitialized) {
void* obj = gBindings->GetXPCOMObject(env, aJavaObject);
NS_ASSERTION(obj != nsnull, "No matching XPCOM obj in FinalizeStub");
if (obj) {
NS_ASSERTION(!IsXPTCStub(obj),
"Expecting JavaXPCOMInstance, got nsJavaXPTCStub");
gBindings->RemoveBinding(env, aJavaObject, nsnull);
delete (JavaXPCOMInstance*) obj;
}
}
}

View File

@ -45,6 +45,8 @@
#include "nsCRT.h"
#include "prmem.h"
#define JAVAPROXY_NATIVE(func) Java_org_mozilla_xpcom_XPCOMJavaProxy_##func
static nsID nullID = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
@ -328,13 +330,29 @@ SetupParams(JNIEnv *env, const jobject aParam, const nsXPTParamInfo &aParamInfo,
java_obj = (jobject) aParam;
} else { // 'inout'
if (aParam)
java_obj = (jobject) env->GetObjectArrayElement((jobjectArray) aParam, 0);
java_obj = (jobject)
env->GetObjectArrayElement((jobjectArray) aParam, 0);
}
void* xpcom_obj;
if (java_obj) {
// Check if we already have a corresponding XPCOM object
void* inst = gBindings->GetXPCOMObject(env, java_obj);
jboolean isProxy = env->CallStaticBooleanMethod(xpcomJavaProxyClass,
isXPCOMJavaProxyMID,
java_obj);
if (env->ExceptionCheck()) {
rv = NS_ERROR_FAILURE;
break;
}
void* inst;
if (isProxy) {
rv = GetXPCOMInstFromProxy(env, java_obj, &inst);
if (NS_FAILED(rv))
break;
} else {
inst = gBindings->GetXPCOMObject(env, java_obj);
}
// Get IID for this param
nsID iid;
@ -767,7 +785,7 @@ nsresult
SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
const nsXPTMethodInfo* aMethodInfo, nsIInterfaceInfo* aIInfo,
PRUint16 aMethodIndex, nsXPTCVariant* aDispatchParams,
nsXPTCVariant &aVariant, jvalue &aResult)
nsXPTCVariant &aVariant, jobject* result)
{
nsresult rv = NS_OK;
const nsXPTType &type = aParamInfo.GetType();
@ -776,54 +794,52 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
{
case nsXPTType::T_I8:
case nsXPTType::T_U8:
aResult.b = aVariant.val.u8;
*result = env->NewObject(byteClass, byteInitMID, aVariant.val.u8);
break;
case nsXPTType::T_I16:
case nsXPTType::T_U16:
aResult.s = aVariant.val.u16;
*result = env->NewObject(shortClass, shortInitMID, aVariant.val.u16);
break;
case nsXPTType::T_I32:
case nsXPTType::T_U32:
aResult.i = aVariant.val.u32;
*result = env->NewObject(intClass, intInitMID, aVariant.val.u32);
break;
case nsXPTType::T_I64:
case nsXPTType::T_U64:
aResult.j = aVariant.val.u64;
*result = env->NewObject(longClass, longInitMID, aVariant.val.u64);
break;
case nsXPTType::T_FLOAT:
aResult.f = aVariant.val.f;
*result = env->NewObject(floatClass, floatInitMID, aVariant.val.f);
break;
case nsXPTType::T_DOUBLE:
aResult.d = aVariant.val.d;
*result = env->NewObject(doubleClass, doubleInitMID, aVariant.val.d);
break;
case nsXPTType::T_BOOL:
aResult.z = aVariant.val.b;
*result = env->NewObject(booleanClass, booleanInitMID, aVariant.val.b);
break;
case nsXPTType::T_CHAR:
aResult.c = aVariant.val.c;
*result = env->NewObject(charClass, charInitMID, aVariant.val.c);
break;
case nsXPTType::T_WCHAR:
aResult.c = aVariant.val.wc;
*result = env->NewObject(charClass, charInitMID, aVariant.val.wc);
break;
case nsXPTType::T_CHAR_STR:
{
if (aVariant.ptr) {
aResult.l = env->NewStringUTF((const char*) aVariant.ptr);
if (aResult.l == nsnull) {
*result = env->NewStringUTF((const char*) aVariant.ptr);
if (*result == nsnull) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
} else {
aResult.l = nsnull;
}
}
break;
@ -832,13 +848,11 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
{
if (aVariant.ptr) {
PRUint32 length = nsCRT::strlen((const PRUnichar*) aVariant.ptr);
aResult.l = env->NewString((const jchar*) aVariant.ptr, length);
if (aResult.l == nsnull) {
*result = env->NewString((const jchar*) aVariant.ptr, length);
if (*result == nsnull) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
} else {
aResult.l = nsnull;
}
}
break;
@ -849,15 +863,13 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
nsID* iid = (nsID*) aVariant.ptr;
char* iid_str = iid->ToString();
if (iid_str) {
aResult.l = env->NewStringUTF(iid_str);
*result = env->NewStringUTF(iid_str);
}
if (iid_str == nsnull || aResult.l == nsnull) {
if (iid_str == nsnull || *result == nsnull) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
PR_Free(iid_str);
} else {
aResult.l = nsnull;
}
}
break;
@ -888,9 +900,7 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
NS_RELEASE(stub);
}
aResult.l = java_obj;
} else {
aResult.l = nsnull;
*result = java_obj;
}
}
break;
@ -900,13 +910,11 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
{
if (aVariant.ptr) {
nsString* str = (nsString*) aVariant.ptr;
aResult.l = env->NewString(str->get(), str->Length());
if (aResult.l == nsnull) {
*result = env->NewString(str->get(), str->Length());
if (*result == nsnull) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
} else {
aResult.l = nsnull;
}
}
break;
@ -916,13 +924,11 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
{
if (aVariant.ptr) {
nsCString* str = (nsCString*) aVariant.ptr;
aResult.l = env->NewStringUTF(str->get());
if (aResult.l == nsnull) {
*result = env->NewStringUTF(str->get());
if (*result == nsnull) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
} else {
aResult.l = nsnull;
}
}
break;
@ -930,7 +936,7 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
case nsXPTType::T_VOID:
// handle "void *" as an "int" in Java
LOG((" returns int (void*)"));
aResult.i = (jint) aVariant.val.p;
*result = env->NewObject(intClass, intInitMID, aVariant.val.p);
break;
case nsXPTType::T_ARRAY:
@ -945,31 +951,132 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
return rv;
}
void
CallXPCOMMethod(JNIEnv *env, jclass that, jobject aJavaObject,
jint aMethodIndex, jobjectArray aParams, jvalue &aResult)
/**
* Given an interface info struct and a method name, returns the method info
* and index, if that method exists.
*
* Most method names are lower case. Unfortunately, the method names of some
* interfaces (such as nsIAppShell) start with a capital letter. This function
* will try all of the permutations.
*/
nsresult
QueryMethodInfo(nsIInterfaceInfo* aIInfo, const char* aMethodName,
PRUint16* aMethodIndex, const nsXPTMethodInfo** aMethodInfo)
{
// Find corresponding XPCOM object
void* xpcomObj = gBindings->GetXPCOMObject(env, aJavaObject);
if (xpcomObj == nsnull) {
ThrowException(env, 0, "Failed to get matching XPCOM object");
return;
// The common case is that the method name is lower case, so we check
// that first.
nsresult rv;
rv = aIInfo->GetMethodInfoForName(aMethodName, aMethodIndex, aMethodInfo);
if (NS_SUCCEEDED(rv))
return rv;
// If there is no method called <aMethodName>, then maybe it is an
// 'attribute'. An 'attribute' will start with "get" or "set". But first,
// we check the length, in order to skip over method names that match exactly
// "get" or "set".
if (strlen(aMethodName) > 3) {
if (strncmp("get", aMethodName, 3) == 0) {
char* getterName = strdup(aMethodName + 3);
getterName[0] = tolower(getterName[0]);
rv = aIInfo->GetMethodInfoForName(getterName, aMethodIndex, aMethodInfo);
free(getterName);
} else if (strncmp("set", aMethodName, 3) == 0) {
char* setterName = strdup(aMethodName + 3);
setterName[0] = tolower(setterName[0]);
rv = aIInfo->GetMethodInfoForName(setterName, aMethodIndex, aMethodInfo);
if (NS_SUCCEEDED(rv)) {
// If this succeeded, GetMethodInfoForName will have returned the
// method info for the 'getter'. We want the 'setter', so increase
// method index by one ('setter' immediately follows the 'getter'),
// and get its method info.
(*aMethodIndex)++;
rv = aIInfo->GetMethodInfo(*aMethodIndex, aMethodInfo);
if (NS_SUCCEEDED(rv)) {
// Double check that this methodInfo matches the given method.
if (!(*aMethodInfo)->IsSetter() ||
strcmp(setterName, (*aMethodInfo)->name) != 0) {
rv = NS_ERROR_FAILURE;
}
}
}
free(setterName);
}
}
if (NS_SUCCEEDED(rv))
return rv;
// If we get here, then maybe the method name is capitalized.
char* methodName = strdup(aMethodName);
methodName[0] = toupper(methodName[0]);
rv = aIInfo->GetMethodInfoForName(methodName, aMethodIndex, aMethodInfo);
free(methodName);
if (NS_SUCCEEDED(rv))
return rv;
// If there is no method called <aMethodName>, then maybe it is an
// 'attribute'.
if (strlen(aMethodName) > 3) {
if (strncmp("get", aMethodName, 3) == 0) {
char* getterName = strdup(aMethodName + 3);
rv = aIInfo->GetMethodInfoForName(getterName, aMethodIndex, aMethodInfo);
free(getterName);
} else if (strncmp("set", aMethodName, 3) == 0) {
char* setterName = strdup(aMethodName + 3);
rv = aIInfo->GetMethodInfoForName(setterName, aMethodIndex, aMethodInfo);
if (NS_SUCCEEDED(rv)) {
// If this succeeded, GetMethodInfoForName will have returned the
// method info for the 'getter'. We want the 'setter', so increase
// method index by one ('setter' immediately follows the 'getter'),
// and get its method info.
(*aMethodIndex)++;
rv = aIInfo->GetMethodInfo(*aMethodIndex, aMethodInfo);
if (NS_SUCCEEDED(rv)) {
// Double check that this methodInfo matches the given method.
if (!(*aMethodInfo)->IsSetter() ||
strcmp(setterName, (*aMethodInfo)->name) != 0) {
rv = NS_ERROR_FAILURE;
}
}
}
free(setterName);
}
}
NS_ASSERTION(!IsXPTCStub(xpcomObj),
"Expected JavaXPCOMInstance, but got nsJavaXPTCStub");
JavaXPCOMInstance* inst = (JavaXPCOMInstance*) xpcomObj;
return rv;
}
/**
* org.mozilla.xpcom.XPCOMJavaProxy.callXPCOMMethod
*/
extern "C" JX_EXPORT jobject JNICALL
JAVAPROXY_NATIVE(callXPCOMMethod) (JNIEnv *env, jclass that, jobject aJavaProxy,
jstring aMethodName, jobjectArray aParams)
{
nsresult rv;
// Get native XPCOM instance
void* xpcom_obj;
rv = GetXPCOMInstFromProxy(env, aJavaProxy, &xpcom_obj);
if (NS_FAILED(rv)) {
ThrowException(env, 0, "Failed to get matching XPCOM object");
return nsnull;
}
JavaXPCOMInstance* inst = NS_STATIC_CAST(JavaXPCOMInstance*, xpcom_obj);
// Get method info
PRUint16 methodIndex;
const nsXPTMethodInfo* methodInfo;
nsIInterfaceInfo* iinfo = inst->InterfaceInfo();
nsresult rv = iinfo->GetMethodInfo(aMethodIndex, &methodInfo);
const char* methodName = env->GetStringUTFChars(aMethodName, nsnull);
rv = QueryMethodInfo(iinfo, methodName, &methodIndex, &methodInfo);
env->ReleaseStringUTFChars(aMethodName, methodName);
if (NS_FAILED(rv)) {
ThrowException(env, rv, "GetMethodInfo failed");
return;
ThrowException(env, rv, "GetMethodInfoForName failed");
return nsnull;
}
#ifdef DEBUG_pedemonte
#ifdef DEBUG_JAVAXPCOM
const char* ifaceName;
iinfo->GetNameShared(&ifaceName);
LOG(("=> Calling %s::%s()\n", ifaceName, methodInfo->GetName()));
@ -983,7 +1090,7 @@ CallXPCOMMethod(JNIEnv *env, jclass that, jobject aJavaObject,
params = new nsXPTCVariant[paramCount];
if (!params) {
ThrowException(env, NS_ERROR_OUT_OF_MEMORY, "Can't create params array");
return;
return nsnull;
}
for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++)
@ -993,7 +1100,7 @@ CallXPCOMMethod(JNIEnv *env, jclass that, jobject aJavaObject,
if (paramInfo.IsIn() && !paramInfo.IsDipper()) {
rv = SetupParams(env, env->GetObjectArrayElement(aParams, i), paramInfo,
methodInfo, iinfo, aMethodIndex, params, params[i]);
methodInfo, iinfo, methodIndex, params, params[i]);
} else if (paramInfo.IsDipper()) {
LOG(("dipper"));
const nsXPTType &type = paramInfo.GetType();
@ -1036,32 +1143,33 @@ CallXPCOMMethod(JNIEnv *env, jclass that, jobject aJavaObject,
}
if (NS_FAILED(rv)) {
ThrowException(env, rv, "SetupParams failed");
return;
return nsnull;
}
}
// Call the XPCOM method
nsresult invokeResult;
invokeResult = XPTC_InvokeByIndex(inst->GetInstance(), aMethodIndex,
invokeResult = XPTC_InvokeByIndex(inst->GetInstance(), methodIndex,
paramCount, params);
// Clean up params
jobject result = nsnull;
for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++)
{
const nsXPTParamInfo &paramInfo = methodInfo->GetParam(i);
if (!paramInfo.IsRetval()) {
rv = FinalizeParams(env, env->GetObjectArrayElement(aParams, i),
paramInfo, methodInfo, iinfo, aMethodIndex,
paramInfo, methodInfo, iinfo, methodIndex,
params, params[i]);
} else {
rv = SetRetval(env, paramInfo, methodInfo, iinfo, aMethodIndex, params,
params[i], aResult);
rv = SetRetval(env, paramInfo, methodInfo, iinfo, methodIndex, params,
params[i], &result);
}
}
if (NS_FAILED(rv)) {
ThrowException(env, rv, "FinalizeParams/SetRetval failed");
return;
return nsnull;
}
// Normally, we would delete any created nsID object in the above loop.
@ -1091,7 +1199,7 @@ CallXPCOMMethod(JNIEnv *env, jclass that, jobject aJavaObject,
ThrowException(env, invokeResult, message.get());
}
return;
return result;
}
nsresult
@ -1102,8 +1210,6 @@ CreateJavaProxy(JNIEnv* env, nsISupports* aXPCOMObject, const nsIID& aIID,
if (!aResult)
return NS_ERROR_NULL_POINTER;
jobject java_obj = nsnull;
nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
NS_ASSERTION(iim != nsnull, "Failed to get InterfaceInfoManager");
if (!iim)
@ -1125,19 +1231,19 @@ CreateJavaProxy(JNIEnv* env, nsISupports* aXPCOMObject, const nsIID& aIID,
rv = info->GetNameShared(&iface_name);
if (NS_SUCCEEDED(rv)) {
// Create proxy class name
nsCAutoString class_name("org/mozilla/xpcom/stubs/");
class_name.AppendASCII(iface_name);
class_name.AppendLiteral("_Stub");
jobject java_obj = nsnull;
// Create java proxy object
jclass clazz;
clazz = env->FindClass(class_name.get());
if (clazz) {
jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V");
if (constructor) {
java_obj = env->NewObject(clazz, constructor);
}
// Create proper Java interface name
nsCAutoString class_name("org/mozilla/xpcom/");
class_name.AppendASCII(iface_name);
jclass ifaceClass = env->FindClass(class_name.get());
if (ifaceClass) {
java_obj = env->CallStaticObjectMethod(xpcomJavaProxyClass,
createProxyMID, ifaceClass,
NS_REINTERPRET_CAST(jlong, inst));
if (env->ExceptionCheck())
java_obj = nsnull;
}
if (java_obj) {
@ -1157,3 +1263,53 @@ CreateJavaProxy(JNIEnv* env, nsISupports* aXPCOMObject, const nsIID& aIID,
return rv;
}
nsresult
GetXPCOMInstFromProxy(JNIEnv* env, jobject aJavaObject, void** aResult)
{
NS_PRECONDITION(aResult != nsnull, "null ptr");
if (!aResult)
return NS_ERROR_NULL_POINTER;
long xpcom_obj = env->CallStaticIntMethod(xpcomJavaProxyClass,
getNativeXPCOMInstMID, aJavaObject);
if (!xpcom_obj || env->ExceptionCheck()) {
return NS_ERROR_FAILURE;
}
*aResult = NS_REINTERPRET_CAST(void*, xpcom_obj);
return NS_OK;
}
/**
* org.mozilla.xpcom.XPCOMJavaProxy.finalizeProxy
*/
extern "C" JX_EXPORT void JNICALL
JAVAPROXY_NATIVE(finalizeProxy) (JNIEnv *env, jclass that, jobject aJavaProxy)
{
#ifdef DEBUG_JAVAXPCOM
jstring string = nsnull;
string = (jstring) env->CallStaticObjectMethod(xpcomJavaProxyClass,
proxyToStringMID, aJavaProxy);
const char* javaObjectName = env->GetStringUTFChars(string, nsnull);
LOG(("*** Finalize(java_obj=%s)\n", javaObjectName));
env->ReleaseStringUTFChars(string, javaObjectName);
#endif
// Due to Java's garbage collection, this finalize statement may get called
// after FreeJavaGlobals(). So check to make sure that everything is still
// initialized.
if (gJavaXPCOMLock) {
nsAutoLock lock(gJavaXPCOMLock);
// Get native XPCOM instance
void* xpcom_obj;
nsresult rv = GetXPCOMInstFromProxy(env, aJavaProxy, &xpcom_obj);
if (NS_SUCCEEDED(rv)) {
JavaXPCOMInstance* inst = NS_STATIC_CAST(JavaXPCOMInstance*, xpcom_obj);
gBindings->RemoveBinding(env, aJavaProxy, nsnull);
delete inst;
}
}
}

View File

@ -42,11 +42,31 @@
#include "nsISupports.h"
void CallXPCOMMethod(JNIEnv *env, jclass that, jobject aJavaObject,
jint aMethodIndex, jobjectArray aParams, jvalue &aResult);
// Creates a Java proxy for the given XPCOM object.
/**
* Creates a Java proxy around an XPCOM C++ object.
*
* @param env pointer to Java context
* @param aXPCOMObject XPCOM object to create proxy for
* @param aIID IID for XPCOM object
* @param aResult on exit, holds reference to Java proxy
*
* @return NS_OK if Java proxy was successfully created;
* any other value denotes an error condition.
*/
nsresult CreateJavaProxy(JNIEnv* env, nsISupports* aXPCOMObject,
const nsIID& aIID, jobject* aResult);
/**
* Returns the XPCOM object for which the given Java proxy was created.
*
* @param env pointer to Java context
* @param aJavaObject a Java proxy created by CreateJavaProxy()
* @param aResult on exit, holds pointer to XPCOM instance
*
* @return NS_OK if the XPCOM object was successfully retrieved;
* any other value denotes an error condition.
*/
nsresult GetXPCOMInstFromProxy(JNIEnv* env, jobject aJavaObject,
void** aResult);
#endif // _nsJavaWrapper_h_

View File

@ -47,26 +47,47 @@
/* Java JNI globals */
jclass booleanClass = nsnull;
jclass charClass = nsnull;
jclass byteClass = nsnull;
jclass shortClass = nsnull;
jclass intClass = nsnull;
jclass longClass = nsnull;
jclass floatClass = nsnull;
jclass doubleClass = nsnull;
jclass stringClass = nsnull;
jclass nsISupportsClass = nsnull;
jclass xpcomExceptionClass = nsnull;
jclass xpcomJavaProxyClass = nsnull;
jmethodID hashCodeMID = nsnull;
jmethodID booleanValueMID = nsnull;
jmethodID booleanInitMID = nsnull;
jmethodID charValueMID = nsnull;
jmethodID charInitMID = nsnull;
jmethodID byteValueMID = nsnull;
jmethodID byteInitMID = nsnull;
jmethodID shortValueMID = nsnull;
jmethodID shortInitMID = nsnull;
jmethodID intValueMID = nsnull;
jmethodID intInitMID = nsnull;
jmethodID longValueMID = nsnull;
jmethodID longInitMID = nsnull;
jmethodID floatValueMID = nsnull;
jmethodID floatInitMID = nsnull;
jmethodID doubleValueMID = nsnull;
jmethodID doubleInitMID = nsnull;
jmethodID createProxyMID = nsnull;
jmethodID isXPCOMJavaProxyMID = nsnull;
jmethodID getNativeXPCOMInstMID = nsnull;
#ifdef DEBUG
#ifdef DEBUG_JAVAXPCOM
jmethodID getNameMID = nsnull;
jmethodID proxyToStringMID = nsnull;
#endif
nsJavaXPCOMBindings* gBindings = nsnull;
PRBool gJavaXPCOMInitialized = PR_FALSE;
PRLock* gJavaXPCOMLock = nsnull;
/**************************************
@ -274,7 +295,7 @@ nsJavaXPCOMBindings::GetXPCOMObject(JNIEnv* env, jobject aJavaObject)
PL_DHASH_LOOKUP));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
#ifdef DEBUG_pedemonte
#ifdef DEBUG_JAVAXPCOM
void* xpcomObjKey = nsnull;
if (IsXPTCStub(entry->mXPCOMInstance))
xpcomObjKey = GetXPTCStubAddr(entry->mXPCOMInstance);
@ -331,7 +352,7 @@ nsJavaXPCOMBindings::GetJavaObject(JNIEnv* env, void* aXPCOMObject,
NS_RELEASE(xpcom_obj); // Owning ref passed on
}
#ifdef DEBUG_pedemonte
#ifdef DEBUG_JAVAXPCOM
if (*aResult) {
LOG(("< Get Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x)\n",
env->CallIntMethod(*aResult, hashCodeMID), (int) aXPCOMObject));
@ -348,96 +369,148 @@ nsJavaXPCOMBindings::GetJavaObject(JNIEnv* env, void* aXPCOMObject,
PRBool
InitializeJavaGlobals(JNIEnv *env)
{
if (gJavaXPCOMInitialized)
if (gJavaXPCOMLock)
return PR_TRUE;
jclass clazz;
if (!(clazz = env->FindClass("java/lang/Object")) ||
!(hashCodeMID = env->GetMethodID(clazz, "hashCode","()I")))
{
NS_WARNING("Problem creating java.lang.Object globals");
goto init_error;
}
if (!(clazz = env->FindClass("java/lang/Boolean")) ||
!(booleanValueMID = env->GetMethodID(clazz,"booleanValue","()Z")))
!(booleanClass = (jclass) env->NewGlobalRef(clazz)) ||
!(booleanValueMID = env->GetMethodID(clazz, "booleanValue", "()Z")) ||
!(booleanInitMID = env->GetMethodID(clazz, "<init>", "(Z)V")))
{
NS_WARNING("Problem creating java.lang.Boolean globals");
goto init_error;
}
if (!(clazz = env->FindClass("java/lang/Character")) ||
!(charValueMID = env->GetMethodID(clazz,"charValue","()C")))
!(charClass = (jclass) env->NewGlobalRef(clazz)) ||
!(charValueMID = env->GetMethodID(clazz, "charValue", "()C")) ||
!(charInitMID = env->GetMethodID(clazz, "<init>", "(C)V")))
{
NS_WARNING("Problem creating java.lang.Character globals");
goto init_error;
}
if (!(clazz = env->FindClass("java/lang/Byte")) ||
!(byteValueMID = env->GetMethodID(clazz,"byteValue","()B")))
!(byteClass = (jclass) env->NewGlobalRef(clazz)) ||
!(byteValueMID = env->GetMethodID(clazz, "byteValue", "()B")) ||
!(byteInitMID = env->GetMethodID(clazz, "<init>", "(B)V")))
{
NS_WARNING("Problem creating java.lang.Byte globals");
goto init_error;
}
if (!(clazz = env->FindClass("java/lang/Short")) ||
!(shortValueMID = env->GetMethodID(clazz,"shortValue","()S")))
!(shortClass = (jclass) env->NewGlobalRef(clazz)) ||
!(shortValueMID = env->GetMethodID(clazz, "shortValue", "()S")) ||
!(shortInitMID = env->GetMethodID(clazz, "<init>", "(S)V")))
{
NS_WARNING("Problem creating java.lang.Short globals");
goto init_error;
}
if (!(clazz = env->FindClass("java/lang/Integer")) ||
!(intValueMID = env->GetMethodID(clazz,"intValue","()I")))
!(intClass = (jclass) env->NewGlobalRef(clazz)) ||
!(intValueMID = env->GetMethodID(clazz, "intValue", "()I")) ||
!(intInitMID = env->GetMethodID(clazz, "<init>", "(I)V")))
{
NS_WARNING("Problem creating java.lang.Integer globals");
goto init_error;
}
if (!(clazz = env->FindClass("java/lang/Long")) ||
!(longValueMID = env->GetMethodID(clazz,"longValue","()J")))
!(longClass = (jclass) env->NewGlobalRef(clazz)) ||
!(longValueMID = env->GetMethodID(clazz, "longValue", "()J")) ||
!(longInitMID = env->GetMethodID(clazz, "<init>", "(J)V")))
{
NS_WARNING("Problem creating java.lang.Long globals");
goto init_error;
}
if (!(clazz = env->FindClass("java/lang/Float")) ||
!(floatValueMID = env->GetMethodID(clazz,"floatValue","()F")))
!(floatClass = (jclass) env->NewGlobalRef(clazz)) ||
!(floatValueMID = env->GetMethodID(clazz, "floatValue", "()F")) ||
!(floatInitMID = env->GetMethodID(clazz, "<init>", "(F)V")))
{
NS_WARNING("Problem creating java.lang.Float globals");
goto init_error;
}
if (!(clazz = env->FindClass("java/lang/Double")) ||
!(doubleValueMID = env->GetMethodID(clazz,"doubleValue","()D")))
!(doubleClass = (jclass) env->NewGlobalRef(clazz)) ||
!(doubleValueMID = env->GetMethodID(clazz, "doubleValue", "()D")) ||
!(doubleInitMID = env->GetMethodID(clazz, "<init>", "(D)V")))
{
NS_WARNING("Problem creating java.lang.Double globals");
goto init_error;
}
if (!(clazz = env->FindClass("java/lang/String")) ||
!(stringClass = (jclass) env->NewGlobalRef(clazz)))
{
NS_WARNING("Problem creating java.lang.String globals");
goto init_error;
}
if (!(clazz = env->FindClass("org/mozilla/xpcom/nsISupports")) ||
!(nsISupportsClass = (jclass) env->NewGlobalRef(clazz)))
{
NS_WARNING("Problem creating org.mozilla.xpcom.nsISupports globals");
goto init_error;
}
if (!(clazz = env->FindClass("org/mozilla/xpcom/XPCOMException")) ||
!(xpcomExceptionClass = (jclass) env->NewGlobalRef(clazz)))
{
NS_WARNING("Problem creating org.mozilla.xpcom.XPCOMException globals");
goto init_error;
}
#ifdef DEBUG
if (!(clazz = env->FindClass("org/mozilla/xpcom/XPCOMJavaProxy")) ||
!(xpcomJavaProxyClass = (jclass) env->NewGlobalRef(clazz)) ||
!(createProxyMID = env->GetStaticMethodID(clazz, "createProxy",
"(Ljava/lang/Class;J)Ljava/lang/Object;")) ||
!(isXPCOMJavaProxyMID = env->GetStaticMethodID(clazz, "isXPCOMJavaProxy",
"(Ljava/lang/Object;)Z")) ||
!(getNativeXPCOMInstMID = env->GetStaticMethodID(xpcomJavaProxyClass,
"getNativeXPCOMInstance",
"(Ljava/lang/Object;)J")))
{
NS_WARNING("Problem creating org.mozilla.xpcom.XPCOMJavaProxy globals");
goto init_error;
}
#ifdef DEBUG_JAVAXPCOM
if (!(clazz = env->FindClass("java/lang/Class")) ||
!(getNameMID = env->GetMethodID(clazz, "getName","()Ljava/lang/String;")))
{
NS_WARNING("Problem creating java.lang.Class globals");
goto init_error;
}
if (!(proxyToStringMID = env->GetStaticMethodID(xpcomJavaProxyClass,
"proxyToString",
"(Ljava/lang/Object;)Ljava/lang/String;")))
{
NS_WARNING("Problem creating proxyToString global");
goto init_error;
}
#endif
gBindings = new nsJavaXPCOMBindings();
if (NS_FAILED(gBindings->Init())) {
NS_WARNING("Problem creating JavaXPCOMBindings");
goto init_error;
}
gJavaXPCOMInitialized = PR_TRUE;
gJavaXPCOMLock = PR_NewLock();
return PR_TRUE;
init_error:
@ -453,6 +526,40 @@ init_error:
void
FreeJavaGlobals(JNIEnv* env)
{
PR_Lock(gJavaXPCOMLock);
if (booleanClass) {
env->DeleteGlobalRef(booleanClass);
booleanClass = nsnull;
}
if (charClass) {
env->DeleteGlobalRef(charClass);
charClass = nsnull;
}
if (byteClass) {
env->DeleteGlobalRef(byteClass);
byteClass = nsnull;
}
if (shortClass) {
env->DeleteGlobalRef(shortClass);
shortClass = nsnull;
}
if (intClass) {
env->DeleteGlobalRef(intClass);
intClass = nsnull;
}
if (longClass) {
env->DeleteGlobalRef(longClass);
longClass = nsnull;
}
if (floatClass) {
env->DeleteGlobalRef(floatClass);
floatClass = nsnull;
}
if (doubleClass) {
env->DeleteGlobalRef(doubleClass);
doubleClass = nsnull;
}
if (stringClass) {
env->DeleteGlobalRef(stringClass);
stringClass = nsnull;
@ -465,13 +572,19 @@ FreeJavaGlobals(JNIEnv* env)
env->DeleteGlobalRef(xpcomExceptionClass);
xpcomExceptionClass = nsnull;
}
if (xpcomJavaProxyClass) {
env->DeleteGlobalRef(xpcomJavaProxyClass);
xpcomJavaProxyClass = nsnull;
}
if (gBindings) {
delete gBindings;
gBindings = nsnull;
}
gJavaXPCOMInitialized = PR_FALSE;
PR_Unlock(gJavaXPCOMLock);
PR_DestroyLock(gJavaXPCOMLock);
gJavaXPCOMLock = nsnull;
}
@ -484,14 +597,18 @@ JavaXPCOMInstance::JavaXPCOMInstance(nsISupports* aInstance,
mIInfo(aIInfo)
{
NS_ADDREF(mInstance);
NS_ADDREF(mIInfo);
}
JavaXPCOMInstance::~JavaXPCOMInstance()
{
// Need to release these objects on the main thread.
nsCOMPtr<nsIEventQueue> eventQ;
nsresult rv = NS_GetMainEventQ(getter_AddRefs(eventQ));
if (NS_SUCCEEDED(rv))
if (NS_SUCCEEDED(rv)) {
rv = NS_ProxyRelease(eventQ, mInstance);
rv += NS_ProxyRelease(eventQ, mIInfo);
}
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to release using NS_ProxyRelease");
}

View File

@ -43,8 +43,10 @@
#include "nsCOMPtr.h"
#include "nsString.h"
#include "pldhash.h"
#include "nsAutoLock.h"
#ifdef DEBUG_pedemonte
//#define DEBUG_JAVAXPCOM
#ifdef DEBUG_JAVAXPCOM
#define LOG(x) printf x
#else
#define LOG(x) /* nothing */
@ -60,28 +62,49 @@
/*********************
* Java JNI globals
*********************/
extern jclass booleanClass;
extern jclass charClass;
extern jclass byteClass;
extern jclass shortClass;
extern jclass intClass;
extern jclass longClass;
extern jclass floatClass;
extern jclass doubleClass;
extern jclass stringClass;
extern jclass nsISupportsClass;
extern jclass xpcomExceptionClass;
extern jclass xpcomJavaProxyClass;
extern jmethodID hashCodeMID;
extern jmethodID booleanValueMID;
extern jmethodID booleanInitMID;
extern jmethodID charValueMID;
extern jmethodID charInitMID;
extern jmethodID byteValueMID;
extern jmethodID byteInitMID;
extern jmethodID shortValueMID;
extern jmethodID shortInitMID;
extern jmethodID intValueMID;
extern jmethodID intInitMID;
extern jmethodID longValueMID;
extern jmethodID longInitMID;
extern jmethodID floatValueMID;
extern jmethodID floatInitMID;
extern jmethodID doubleValueMID;
extern jmethodID doubleInitMID;
extern jmethodID createProxyMID;
extern jmethodID isXPCOMJavaProxyMID;
extern jmethodID getNativeXPCOMInstMID;
#ifdef DEBUG
#ifdef DEBUG_JAVAXPCOM
extern jmethodID getNameMID;
extern jmethodID proxyToStringMID;
#endif
class nsJavaXPCOMBindings;
extern nsJavaXPCOMBindings* gBindings;
extern PRBool gJavaXPCOMInitialized;
extern PRLock* gJavaXPCOMLock;
PRBool InitializeJavaGlobals(JNIEnv *env);
void FreeJavaGlobals(JNIEnv* env);
@ -100,8 +123,8 @@ public:
nsIInterfaceInfo* InterfaceInfo() { return mIInfo; }
private:
nsISupports* mInstance;
nsCOMPtr<nsIInterfaceInfo> mIInfo;
nsISupports* mInstance;
nsIInterfaceInfo* mIInfo;
};

View File

@ -53,13 +53,14 @@ nsJavaXPTCStub::nsJavaXPTCStub(JNIEnv* aJavaEnv, jobject aJavaObject,
{
mJavaObject = aJavaEnv->NewGlobalRef(aJavaObject);
#ifdef DEBUG_pedemonte
#ifdef DEBUG_JAVAXPCOM
jstring name;
const char* javaObjectName = nsnull;
jclass clazz = mJavaEnv->GetObjectClass(mJavaObject);
if (clazz) {
name = (jstring) mJavaEnv->CallObjectMethod(clazz, getNameMID);
javaObjectName = mJavaEnv->GetStringUTFChars(name, nsnull);
if (name)
javaObjectName = mJavaEnv->GetStringUTFChars(name, nsnull);
}
nsID* iid = nsnull;
@ -75,7 +76,8 @@ nsJavaXPTCStub::nsJavaXPTCStub(JNIEnv* aJavaEnv, jobject aJavaObject,
LOG(("+++ nsJavaXPTCStub(this=0x%08x java_obj=0x%08x %s iid=%s)\n", (int) this,
mJavaEnv->CallIntMethod(mJavaObject, hashCodeMID),
javaObjectName ? javaObjectName : "<-->", iid_str ? iid_str : "NULL"));
mJavaEnv->ReleaseStringUTFChars(name, javaObjectName);
if (name)
mJavaEnv->ReleaseStringUTFChars(name, javaObjectName);
if (iid_str)
nsMemory::Free(iid_str);
#endif
@ -83,19 +85,21 @@ nsJavaXPTCStub::nsJavaXPTCStub(JNIEnv* aJavaEnv, jobject aJavaObject,
nsJavaXPTCStub::~nsJavaXPTCStub()
{
#ifdef DEBUG_pedemonte
#ifdef DEBUG_JAVAXPCOM
jstring name;
const char* javaObjectName = nsnull;
jclass clazz = mJavaEnv->GetObjectClass(mJavaObject);
if (clazz) {
name = (jstring) mJavaEnv->CallObjectMethod(clazz, getNameMID);
javaObjectName = mJavaEnv->GetStringUTFChars(name, nsnull);
if (name)
javaObjectName = mJavaEnv->GetStringUTFChars(name, nsnull);
}
LOG(("--- ~nsJavaXPTCStub(this=0x%08x java_obj=0x%08x %s)\n", (int) this,
mJavaEnv->CallIntMethod(mJavaObject, hashCodeMID),
javaObjectName ? javaObjectName : "<-->"));
mJavaEnv->ReleaseStringUTFChars(name, javaObjectName);
if (name)
mJavaEnv->ReleaseStringUTFChars(name, javaObjectName);
#endif
if (!mMaster) {
@ -309,7 +313,7 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex,
const nsXPTMethodInfo *aMethodInfo,
nsXPTCMiniVariant *aParams)
{
#ifdef DEBUG_pedemonte
#ifdef DEBUG_JAVAXPCOM
const char* ifaceName;
mIInfo->GetNameShared(&ifaceName);
LOG(("nsJavaXPTCStub::CallMethod [%s::%s]\n", ifaceName, aMethodInfo->GetName()));
@ -1346,7 +1350,23 @@ nsJavaXPTCStub::FinalizeJavaParams(const nsXPTParamInfo &aParamInfo,
nsISupports** variant = NS_STATIC_CAST(nsISupports**, aVariant.val.p);
if (java_obj) {
// Check if we already have a corresponding XPCOM object
void* inst = gBindings->GetXPCOMObject(mJavaEnv, java_obj);
jboolean isProxy;
isProxy = mJavaEnv->CallStaticBooleanMethod(xpcomJavaProxyClass,
isXPCOMJavaProxyMID,
java_obj);
if (mJavaEnv->ExceptionCheck()) {
rv = NS_ERROR_FAILURE;
break;
}
void* inst;
if (isProxy) {
rv = GetXPCOMInstFromProxy(mJavaEnv, java_obj, &inst);
if (NS_FAILED(rv))
break;
} else {
inst = gBindings->GetXPCOMObject(mJavaEnv, java_obj);
}
// Get IID for this param
nsID iid;

View File

@ -61,7 +61,6 @@ CSRCS = \
xpidl_typelib.c \
xpidl_doc.c \
xpidl_java.c \
xpidl_javastub.c \
$(NULL)
SDK_BINARY = \

View File

@ -46,7 +46,6 @@ static ModeData modes[] = {
{"typelib", "Generate XPConnect typelib", "xpt", xpidl_typelib_dispatch},
{"doc", "Generate HTML documentation", "html", xpidl_doc_dispatch},
{"java", "Generate Java interface", "java", xpidl_java_dispatch},
{"javastub","Generate Java Stub", "java", xpidl_javastub_dispatch},
{0, 0, 0, 0}
};

View File

@ -112,7 +112,6 @@ extern backend *xpidl_header_dispatch(void);
extern backend *xpidl_typelib_dispatch(void);
extern backend *xpidl_doc_dispatch(void);
extern backend *xpidl_java_dispatch(void);
extern backend *xpidl_javastub_dispatch(void);
typedef struct ModeData {
char *mode;

View File

@ -760,8 +760,7 @@ xpidl_process_idl(char *filename, IncludePathEntry *include_path,
}
/* don't create/open file here for Java */
if (strcmp(mode->mode, "java") == 0 ||
strcmp(mode->mode, "javastub") == 0)
if (strcmp(mode->mode, "java") == 0)
{
state.filename = real_outname;
} else {
@ -785,8 +784,7 @@ xpidl_process_idl(char *filename, IncludePathEntry *include_path,
if (emitter->emit_epilog)
emitter->emit_epilog(&state);
if (strcmp(mode->mode, "java") != 0 &&
strcmp(mode->mode, "javastub") != 0)
if (strcmp(mode->mode, "java") != 0)
{
if (state.file != stdout)
fclose(state.file);