Back to index

lightning-sunbird  0.9+nobinonly
nsProxyObjectManager.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  *   Doug Turner <dougt@netscape.com> (Original Author)
00024  *   Judson Valeski <valeski@netscape.com>
00025  *   Dan Matejka <danm@netscape.com>
00026  *   Scott Collins <scc@netscape.com>
00027  *   Heikki Toivonen <heiki@citec.fi>
00028  *   Patrick Beard <beard@netscape.com>
00029  *   Pierre Phaneuf <pp@ludusdesign.com>
00030  *   Warren Harris <warren@netscape.com>
00031  *   Chris Seawood <cls@seawood.org>
00032  *   Chris Waterson <waterson@netscape.com>
00033  *   Dan Mosedale <dmose@netscape.com>
00034  *
00035  * Alternatively, the contents of this file may be used under the terms of
00036  * either of the GNU General Public License Version 2 or later (the "GPL"),
00037  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00038  * in which case the provisions of the GPL or the LGPL are applicable instead
00039  * of those above. If you wish to allow use of your version of this file only
00040  * under the terms of either the GPL or the LGPL, and not to allow others to
00041  * use your version of this file under the terms of the MPL, indicate your
00042  * decision by deleting the provisions above and replace them with the notice
00043  * and other provisions required by the GPL or the LGPL. If you do not delete
00044  * the provisions above, a recipient may use your version of this file under
00045  * the terms of any one of the MPL, the GPL or the LGPL.
00046  *
00047  * ***** END LICENSE BLOCK ***** */
00048 
00049 
00050 #include "nsProxyEvent.h"
00051 #include "nsIProxyObjectManager.h"
00052 #include "nsProxyEventPrivate.h"
00053 
00054 #include "nsIProxyCreateInstance.h"
00055 
00056 #include "nsIComponentManager.h"
00057 #include "nsIServiceManager.h"
00058 #include "nsCOMPtr.h"
00059 
00060 #include "nsIEventQueueService.h"
00061 #include "nsIThread.h"
00062 
00063 
00064 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00065 
00066 /***************************************************************************/
00067 /* nsProxyCreateInstance                                                   */
00068 /* This private class will allow us to create Instances on another thread  */
00069 /***************************************************************************/
00070 class nsProxyCreateInstance : public nsIProxyCreateInstance
00071 {
00072     NS_DECL_ISUPPORTS
00073     NS_IMETHOD CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result);
00074     NS_IMETHOD CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result);
00075 
00076     nsProxyCreateInstance()
00077     {
00078         NS_GetComponentManager(getter_AddRefs(mCompMgr));
00079         NS_ASSERTION(mCompMgr, "no component manager");
00080     }
00081 
00082 private:
00083 
00084     nsCOMPtr<nsIComponentManager> mCompMgr;
00085 };
00086 
00087 NS_IMPL_ISUPPORTS1(nsProxyCreateInstance, nsIProxyCreateInstance)
00088 
00089 NS_IMETHODIMP nsProxyCreateInstance::CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result)
00090 {
00091     return mCompMgr->CreateInstance(cid, 
00092                                     aOuter,
00093                                     iid,
00094                                     result);
00095 }
00096 
00097 
00098 NS_IMETHODIMP nsProxyCreateInstance::CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result)
00099 {
00100     return mCompMgr->CreateInstanceByContractID(aContractID, 
00101                                                 aOuter,
00102                                                 iid,
00103                                                 result);
00104 }
00105 
00107 // nsProxyObjectManager
00109 
00110 nsProxyObjectManager* nsProxyObjectManager::mInstance = nsnull;
00111 
00112 NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyObjectManager, nsIProxyObjectManager)
00113 
00114 nsProxyObjectManager::nsProxyObjectManager()
00115     : mProxyObjectMap(256, PR_TRUE),
00116       mProxyClassMap(256, PR_TRUE)
00117 {
00118     mProxyCreationMonitor = PR_NewMonitor();
00119 }
00120 
00121 static PRBool PurgeProxyClasses(nsHashKey *aKey, void *aData, void* closure)
00122 {
00123     nsProxyEventClass* ptr = NS_REINTERPRET_CAST(nsProxyEventClass*, aData);
00124     NS_RELEASE(ptr);
00125     return PR_TRUE;
00126 }
00127 
00128 nsProxyObjectManager::~nsProxyObjectManager()
00129 {
00130     mProxyClassMap.Reset((nsHashtableEnumFunc)PurgeProxyClasses, nsnull);
00131 
00132     if (mProxyCreationMonitor) {
00133         PR_DestroyMonitor(mProxyCreationMonitor);
00134     }
00135 
00136     nsProxyObjectManager::mInstance = nsnull;
00137 }
00138 
00139 PRBool
00140 nsProxyObjectManager::IsManagerShutdown()
00141 {
00142     if (mInstance) 
00143         return PR_FALSE;
00144     return PR_TRUE;
00145 }
00146 
00147 nsProxyObjectManager *
00148 nsProxyObjectManager::GetInstance()
00149 {
00150     if (! mInstance) 
00151     {
00152         mInstance = new nsProxyObjectManager();
00153     }
00154     return mInstance;
00155 }
00156 
00157 
00158 void
00159 nsProxyObjectManager::Shutdown()
00160 {
00161     mInstance = nsnull;
00162 }
00163 
00164 
00165 // Helpers
00166 NS_IMETHODIMP 
00167 nsProxyObjectManager::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
00168 {
00169     nsProxyObjectManager *proxyObjectManager = GetInstance();
00170 
00171     if (proxyObjectManager == nsnull)
00172         return NS_ERROR_OUT_OF_MEMORY;
00173 
00174     return proxyObjectManager->QueryInterface(aIID, aInstancePtr);
00175 }
00176 
00177 
00178 NS_IMETHODIMP 
00179 nsProxyObjectManager::GetProxyForObject(nsIEventQueue *destQueue, 
00180                                         REFNSIID aIID, 
00181                                         nsISupports* aObj, 
00182                                         PRInt32 proxyType, 
00183                                         void** aProxyObject)
00184 {
00185     if (!aObj) return NS_ERROR_NULL_POINTER;
00186     if (!aProxyObject) return NS_ERROR_NULL_POINTER;
00187 
00188     nsresult rv;
00189     nsCOMPtr<nsIEventQueue> postQ;
00190     
00191 
00192     *aProxyObject = nsnull;
00193 
00194     //  check to see if the destination Q is a special case.
00195     
00196     nsCOMPtr<nsIEventQueueService> eventQService = 
00197              do_GetService(kEventQueueServiceCID, &rv);
00198     if (NS_FAILED(rv)) 
00199         return rv;
00200     
00201     rv = eventQService->ResolveEventQueue(destQueue, getter_AddRefs(postQ));
00202     if (NS_FAILED(rv)) 
00203         return rv;
00204     
00205     // check to see if the eventQ is on our thread.  If so, just return the real object.
00206     
00207     if (postQ && !(proxyType & PROXY_ASYNC) && !(proxyType & PROXY_ALWAYS))
00208     {
00209         PRBool aResult;
00210         postQ->IsOnCurrentThread(&aResult);
00211      
00212         if (aResult)
00213         {
00214             return aObj->QueryInterface(aIID, aProxyObject);
00215         }
00216     }
00217     
00218     // check to see if proxy is there or not.
00219     *aProxyObject = nsProxyEventObject::GetNewOrUsedProxy(postQ, proxyType, aObj, aIID);
00220     
00221     if (*aProxyObject == nsnull)
00222         return NS_ERROR_NO_INTERFACE; //fix error code?
00223         
00224     return NS_OK;   
00225 }   
00226 
00227 
00228 NS_IMETHODIMP 
00229 nsProxyObjectManager::GetProxy(  nsIEventQueue *destQueue, 
00230                                  const nsCID &aClass, 
00231                                  nsISupports *aDelegate, 
00232                                  const nsIID &aIID, 
00233                                  PRInt32 proxyType, 
00234                                  void** aProxyObject)
00235 {
00236     if (!aProxyObject) return NS_ERROR_NULL_POINTER;
00237     *aProxyObject = nsnull;
00238     
00239     // 1. Create a proxy for creating an instance on another thread.
00240 
00241     nsIProxyCreateInstance* ciProxy = nsnull;
00242 
00243     nsProxyCreateInstance* ciObject = new nsProxyCreateInstance(); 
00244     
00245     if (ciObject == nsnull)
00246         return NS_ERROR_NULL_POINTER;
00247 
00248     NS_ADDREF(ciObject);
00249     
00250     nsresult rv = GetProxyForObject(destQueue, 
00251                                     NS_GET_IID(nsIProxyCreateInstance), 
00252                                     ciObject, 
00253                                     PROXY_SYNC, 
00254                                     (void**)&ciProxy);
00255     
00256     if (NS_FAILED(rv))
00257     {
00258         NS_RELEASE(ciObject);
00259         return rv;
00260     }
00261         
00262     // 2. now create a new instance of the request object via our proxy.
00263 
00264     nsISupports* aObj;
00265 
00266     rv = ciProxy->CreateInstanceByIID(aClass, 
00267                                       aDelegate, 
00268                                       aIID, 
00269                                       (void**)&aObj);
00270 
00271     
00272     // 3.  Delete the create instance proxy and its real object.
00273     
00274     NS_RELEASE(ciProxy);
00275     NS_RELEASE(ciObject);
00276 
00277     // 4.  Check to see if creating the requested instance failed.
00278     if ( NS_FAILED(rv))
00279     {
00280         return rv;
00281     }
00282 
00283     // 5.  Now create a proxy object for the requested object.
00284 
00285     rv = GetProxyForObject(destQueue, aIID, aObj, proxyType, aProxyObject);
00286 
00287     // 6. release ownership of aObj so that aProxyObject owns it.
00288     
00289     NS_RELEASE(aObj);
00290 
00291     // 7. return the error returned from GetProxyForObject.  Either way, we our out of here.
00292 
00293     return rv;   
00294 }
00295 
00303 NS_COM nsresult
00304 NS_GetProxyForObject(nsIEventQueue *destQueue, 
00305                      REFNSIID aIID, 
00306                      nsISupports* aObj, 
00307                      PRInt32 proxyType, 
00308                      void** aProxyObject) 
00309 {
00310     static NS_DEFINE_CID(proxyObjMgrCID, NS_PROXYEVENT_MANAGER_CID);
00311 
00312     nsresult rv;    // temp for return value
00313 
00314     // get the proxy object manager
00315     //
00316     nsCOMPtr<nsIProxyObjectManager> proxyObjMgr = 
00317         do_GetService(proxyObjMgrCID, &rv);
00318 
00319     if (NS_FAILED(rv))
00320         return NS_ERROR_FAILURE;
00321     
00322     // and try to get the proxy object
00323     //
00324     return proxyObjMgr->GetProxyForObject(destQueue, aIID, aObj,
00325                                           proxyType, aProxyObject);
00326 }