Bug 281102 - Allow many Java proxies per XPCOM object. r=darin
git-svn-id: svn://10.0.0.236/trunk@169791 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -334,26 +334,8 @@ SetupParams(JNIEnv *env, const jobject aParam, const nsXPTParamInfo &aParamInfo,
|
||||
env->GetObjectArrayElement((jobjectArray) aParam, 0);
|
||||
}
|
||||
|
||||
void* xpcom_obj;
|
||||
nsISupports* xpcom_obj;
|
||||
if (java_obj) {
|
||||
// Check if we already have a corresponding XPCOM object
|
||||
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;
|
||||
rv = GetIIDForMethodParam(aIInfo, aMethodInfo, aParamInfo,
|
||||
@@ -362,53 +344,57 @@ SetupParams(JNIEnv *env, const jobject aParam, const nsXPTParamInfo &aParamInfo,
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
PRBool isWeakRef = iid.Equals(NS_GET_IID(nsIWeakReference));
|
||||
|
||||
if (inst == nsnull && !isWeakRef) {
|
||||
// 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<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
|
||||
nsCOMPtr<nsIInterfaceInfo> iinfo;
|
||||
rv = iim->GetInfoForIID(&iid, getter_AddRefs(iinfo));
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
// Create XPCOM stub
|
||||
nsJavaXPTCStub* xpcomStub = new nsJavaXPTCStub(env, java_obj, iinfo);
|
||||
if (!xpcomStub) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
inst = SetAsXPTCStub(xpcomStub);
|
||||
gBindings->AddBinding(env, java_obj, inst);
|
||||
// If the requested interface is nsIWeakReference, then we look for or
|
||||
// create a stub for the nsISupports interface. Then we create a weak
|
||||
// reference from that stub.
|
||||
PRBool isWeakRef;
|
||||
if (iid.Equals(NS_GET_IID(nsIWeakReference))) {
|
||||
isWeakRef = PR_TRUE;
|
||||
iid = NS_GET_IID(nsISupports);
|
||||
} else {
|
||||
isWeakRef = PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool isXPTCStub;
|
||||
rv = GetNewOrUsedXPCOMObject(env, java_obj, iid, &xpcom_obj,
|
||||
&isXPTCStub);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
// If the function expects a weak reference, then we need to
|
||||
// create it here.
|
||||
if (isWeakRef) {
|
||||
// If the function expects an weak reference, then we need to
|
||||
// create it here.
|
||||
nsJavaXPTCStubWeakRef* weakref =
|
||||
new nsJavaXPTCStubWeakRef(env, java_obj);
|
||||
if (!weakref) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
if (isXPTCStub) {
|
||||
nsJavaXPTCStub* stub = NS_STATIC_CAST(nsJavaXPTCStub*,
|
||||
NS_STATIC_CAST(nsXPTCStubBase*,
|
||||
xpcom_obj));
|
||||
nsJavaXPTCStubWeakRef* weakref;
|
||||
weakref = new nsJavaXPTCStubWeakRef(env, java_obj, stub);
|
||||
if (!weakref) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
xpcom_obj = weakref;
|
||||
NS_ADDREF(xpcom_obj);
|
||||
aVariant.SetValIsAllocated();
|
||||
} else { // if is native XPCOM object
|
||||
nsCOMPtr<nsISupportsWeakReference> supportsweak =
|
||||
do_QueryInterface(xpcom_obj);
|
||||
if (supportsweak) {
|
||||
nsWeakPtr weakref;
|
||||
supportsweak->GetWeakReference(getter_AddRefs(weakref));
|
||||
xpcom_obj = weakref;
|
||||
NS_ADDREF(xpcom_obj);
|
||||
} else {
|
||||
xpcom_obj = nsnull;
|
||||
}
|
||||
}
|
||||
NS_ADDREF(weakref);
|
||||
xpcom_obj = (void*) weakref;
|
||||
|
||||
} else if (isXPTCStub) {
|
||||
aVariant.SetValIsAllocated();
|
||||
|
||||
} else if (IsXPTCStub(inst)) {
|
||||
nsJavaXPTCStub* xpcomStub = GetXPTCStubAddr(inst);
|
||||
NS_ADDREF(xpcomStub);
|
||||
xpcom_obj = (void*) xpcomStub;
|
||||
aVariant.SetValIsAllocated();
|
||||
|
||||
} else {
|
||||
JavaXPCOMInstance* xpcomInst = (JavaXPCOMInstance*) inst;
|
||||
xpcom_obj = (void*) xpcomInst->GetInstance();
|
||||
} else { // if is native XPCOM object
|
||||
xpcom_obj->Release();
|
||||
}
|
||||
} else {
|
||||
xpcom_obj = nsnull;
|
||||
@@ -682,7 +668,7 @@ FinalizeParams(JNIEnv *env, const jobject aParam,
|
||||
case nsXPTType::T_INTERFACE:
|
||||
case nsXPTType::T_INTERFACE_IS:
|
||||
{
|
||||
void* xpcom_obj = aVariant.val.p;
|
||||
nsISupports* xpcom_obj = NS_STATIC_CAST(nsISupports*, aVariant.val.p);
|
||||
|
||||
if (aParamInfo.IsOut() && aParam) { // 'inout' & 'out'
|
||||
jobject java_obj = nsnull;
|
||||
@@ -694,9 +680,13 @@ FinalizeParams(JNIEnv *env, const jobject aParam,
|
||||
break;
|
||||
|
||||
// Get matching Java object for given xpcom object
|
||||
rv = gBindings->GetJavaObject(env, xpcom_obj, iid, PR_TRUE, &java_obj);
|
||||
PRBool isNewProxy;
|
||||
rv = GetNewOrUsedJavaObject(env, xpcom_obj, iid, &java_obj,
|
||||
&isNewProxy);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
if (isNewProxy)
|
||||
NS_RELEASE(xpcom_obj); // Java proxy owns ref to object
|
||||
}
|
||||
|
||||
// put new Java object into output array
|
||||
@@ -706,8 +696,7 @@ FinalizeParams(JNIEnv *env, const jobject aParam,
|
||||
// If VAL_IS_ALLOCD is set, that means that an XPCOM object was created
|
||||
// is SetupParams that now needs to be released.
|
||||
if (xpcom_obj && aVariant.IsValAllocated()) {
|
||||
nsISupports* variant = NS_STATIC_CAST(nsISupports*, xpcom_obj);
|
||||
NS_RELEASE(variant);
|
||||
NS_RELEASE(xpcom_obj);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -877,7 +866,8 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
|
||||
case nsXPTType::T_INTERFACE:
|
||||
case nsXPTType::T_INTERFACE_IS:
|
||||
{
|
||||
if (aVariant.val.p) {
|
||||
nsISupports* xpcom_obj = NS_STATIC_CAST(nsISupports*, aVariant.val.p);
|
||||
if (xpcom_obj) {
|
||||
nsID iid;
|
||||
rv = GetIIDForMethodParam(aIInfo, aMethodInfo, aParamInfo, aMethodIndex,
|
||||
aDispatchParams, PR_TRUE, iid);
|
||||
@@ -886,13 +876,15 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo,
|
||||
|
||||
// Get matching Java object for given xpcom object
|
||||
jobject java_obj;
|
||||
rv = gBindings->GetJavaObject(env, aVariant.val.p, iid, PR_TRUE,
|
||||
&java_obj);
|
||||
PRBool isNewProxy;
|
||||
rv = GetNewOrUsedJavaObject(env, xpcom_obj, iid, &java_obj,
|
||||
&isNewProxy);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
if (isNewProxy)
|
||||
xpcom_obj->Release(); // Java proxy owns ref to object
|
||||
|
||||
// If returned object is an nsJavaXPTCStub, release it.
|
||||
nsISupports* xpcom_obj = NS_STATIC_CAST(nsISupports*, aVariant.val.p);
|
||||
nsJavaXPTCStub* stub = nsnull;
|
||||
xpcom_obj->QueryInterface(NS_GET_IID(nsJavaXPTCStub), (void**) &stub);
|
||||
if (stub) {
|
||||
@@ -1079,7 +1071,7 @@ JAVAPROXY_NATIVE(callXPCOMMethod) (JNIEnv *env, jclass that, jobject aJavaProxy,
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
const char* ifaceName;
|
||||
iinfo->GetNameShared(&ifaceName);
|
||||
LOG(("=> Calling %s::%s()\n", ifaceName, methodInfo->GetName()));
|
||||
LOG(("===> (XPCOM) %s::%s()\n", ifaceName, methodInfo->GetName()));
|
||||
#endif
|
||||
|
||||
// Convert the Java params
|
||||
@@ -1199,6 +1191,7 @@ JAVAPROXY_NATIVE(callXPCOMMethod) (JNIEnv *env, jclass that, jobject aJavaProxy,
|
||||
ThrowException(env, invokeResult, message.get());
|
||||
}
|
||||
|
||||
LOG(("<=== (XPCOM) %s::%s()\n", ifaceName, methodInfo->GetName()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1247,8 +1240,16 @@ CreateJavaProxy(JNIEnv* env, nsISupports* aXPCOMObject, const nsIID& aIID,
|
||||
}
|
||||
|
||||
if (java_obj) {
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
char* iid_str = aIID.ToString();
|
||||
LOG(("+ CreateJavaProxy (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
env->CallIntMethod(java_obj, hashCodeMID),
|
||||
(int) aXPCOMObject, iid_str));
|
||||
PR_Free(iid_str);
|
||||
#endif
|
||||
|
||||
// Associate XPCOM object with Java proxy
|
||||
rv = gBindings->AddBinding(env, java_obj, inst);
|
||||
rv = gNativeToJavaProxyMap->Add(env, aXPCOMObject, aIID, java_obj);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
*aResult = java_obj;
|
||||
return NS_OK;
|
||||
@@ -1278,6 +1279,17 @@ GetXPCOMInstFromProxy(JNIEnv* env, jobject aJavaObject, void** aResult)
|
||||
}
|
||||
|
||||
*aResult = NS_REINTERPRET_CAST(void*, xpcom_obj);
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
JavaXPCOMInstance* inst = NS_STATIC_CAST(JavaXPCOMInstance*, *aResult);
|
||||
nsIID* iid;
|
||||
inst->InterfaceInfo()->GetInterfaceIID(&iid);
|
||||
char* iid_str = iid->ToString();
|
||||
LOG(("< GetXPCOMInstFromProxy (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
env->CallIntMethod(aJavaObject, hashCodeMID),
|
||||
(int) inst->GetInstance(), iid_str));
|
||||
PR_Free(iid_str);
|
||||
nsMemory::Free(iid);
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -1287,15 +1299,6 @@ GetXPCOMInstFromProxy(JNIEnv* env, jobject aJavaObject, void** aResult)
|
||||
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.
|
||||
@@ -1307,7 +1310,20 @@ JAVAPROXY_NATIVE(finalizeProxy) (JNIEnv *env, jclass that, jobject aJavaProxy)
|
||||
nsresult rv = GetXPCOMInstFromProxy(env, aJavaProxy, &xpcom_obj);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
JavaXPCOMInstance* inst = NS_STATIC_CAST(JavaXPCOMInstance*, xpcom_obj);
|
||||
gBindings->RemoveBinding(env, aJavaProxy, nsnull);
|
||||
nsIID* iid;
|
||||
rv = inst->InterfaceInfo()->GetInterfaceIID(&iid);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = gNativeToJavaProxyMap->Remove(env, inst->GetInstance(), *iid);
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
char* iid_str = iid->ToString();
|
||||
LOG(("- Finalize (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
env->CallIntMethod(aJavaProxy, hashCodeMID),
|
||||
(int) inst->GetInstance(), iid_str));
|
||||
PR_Free(iid_str);
|
||||
#endif
|
||||
nsMemory::Free(iid);
|
||||
}
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to RemoveJavaProxy");
|
||||
delete inst;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,283 +86,12 @@ jmethodID getNameMID = nsnull;
|
||||
jmethodID proxyToStringMID = nsnull;
|
||||
#endif
|
||||
|
||||
nsJavaXPCOMBindings* gBindings = nsnull;
|
||||
NativeToJavaProxyMap* gNativeToJavaProxyMap = nsnull;
|
||||
JavaToXPTCStubMap* gJavaToXPTCStubMap = nsnull;
|
||||
|
||||
PRLock* gJavaXPCOMLock = nsnull;
|
||||
|
||||
|
||||
/**************************************
|
||||
* Java<->XPCOM binding stores
|
||||
**************************************/
|
||||
class JavaXPCOMBindingEntry : public PLDHashEntryHdr
|
||||
{
|
||||
public:
|
||||
// mKey will either be a Java hash of the Java object, or the address of
|
||||
// the XPCOM object, depending on which hash table this entry is used in.
|
||||
const void* mKey;
|
||||
jobject mJavaObject;
|
||||
void* mXPCOMInstance;
|
||||
};
|
||||
|
||||
PR_STATIC_CALLBACK(PRBool)
|
||||
InitJavaXPCOMBindingEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
|
||||
const void *key)
|
||||
{
|
||||
JavaXPCOMBindingEntry *e =
|
||||
NS_CONST_CAST(JavaXPCOMBindingEntry *,
|
||||
NS_STATIC_CAST(const JavaXPCOMBindingEntry *, entry));
|
||||
|
||||
e->mKey = key;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJavaXPCOMBindings::Init()
|
||||
{
|
||||
static PLDHashTableOps java_to_xpcom_hash_ops =
|
||||
{
|
||||
PL_DHashAllocTable,
|
||||
PL_DHashFreeTable,
|
||||
PL_DHashGetKeyStub,
|
||||
PL_DHashVoidPtrKeyStub,
|
||||
PL_DHashMatchEntryStub,
|
||||
PL_DHashMoveEntryStub,
|
||||
PL_DHashClearEntryStub,
|
||||
PL_DHashFinalizeStub,
|
||||
InitJavaXPCOMBindingEntry
|
||||
};
|
||||
|
||||
mJAVAtoXPCOMBindings = PL_NewDHashTable(&java_to_xpcom_hash_ops, nsnull,
|
||||
sizeof(JavaXPCOMBindingEntry), 16);
|
||||
if (!mJAVAtoXPCOMBindings)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
static PLDHashTableOps xpcom_to_java_hash_ops =
|
||||
{
|
||||
PL_DHashAllocTable,
|
||||
PL_DHashFreeTable,
|
||||
PL_DHashGetKeyStub,
|
||||
PL_DHashVoidPtrKeyStub,
|
||||
PL_DHashMatchEntryStub,
|
||||
PL_DHashMoveEntryStub,
|
||||
PL_DHashClearEntryStub,
|
||||
PL_DHashFinalizeStub,
|
||||
InitJavaXPCOMBindingEntry
|
||||
};
|
||||
|
||||
mXPCOMtoJAVABindings = PL_NewDHashTable(&xpcom_to_java_hash_ops, nsnull,
|
||||
sizeof(JavaXPCOMBindingEntry), 16);
|
||||
if (!mXPCOMtoJAVABindings)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsJavaXPCOMBindings::~nsJavaXPCOMBindings()
|
||||
{
|
||||
if (mJAVAtoXPCOMBindings)
|
||||
PL_DHashTableDestroy(mJAVAtoXPCOMBindings);
|
||||
if (mXPCOMtoJAVABindings)
|
||||
PL_DHashTableDestroy(mXPCOMtoJAVABindings);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJavaXPCOMBindings::AddBinding(JNIEnv* env, jobject aJavaObject,
|
||||
void* aXPCOMObject)
|
||||
{
|
||||
// We use a Java hash of the Java object as a key since the JVM can return
|
||||
// different "addresses" for the same Java object, but the hash code (the
|
||||
// result of calling |hashCode()| on the Java object) will always be the same.
|
||||
jint hash = env->CallIntMethod(aJavaObject, hashCodeMID);
|
||||
jweak java_ref = env->NewWeakGlobalRef(aJavaObject);
|
||||
if (!java_ref)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Add a new entry into hash
|
||||
JavaXPCOMBindingEntry *entry =
|
||||
NS_STATIC_CAST(JavaXPCOMBindingEntry*,
|
||||
PL_DHashTableOperate(mJAVAtoXPCOMBindings,
|
||||
NS_INT32_TO_PTR(hash),
|
||||
PL_DHASH_ADD));
|
||||
if (!entry)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Set entry fields
|
||||
entry->mJavaObject = java_ref;
|
||||
entry->mXPCOMInstance = aXPCOMObject;
|
||||
|
||||
// We want the hash key to be the actual XPCOM object
|
||||
void* xpcomObjKey = nsnull;
|
||||
if (IsXPTCStub(aXPCOMObject))
|
||||
xpcomObjKey = GetXPTCStubAddr(aXPCOMObject);
|
||||
else
|
||||
xpcomObjKey = ((JavaXPCOMInstance*) aXPCOMObject)->GetInstance();
|
||||
|
||||
// Add a new entry into other hash table
|
||||
entry =
|
||||
NS_STATIC_CAST(JavaXPCOMBindingEntry*,
|
||||
PL_DHashTableOperate(mXPCOMtoJAVABindings, xpcomObjKey,
|
||||
PL_DHASH_ADD));
|
||||
if (!entry)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
entry->mJavaObject = java_ref;
|
||||
entry->mXPCOMInstance = aXPCOMObject;
|
||||
|
||||
LOG(("+ Adding Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x) weakref=0x%08x\n",
|
||||
hash, (int) xpcomObjKey, (PRUint32) java_ref));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJavaXPCOMBindings::RemoveBinding(JNIEnv* env, jobject aJavaObject,
|
||||
void* aXPCOMObject)
|
||||
{
|
||||
// Given a Java or XPCOM object, find the associated object.
|
||||
NS_PRECONDITION(aJavaObject != nsnull || aXPCOMObject != nsnull,
|
||||
"Need either a Java or XPCOM object");
|
||||
|
||||
jint hash = 0;
|
||||
void* xpcomObjKey = nsnull;
|
||||
JavaXPCOMBindingEntry* entry = nsnull;
|
||||
|
||||
if (aJavaObject) {
|
||||
hash = env->CallIntMethod(aJavaObject, hashCodeMID);
|
||||
JavaXPCOMBindingEntry* e =
|
||||
NS_STATIC_CAST(JavaXPCOMBindingEntry*,
|
||||
PL_DHashTableOperate(mJAVAtoXPCOMBindings,
|
||||
NS_INT32_TO_PTR(hash),
|
||||
PL_DHASH_LOOKUP));
|
||||
if (PL_DHASH_ENTRY_IS_BUSY(e))
|
||||
entry = e;
|
||||
} else {
|
||||
JavaXPCOMBindingEntry* e =
|
||||
NS_STATIC_CAST(JavaXPCOMBindingEntry*,
|
||||
PL_DHashTableOperate(mXPCOMtoJAVABindings, aXPCOMObject,
|
||||
PL_DHASH_LOOKUP));
|
||||
if (PL_DHASH_ENTRY_IS_BUSY(e))
|
||||
entry = e;
|
||||
}
|
||||
if (!entry) {
|
||||
NS_WARNING("Failed to find matching entry");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
jobject jweakref = entry->mJavaObject;
|
||||
void* xpcom_obj = entry->mXPCOMInstance;
|
||||
|
||||
// Get keys. For Java, we use the hash key of the Java object. For XPCOM,
|
||||
// we get the 'actual' object (either the nsJavaXPTCStub or the instance
|
||||
// that is wrapped by JavaXPCOMInstance).
|
||||
if (hash == 0) {
|
||||
hash = env->CallIntMethod(jweakref, hashCodeMID);
|
||||
}
|
||||
if (aXPCOMObject) {
|
||||
xpcomObjKey = aXPCOMObject;
|
||||
} else {
|
||||
if (IsXPTCStub(xpcom_obj))
|
||||
xpcomObjKey = GetXPTCStubAddr(xpcom_obj);
|
||||
else
|
||||
xpcomObjKey = ((JavaXPCOMInstance*) xpcom_obj)->GetInstance();
|
||||
}
|
||||
|
||||
NS_ASSERTION(env->IsSameObject(jweakref, aJavaObject),
|
||||
"Weakref does not point to expected Java object");
|
||||
NS_ASSERTION(!env->IsSameObject(jweakref, NULL),
|
||||
"Weakref refers to garbage collected Java object. No longer valid");
|
||||
|
||||
// Remove both instances from stores
|
||||
PL_DHashTableOperate(mJAVAtoXPCOMBindings, NS_INT32_TO_PTR(hash),
|
||||
PL_DHASH_REMOVE);
|
||||
PL_DHashTableOperate(mXPCOMtoJAVABindings, xpcomObjKey, PL_DHASH_REMOVE);
|
||||
LOG(("- Removing Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x) weakref=0x%08x\n",
|
||||
hash, (int) xpcomObjKey, (PRUint32) jweakref));
|
||||
|
||||
env->DeleteWeakGlobalRef(NS_STATIC_CAST(jweak, jweakref));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void*
|
||||
nsJavaXPCOMBindings::GetXPCOMObject(JNIEnv* env, jobject aJavaObject)
|
||||
{
|
||||
jint hash = env->CallIntMethod(aJavaObject, hashCodeMID);
|
||||
|
||||
JavaXPCOMBindingEntry *entry =
|
||||
NS_STATIC_CAST(JavaXPCOMBindingEntry*,
|
||||
PL_DHashTableOperate(mJAVAtoXPCOMBindings,
|
||||
NS_INT32_TO_PTR(hash),
|
||||
PL_DHASH_LOOKUP));
|
||||
|
||||
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
void* xpcomObjKey = nsnull;
|
||||
if (IsXPTCStub(entry->mXPCOMInstance))
|
||||
xpcomObjKey = GetXPTCStubAddr(entry->mXPCOMInstance);
|
||||
else
|
||||
xpcomObjKey = ((JavaXPCOMInstance*) entry->mXPCOMInstance)->GetInstance();
|
||||
LOG(("< Get Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x)\n",
|
||||
hash, (int) xpcomObjKey));
|
||||
#endif
|
||||
return entry->mXPCOMInstance;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJavaXPCOMBindings::GetJavaObject(JNIEnv* env, void* aXPCOMObject,
|
||||
const nsIID& aIID, PRBool aDoReleaseObject,
|
||||
jobject* aResult)
|
||||
{
|
||||
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
||||
if (!aResult)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aResult = nsnull;
|
||||
nsISupports* xpcom_obj = NS_STATIC_CAST(nsISupports*, aXPCOMObject);
|
||||
nsresult rv;
|
||||
|
||||
nsJavaXPTCStub* stub = nsnull;
|
||||
xpcom_obj->QueryInterface(NS_GET_IID(nsJavaXPTCStub), (void**) &stub);
|
||||
if (stub) {
|
||||
// Get associated Java object directly from nsJavaXPTCStub
|
||||
*aResult = stub->GetJavaObject();
|
||||
NS_ASSERTION(*aResult != nsnull, "nsJavaXPTCStub w/o matching Java object");
|
||||
NS_RELEASE(stub);
|
||||
rv = NS_OK;
|
||||
} else {
|
||||
// Get associated Java object from hash table
|
||||
JavaXPCOMBindingEntry *entry =
|
||||
NS_STATIC_CAST(JavaXPCOMBindingEntry*,
|
||||
PL_DHashTableOperate(mXPCOMtoJAVABindings, aXPCOMObject,
|
||||
PL_DHASH_LOOKUP));
|
||||
|
||||
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
|
||||
*aResult = entry->mJavaObject;
|
||||
rv = NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (*aResult == nsnull) {
|
||||
// No Java object is associated with the given XPCOM object, so we create
|
||||
// a Java proxy.
|
||||
rv = CreateJavaProxy(env, xpcom_obj, aIID, aResult);
|
||||
if (NS_SUCCEEDED(rv) && aDoReleaseObject)
|
||||
NS_RELEASE(xpcom_obj); // Owning ref passed on
|
||||
}
|
||||
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
if (*aResult) {
|
||||
LOG(("< Get Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x)\n",
|
||||
env->CallIntMethod(*aResult, hashCodeMID), (int) aXPCOMObject));
|
||||
}
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/******************************
|
||||
* InitializeJavaGlobals
|
||||
******************************/
|
||||
@@ -504,9 +233,14 @@ InitializeJavaGlobals(JNIEnv *env)
|
||||
}
|
||||
#endif
|
||||
|
||||
gBindings = new nsJavaXPCOMBindings();
|
||||
if (NS_FAILED(gBindings->Init())) {
|
||||
NS_WARNING("Problem creating JavaXPCOMBindings");
|
||||
gNativeToJavaProxyMap = new NativeToJavaProxyMap();
|
||||
if (NS_FAILED(gNativeToJavaProxyMap->Init())) {
|
||||
NS_WARNING("Problem creating NativeToJavaProxyMap");
|
||||
goto init_error;
|
||||
}
|
||||
gJavaToXPTCStubMap = new JavaToXPTCStubMap();
|
||||
if (NS_FAILED(gJavaToXPTCStubMap->Init())) {
|
||||
NS_WARNING("Problem creating JavaToXPTCStubMap");
|
||||
goto init_error;
|
||||
}
|
||||
|
||||
@@ -577,9 +311,13 @@ FreeJavaGlobals(JNIEnv* env)
|
||||
xpcomJavaProxyClass = nsnull;
|
||||
}
|
||||
|
||||
if (gBindings) {
|
||||
delete gBindings;
|
||||
gBindings = nsnull;
|
||||
if (gNativeToJavaProxyMap) {
|
||||
delete gNativeToJavaProxyMap;
|
||||
gNativeToJavaProxyMap = nsnull;
|
||||
}
|
||||
if (gJavaToXPTCStubMap) {
|
||||
delete gJavaToXPTCStubMap;
|
||||
gJavaToXPTCStubMap = nsnull;
|
||||
}
|
||||
|
||||
PR_Unlock(gJavaXPCOMLock);
|
||||
@@ -588,13 +326,252 @@ FreeJavaGlobals(JNIEnv* env)
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* Java<->XPCOM object mappings
|
||||
**************************************/
|
||||
|
||||
static PLDHashTableOps hash_ops =
|
||||
{
|
||||
PL_DHashAllocTable,
|
||||
PL_DHashFreeTable,
|
||||
PL_DHashGetKeyStub,
|
||||
PL_DHashVoidPtrKeyStub,
|
||||
PL_DHashMatchEntryStub,
|
||||
PL_DHashMoveEntryStub,
|
||||
PL_DHashClearEntryStub,
|
||||
PL_DHashFinalizeStub
|
||||
};
|
||||
|
||||
// NativeToJavaProxyMap: The common case is that each XPCOM object will have
|
||||
// one Java proxy. But there are instances where there will be multiple Java
|
||||
// proxies for a given XPCOM object, each representing a different interface.
|
||||
// So we optimize the common case by using a hash table. Then, if there are
|
||||
// multiple Java proxies, we cycle through the linked list, comparing IIDs.
|
||||
|
||||
NativeToJavaProxyMap::~NativeToJavaProxyMap()
|
||||
{
|
||||
PL_DHashTableDestroy(mHashTable);
|
||||
}
|
||||
|
||||
nsresult
|
||||
NativeToJavaProxyMap::Init()
|
||||
{
|
||||
mHashTable = PL_NewDHashTable(&hash_ops, nsnull, sizeof(Entry), 16);
|
||||
if (!mHashTable)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NativeToJavaProxyMap::Add(JNIEnv* env, nsISupports* aXPCOMObject,
|
||||
const nsIID& aIID, jobject aProxy)
|
||||
{
|
||||
Entry* e = NS_STATIC_CAST(Entry*, PL_DHashTableOperate(mHashTable,
|
||||
aXPCOMObject,
|
||||
PL_DHASH_ADD));
|
||||
if (!e)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
jweak ref = env->NewWeakGlobalRef(aProxy);
|
||||
if (!ref)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Add Java proxy ref to start of list
|
||||
ProxyList* item = new ProxyList(ref, aIID, e->list);
|
||||
e->key = aXPCOMObject;
|
||||
e->list = item;
|
||||
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
char* iid_str = aIID.ToString();
|
||||
LOG(("+ NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
env->CallIntMethod(aProxy, hashCodeMID), (int) aXPCOMObject, iid_str));
|
||||
PR_Free(iid_str);
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NativeToJavaProxyMap::Find(JNIEnv* env, nsISupports* aNativeObject,
|
||||
const nsIID& aIID, jobject* aResult)
|
||||
{
|
||||
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
||||
if (!aResult)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*aResult = nsnull;
|
||||
Entry* e = NS_STATIC_CAST(Entry*, PL_DHashTableOperate(mHashTable,
|
||||
aNativeObject,
|
||||
PL_DHASH_LOOKUP));
|
||||
|
||||
if (PL_DHASH_ENTRY_IS_FREE(e))
|
||||
return NS_OK;
|
||||
|
||||
ProxyList* item = e->list;
|
||||
while (item != nsnull && *aResult == nsnull) {
|
||||
if (item->iid.Equals(aIID)) {
|
||||
jobject javaObject = env->NewLocalRef(item->javaObject);
|
||||
if (javaObject) {
|
||||
*aResult = javaObject;
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
char* iid_str = aIID.ToString();
|
||||
LOG(("< NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
env->CallIntMethod(*aResult, hashCodeMID),
|
||||
(int) aNativeObject, iid_str));
|
||||
PR_Free(iid_str);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NativeToJavaProxyMap::Remove(JNIEnv* env, nsISupports* aNativeObject,
|
||||
const nsIID& aIID)
|
||||
{
|
||||
Entry* e = NS_STATIC_CAST(Entry*, PL_DHashTableOperate(mHashTable,
|
||||
aNativeObject,
|
||||
PL_DHASH_LOOKUP));
|
||||
|
||||
if (PL_DHASH_ENTRY_IS_FREE(e)) {
|
||||
NS_WARNING("XPCOM object not found in hash table");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ProxyList* item = e->list;
|
||||
ProxyList* last = e->list;
|
||||
while (item != nsnull) {
|
||||
if (item->iid.Equals(aIID)) {
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
char* iid_str = aIID.ToString();
|
||||
LOG(("- NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
env->CallIntMethod(item->javaObject, hashCodeMID),
|
||||
(int) aNativeObject, iid_str));
|
||||
PR_Free(iid_str);
|
||||
#endif
|
||||
|
||||
env->DeleteWeakGlobalRef(item->javaObject);
|
||||
if (item == e->list) {
|
||||
e->list = item->next;
|
||||
if (e->list == nsnull)
|
||||
PL_DHashTableOperate(mHashTable, aNativeObject, PL_DHASH_REMOVE);
|
||||
} else {
|
||||
last->next = item->next;
|
||||
}
|
||||
|
||||
delete item;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
last = item;
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
NS_WARNING("Java proxy matching given IID not found");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JavaToXPTCStubMap::~JavaToXPTCStubMap()
|
||||
{
|
||||
PL_DHashTableDestroy(mHashTable);
|
||||
}
|
||||
|
||||
nsresult
|
||||
JavaToXPTCStubMap::Init()
|
||||
{
|
||||
mHashTable = PL_NewDHashTable(&hash_ops, nsnull, sizeof(Entry), 16);
|
||||
if (!mHashTable)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
JavaToXPTCStubMap::Add(JNIEnv* env, jobject aJavaObject, nsJavaXPTCStub* aProxy)
|
||||
{
|
||||
jint hash = env->CallIntMethod(aJavaObject, hashCodeMID);
|
||||
Entry* e = NS_STATIC_CAST(Entry*, PL_DHashTableOperate(mHashTable,
|
||||
NS_INT32_TO_PTR(hash),
|
||||
PL_DHASH_ADD));
|
||||
if (!e)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_ASSERTION(e->key == nsnull,
|
||||
"XPTCStub for given Java object already exists in hash table");
|
||||
e->key = hash;
|
||||
e->xptcstub = aProxy;
|
||||
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
nsIInterfaceInfo* iface_info;
|
||||
aProxy->GetInterfaceInfo(&iface_info);
|
||||
nsIID* iid;
|
||||
iface_info->GetInterfaceIID(&iid);
|
||||
char* iid_str = iid->ToString();
|
||||
LOG(("+ JavaToXPTCStubMap (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
hash, (int) aProxy, iid_str));
|
||||
PR_Free(iid_str);
|
||||
nsMemory::Free(iid);
|
||||
NS_RELEASE(iface_info);
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
JavaToXPTCStubMap::Find(JNIEnv* env, jobject aJavaObject, const nsIID& aIID,
|
||||
nsJavaXPTCStub** aResult)
|
||||
{
|
||||
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
||||
if (!aResult)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*aResult = nsnull;
|
||||
jint hash = env->CallIntMethod(aJavaObject, hashCodeMID);
|
||||
Entry* e = NS_STATIC_CAST(Entry*, PL_DHashTableOperate(mHashTable,
|
||||
NS_INT32_TO_PTR(hash),
|
||||
PL_DHASH_LOOKUP));
|
||||
|
||||
if (PL_DHASH_ENTRY_IS_FREE(e))
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv = e->xptcstub->QueryInterface(aIID, (void**) aResult);
|
||||
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
char* iid_str = aIID.ToString();
|
||||
LOG(("< JavaToXPTCStubMap (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
hash, (int) *aResult, iid_str));
|
||||
PR_Free(iid_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
// NS_NOINTERFACE is not an error condition
|
||||
if (rv == NS_NOINTERFACE)
|
||||
rv = NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
JavaToXPTCStubMap::Remove(JNIEnv* env, jobject aJavaObject)
|
||||
{
|
||||
jint hash = env->CallIntMethod(aJavaObject, hashCodeMID);
|
||||
PL_DHashTableOperate(mHashTable, NS_INT32_TO_PTR(hash), PL_DHASH_REMOVE);
|
||||
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
LOG(("- JavaToXPTCStubMap (Java=%08x)\n", hash));
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************
|
||||
* JavaXPCOMInstance
|
||||
*********************************************************/
|
||||
JavaXPCOMInstance::JavaXPCOMInstance(nsISupports* aInstance,
|
||||
nsIInterfaceInfo* aIInfo)
|
||||
: mInstance(aInstance),
|
||||
mIInfo(aIInfo)
|
||||
: mInstance(aInstance)
|
||||
, mIInfo(aIInfo)
|
||||
{
|
||||
NS_ADDREF(mInstance);
|
||||
NS_ADDREF(mIInfo);
|
||||
@@ -613,6 +590,124 @@ JavaXPCOMInstance::~JavaXPCOMInstance()
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* Helper functions
|
||||
*******************************/
|
||||
|
||||
nsresult
|
||||
GetNewOrUsedJavaObject(JNIEnv* env, nsISupports* aXPCOMObject,
|
||||
const nsIID& aIID, jobject* aResult, PRBool* aIsNewProxy)
|
||||
{
|
||||
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
||||
if (!aResult)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (aIsNewProxy) {
|
||||
*aIsNewProxy = PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsJavaXPTCStub* stub = nsnull;
|
||||
aXPCOMObject->QueryInterface(NS_GET_IID(nsJavaXPTCStub), (void**) &stub);
|
||||
if (stub) {
|
||||
// Get Java object directly from nsJavaXPTCStub
|
||||
*aResult = stub->GetJavaObject();
|
||||
NS_ASSERTION(*aResult != nsnull, "nsJavaXPTCStub w/o matching Java object");
|
||||
NS_RELEASE(stub);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get associated Java object from hash table
|
||||
rv = gNativeToJavaProxyMap->Find(env, aXPCOMObject, aIID, aResult);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (*aResult)
|
||||
return NS_OK;
|
||||
|
||||
// No Java object is associated with the given XPCOM object, so we
|
||||
// create a Java proxy.
|
||||
if (aIsNewProxy) {
|
||||
*aIsNewProxy = PR_TRUE;
|
||||
}
|
||||
return CreateJavaProxy(env, aXPCOMObject, aIID, aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetNewOrUsedXPCOMObject(JNIEnv* env, jobject aJavaObject, const nsIID& aIID,
|
||||
nsISupports** aResult, PRBool* aIsXPTCStub)
|
||||
{
|
||||
NS_PRECONDITION(aResult != nsnull && aIsXPTCStub != nsnull, "null ptr");
|
||||
if (!aResult || !aIsXPTCStub)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsresult rv;
|
||||
*aResult = nsnull;
|
||||
|
||||
// Check if the given Java object is actually one of our Java proxies. If so,
|
||||
// then we query the associated XPCOM object directly from the proxy.
|
||||
// If Java object is not a proxy, then we try to find associated XPCOM object
|
||||
// in the mapping table.
|
||||
jboolean isProxy = env->CallStaticBooleanMethod(xpcomJavaProxyClass,
|
||||
isXPCOMJavaProxyMID,
|
||||
aJavaObject);
|
||||
if (env->ExceptionCheck())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (isProxy) {
|
||||
void* inst;
|
||||
rv = GetXPCOMInstFromProxy(env, aJavaObject, &inst);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
*aResult = NS_STATIC_CAST(JavaXPCOMInstance*, inst)->GetInstance();
|
||||
NS_ADDREF(*aResult);
|
||||
*aIsXPTCStub = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
*aIsXPTCStub = PR_TRUE;
|
||||
|
||||
nsJavaXPTCStub* stub;
|
||||
rv = gJavaToXPTCStubMap->Find(env, aJavaObject, aIID, &stub);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (stub) {
|
||||
// stub is already AddRef'd
|
||||
*aResult = NS_STATIC_CAST(nsISupports*,
|
||||
NS_STATIC_CAST(nsXPTCStubBase*, stub));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If there is no corresponding XPCOM object, then that means that the
|
||||
// parameter is a 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<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
|
||||
nsCOMPtr<nsIInterfaceInfo> iinfo;
|
||||
rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Create XPCOM stub
|
||||
stub = new nsJavaXPTCStub(env, aJavaObject, iinfo);
|
||||
if (!stub) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
rv = gJavaToXPTCStubMap->Add(env, aJavaObject, stub);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete stub;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_ADDREF(stub);
|
||||
*aResult = NS_STATIC_CAST(nsISupports*,
|
||||
NS_STATIC_CAST(nsXPTCStubBase*, stub));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetIIDForMethodParam(nsIInterfaceInfo *iinfo, const nsXPTMethodInfo *methodInfo,
|
||||
const nsXPTParamInfo ¶mInfo, PRUint16 methodIndex,
|
||||
|
||||
@@ -43,9 +43,12 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "pldhash.h"
|
||||
#include "nsJavaXPTCStub.h"
|
||||
#include "nsAutoLock.h"
|
||||
|
||||
//#define DEBUG_JAVAXPCOM
|
||||
//#define DEBUG_JAVAXPCOM_REFCNT
|
||||
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
#define LOG(x) printf x
|
||||
#else
|
||||
@@ -62,6 +65,7 @@
|
||||
/*********************
|
||||
* Java JNI globals
|
||||
*********************/
|
||||
|
||||
extern jclass booleanClass;
|
||||
extern jclass charClass;
|
||||
extern jclass byteClass;
|
||||
@@ -101,11 +105,24 @@ extern jmethodID getNameMID;
|
||||
extern jmethodID proxyToStringMID;
|
||||
#endif
|
||||
|
||||
class nsJavaXPCOMBindings;
|
||||
extern nsJavaXPCOMBindings* gBindings;
|
||||
class NativeToJavaProxyMap;
|
||||
extern NativeToJavaProxyMap* gNativeToJavaProxyMap;
|
||||
class JavaToXPTCStubMap;
|
||||
extern JavaToXPTCStubMap* gJavaToXPTCStubMap;
|
||||
|
||||
extern PRLock* gJavaXPCOMLock;
|
||||
|
||||
/**
|
||||
* Initialize global structures used by Javaconnect.
|
||||
* @param env Java environment pointer
|
||||
* @return PR_TRUE if Javaconnect is initialized; PR_FALSE if an error occurred
|
||||
*/
|
||||
PRBool InitializeJavaGlobals(JNIEnv *env);
|
||||
|
||||
/**
|
||||
* Frees global structures that were allocated by InitializeJavaGlobals().
|
||||
* @param env Java environment pointer
|
||||
*/
|
||||
void FreeJavaGlobals(JNIEnv* env);
|
||||
|
||||
|
||||
@@ -129,42 +146,125 @@ private:
|
||||
|
||||
|
||||
/**************************************
|
||||
* Java<->XPCOM binding stores
|
||||
* Java<->XPCOM object mappings
|
||||
**************************************/
|
||||
// This class is used to store the associations between existing Java object
|
||||
// and XPCOM objects.
|
||||
class nsJavaXPCOMBindings
|
||||
|
||||
/**
|
||||
* Maps native XPCOM objects to their associated Java proxy object.
|
||||
*/
|
||||
class NativeToJavaProxyMap
|
||||
{
|
||||
protected:
|
||||
struct ProxyList
|
||||
{
|
||||
ProxyList(const jobject aRef, const nsIID& aIID, ProxyList* aList)
|
||||
: javaObject(aRef)
|
||||
, iid(aIID)
|
||||
, next(aList)
|
||||
{ }
|
||||
|
||||
const jobject javaObject;
|
||||
const nsIID iid;
|
||||
ProxyList* next;
|
||||
};
|
||||
|
||||
struct Entry : public PLDHashEntryHdr
|
||||
{
|
||||
nsISupports* key;
|
||||
ProxyList* list;
|
||||
};
|
||||
|
||||
public:
|
||||
nsJavaXPCOMBindings()
|
||||
: mJAVAtoXPCOMBindings(nsnull)
|
||||
, mXPCOMtoJAVABindings(nsnull)
|
||||
NativeToJavaProxyMap()
|
||||
: mHashTable(nsnull)
|
||||
{ }
|
||||
~nsJavaXPCOMBindings();
|
||||
|
||||
// Initializes internal structures.
|
||||
NS_IMETHOD Init();
|
||||
~NativeToJavaProxyMap();
|
||||
|
||||
// Associates the given Java object with the given XPCOM object
|
||||
NS_IMETHOD AddBinding(JNIEnv* env, jobject aJavaStub, void* aXPCOMObject);
|
||||
nsresult Init();
|
||||
|
||||
// Given either a Java object or XPCOM object, removes the association
|
||||
// between the two.
|
||||
NS_IMETHOD RemoveBinding(JNIEnv* env, jobject aJavaObject, void* aXPCOMObject);
|
||||
nsresult Add(JNIEnv* env, nsISupports* aXPCOMObject, const nsIID& aIID,
|
||||
jobject aProxy);
|
||||
|
||||
// Given a Java object, returns the associated XPCOM object.
|
||||
void* GetXPCOMObject(JNIEnv* env, jobject aJavaObject);
|
||||
nsresult Find(JNIEnv* env, nsISupports* aNativeObject, const nsIID& aIID,
|
||||
jobject* aResult);
|
||||
|
||||
// Given an XPCOM object, returns the associated Java Object. If a Java
|
||||
// object doesn't exist, then create a Java proxy for the XPCOM object.
|
||||
NS_IMETHOD GetJavaObject(JNIEnv* env, void* aXPCOMObject, const nsIID& aIID,
|
||||
PRBool aDoReleaseObject, jobject* aResult);
|
||||
private:
|
||||
PLDHashTable* mJAVAtoXPCOMBindings;
|
||||
PLDHashTable* mXPCOMtoJAVABindings;
|
||||
nsresult Remove(JNIEnv* env, nsISupports* aNativeObject, const nsIID& aIID);
|
||||
|
||||
protected:
|
||||
PLDHashTable* mHashTable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Maps Java objects to their associated nsJavaXPTCStub.
|
||||
*/
|
||||
class JavaToXPTCStubMap
|
||||
{
|
||||
protected:
|
||||
struct Entry : public PLDHashEntryHdr
|
||||
{
|
||||
jint key;
|
||||
nsJavaXPTCStub* xptcstub;
|
||||
};
|
||||
|
||||
public:
|
||||
JavaToXPTCStubMap()
|
||||
: mHashTable(nsnull)
|
||||
{ }
|
||||
|
||||
~JavaToXPTCStubMap();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
nsresult Add(JNIEnv* env, jobject aJavaObject, nsJavaXPTCStub* aProxy);
|
||||
|
||||
nsresult Find(JNIEnv* env, jobject aJavaObject, const nsIID& aIID,
|
||||
nsJavaXPTCStub** aResult);
|
||||
|
||||
nsresult Remove(JNIEnv* env, jobject aJavaObject);
|
||||
|
||||
protected:
|
||||
PLDHashTable* mHashTable;
|
||||
};
|
||||
|
||||
|
||||
/*******************************
|
||||
* Helper functions
|
||||
*******************************/
|
||||
|
||||
/**
|
||||
* Finds the associated Java object for the given XPCOM object and IID. If no
|
||||
* such Java object exists, then it creates one.
|
||||
*
|
||||
* @param env Java environment pointer
|
||||
* @param aXPCOMObject XPCOM object for which to find/create Java object
|
||||
* @param aIID desired interface IID for Java object
|
||||
* @param aResult on success, holds reference to Java object
|
||||
* @param aIsNewProxy on success, holds PR_TRUE if aResult points to newlyXPTCStub;
|
||||
* created Java proxy; PR_FALSE otherwise
|
||||
*
|
||||
* @return NS_OK if succeeded; all other return values are error codes.
|
||||
*/
|
||||
nsresult GetNewOrUsedJavaObject(JNIEnv* env, nsISupports* aXPCOMObject,
|
||||
const nsIID& aIID, jobject* aResult,
|
||||
PRBool* aIsNewProxy);
|
||||
|
||||
/**
|
||||
* Finds the associated XPCOM object for the given Java object and IID. If no
|
||||
* such XPCOM object exists, then it creates one.
|
||||
*
|
||||
* @param env Java environment pointer
|
||||
* @param aJavaObject Java object for which to find/create XPCOM object
|
||||
* @param aIID desired interface IID for XPCOM object
|
||||
* @param aResult on success, holds AddRef'd reference to XPCOM object
|
||||
* @param aIsXPTCStub on success, holds PR_TRUE if aResult points to XPTCStub;
|
||||
* PR_FALSE if aResult points to native XPCOM object
|
||||
*
|
||||
* @return NS_OK if succeeded; all other return values are error codes.
|
||||
*/
|
||||
nsresult GetNewOrUsedXPCOMObject(JNIEnv* env, jobject aJavaObject,
|
||||
const nsIID& aIID, nsISupports** aResult,
|
||||
PRBool* aIsXPTCStub);
|
||||
|
||||
nsresult GetIIDForMethodParam(nsIInterfaceInfo *iinfo,
|
||||
const nsXPTMethodInfo *methodInfo,
|
||||
|
||||
@@ -48,58 +48,42 @@
|
||||
nsJavaXPTCStub::nsJavaXPTCStub(JNIEnv* aJavaEnv, jobject aJavaObject,
|
||||
nsIInterfaceInfo *aIInfo)
|
||||
: mJavaEnv(aJavaEnv)
|
||||
, mJavaStrongRef(nsnull)
|
||||
, mIInfo(aIInfo)
|
||||
, mMaster(nsnull)
|
||||
, mWeakRefCnt(0)
|
||||
{
|
||||
mJavaObject = aJavaEnv->NewGlobalRef(aJavaObject);
|
||||
mJavaWeakRef = aJavaEnv->NewWeakGlobalRef(aJavaObject);
|
||||
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
jstring name;
|
||||
const char* javaObjectName = nsnull;
|
||||
jclass clazz = mJavaEnv->GetObjectClass(mJavaObject);
|
||||
if (clazz) {
|
||||
name = (jstring) mJavaEnv->CallObjectMethod(clazz, getNameMID);
|
||||
if (name)
|
||||
javaObjectName = mJavaEnv->GetStringUTFChars(name, nsnull);
|
||||
}
|
||||
|
||||
nsID* iid = nsnull;
|
||||
char* iid_str = nsnull;
|
||||
if (mIInfo) {
|
||||
nsresult rv = mIInfo->GetInterfaceIID(&iid);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
iid_str = iid->ToString();
|
||||
nsMemory::Free(iid);
|
||||
}
|
||||
}
|
||||
|
||||
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"));
|
||||
if (name)
|
||||
mJavaEnv->ReleaseStringUTFChars(name, javaObjectName);
|
||||
if (iid_str)
|
||||
nsMemory::Free(iid_str);
|
||||
nsIID* iid;
|
||||
mIInfo->GetInterfaceIID(&iid);
|
||||
char* iid_str = iid->ToString();
|
||||
LOG(("+ nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
aJavaEnv->CallIntMethod(aJavaObject, hashCodeMID),
|
||||
(int) this, iid_str));
|
||||
PR_Free(iid_str);
|
||||
nsMemory::Free(iid);
|
||||
#endif
|
||||
}
|
||||
|
||||
nsJavaXPTCStub::~nsJavaXPTCStub()
|
||||
{
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
jstring name;
|
||||
const char* javaObjectName = nsnull;
|
||||
jclass clazz = mJavaEnv->GetObjectClass(mJavaObject);
|
||||
if (clazz) {
|
||||
name = (jstring) mJavaEnv->CallObjectMethod(clazz, getNameMID);
|
||||
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 : "<-->"));
|
||||
if (name)
|
||||
mJavaEnv->ReleaseStringUTFChars(name, javaObjectName);
|
||||
void
|
||||
nsJavaXPTCStub::Destroy()
|
||||
{
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
nsIID* iid;
|
||||
mIInfo->GetInterfaceIID(&iid);
|
||||
char* iid_str = iid->ToString();
|
||||
jobject javaObject = mJavaEnv->NewLocalRef(mJavaWeakRef);
|
||||
LOG(("- nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
mJavaEnv->CallIntMethod(javaObject, hashCodeMID),
|
||||
(int) this, iid_str));
|
||||
PR_Free(iid_str);
|
||||
nsMemory::Free(iid);
|
||||
#endif
|
||||
|
||||
if (!mMaster) {
|
||||
@@ -108,18 +92,21 @@ nsJavaXPTCStub::~nsJavaXPTCStub()
|
||||
delete (nsJavaXPTCStub*) mChildren[i];
|
||||
}
|
||||
|
||||
gBindings->RemoveBinding(mJavaEnv, mJavaObject, this);
|
||||
gJavaToXPTCStubMap->Remove(mJavaEnv, mJavaStrongRef);
|
||||
}
|
||||
|
||||
mJavaEnv->DeleteGlobalRef(mJavaObject);
|
||||
mJavaEnv->DeleteWeakGlobalRef(mJavaWeakRef);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsJavaXPTCStub::AddRef()
|
||||
nsJavaXPTCStub::AddRefInternal()
|
||||
{
|
||||
// if this is a child
|
||||
if (mMaster)
|
||||
return mMaster->AddRef();
|
||||
// If this is the first AddRef call, we create a strong global ref to the
|
||||
// Java object to keep it from being garbage collected.
|
||||
if (mRefCnt == 0) {
|
||||
mJavaStrongRef = mJavaEnv->NewGlobalRef(mJavaWeakRef);
|
||||
NS_ASSERTION(mJavaStrongRef != nsnull, "Failed to acquire strong ref");
|
||||
}
|
||||
|
||||
// if this is the master interface
|
||||
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
|
||||
@@ -130,24 +117,85 @@ nsJavaXPTCStub::AddRef()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsJavaXPTCStub::Release()
|
||||
nsJavaXPTCStub::AddRef()
|
||||
{
|
||||
// if this is a child
|
||||
if (mMaster)
|
||||
return mMaster->Release();
|
||||
#ifdef DEBUG_JAVAXPCOM_REFCNT
|
||||
nsIID* iid;
|
||||
mIInfo->GetInterfaceIID(&iid);
|
||||
char* iid_str = iid->ToString();
|
||||
int refcnt = PRInt32(mMaster ? mMaster->mRefCnt : mRefCnt) + 1;
|
||||
LOG(("= nsJavaXPTCStub::AddRef (XPCOM=%08x | refcnt = %d | IID=%s)\n",
|
||||
(int) this, refcnt, iid_str));
|
||||
PR_Free(iid_str);
|
||||
nsMemory::Free(iid);
|
||||
#endif
|
||||
|
||||
nsJavaXPTCStub* master = mMaster ? mMaster : this;
|
||||
return master->AddRefInternal();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsJavaXPTCStub::ReleaseInternal()
|
||||
{
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub);
|
||||
--mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "nsJavaXPTCStub");
|
||||
if (mRefCnt == 0) {
|
||||
mRefCnt = 1; /* stabilize */
|
||||
delete this;
|
||||
// If we have a weak ref, we don't delete this object.
|
||||
if (mWeakRefCnt == 0) {
|
||||
mRefCnt = 1; /* stabilize */
|
||||
Destroy();
|
||||
|
||||
// delete strong ref; allows Java object to be garbage collected
|
||||
mJavaEnv->DeleteGlobalRef(mJavaStrongRef);
|
||||
delete this;
|
||||
} else {
|
||||
// delete strong ref; allows Java object to be garbage collected
|
||||
mJavaEnv->DeleteGlobalRef(mJavaStrongRef);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsJavaXPTCStub::Release()
|
||||
{
|
||||
#ifdef DEBUG_JAVAXPCOM_REFCNT
|
||||
nsIID* iid;
|
||||
mIInfo->GetInterfaceIID(&iid);
|
||||
char* iid_str = iid->ToString();
|
||||
int refcnt = PRInt32(mMaster ? mMaster->mRefCnt : mRefCnt) - 1;
|
||||
LOG(("= nsJavaXPTCStub::Release (XPCOM=%08x | refcnt = %d | IID=%s)\n",
|
||||
(int) this, refcnt, iid_str));
|
||||
PR_Free(iid_str);
|
||||
nsMemory::Free(iid);
|
||||
#endif
|
||||
|
||||
nsJavaXPTCStub* master = mMaster ? mMaster : this;
|
||||
return master->ReleaseInternal();
|
||||
}
|
||||
|
||||
void
|
||||
nsJavaXPTCStub::ReleaseWeakRef()
|
||||
{
|
||||
// if this is a child
|
||||
if (mMaster)
|
||||
return mMaster->ReleaseWeakRef();
|
||||
|
||||
--mWeakRefCnt;
|
||||
|
||||
// If there are no more associated weak refs, and no one else holds a strong
|
||||
// ref to this object, then delete it.
|
||||
if (mWeakRefCnt == 0 && mRefCnt == 0) {
|
||||
NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub);
|
||||
mRefCnt = 1; /* stabilize */
|
||||
Destroy();
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr)
|
||||
{
|
||||
@@ -191,15 +239,17 @@ nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr)
|
||||
|
||||
// Query Java object
|
||||
LOG(("\tCalling Java object queryInterface\n"));
|
||||
jobject javaObject = mJavaEnv->NewLocalRef(mJavaWeakRef);
|
||||
|
||||
jmethodID qiMID = 0;
|
||||
jclass clazz = mJavaEnv->GetObjectClass(mJavaObject);
|
||||
jclass clazz = mJavaEnv->GetObjectClass(javaObject);
|
||||
if (clazz) {
|
||||
char* sig = "(Ljava/lang/String;)Lorg/mozilla/xpcom/nsISupports;";
|
||||
qiMID = mJavaEnv->GetMethodID(clazz, "queryInterface", sig);
|
||||
NS_ASSERTION(qiMID, "Failed to get queryInterface method ID");
|
||||
}
|
||||
|
||||
if (qiMID == nsnull) {
|
||||
if (qiMID == 0) {
|
||||
mJavaEnv->ExceptionClear();
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
@@ -217,7 +267,7 @@ nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr)
|
||||
PR_Free(iid_str);
|
||||
|
||||
// call queryInterface method
|
||||
jobject obj = mJavaEnv->CallObjectMethod(mJavaObject, qiMID, iid_jstr);
|
||||
jobject obj = mJavaEnv->CallObjectMethod(javaObject, qiMID, iid_jstr);
|
||||
if (mJavaEnv->ExceptionCheck()) {
|
||||
mJavaEnv->ExceptionClear();
|
||||
return NS_ERROR_FAILURE;
|
||||
@@ -316,10 +366,11 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex,
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
const char* ifaceName;
|
||||
mIInfo->GetNameShared(&ifaceName);
|
||||
LOG(("nsJavaXPTCStub::CallMethod [%s::%s]\n", ifaceName, aMethodInfo->GetName()));
|
||||
LOG(("---> (Java) %s::%s()\n", ifaceName, aMethodInfo->GetName()));
|
||||
#endif
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
jobject javaObject = mJavaEnv->NewLocalRef(mJavaWeakRef);
|
||||
|
||||
nsCAutoString methodSig("(");
|
||||
|
||||
@@ -375,7 +426,7 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex,
|
||||
methodName.SetCharAt(tolower(methodName[0]), 0);
|
||||
}
|
||||
|
||||
jclass clazz = mJavaEnv->GetObjectClass(mJavaObject);
|
||||
jclass clazz = mJavaEnv->GetObjectClass(javaObject);
|
||||
if (clazz)
|
||||
mid = mJavaEnv->GetMethodID(clazz, methodName.get(), methodSig.get());
|
||||
NS_ASSERTION(mid, "Failed to get requested method for Java object");
|
||||
@@ -387,46 +438,46 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex,
|
||||
jvalue retval;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (!retvalInfo) {
|
||||
mJavaEnv->CallVoidMethodA(mJavaObject, mid, java_params);
|
||||
mJavaEnv->CallVoidMethodA(javaObject, mid, java_params);
|
||||
} else {
|
||||
switch (retvalInfo->GetType().TagPart())
|
||||
{
|
||||
case nsXPTType::T_I8:
|
||||
case nsXPTType::T_U8:
|
||||
retval.b = mJavaEnv->CallByteMethodA(mJavaObject, mid,
|
||||
retval.b = mJavaEnv->CallByteMethodA(javaObject, mid,
|
||||
java_params);
|
||||
break;
|
||||
|
||||
case nsXPTType::T_I16:
|
||||
case nsXPTType::T_U16:
|
||||
retval.s = mJavaEnv->CallShortMethodA(mJavaObject, mid,
|
||||
retval.s = mJavaEnv->CallShortMethodA(javaObject, mid,
|
||||
java_params);
|
||||
break;
|
||||
|
||||
case nsXPTType::T_I32:
|
||||
case nsXPTType::T_U32:
|
||||
retval.i = mJavaEnv->CallIntMethodA(mJavaObject, mid,
|
||||
retval.i = mJavaEnv->CallIntMethodA(javaObject, mid,
|
||||
java_params);
|
||||
break;
|
||||
|
||||
case nsXPTType::T_FLOAT:
|
||||
retval.f = mJavaEnv->CallFloatMethodA(mJavaObject, mid,
|
||||
retval.f = mJavaEnv->CallFloatMethodA(javaObject, mid,
|
||||
java_params);
|
||||
break;
|
||||
|
||||
case nsXPTType::T_DOUBLE:
|
||||
retval.d = mJavaEnv->CallDoubleMethodA(mJavaObject, mid,
|
||||
retval.d = mJavaEnv->CallDoubleMethodA(javaObject, mid,
|
||||
java_params);
|
||||
break;
|
||||
|
||||
case nsXPTType::T_BOOL:
|
||||
retval.z = mJavaEnv->CallBooleanMethodA(mJavaObject, mid,
|
||||
retval.z = mJavaEnv->CallBooleanMethodA(javaObject, mid,
|
||||
java_params);
|
||||
break;
|
||||
|
||||
case nsXPTType::T_CHAR:
|
||||
case nsXPTType::T_WCHAR:
|
||||
retval.c = mJavaEnv->CallCharMethodA(mJavaObject, mid,
|
||||
retval.c = mJavaEnv->CallCharMethodA(javaObject, mid,
|
||||
java_params);
|
||||
break;
|
||||
|
||||
@@ -439,12 +490,12 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex,
|
||||
case nsXPTType::T_CSTRING:
|
||||
case nsXPTType::T_INTERFACE:
|
||||
case nsXPTType::T_INTERFACE_IS:
|
||||
retval.l = mJavaEnv->CallObjectMethodA(mJavaObject, mid,
|
||||
retval.l = mJavaEnv->CallObjectMethodA(javaObject, mid,
|
||||
java_params);
|
||||
break;
|
||||
|
||||
case nsXPTType::T_VOID:
|
||||
retval.i = mJavaEnv->CallIntMethodA(mJavaObject, mid,
|
||||
retval.i = mJavaEnv->CallIntMethodA(javaObject, mid,
|
||||
java_params);
|
||||
break;
|
||||
|
||||
@@ -505,6 +556,7 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex,
|
||||
if (java_params)
|
||||
delete [] java_params;
|
||||
|
||||
LOG(("<--- (Java) %s::%s()\n", ifaceName, aMethodInfo->GetName()));
|
||||
mJavaEnv->ExceptionClear();
|
||||
return rv;
|
||||
}
|
||||
@@ -811,11 +863,11 @@ nsJavaXPTCStub::SetupJavaParams(const nsXPTParamInfo &aParamInfo,
|
||||
case nsXPTType::T_INTERFACE:
|
||||
case nsXPTType::T_INTERFACE_IS:
|
||||
{
|
||||
void* xpcom_obj = nsnull;
|
||||
nsISupports* xpcom_obj = nsnull;
|
||||
if (!aParamInfo.IsOut()) { // 'in'
|
||||
xpcom_obj = aVariant.val.p;
|
||||
xpcom_obj = NS_STATIC_CAST(nsISupports*, aVariant.val.p);
|
||||
} else if (aVariant.val.p) { // 'inout' & 'out'
|
||||
void** variant = NS_STATIC_CAST(void**, aVariant.val.p);
|
||||
nsISupports** variant = NS_STATIC_CAST(nsISupports**, aVariant.val.p);
|
||||
xpcom_obj = *variant;
|
||||
}
|
||||
|
||||
@@ -828,8 +880,8 @@ nsJavaXPTCStub::SetupJavaParams(const nsXPTParamInfo &aParamInfo,
|
||||
break;
|
||||
|
||||
// Get matching Java object for given xpcom object
|
||||
rv = gBindings->GetJavaObject(mJavaEnv, xpcom_obj, iid, PR_FALSE,
|
||||
&java_stub);
|
||||
rv = GetNewOrUsedJavaObject(mJavaEnv, xpcom_obj, iid, &java_stub,
|
||||
nsnull);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
}
|
||||
@@ -1349,25 +1401,6 @@ 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
|
||||
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;
|
||||
rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo,
|
||||
@@ -1376,55 +1409,63 @@ nsJavaXPTCStub::FinalizeJavaParams(const nsXPTParamInfo &aParamInfo,
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
PRBool isWeakRef = iid.Equals(NS_GET_IID(nsIWeakReference));
|
||||
|
||||
if (inst == nsnull && !isWeakRef) {
|
||||
// Get interface info for class
|
||||
nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
|
||||
nsCOMPtr<nsIInterfaceInfo> iinfo;
|
||||
rv = iim->GetInfoForIID(&iid, getter_AddRefs(iinfo));
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
// Create XPCOM stub
|
||||
nsJavaXPTCStub* xpcomStub;
|
||||
xpcomStub = new nsJavaXPTCStub(mJavaEnv, java_obj, iinfo);
|
||||
if (!xpcomStub) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
inst = SetAsXPTCStub(xpcomStub);
|
||||
rv = gBindings->AddBinding(mJavaEnv, java_obj, inst);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
}
|
||||
|
||||
// Get appropriate XPCOM object
|
||||
void* xpcom_obj;
|
||||
if (isWeakRef) {
|
||||
// If the function expects an weak reference, then we need to
|
||||
// create it here.
|
||||
nsJavaXPTCStubWeakRef* weakref;
|
||||
weakref = new nsJavaXPTCStubWeakRef(mJavaEnv, java_obj);
|
||||
if (!weakref) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
NS_ADDREF(weakref);
|
||||
xpcom_obj = weakref;
|
||||
} else if (IsXPTCStub(inst)) {
|
||||
nsJavaXPTCStub* xpcomStub = GetXPTCStubAddr(inst);
|
||||
NS_ADDREF(xpcomStub);
|
||||
xpcom_obj = xpcomStub;
|
||||
// If the requested interface is nsIWeakReference, then we look for or
|
||||
// create a stub for the nsISupports interface. Then we create a weak
|
||||
// reference from that stub.
|
||||
PRBool isWeakRef;
|
||||
if (iid.Equals(NS_GET_IID(nsIWeakReference))) {
|
||||
isWeakRef = PR_TRUE;
|
||||
iid = NS_GET_IID(nsISupports);
|
||||
} else {
|
||||
JavaXPCOMInstance* xpcomInst = (JavaXPCOMInstance*) inst;
|
||||
xpcom_obj = xpcomInst->GetInstance();
|
||||
isWeakRef = PR_FALSE;
|
||||
}
|
||||
|
||||
nsISupports* xpcom_obj;
|
||||
PRBool isXPTCStub;
|
||||
rv = GetNewOrUsedXPCOMObject(mJavaEnv, java_obj, iid, &xpcom_obj,
|
||||
&isXPTCStub);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
// If the function expects a weak reference, then we need to
|
||||
// create it here.
|
||||
if (isWeakRef) {
|
||||
if (isXPTCStub) {
|
||||
nsJavaXPTCStub* stub = NS_STATIC_CAST(nsJavaXPTCStub*,
|
||||
NS_STATIC_CAST(nsXPTCStubBase*,
|
||||
xpcom_obj));
|
||||
nsJavaXPTCStubWeakRef* weakref;
|
||||
weakref = new nsJavaXPTCStubWeakRef(mJavaEnv, java_obj, stub);
|
||||
if (!weakref) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
xpcom_obj = weakref;
|
||||
NS_ADDREF(xpcom_obj);
|
||||
} else { // if is native XPCOM object
|
||||
nsCOMPtr<nsISupportsWeakReference> supportsweak =
|
||||
do_QueryInterface(xpcom_obj);
|
||||
if (supportsweak) {
|
||||
nsWeakPtr weakref;
|
||||
supportsweak->GetWeakReference(getter_AddRefs(weakref));
|
||||
xpcom_obj = weakref;
|
||||
NS_ADDREF(xpcom_obj);
|
||||
} else {
|
||||
xpcom_obj = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!isXPTCStub) { // if is native XPCOM object
|
||||
xpcom_obj->Release();
|
||||
}
|
||||
|
||||
// } else if (isXPTCStub) {
|
||||
// nothing to do
|
||||
|
||||
if (*variant && !aParamInfo.IsRetval()) {
|
||||
NS_RELEASE(*variant);
|
||||
}
|
||||
*variant = (nsISupports*) xpcom_obj;
|
||||
*variant = xpcom_obj;
|
||||
} else {
|
||||
// If were passed in an object, release it now, and set to null.
|
||||
if (*variant && !aParamInfo.IsRetval()) {
|
||||
@@ -1565,13 +1606,15 @@ nsJavaXPTCStub::GetWeakReference(nsIWeakReference** aInstancePtr)
|
||||
if (!aInstancePtr)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
jobject javaObject = mJavaEnv->NewLocalRef(mJavaWeakRef);
|
||||
nsJavaXPTCStubWeakRef* weakref;
|
||||
weakref = new nsJavaXPTCStubWeakRef(mJavaEnv, mJavaObject);
|
||||
weakref = new nsJavaXPTCStubWeakRef(mJavaEnv, javaObject, this);
|
||||
if (!weakref)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
*aInstancePtr = weakref;
|
||||
NS_ADDREF(*aInstancePtr);
|
||||
++mWeakRefCnt;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -1579,5 +1622,18 @@ nsJavaXPTCStub::GetWeakReference(nsIWeakReference** aInstancePtr)
|
||||
jobject
|
||||
nsJavaXPTCStub::GetJavaObject()
|
||||
{
|
||||
return mJavaObject;
|
||||
jobject javaObject = mJavaEnv->NewLocalRef(mJavaWeakRef);
|
||||
|
||||
#ifdef DEBUG_JAVAXPCOM
|
||||
nsIID* iid;
|
||||
mIInfo->GetInterfaceIID(&iid);
|
||||
char* iid_str = iid->ToString();
|
||||
LOG(("< nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n",
|
||||
mJavaEnv->CallIntMethod(javaObject, hashCodeMID),
|
||||
(int) this, iid_str));
|
||||
PR_Free(iid_str);
|
||||
nsMemory::Free(iid);
|
||||
#endif
|
||||
|
||||
return javaObject;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
class nsJavaXPTCStub : public nsXPTCStubBase,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
friend class nsJavaXPTCStubWeakRef;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSWEAKREFERENCE
|
||||
@@ -76,14 +78,23 @@ public:
|
||||
jobject GetJavaObject();
|
||||
|
||||
private:
|
||||
// NS_HIDDEN ~JavaStub();
|
||||
NS_IMETHOD_(nsrefcnt) AddRefInternal();
|
||||
NS_IMETHOD_(nsrefcnt) ReleaseInternal();
|
||||
|
||||
// Deletes this object and its members. Called by ReleaseInternal() and
|
||||
// ReleaseWeakRef().
|
||||
void Destroy();
|
||||
|
||||
// When a nsJavaXPTCStubWeakRef associated with this object is released, it
|
||||
// calls this function to let this object know that there is one less weak
|
||||
// ref. If there are no more weakrefs referencing this object, and no one
|
||||
// holds a strong ref, then this function takes care of deleting the object.
|
||||
void ReleaseWeakRef();
|
||||
|
||||
// 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,
|
||||
@@ -103,23 +114,14 @@ private:
|
||||
nsresult SetXPCOMRetval();
|
||||
|
||||
JNIEnv* mJavaEnv;
|
||||
jobject mJavaObject;
|
||||
jweak mJavaWeakRef;
|
||||
jobject mJavaStrongRef;
|
||||
nsCOMPtr<nsIInterfaceInfo> mIInfo;
|
||||
|
||||
nsVoidArray mChildren; // weak references (cleared by the children)
|
||||
nsJavaXPTCStub *mMaster; // strong reference
|
||||
|
||||
nsAutoRefCnt mWeakRefCnt; // count for number of associated weak refs
|
||||
};
|
||||
|
||||
inline void* SetAsXPTCStub(nsJavaXPTCStub* ptr)
|
||||
{ NS_PRECONDITION(ptr, "null pointer");
|
||||
return (void*) (((unsigned long) ptr) | 0x1); }
|
||||
|
||||
inline PRBool IsXPTCStub(void* ptr)
|
||||
{ NS_PRECONDITION(ptr, "null pointer");
|
||||
return ((unsigned long) ptr) & 0x1; }
|
||||
|
||||
inline nsJavaXPTCStub* GetXPTCStubAddr(void* ptr)
|
||||
{ NS_PRECONDITION(ptr, "null pointer");
|
||||
return (nsJavaXPTCStub*) (((unsigned long) ptr) & ~0x1); }
|
||||
|
||||
#endif // _nsJavaXPTCStub_h_
|
||||
|
||||
@@ -42,15 +42,32 @@
|
||||
#include "nsIInterfaceInfoManager.h"
|
||||
|
||||
|
||||
nsJavaXPTCStubWeakRef::nsJavaXPTCStubWeakRef(JNIEnv* env, jobject aJavaObject)
|
||||
/**
|
||||
* How we handle XPCOM weak references to a Java object:
|
||||
*
|
||||
* If XPCOM requires or asks for a weak reference of a Java object, we first
|
||||
* find (or create) an nsJavaXPTCStub for that Java object. That way, there is
|
||||
* always an nsJavaXPTCStub for any nsJavaXPTCStubWeakRef. However, the
|
||||
* XPTCStub may not always be 'valid'; that is, its refcount may be zero if
|
||||
* is not currently referenced by any XPCOM class.
|
||||
* When an XPCOM method queries the referent from the weak reference, the
|
||||
* weak ref checks first whether the Java object is still valid. If so, we can
|
||||
* immediately return an addref'd nsJavaXPTCStub. The XPTCStub takes care of
|
||||
* finding an XPTCStub for the required IID.
|
||||
*/
|
||||
|
||||
nsJavaXPTCStubWeakRef::nsJavaXPTCStubWeakRef(JNIEnv* env, jobject aJavaObject,
|
||||
nsJavaXPTCStub* aXPTCStub)
|
||||
: mJavaEnv(env)
|
||||
, mXPTCStub(aXPTCStub)
|
||||
{
|
||||
mJavaEnv = env;
|
||||
mWeakRef = mJavaEnv->NewWeakGlobalRef(aJavaObject);
|
||||
}
|
||||
|
||||
nsJavaXPTCStubWeakRef::~nsJavaXPTCStubWeakRef()
|
||||
{
|
||||
mJavaEnv->DeleteWeakGlobalRef(mWeakRef);
|
||||
mXPTCStub->ReleaseWeakRef();
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsJavaXPTCStubWeakRef)
|
||||
@@ -61,6 +78,8 @@ NS_IMPL_QUERY_INTERFACE1(nsJavaXPTCStubWeakRef, nsIWeakReference)
|
||||
NS_IMETHODIMP
|
||||
nsJavaXPTCStubWeakRef::QueryReferent(const nsIID& aIID, void** aInstancePtr)
|
||||
{
|
||||
LOG(("nsJavaXPTCStubWeakRef::QueryReferent()\n"));
|
||||
|
||||
// Is weak ref still valid?
|
||||
// We create a strong local ref to make sure Java object isn't garbage
|
||||
// collected during this call.
|
||||
@@ -68,35 +87,7 @@ nsJavaXPTCStubWeakRef::QueryReferent(const nsIID& aIID, void** aInstancePtr)
|
||||
if (!javaObject)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// Java object has not been garbage collected. Do we have an
|
||||
// associated nsJavaXPTCStub?
|
||||
void* inst = gBindings->GetXPCOMObject(mJavaEnv, javaObject);
|
||||
|
||||
if (!inst) {
|
||||
// No XPTCStub exists, so create one
|
||||
|
||||
// Get interface info for class
|
||||
nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
|
||||
nsCOMPtr<nsIInterfaceInfo> iinfo;
|
||||
nsresult rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Create XPCOM stub
|
||||
nsJavaXPTCStub* xpcomStub = new nsJavaXPTCStub(mJavaEnv, javaObject, iinfo);
|
||||
if (!xpcomStub)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(xpcomStub);
|
||||
gBindings->AddBinding(mJavaEnv, javaObject, SetAsXPTCStub(xpcomStub));
|
||||
|
||||
// return created stub
|
||||
*aInstancePtr = (void*) xpcomStub;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ASSERTION(IsXPTCStub(inst), "Found xpcom object was not an XPTCStub");
|
||||
|
||||
// We have an exising XPTCStub, so return QI result
|
||||
nsJavaXPTCStub* xpcomStub = GetXPTCStubAddr(inst);
|
||||
return xpcomStub->QueryInterface(aIID, aInstancePtr);
|
||||
// Java object has not been garbage collected, so return QI from XPTCStub.
|
||||
return mXPTCStub->QueryInterface(aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,17 +42,24 @@
|
||||
#include "nsIWeakReference.h"
|
||||
|
||||
|
||||
class nsJavaXPTCStub;
|
||||
|
||||
/**
|
||||
* This class represents an XPCOM weak reference to a Java object.
|
||||
*/
|
||||
class nsJavaXPTCStubWeakRef : public nsIWeakReference
|
||||
{
|
||||
public:
|
||||
nsJavaXPTCStubWeakRef(JNIEnv* env, jobject aJavaObject);
|
||||
nsJavaXPTCStubWeakRef(JNIEnv* env, jobject aJavaObject,
|
||||
nsJavaXPTCStub* aXPTCStub);
|
||||
virtual ~nsJavaXPTCStubWeakRef();
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIWEAKREFERENCE
|
||||
|
||||
protected:
|
||||
JNIEnv* mJavaEnv;
|
||||
jweak mWeakRef;
|
||||
JNIEnv* mJavaEnv;
|
||||
jweak mWeakRef;
|
||||
nsJavaXPTCStub* mXPTCStub;
|
||||
};
|
||||
|
||||
#endif // _nsJavaXPTCStubWeakRef_h_
|
||||
|
||||
@@ -46,7 +46,8 @@ public class Foo implements IFoo {
|
||||
{
|
||||
mID = aID;
|
||||
++gCount;
|
||||
System.out.println("init: " + mID + " (" + this.hashCode() + "), " +
|
||||
System.out.println("init: " + mID + " (" +
|
||||
Integer.toHexString(this.hashCode()) + "), " +
|
||||
gCount +" total");
|
||||
}
|
||||
|
||||
@@ -65,7 +66,8 @@ public class Foo implements IFoo {
|
||||
protected void finalize() throws Throwable
|
||||
{
|
||||
--gCount;
|
||||
System.out.println("destruct: " + mID + " (" + this.hashCode() + "), " +
|
||||
System.out.println("destruct: " + mID + " (" +
|
||||
Integer.toHexString(this.hashCode()) + "), " +
|
||||
gCount +" remain");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ JAVA_SRCS = \
|
||||
TestArray.java \
|
||||
TestProps.java \
|
||||
TestQI.java \
|
||||
TestJavaProxy.java \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
|
||||
@@ -211,7 +211,8 @@ public class TestArray {
|
||||
for (int index = 0; (index < count) && (index < aExpectedCount); index++) {
|
||||
IFoo foo = (IFoo) aArray.queryElementAt(index, IFoo.IFOO_IID);
|
||||
System.out.println(index + ": " + aElementIDs[index] + "=" +
|
||||
foo.getId() + " (" + foo.hashCode() + ") " +
|
||||
foo.getId() + " (" +
|
||||
Integer.toHexString(foo.hashCode()) + ") " +
|
||||
assertEqual(foo.getId(), aElementIDs[index]));
|
||||
foo = null;
|
||||
}
|
||||
|
||||
76
mozilla/extensions/java/xpcom/tests/TestJavaProxy.java
Normal file
76
mozilla/extensions/java/xpcom/tests/TestJavaProxy.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/* ***** 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 ***** */
|
||||
|
||||
import org.mozilla.xpcom.*;
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* Tests that if calls to XPCOM functions return the same object, then
|
||||
* the Javaconnect interface creates the proper Java proxies.
|
||||
* <p>
|
||||
* The XPCOM call to <code>nsISupports supp = entries.getNext()</code> returns
|
||||
* an object, for which we create an <code>nsISupports</code> Java proxy. Then,
|
||||
* the XPCOM call to <code>supp.queryInterface(nsIFile.NS_IFILE_IID)</code>
|
||||
* will return the same object (same address). Javaconnect needs to be smart
|
||||
* enough to create a new <code>nsIFile</code> proxy, rather than reusing the
|
||||
* <code>nsISupports</code> one that was previously created.
|
||||
* </p>
|
||||
*/
|
||||
public class TestJavaProxy {
|
||||
public static void main(String [] args) throws Exception {
|
||||
System.loadLibrary("javaxpcom");
|
||||
|
||||
String mozillaPath = System.getProperty("MOZILLA_FIVE_HOME");
|
||||
if (mozillaPath == null) {
|
||||
throw new RuntimeException("MOZILLA_FIVE_HOME system property not set.");
|
||||
}
|
||||
|
||||
File localFile = new File(mozillaPath);
|
||||
XPCOM.initXPCOM(localFile, null);
|
||||
|
||||
nsILocalFile directory = XPCOM.newLocalFile("/usr", false);
|
||||
nsISimpleEnumerator entries = (nsISimpleEnumerator) directory.getDirectoryEntries();
|
||||
while (entries.hasMoreElements()) {
|
||||
nsISupports supp = entries.getNext();
|
||||
nsIFile file = (nsIFile) supp.queryInterface(nsIFile.NS_IFILE_IID);
|
||||
System.out.println(file.getPath());
|
||||
}
|
||||
|
||||
XPCOM.shutdownXPCOM(null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user