Back to index

lightning-sunbird  0.9+nobinonly
nsObserverService.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 #include "prlog.h"
00040 #include "prlock.h"
00041 #include "nsIFactory.h"
00042 #include "nsIServiceManager.h"
00043 #include "nsIComponentManager.h"
00044 #include "nsIObserverService.h"
00045 #include "nsObserverService.h"
00046 #include "nsObserverList.h"
00047 #include "nsHashtable.h"
00048 #include "nsIWeakReference.h"
00049 
00050 #define NS_WEAK_OBSERVERS
00051 #define NOTIFY_GLOBAL_OBSERVERS
00052 
00053 #if defined(PR_LOGGING)
00054 // Log module for nsObserverService logging...
00055 //
00056 // To enable logging (see prlog.h for full details):
00057 //
00058 //    set NSPR_LOG_MODULES=ObserverService:5
00059 //    set NSPR_LOG_FILE=nspr.log
00060 //
00061 // this enables PR_LOG_DEBUG level information and places all output in
00062 // the file nspr.log
00063 PRLogModuleInfo* observerServiceLog = nsnull;
00064 #endif /* PR_LOGGING */
00065 
00067 // nsObserverService Implementation
00068 
00069 
00070 NS_IMPL_THREADSAFE_ISUPPORTS1(nsObserverService, nsIObserverService)
00071 
00072 nsObserverService::nsObserverService()
00073     : mObserverTopicTable(nsnull)
00074 {
00075 }
00076 
00077 nsObserverService::~nsObserverService(void)
00078 {
00079     if(mObserverTopicTable)
00080         delete mObserverTopicTable;
00081 }
00082 
00083 NS_METHOD
00084 nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
00085 {
00086 #if defined(PR_LOGGING)
00087     if (!observerServiceLog)
00088         observerServiceLog = PR_NewLogModule("ObserverService");
00089 #endif
00090 
00091     nsresult rv;
00092     nsObserverService* os = new nsObserverService();
00093     if (os == nsnull)
00094         return NS_ERROR_OUT_OF_MEMORY;
00095     NS_ADDREF(os);
00096     rv = os->QueryInterface(aIID, aInstancePtr);
00097     NS_RELEASE(os);
00098     return rv;
00099 }
00100 
00101 static PRBool PR_CALLBACK 
00102 ReleaseObserverList(nsHashKey *aKey, void *aData, void* closure)
00103 {
00104     nsObserverList* observerList = NS_STATIC_CAST(nsObserverList*, aData);
00105     delete(observerList);
00106     return PR_TRUE;
00107 }
00108 
00109 nsresult nsObserverService::GetObserverList(const char* aTopic, nsObserverList** anObserverList)
00110 {
00111     if (anObserverList == nsnull)
00112         return NS_ERROR_NULL_POINTER;
00113     
00114     if(mObserverTopicTable == nsnull) 
00115     {
00116         mObserverTopicTable = new nsObjectHashtable(nsnull, 
00117                                                     nsnull,   // should never be cloned
00118                                                     ReleaseObserverList, 
00119                                                     nsnull,
00120                                                     256, 
00121                                                     PR_TRUE);
00122         if (mObserverTopicTable == nsnull)
00123             return NS_ERROR_OUT_OF_MEMORY;
00124     }
00125     
00126 
00127     nsCStringKey key(aTopic);
00128 
00129     nsObserverList *topicObservers;
00130     topicObservers = (nsObserverList *) mObserverTopicTable->Get(&key);
00131 
00132     if (topicObservers) 
00133     {
00134         *anObserverList = topicObservers;    
00135         return NS_OK;
00136     }
00137 
00138     topicObservers = new nsObserverList();
00139     if (!topicObservers)
00140         return NS_ERROR_OUT_OF_MEMORY;
00141     
00142     *anObserverList = topicObservers;
00143     mObserverTopicTable->Put(&key, topicObservers);
00144     
00145     return NS_OK;
00146 }
00147 
00148 NS_IMETHODIMP nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic, PRBool ownsWeak)
00149 {
00150     nsObserverList* anObserverList;
00151     nsresult rv;
00152 
00153     if (anObserver == nsnull || aTopic == nsnull)
00154         return NS_ERROR_NULL_POINTER;
00155 
00156     rv = GetObserverList(aTopic, &anObserverList);
00157     if (NS_FAILED(rv)) return rv;
00158 
00159     return anObserverList->AddObserver(anObserver, ownsWeak);
00160 }
00161 
00162 NS_IMETHODIMP nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic)
00163 {
00164     nsObserverList* anObserverList;
00165     nsresult rv;
00166 
00167     if (anObserver == nsnull || aTopic == nsnull)
00168         return NS_ERROR_NULL_POINTER;
00169 
00170     rv = GetObserverList(aTopic, &anObserverList);
00171     if (NS_FAILED(rv)) return rv;
00172 
00173     return anObserverList->RemoveObserver(anObserver);
00174 }
00175 
00176 NS_IMETHODIMP nsObserverService::EnumerateObservers(const char* aTopic, nsISimpleEnumerator** anEnumerator)
00177 {
00178     nsObserverList* anObserverList;
00179     nsresult rv;
00180 
00181     if (anEnumerator == nsnull || aTopic == nsnull)
00182         return NS_ERROR_NULL_POINTER;
00183 
00184     rv = GetObserverList(aTopic, &anObserverList);
00185     if (NS_FAILED(rv)) return rv;
00186 
00187     return anObserverList->GetObserverList(anEnumerator);
00188 }
00189 
00190 // Enumerate observers of aTopic and call Observe on each.
00191 NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports *aSubject,
00192                                                  const char *aTopic,
00193                                                  const PRUnichar *someData) {
00194     nsresult rv = NS_OK;
00195 #ifdef NOTIFY_GLOBAL_OBSERVERS
00196     nsCOMPtr<nsISimpleEnumerator> globalObservers;
00197 #endif
00198     nsCOMPtr<nsISimpleEnumerator> observers;
00199     nsCOMPtr<nsISupports> observerRef;
00200 
00201 #ifdef NOTIFY_GLOBAL_OBSERVERS
00202     EnumerateObservers("*", getter_AddRefs(globalObservers));
00203 #endif
00204     rv = EnumerateObservers(aTopic, getter_AddRefs(observers));
00205 #ifdef NOTIFY_GLOBAL_OBSERVERS
00206     /* If there are no global observers and we failed to get normal observers
00207      * then we return the error indicating failure to get normal observers.
00208      */
00209     if (!globalObservers && NS_FAILED(rv))
00210         return rv;
00211 #endif
00212 
00213     do
00214     {
00215         PRBool more = PR_FALSE;
00216         /* If observers is non null then null it out unless it really
00217          * has more elements (i.e. that call doesn't fail).
00218          */
00219         if (observers && NS_FAILED(observers->HasMoreElements(&more)) || !more)
00220         {
00221 #ifdef NOTIFY_GLOBAL_OBSERVERS
00222             if (observers = globalObservers) 
00223                 globalObservers = nsnull;
00224 #else
00225             observers = nsnull;
00226 #endif
00227         }
00228         else
00229         {
00230             observers->GetNext(getter_AddRefs(observerRef));
00231             nsCOMPtr<nsIObserver> observer = do_QueryInterface(observerRef);
00232             if (observer) 
00233                 observer->Observe(aSubject, aTopic, someData);
00234 #ifdef NS_WEAK_OBSERVERS
00235             else
00236             {  // check for weak reference.
00237                 nsCOMPtr<nsIWeakReference> weakRef = do_QueryInterface(observerRef);     
00238                 if (weakRef)                                                              
00239                     weakRef->QueryReferent(NS_GET_IID(nsIObserver), getter_AddRefs(observer));
00240 
00241                 if (observer) 
00242                     observer->Observe(aSubject, aTopic, someData);
00243 
00244                 PR_LOG(observerServiceLog, PR_LOG_DEBUG, ("Notification - %s\n", aTopic ? aTopic : "undefined"));
00245 
00246             }
00247 #endif
00248         }
00249     } while (observers);
00250     return NS_OK;
00251 }
00253