summaryrefslogtreecommitdiff
path: root/xpcom/glue/nsCategoryCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/glue/nsCategoryCache.cpp')
-rw-r--r--xpcom/glue/nsCategoryCache.cpp149
1 files changed, 149 insertions, 0 deletions
diff --git a/xpcom/glue/nsCategoryCache.cpp b/xpcom/glue/nsCategoryCache.cpp
new file mode 100644
index 0000000000..30501b8e39
--- /dev/null
+++ b/xpcom/glue/nsCategoryCache.cpp
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIObserverService.h"
+#include "mozilla/Services.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIStringEnumerator.h"
+
+#include "nsXPCOMCID.h"
+
+#include "nsCategoryCache.h"
+
+nsCategoryObserver::nsCategoryObserver(const char* aCategory)
+ : mCategory(aCategory)
+ , mObserversRemoved(false)
+{
+ // First, enumerate the currently existing entries
+ nsCOMPtr<nsICategoryManager> catMan =
+ do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
+ if (!catMan) {
+ return;
+ }
+
+ nsCOMPtr<nsISimpleEnumerator> enumerator;
+ nsresult rv = catMan->EnumerateCategory(aCategory,
+ getter_AddRefs(enumerator));
+ if (NS_FAILED(rv)) {
+ return;
+ }
+
+ nsCOMPtr<nsIUTF8StringEnumerator> strings = do_QueryInterface(enumerator);
+ MOZ_ASSERT(strings);
+
+ bool more;
+ while (NS_SUCCEEDED(strings->HasMore(&more)) && more) {
+ nsAutoCString entryName;
+ strings->GetNext(entryName);
+
+ nsCString entryValue;
+ rv = catMan->GetCategoryEntry(aCategory,
+ entryName.get(),
+ getter_Copies(entryValue));
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsISupports> service = do_GetService(entryValue.get());
+ if (service) {
+ mHash.Put(entryName, service);
+ }
+ }
+ }
+
+ // Now, listen for changes
+ nsCOMPtr<nsIObserverService> serv =
+ mozilla::services::GetObserverService();
+ if (serv) {
+ serv->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
+ serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, false);
+ serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID, false);
+ serv->AddObserver(this, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID, false);
+ }
+}
+
+nsCategoryObserver::~nsCategoryObserver()
+{
+}
+
+NS_IMPL_ISUPPORTS(nsCategoryObserver, nsIObserver)
+
+void
+nsCategoryObserver::ListenerDied()
+{
+ RemoveObservers();
+}
+
+void
+nsCategoryObserver::RemoveObservers()
+{
+ if (mObserversRemoved) {
+ return;
+ }
+
+ mObserversRemoved = true;
+ nsCOMPtr<nsIObserverService> obsSvc =
+ mozilla::services::GetObserverService();
+ if (obsSvc) {
+ obsSvc->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+ obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID);
+ obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID);
+ obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID);
+ }
+}
+
+NS_IMETHODIMP
+nsCategoryObserver::Observe(nsISupports* aSubject, const char* aTopic,
+ const char16_t* aData)
+{
+ if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
+ mHash.Clear();
+ RemoveObservers();
+
+ return NS_OK;
+ }
+
+ if (!aData ||
+ !nsDependentString(aData).Equals(NS_ConvertASCIItoUTF16(mCategory))) {
+ return NS_OK;
+ }
+
+ nsAutoCString str;
+ nsCOMPtr<nsISupportsCString> strWrapper(do_QueryInterface(aSubject));
+ if (strWrapper) {
+ strWrapper->GetData(str);
+ }
+
+ if (strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID) == 0) {
+ // We may get an add notification even when we already have an entry. This
+ // is due to the notification happening asynchronously, so if the entry gets
+ // added and an nsCategoryObserver gets instantiated before events get
+ // processed, we'd get the notification for an existing entry.
+ // Do nothing in that case.
+ if (mHash.GetWeak(str)) {
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsICategoryManager> catMan =
+ do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
+ if (!catMan) {
+ return NS_OK;
+ }
+
+ nsCString entryValue;
+ catMan->GetCategoryEntry(mCategory.get(),
+ str.get(),
+ getter_Copies(entryValue));
+
+ nsCOMPtr<nsISupports> service = do_GetService(entryValue.get());
+
+ if (service) {
+ mHash.Put(str, service);
+ }
+ } else if (strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID) == 0) {
+ mHash.Remove(str);
+ } else if (strcmp(aTopic, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID) == 0) {
+ mHash.Clear();
+ }
+ return NS_OK;
+}