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:
pedemont%us.ibm.com
2005-02-24 21:53:46 +00:00
parent e3695895b7
commit adc22c6db9
11 changed files with 926 additions and 579 deletions

View File

@@ -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;
}
}

View File

@@ -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 &paramInfo, PRUint16 methodIndex,

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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_

View File

@@ -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);
}

View File

@@ -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_

View File

@@ -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");
}
}

View File

@@ -54,6 +54,7 @@ JAVA_SRCS = \
TestArray.java \
TestProps.java \
TestQI.java \
TestJavaProxy.java \
$(NULL)
ifeq ($(OS_ARCH),WINNT)

View File

@@ -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;
}

View 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);
}
}