1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef nsCategoryCache_h_ 8 #define nsCategoryCache_h_ 9 10 #include "mozilla/Attributes.h" 11 12 #include "nsICategoryManager.h" 13 #include "nsIObserver.h" 14 #include "nsISimpleEnumerator.h" 15 #include "nsISupportsPrimitives.h" 16 17 #include "nsServiceManagerUtils.h" 18 19 #include "nsAutoPtr.h" 20 #include "nsCOMArray.h" 21 #include "nsInterfaceHashtable.h" 22 23 #include "nsXPCOM.h" 24 25 class nsCategoryObserver final : public nsIObserver 26 { 27 ~nsCategoryObserver(); 28 29 public: 30 explicit nsCategoryObserver(const char* aCategory); 31 32 void ListenerDied(); GetHash()33 nsInterfaceHashtable<nsCStringHashKey, nsISupports>& GetHash() 34 { 35 return mHash; 36 } 37 38 NS_DECL_ISUPPORTS 39 NS_DECL_NSIOBSERVER 40 private: 41 void RemoveObservers(); 42 43 nsInterfaceHashtable<nsCStringHashKey, nsISupports> mHash; 44 nsCString mCategory; 45 bool mObserversRemoved; 46 }; 47 48 /** 49 * This is a helper class that caches services that are registered in a certain 50 * category. The intended usage is that a service stores a variable of type 51 * nsCategoryCache<nsIFoo> in a member variable, where nsIFoo is the interface 52 * that these services should implement. The constructor of this class should 53 * then get the name of the category. 54 */ 55 template<class T> 56 class nsCategoryCache final 57 { 58 public: nsCategoryCache(const char * aCategory)59 explicit nsCategoryCache(const char* aCategory) 60 : mCategoryName(aCategory) 61 { 62 } ~nsCategoryCache()63 ~nsCategoryCache() 64 { 65 if (mObserver) { 66 mObserver->ListenerDied(); 67 } 68 } 69 GetEntries(nsCOMArray<T> & aResult)70 void GetEntries(nsCOMArray<T>& aResult) 71 { 72 // Lazy initialization, so that services in this category can't 73 // cause reentrant getService (bug 386376) 74 if (!mObserver) { 75 mObserver = new nsCategoryObserver(mCategoryName.get()); 76 } 77 78 for (auto iter = mObserver->GetHash().Iter(); !iter.Done(); iter.Next()) { 79 nsISupports* entry = iter.UserData(); 80 nsCOMPtr<T> service = do_QueryInterface(entry); 81 if (service) { 82 aResult.AppendElement(service.forget()); 83 } 84 } 85 } 86 87 private: 88 // Not to be implemented 89 nsCategoryCache(const nsCategoryCache<T>&); 90 91 nsCString mCategoryName; 92 RefPtr<nsCategoryObserver> mObserver; 93 }; 94 95 #endif 96