no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / xpcom / components / nsCategoryCache.cpp
blob35f555fa51d4b4c7c807e5c1e1033b4ac513303b
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/. */
7 #include "nsIObserverService.h"
8 #include "mozilla/Services.h"
9 #include "mozilla/SimpleEnumerator.h"
11 #include "nsICategoryManager.h"
12 #include "nsISupportsPrimitives.h"
14 #include "nsXPCOMCID.h"
16 #include "nsCategoryCache.h"
18 using mozilla::SimpleEnumerator;
20 nsCategoryObserver::nsCategoryObserver(const nsACString& aCategory)
21 : mCategory(aCategory),
22 mCallback(nullptr),
23 mClosure(nullptr),
24 mObserversRemoved(false) {
25 MOZ_ASSERT(NS_IsMainThread());
26 // First, enumerate the currently existing entries
27 nsCOMPtr<nsICategoryManager> catMan =
28 do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
29 if (!catMan) {
30 return;
33 nsCOMPtr<nsISimpleEnumerator> enumerator;
34 nsresult rv =
35 catMan->EnumerateCategory(aCategory, getter_AddRefs(enumerator));
36 if (NS_FAILED(rv)) {
37 return;
40 for (auto& categoryEntry : SimpleEnumerator<nsICategoryEntry>(enumerator)) {
41 nsAutoCString entryValue;
42 categoryEntry->GetValue(entryValue);
44 if (nsCOMPtr<nsISupports> service = do_GetService(entryValue.get())) {
45 nsAutoCString entryName;
46 categoryEntry->GetEntry(entryName);
48 mHash.InsertOrUpdate(entryName, service);
52 // Now, listen for changes
53 nsCOMPtr<nsIObserverService> serv = mozilla::services::GetObserverService();
54 if (serv) {
55 serv->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
56 serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, false);
57 serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID, false);
58 serv->AddObserver(this, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID, false);
62 nsCategoryObserver::~nsCategoryObserver() = default;
64 NS_IMPL_ISUPPORTS(nsCategoryObserver, nsIObserver)
66 void nsCategoryObserver::ListenerDied() {
67 MOZ_ASSERT(NS_IsMainThread());
68 RemoveObservers();
69 mCallback = nullptr;
70 mClosure = nullptr;
73 void nsCategoryObserver::SetListener(void(aCallback)(void*), void* aClosure) {
74 MOZ_ASSERT(NS_IsMainThread());
75 mCallback = aCallback;
76 mClosure = aClosure;
79 void nsCategoryObserver::RemoveObservers() {
80 MOZ_ASSERT(NS_IsMainThread());
82 if (mObserversRemoved) {
83 return;
86 if (mCallback) {
87 mCallback(mClosure);
90 mObserversRemoved = true;
91 nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
92 if (obsSvc) {
93 obsSvc->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
94 obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID);
95 obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID);
96 obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID);
100 NS_IMETHODIMP
101 nsCategoryObserver::Observe(nsISupports* aSubject, const char* aTopic,
102 const char16_t* aData) {
103 MOZ_ASSERT(NS_IsMainThread());
105 if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
106 mHash.Clear();
107 RemoveObservers();
109 return NS_OK;
112 if (!aData ||
113 !nsDependentString(aData).Equals(NS_ConvertASCIItoUTF16(mCategory))) {
114 return NS_OK;
117 nsAutoCString str;
118 nsCOMPtr<nsISupportsCString> strWrapper(do_QueryInterface(aSubject));
119 if (strWrapper) {
120 strWrapper->GetData(str);
123 if (strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID) == 0) {
124 // We may get an add notification even when we already have an entry. This
125 // is due to the notification happening asynchronously, so if the entry gets
126 // added and an nsCategoryObserver gets instantiated before events get
127 // processed, we'd get the notification for an existing entry.
128 // Do nothing in that case.
129 if (mHash.GetWeak(str)) {
130 return NS_OK;
133 nsCOMPtr<nsICategoryManager> catMan =
134 do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
135 if (!catMan) {
136 return NS_OK;
139 nsCString entryValue;
140 catMan->GetCategoryEntry(mCategory, str, entryValue);
142 nsCOMPtr<nsISupports> service = do_GetService(entryValue.get());
144 if (service) {
145 mHash.InsertOrUpdate(str, service);
147 if (mCallback) {
148 mCallback(mClosure);
150 } else if (strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID) == 0) {
151 mHash.Remove(str);
152 if (mCallback) {
153 mCallback(mClosure);
155 } else if (strcmp(aTopic, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID) == 0) {
156 mHash.Clear();
157 if (mCallback) {
158 mCallback(mClosure);
161 return NS_OK;