Back to index

lightning-sunbird  0.9+nobinonly
nsProxyEventClass.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 
00040 #include "nsProxyEvent.h"
00041 #include "nsIProxyObjectManager.h"
00042 #include "nsProxyEventPrivate.h"
00043 
00044 #include "nsIComponentManager.h"
00045 #include "nsIServiceManager.h"
00046 #include "nsCOMPtr.h"
00047 
00048 #include "nsMemory.h"
00049 #include "nsHashtable.h"
00050 
00051 #include "nsAutoLock.h"
00052 #include "nsIInterfaceInfoManager.h"
00053 #include "xptcall.h"
00054 
00055 // LIFETIME_CACHE will cache class for the entire cyle of the application.
00056 #define LIFETIME_CACHE
00057 
00058 static uint32 zero_methods_descriptor;
00059 
00060 
00061 /* ssc@netscape.com wishes he could get rid of this instance of
00062  * |NS_DEFINE_IID|, but |ProxyEventClassIdentity| is not visible from
00063  * here.
00064  */
00065 static NS_DEFINE_IID(kProxyObject_Identity_Class_IID, NS_PROXYEVENT_IDENTITY_CLASS_IID);
00066 
00068 //  nsProxyEventClass
00070 NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyEventClass, nsProxyEventClass)
00071 
00072 // static
00073 nsProxyEventClass*
00074 nsProxyEventClass::GetNewOrUsedClass(REFNSIID aIID)
00075 {
00076     /* find in our hash table */
00077     
00078     nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance();
00079     if (manager == nsnull) return nsnull;
00080        
00081        // dont need to lock the map, because this is only called
00082        // by nsProxyEventClass::GetNewOrUsed which locks it for us.
00083 
00084        nsHashtable *iidToClassMap =  manager->GetIIDToProxyClassMap();
00085     
00086     if (iidToClassMap == nsnull)
00087     {
00088         return nsnull;
00089     }
00090 
00091     nsProxyEventClass* clazz = nsnull;
00092     nsIDKey key(aIID);
00093 
00094 #ifdef PROXYEVENTCLASS_DEBUG 
00095        char* iidStr = aIID.ToString();
00096        printf("GetNewOrUsedClass  %s\n", iidStr);
00097        nsCRT::free(iidStr);
00098 #endif
00099 
00100     clazz = (nsProxyEventClass*) iidToClassMap->Get(&key);
00101        if(clazz)
00102        {
00103         NS_ADDREF(clazz);
00104 #ifdef PROXYEVENTCLASS_DEBUG
00105               char* iidStr = aIID.ToString();
00106               printf("GetNewOrUsedClass  %s hit\n", iidStr);
00107               nsCRT::free(iidStr);
00108 #endif
00109     }
00110     else
00111     {
00112         nsCOMPtr<nsIInterfaceInfoManager> iimgr = getter_AddRefs(XPTI_GetInterfaceInfoManager());
00113         if(iimgr)
00114         {
00115             nsCOMPtr<nsIInterfaceInfo> info;
00116             if(NS_SUCCEEDED(iimgr->GetInfoForIID(&aIID, getter_AddRefs(info))))
00117             {
00118                 /* 
00119                    Check to see if isISupportsDescendent 
00120                 */
00121                 nsCOMPtr<nsIInterfaceInfo> oldest = info;
00122                 nsCOMPtr<nsIInterfaceInfo> parent;
00123 
00124                 while(NS_SUCCEEDED(oldest->GetParent(getter_AddRefs(parent)))&&
00125                       parent)
00126                 {
00127                     oldest = parent;
00128                 }
00129 
00130                 PRBool isISupportsDescendent = PR_FALSE;
00131                 nsID* iid;
00132                 if(NS_SUCCEEDED(oldest->GetInterfaceIID(&iid))) 
00133                 {
00134                     isISupportsDescendent = iid->Equals(NS_GET_IID(nsISupports));
00135                     nsMemory::Free(iid);
00136                 }
00137                 
00138                 NS_ASSERTION(isISupportsDescendent, "!isISupportsDescendent");
00139 
00140                 if (isISupportsDescendent)  
00141                 {
00142                     clazz = new nsProxyEventClass(aIID, info);
00143                     if(!clazz->mDescriptors)
00144                         NS_RELEASE(clazz);  // sets clazz to NULL
00145                 }
00146             }
00147         }
00148     }
00149     return clazz;
00150 }
00151 
00152 nsProxyEventClass::nsProxyEventClass()
00153 {
00154     NS_WARNING("This constructor should never be called");
00155 }
00156 
00157 nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo)
00158 : mIID(aIID),
00159   mDescriptors(NULL)
00160 {
00161     NS_ADDREF_THIS();
00162     
00163     mInfo = aInfo;
00164 
00165     /* add use to the used classes */
00166     nsIDKey key(aIID);
00167 
00168     nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance();
00169     if (manager == nsnull) return;
00170        // dont need to lock the map, because this is only called
00171        // by GetNewOrUsed which locks it for us.
00172 
00173        nsHashtable *iidToClassMap =  manager->GetIIDToProxyClassMap();
00174     
00175     if (iidToClassMap != nsnull)
00176     {
00177         iidToClassMap->Put(&key, this);
00178 #ifdef LIFETIME_CACHE
00179               // extra addref to hold it in the cache
00180         NS_ADDREF_THIS();
00181 #endif
00182 #ifdef PROXYEVENTCLASS_DEBUG
00183               char* iidStr = aIID.ToString();
00184               printf("GetNewOrUsedClass  %s put\n", iidStr);
00185               nsCRT::free(iidStr);
00186 #endif
00187     }
00188 
00189     uint16 methodCount;
00190     if(NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount)))
00191     {
00192         if(methodCount)
00193         {
00194             int wordCount = (methodCount/32)+1;
00195             if(NULL != (mDescriptors = new uint32[wordCount]))
00196             {
00197                 memset(mDescriptors, 0, wordCount * sizeof(uint32));
00198             }
00199         }
00200         else
00201         {
00202             mDescriptors = &zero_methods_descriptor;
00203         }
00204     }
00205 }
00206 
00207 nsProxyEventClass::~nsProxyEventClass()
00208 {
00209     if(mDescriptors && mDescriptors != &zero_methods_descriptor)
00210         delete [] mDescriptors;
00211 
00212     if (nsProxyObjectManager::IsManagerShutdown())
00213         return;
00214 
00215 #ifndef LIFETIME_CACHE
00216     nsIDKey key(mIID);
00217                 
00218     nsCOMPtr<nsProxyObjectManager> manager = getter_AddRefs(nsProxyObjectManager::GetInstance());
00219     if (manager == nsnull) return;
00220        nsHashtable *iidToClassMap =  manager->GetIIDToProxyClassMap();
00221     
00222     if (iidToClassMap != nsnull)
00223     {
00224         iidToClassMap->Remove(&key);
00225 #ifdef PROXYEVENTCLASS_DEBUG
00226               char* iidStr = mIID.ToString();
00227               printf("GetNewOrUsedClass  %s remove\n", iidStr);
00228               nsCRT::free(iidStr);
00229 #endif
00230     }
00231 #endif
00232 }
00233 
00234 nsresult
00235 nsProxyEventClass::CallQueryInterfaceOnProxy(nsProxyEventObject* self, REFNSIID aIID, nsProxyEventObject** aInstancePtr)
00236 {
00237     NS_PRECONDITION(aInstancePtr, "Requires non-null result");
00238 
00239     nsresult rv;
00240 
00241     *aInstancePtr = nsnull;  // in case of error.
00242 
00243 
00244     // The functions we will call: QueryInterface(REFNSIID aIID, void** aInstancePtr)
00245 
00246     nsXPTCMiniVariant var[2];
00247 
00248     var[0].val.p     = (void*)&aIID;
00249     var[1].val.p     = (void*)aInstancePtr;
00250 
00251     nsCOMPtr<nsIInterfaceInfo> interfaceInfo;
00252     const nsXPTMethodInfo *mi;
00253 
00254     nsCOMPtr<nsIInterfaceInfoManager> iim = getter_AddRefs(XPTI_GetInterfaceInfoManager());
00255 
00256     if (!iim) return NS_NOINTERFACE;
00257     iim->GetInfoForName("nsISupports", getter_AddRefs(interfaceInfo));
00258     interfaceInfo->GetMethodInfo(0, &mi); // 0 is QueryInterface
00259 
00260     rv = self->CallMethod(0, mi, var);
00261 
00262     if (NS_SUCCEEDED(rv))
00263     {
00264         nsISupports *aIdentificationObject;
00265 
00266         rv = (*aInstancePtr)->QueryInterface(kProxyObject_Identity_Class_IID, (void**)&aIdentificationObject);
00267 
00268         if (NS_FAILED(rv))
00269         {
00270             // okay, aInstancePtr was not a proxy.  Lets create one.
00271             nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance();
00272             if (manager == nsnull) 
00273             {
00274                 NS_IF_RELEASE((*aInstancePtr));
00275                 return NS_ERROR_FAILURE;
00276             }
00277 
00278             rv = manager->GetProxyForObject(self->GetQueue(), 
00279                                             aIID, 
00280                                             self->GetRealObject(), 
00281                                             self->GetProxyType(),
00282                                             (void**) &aIdentificationObject);
00283         }
00284 
00285         NS_IF_RELEASE((*aInstancePtr));
00286         (*aInstancePtr) = NS_STATIC_CAST(nsProxyEventObject*, aIdentificationObject);
00287     }
00288     return rv;
00289 }
00290 
00291 
00292 /***************************************************************************/
00293 // This 'ProxyEventClassIdentity' class and singleton allow us to figure out if
00294 // any given nsISupports* is implemented by a nsProxy object. This is done
00295 // using a QueryInterface call on the interface pointer with our ID. If
00296 // that call returns NS_OK and the pointer is to a nsProxyEventObject.  It must
00297 // be released when done.
00298 
00299 // NS_PROXYEVENT_IDENTITY_CLASS_IID defined in nsProxyEventPrivate.h
00300 class ProxyEventClassIdentity
00301 {
00302     // no instance methods...
00303 public:
00304     NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_IDENTITY_CLASS_IID)
00305 
00306     static void* GetSingleton()
00307     {
00308         static ProxyEventClassIdentity* singleton = NULL;
00309         if(!singleton)
00310             singleton = new ProxyEventClassIdentity();
00311         return (void*) singleton;
00312     }
00313 };
00314 
00315 NS_IMETHODIMP
00316 nsProxyEventClass::DelegatedQueryInterface(nsProxyEventObject* self,
00317                                           REFNSIID aIID,
00318                                           void** aInstancePtr)
00319 {
00320     
00321     if(aIID.Equals(NS_GET_IID(ProxyEventClassIdentity)))
00322     {
00323         *aInstancePtr = NS_STATIC_CAST(void*, self);  
00324         NS_ADDREF(self);
00325         return NS_OK;
00326     }
00327 
00328     nsProxyEventObject* sibling;
00329     {
00330     nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance();
00331     nsAutoMonitor mon(manager->GetMonitor());
00332 
00333     // This includes checking for nsISupports and the iid of self.
00334     // And it also checks for other wrappers that have been constructed
00335     // for this object.
00336     if(nsnull != (sibling = self->LockedFind(aIID)))
00337     {
00338         NS_ADDREF(sibling);
00339         *aInstancePtr = (void*) sibling;
00340         return NS_OK;
00341     }
00342 
00343     // check if asking for an interface that we inherit from
00344     nsCOMPtr<nsIInterfaceInfo> current = GetInterfaceInfo();
00345     nsCOMPtr<nsIInterfaceInfo> parent;
00346 
00347     while(NS_SUCCEEDED(current->GetParent(getter_AddRefs(parent))) && parent)
00348     {
00349         current = parent;
00350 
00351         nsIID* iid;
00352         if(NS_SUCCEEDED(current->GetInterfaceIID(&iid)) && iid)
00353         {
00354             PRBool found = aIID.Equals(*iid);
00355             nsMemory::Free(iid);
00356             if(found)
00357             {
00358                 *aInstancePtr = (void*) self;
00359                 NS_ADDREF(self);
00360                 return NS_OK;
00361             }
00362         }
00363     }
00364     }
00365 
00366     return CallQueryInterfaceOnProxy(self, aIID, (nsProxyEventObject**)aInstancePtr);
00367 }