xpcom/components/nsCategoryManager.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:9b8dbc0384fa
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #define PL_ARENA_CONST_ALIGN_MASK 7
7
8 #include "nsICategoryManager.h"
9 #include "nsCategoryManager.h"
10
11 #include "plarena.h"
12 #include "prio.h"
13 #include "prprf.h"
14 #include "prlock.h"
15 #include "nsCOMPtr.h"
16 #include "nsTHashtable.h"
17 #include "nsClassHashtable.h"
18 #include "nsIFactory.h"
19 #include "nsIStringEnumerator.h"
20 #include "nsSupportsPrimitives.h"
21 #include "nsComponentManagerUtils.h"
22 #include "nsServiceManagerUtils.h"
23 #include "nsIObserver.h"
24 #include "nsIObserverService.h"
25 #include "nsReadableUtils.h"
26 #include "nsCRT.h"
27 #include "nsQuickSort.h"
28 #include "nsEnumeratorUtils.h"
29 #include "nsThreadUtils.h"
30 #include "mozilla/MemoryReporting.h"
31 #include "mozilla/Services.h"
32
33 #include "ManifestParser.h"
34 #include "nsISimpleEnumerator.h"
35
36 using namespace mozilla;
37 class nsIComponentLoaderManager;
38
39 /*
40 CategoryDatabase
41 contains 0 or more 1-1 mappings of string to Category
42 each Category contains 0 or more 1-1 mappings of string keys to string values
43
44 In other words, the CategoryDatabase is a tree, whose root is a hashtable.
45 Internal nodes (or Categories) are hashtables. Leaf nodes are strings.
46
47 The leaf strings are allocated in an arena, because we assume they're not
48 going to change much ;)
49 */
50
51 #define NS_CATEGORYMANAGER_ARENA_SIZE (1024 * 8)
52
53 // pulled in from nsComponentManager.cpp
54 char* ArenaStrdup(const char* s, PLArenaPool* aArena);
55
56 //
57 // BaseStringEnumerator is subclassed by EntryEnumerator and
58 // CategoryEnumerator
59 //
60 class BaseStringEnumerator
61 : public nsISimpleEnumerator,
62 private nsIUTF8StringEnumerator
63 {
64 public:
65 NS_DECL_ISUPPORTS
66 NS_DECL_NSISIMPLEENUMERATOR
67 NS_DECL_NSIUTF8STRINGENUMERATOR
68
69 protected:
70 // Callback function for NS_QuickSort to sort mArray
71 static int SortCallback(const void *, const void *, void *);
72
73 BaseStringEnumerator()
74 : mArray(nullptr),
75 mCount(0),
76 mSimpleCurItem(0),
77 mStringCurItem(0) { }
78
79 // A virtual destructor is needed here because subclasses of
80 // BaseStringEnumerator do not implement their own Release() method.
81
82 virtual ~BaseStringEnumerator()
83 {
84 if (mArray)
85 delete[] mArray;
86 }
87
88 void Sort();
89
90 const char** mArray;
91 uint32_t mCount;
92 uint32_t mSimpleCurItem;
93 uint32_t mStringCurItem;
94 };
95
96 NS_IMPL_ISUPPORTS(BaseStringEnumerator, nsISimpleEnumerator, nsIUTF8StringEnumerator)
97
98 NS_IMETHODIMP
99 BaseStringEnumerator::HasMoreElements(bool *_retval)
100 {
101 *_retval = (mSimpleCurItem < mCount);
102
103 return NS_OK;
104 }
105
106 NS_IMETHODIMP
107 BaseStringEnumerator::GetNext(nsISupports **_retval)
108 {
109 if (mSimpleCurItem >= mCount)
110 return NS_ERROR_FAILURE;
111
112 nsSupportsDependentCString* str =
113 new nsSupportsDependentCString(mArray[mSimpleCurItem++]);
114 if (!str)
115 return NS_ERROR_OUT_OF_MEMORY;
116
117 *_retval = str;
118 NS_ADDREF(*_retval);
119 return NS_OK;
120 }
121
122 NS_IMETHODIMP
123 BaseStringEnumerator::HasMore(bool *_retval)
124 {
125 *_retval = (mStringCurItem < mCount);
126
127 return NS_OK;
128 }
129
130 NS_IMETHODIMP
131 BaseStringEnumerator::GetNext(nsACString& _retval)
132 {
133 if (mStringCurItem >= mCount)
134 return NS_ERROR_FAILURE;
135
136 _retval = nsDependentCString(mArray[mStringCurItem++]);
137 return NS_OK;
138 }
139
140 int
141 BaseStringEnumerator::SortCallback(const void *e1, const void *e2,
142 void * /*unused*/)
143 {
144 char const *const *s1 = reinterpret_cast<char const *const *>(e1);
145 char const *const *s2 = reinterpret_cast<char const *const *>(e2);
146
147 return strcmp(*s1, *s2);
148 }
149
150 void
151 BaseStringEnumerator::Sort()
152 {
153 NS_QuickSort(mArray, mCount, sizeof(mArray[0]), SortCallback, nullptr);
154 }
155
156 //
157 // EntryEnumerator is the wrapper that allows nsICategoryManager::EnumerateCategory
158 //
159 class EntryEnumerator
160 : public BaseStringEnumerator
161 {
162 public:
163 static EntryEnumerator* Create(nsTHashtable<CategoryLeaf>& aTable);
164
165 private:
166 static PLDHashOperator
167 enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg);
168 };
169
170
171 PLDHashOperator
172 EntryEnumerator::enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg)
173 {
174 EntryEnumerator* mythis = static_cast<EntryEnumerator*>(userArg);
175 if (aLeaf->value)
176 mythis->mArray[mythis->mCount++] = aLeaf->GetKey();
177
178 return PL_DHASH_NEXT;
179 }
180
181 EntryEnumerator*
182 EntryEnumerator::Create(nsTHashtable<CategoryLeaf>& aTable)
183 {
184 EntryEnumerator* enumObj = new EntryEnumerator();
185 if (!enumObj)
186 return nullptr;
187
188 enumObj->mArray = new char const* [aTable.Count()];
189 if (!enumObj->mArray) {
190 delete enumObj;
191 return nullptr;
192 }
193
194 aTable.EnumerateEntries(enumfunc_createenumerator, enumObj);
195
196 enumObj->Sort();
197
198 return enumObj;
199 }
200
201
202 //
203 // CategoryNode implementations
204 //
205
206 CategoryNode*
207 CategoryNode::Create(PLArenaPool* aArena)
208 {
209 CategoryNode* node = new(aArena) CategoryNode();
210 if (!node)
211 return nullptr;
212
213 return node;
214 }
215
216 CategoryNode::~CategoryNode()
217 {
218 }
219
220 void*
221 CategoryNode::operator new(size_t aSize, PLArenaPool* aArena)
222 {
223 void* p;
224 PL_ARENA_ALLOCATE(p, aArena, aSize);
225 return p;
226 }
227
228 NS_METHOD
229 CategoryNode::GetLeaf(const char* aEntryName,
230 char** _retval)
231 {
232 MutexAutoLock lock(mLock);
233 nsresult rv = NS_ERROR_NOT_AVAILABLE;
234 CategoryLeaf* ent =
235 mTable.GetEntry(aEntryName);
236
237 if (ent && ent->value) {
238 *_retval = NS_strdup(ent->value);
239 if (*_retval)
240 rv = NS_OK;
241 }
242
243 return rv;
244 }
245
246 NS_METHOD
247 CategoryNode::AddLeaf(const char* aEntryName,
248 const char* aValue,
249 bool aReplace,
250 char** _retval,
251 PLArenaPool* aArena)
252 {
253 if (_retval)
254 *_retval = nullptr;
255
256 MutexAutoLock lock(mLock);
257 CategoryLeaf* leaf =
258 mTable.GetEntry(aEntryName);
259
260 if (!leaf) {
261 const char* arenaEntryName = ArenaStrdup(aEntryName, aArena);
262 if (!arenaEntryName)
263 return NS_ERROR_OUT_OF_MEMORY;
264
265 leaf = mTable.PutEntry(arenaEntryName);
266 if (!leaf)
267 return NS_ERROR_OUT_OF_MEMORY;
268 }
269
270 if (leaf->value && !aReplace)
271 return NS_ERROR_INVALID_ARG;
272
273 const char* arenaValue = ArenaStrdup(aValue, aArena);
274 if (!arenaValue)
275 return NS_ERROR_OUT_OF_MEMORY;
276
277 if (_retval && leaf->value) {
278 *_retval = ToNewCString(nsDependentCString(leaf->value));
279 if (!*_retval)
280 return NS_ERROR_OUT_OF_MEMORY;
281 }
282
283 leaf->value = arenaValue;
284 return NS_OK;
285 }
286
287 void
288 CategoryNode::DeleteLeaf(const char* aEntryName)
289 {
290 // we don't throw any errors, because it normally doesn't matter
291 // and it makes JS a lot cleaner
292 MutexAutoLock lock(mLock);
293
294 // we can just remove the entire hash entry without introspection
295 mTable.RemoveEntry(aEntryName);
296 }
297
298 NS_METHOD
299 CategoryNode::Enumerate(nsISimpleEnumerator **_retval)
300 {
301 if (NS_WARN_IF(!_retval))
302 return NS_ERROR_INVALID_ARG;
303
304 MutexAutoLock lock(mLock);
305 EntryEnumerator* enumObj = EntryEnumerator::Create(mTable);
306
307 if (!enumObj)
308 return NS_ERROR_OUT_OF_MEMORY;
309
310 *_retval = enumObj;
311 NS_ADDREF(*_retval);
312 return NS_OK;
313 }
314
315 size_t
316 CategoryNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf)
317 {
318 // We don't measure the strings pointed to by the entries because the
319 // pointers are non-owning.
320 return mTable.SizeOfExcludingThis(nullptr, aMallocSizeOf);
321 }
322
323 struct persistent_userstruct {
324 PRFileDesc* fd;
325 const char* categoryName;
326 bool success;
327 };
328
329 PLDHashOperator
330 enumfunc_pentries(CategoryLeaf* aLeaf, void* userArg)
331 {
332 persistent_userstruct* args =
333 static_cast<persistent_userstruct*>(userArg);
334
335 PLDHashOperator status = PL_DHASH_NEXT;
336
337 if (aLeaf->value) {
338 if (PR_fprintf(args->fd,
339 "%s,%s,%s\n",
340 args->categoryName,
341 aLeaf->GetKey(),
342 aLeaf->value) == (uint32_t) -1) {
343 args->success = false;
344 status = PL_DHASH_STOP;
345 }
346 }
347
348 return status;
349 }
350
351 //
352 // CategoryEnumerator class
353 //
354
355 class CategoryEnumerator
356 : public BaseStringEnumerator
357 {
358 public:
359 static CategoryEnumerator* Create(nsClassHashtable<nsDepCharHashKey, CategoryNode>& aTable);
360
361 private:
362 static PLDHashOperator
363 enumfunc_createenumerator(const char* aStr,
364 CategoryNode* aNode,
365 void* userArg);
366 };
367
368 CategoryEnumerator*
369 CategoryEnumerator::Create(nsClassHashtable<nsDepCharHashKey, CategoryNode>& aTable)
370 {
371 CategoryEnumerator* enumObj = new CategoryEnumerator();
372 if (!enumObj)
373 return nullptr;
374
375 enumObj->mArray = new const char* [aTable.Count()];
376 if (!enumObj->mArray) {
377 delete enumObj;
378 return nullptr;
379 }
380
381 aTable.EnumerateRead(enumfunc_createenumerator, enumObj);
382
383 return enumObj;
384 }
385
386 PLDHashOperator
387 CategoryEnumerator::enumfunc_createenumerator(const char* aStr, CategoryNode* aNode, void* userArg)
388 {
389 CategoryEnumerator* mythis = static_cast<CategoryEnumerator*>(userArg);
390
391 // if a category has no entries, we pretend it doesn't exist
392 if (aNode->Count())
393 mythis->mArray[mythis->mCount++] = aStr;
394
395 return PL_DHASH_NEXT;
396 }
397
398
399 //
400 // nsCategoryManager implementations
401 //
402
403 NS_IMPL_QUERY_INTERFACE(nsCategoryManager, nsICategoryManager, nsIMemoryReporter)
404
405 NS_IMETHODIMP_(MozExternalRefCountType)
406 nsCategoryManager::AddRef()
407 {
408 return 2;
409 }
410
411 NS_IMETHODIMP_(MozExternalRefCountType)
412 nsCategoryManager::Release()
413 {
414 return 1;
415 }
416
417 nsCategoryManager* nsCategoryManager::gCategoryManager;
418
419 /* static */ nsCategoryManager*
420 nsCategoryManager::GetSingleton()
421 {
422 if (!gCategoryManager)
423 gCategoryManager = new nsCategoryManager();
424 return gCategoryManager;
425 }
426
427 /* static */ void
428 nsCategoryManager::Destroy()
429 {
430 delete gCategoryManager;
431 gCategoryManager = nullptr;
432 }
433
434 nsresult
435 nsCategoryManager::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
436 {
437 if (aOuter)
438 return NS_ERROR_NO_AGGREGATION;
439
440 return GetSingleton()->QueryInterface(aIID, aResult);
441 }
442
443 nsCategoryManager::nsCategoryManager()
444 : mLock("nsCategoryManager")
445 , mSuppressNotifications(false)
446 {
447 PL_INIT_ARENA_POOL(&mArena, "CategoryManagerArena",
448 NS_CATEGORYMANAGER_ARENA_SIZE);
449 }
450
451 void
452 nsCategoryManager::InitMemoryReporter()
453 {
454 RegisterWeakMemoryReporter(this);
455 }
456
457 nsCategoryManager::~nsCategoryManager()
458 {
459 UnregisterWeakMemoryReporter(this);
460
461 // the hashtable contains entries that must be deleted before the arena is
462 // destroyed, or else you will have PRLocks undestroyed and other Really
463 // Bad Stuff (TM)
464 mTable.Clear();
465
466 PL_FinishArenaPool(&mArena);
467 }
468
469 inline CategoryNode*
470 nsCategoryManager::get_category(const char* aName) {
471 CategoryNode* node;
472 if (!mTable.Get(aName, &node)) {
473 return nullptr;
474 }
475 return node;
476 }
477
478 MOZ_DEFINE_MALLOC_SIZE_OF(CategoryManagerMallocSizeOf)
479
480 NS_IMETHODIMP
481 nsCategoryManager::CollectReports(nsIHandleReportCallback* aHandleReport,
482 nsISupports* aData)
483 {
484 return MOZ_COLLECT_REPORT(
485 "explicit/xpcom/category-manager", KIND_HEAP, UNITS_BYTES,
486 SizeOfIncludingThis(CategoryManagerMallocSizeOf),
487 "Memory used for the XPCOM category manager.");
488 }
489
490 static size_t
491 SizeOfCategoryManagerTableEntryExcludingThis(nsDepCharHashKey::KeyType aKey,
492 const nsAutoPtr<CategoryNode> &aData,
493 MallocSizeOf aMallocSizeOf,
494 void* aUserArg)
495 {
496 // We don't measure the string pointed to by aKey because it's a non-owning
497 // pointer.
498 return aData.get()->SizeOfExcludingThis(aMallocSizeOf);
499 }
500
501 size_t
502 nsCategoryManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
503 {
504 size_t n = aMallocSizeOf(this);
505
506 n += PL_SizeOfArenaPoolExcludingPool(&mArena, aMallocSizeOf);
507
508 n += mTable.SizeOfExcludingThis(SizeOfCategoryManagerTableEntryExcludingThis,
509 aMallocSizeOf);
510
511 return n;
512 }
513
514 namespace {
515
516 class CategoryNotificationRunnable : public nsRunnable
517 {
518 public:
519 CategoryNotificationRunnable(nsISupports* aSubject,
520 const char* aTopic,
521 const char* aData)
522 : mSubject(aSubject)
523 , mTopic(aTopic)
524 , mData(aData)
525 { }
526
527 NS_DECL_NSIRUNNABLE
528
529 private:
530 nsCOMPtr<nsISupports> mSubject;
531 const char* mTopic;
532 NS_ConvertUTF8toUTF16 mData;
533 };
534
535 NS_IMETHODIMP
536 CategoryNotificationRunnable::Run()
537 {
538 nsCOMPtr<nsIObserverService> observerService =
539 mozilla::services::GetObserverService();
540 if (observerService)
541 observerService->NotifyObservers(mSubject, mTopic, mData.get());
542
543 return NS_OK;
544 }
545
546 } // anonymous namespace
547
548
549 void
550 nsCategoryManager::NotifyObservers( const char *aTopic,
551 const char *aCategoryName,
552 const char *aEntryName )
553 {
554 if (mSuppressNotifications)
555 return;
556
557 nsRefPtr<CategoryNotificationRunnable> r;
558
559 if (aEntryName) {
560 nsCOMPtr<nsISupportsCString> entry
561 (do_CreateInstance (NS_SUPPORTS_CSTRING_CONTRACTID));
562 if (!entry)
563 return;
564
565 nsresult rv = entry->SetData(nsDependentCString(aEntryName));
566 if (NS_FAILED(rv))
567 return;
568
569 r = new CategoryNotificationRunnable(entry, aTopic, aCategoryName);
570 } else {
571 r = new CategoryNotificationRunnable(
572 NS_ISUPPORTS_CAST(nsICategoryManager*, this),
573 aTopic, aCategoryName);
574 }
575
576 NS_DispatchToMainThread(r);
577 }
578
579 NS_IMETHODIMP
580 nsCategoryManager::GetCategoryEntry( const char *aCategoryName,
581 const char *aEntryName,
582 char **_retval )
583 {
584 if (NS_WARN_IF(!aCategoryName) ||
585 NS_WARN_IF(!aEntryName) ||
586 NS_WARN_IF(!_retval))
587 return NS_ERROR_INVALID_ARG;;
588
589 nsresult status = NS_ERROR_NOT_AVAILABLE;
590
591 CategoryNode* category;
592 {
593 MutexAutoLock lock(mLock);
594 category = get_category(aCategoryName);
595 }
596
597 if (category) {
598 status = category->GetLeaf(aEntryName, _retval);
599 }
600
601 return status;
602 }
603
604 NS_IMETHODIMP
605 nsCategoryManager::AddCategoryEntry( const char *aCategoryName,
606 const char *aEntryName,
607 const char *aValue,
608 bool aPersist,
609 bool aReplace,
610 char **_retval )
611 {
612 if (aPersist) {
613 NS_ERROR("Category manager doesn't support persistence.");
614 return NS_ERROR_INVALID_ARG;
615 }
616
617 AddCategoryEntry(aCategoryName, aEntryName, aValue, aReplace, _retval);
618 return NS_OK;
619 }
620
621 void
622 nsCategoryManager::AddCategoryEntry(const char *aCategoryName,
623 const char *aEntryName,
624 const char *aValue,
625 bool aReplace,
626 char** aOldValue)
627 {
628 if (aOldValue)
629 *aOldValue = nullptr;
630
631 // Before we can insert a new entry, we'll need to
632 // find the |CategoryNode| to put it in...
633 CategoryNode* category;
634 {
635 MutexAutoLock lock(mLock);
636 category = get_category(aCategoryName);
637
638 if (!category) {
639 // That category doesn't exist yet; let's make it.
640 category = CategoryNode::Create(&mArena);
641
642 char* categoryName = ArenaStrdup(aCategoryName, &mArena);
643 mTable.Put(categoryName, category);
644 }
645 }
646
647 if (!category)
648 return;
649
650 // We will need the return value of AddLeaf even if the called doesn't want it
651 char *oldEntry = nullptr;
652
653 nsresult rv = category->AddLeaf(aEntryName,
654 aValue,
655 aReplace,
656 &oldEntry,
657 &mArena);
658
659 if (NS_SUCCEEDED(rv)) {
660 if (oldEntry) {
661 NotifyObservers(NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID,
662 aCategoryName, aEntryName);
663 }
664 NotifyObservers(NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID,
665 aCategoryName, aEntryName);
666
667 if (aOldValue)
668 *aOldValue = oldEntry;
669 else
670 NS_Free(oldEntry);
671 }
672 }
673
674 NS_IMETHODIMP
675 nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName,
676 const char *aEntryName,
677 bool aDontPersist)
678 {
679 if (NS_WARN_IF(!aCategoryName) ||
680 NS_WARN_IF(!aEntryName))
681 return NS_ERROR_INVALID_ARG;
682
683 /*
684 Note: no errors are reported since failure to delete
685 probably won't hurt you, and returning errors seriously
686 inconveniences JS clients
687 */
688
689 CategoryNode* category;
690 {
691 MutexAutoLock lock(mLock);
692 category = get_category(aCategoryName);
693 }
694
695 if (category) {
696 category->DeleteLeaf(aEntryName);
697
698 NotifyObservers(NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID,
699 aCategoryName, aEntryName);
700 }
701
702 return NS_OK;
703 }
704
705 NS_IMETHODIMP
706 nsCategoryManager::DeleteCategory( const char *aCategoryName )
707 {
708 if (NS_WARN_IF(!aCategoryName))
709 return NS_ERROR_INVALID_ARG;
710
711 // the categories are arena-allocated, so we don't
712 // actually delete them. We just remove all of the
713 // leaf nodes.
714
715 CategoryNode* category;
716 {
717 MutexAutoLock lock(mLock);
718 category = get_category(aCategoryName);
719 }
720
721 if (category) {
722 category->Clear();
723 NotifyObservers(NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID,
724 aCategoryName, nullptr);
725 }
726
727 return NS_OK;
728 }
729
730 NS_IMETHODIMP
731 nsCategoryManager::EnumerateCategory( const char *aCategoryName,
732 nsISimpleEnumerator **_retval )
733 {
734 if (NS_WARN_IF(!aCategoryName) ||
735 NS_WARN_IF(!_retval))
736 return NS_ERROR_INVALID_ARG;
737
738 CategoryNode* category;
739 {
740 MutexAutoLock lock(mLock);
741 category = get_category(aCategoryName);
742 }
743
744 if (!category) {
745 return NS_NewEmptyEnumerator(_retval);
746 }
747
748 return category->Enumerate(_retval);
749 }
750
751 NS_IMETHODIMP
752 nsCategoryManager::EnumerateCategories(nsISimpleEnumerator **_retval)
753 {
754 if (NS_WARN_IF(!_retval))
755 return NS_ERROR_INVALID_ARG;
756
757 MutexAutoLock lock(mLock);
758 CategoryEnumerator* enumObj = CategoryEnumerator::Create(mTable);
759
760 if (!enumObj)
761 return NS_ERROR_OUT_OF_MEMORY;
762
763 *_retval = enumObj;
764 NS_ADDREF(*_retval);
765 return NS_OK;
766 }
767
768 struct writecat_struct {
769 PRFileDesc* fd;
770 bool success;
771 };
772
773 NS_METHOD
774 nsCategoryManager::SuppressNotifications(bool aSuppress)
775 {
776 mSuppressNotifications = aSuppress;
777 return NS_OK;
778 }
779
780 /*
781 * CreateServicesFromCategory()
782 *
783 * Given a category, this convenience functions enumerates the category and
784 * creates a service of every CID or ContractID registered under the category.
785 * If observerTopic is non null and the service implements nsIObserver,
786 * this will attempt to notify the observer with the origin, observerTopic string
787 * as parameter.
788 */
789 void
790 NS_CreateServicesFromCategory(const char *category,
791 nsISupports *origin,
792 const char *observerTopic)
793 {
794 nsresult rv;
795
796 nsCOMPtr<nsICategoryManager> categoryManager =
797 do_GetService("@mozilla.org/categorymanager;1");
798 if (!categoryManager)
799 return;
800
801 nsCOMPtr<nsISimpleEnumerator> enumerator;
802 rv = categoryManager->EnumerateCategory(category,
803 getter_AddRefs(enumerator));
804 if (NS_FAILED(rv))
805 return;
806
807 nsCOMPtr<nsIUTF8StringEnumerator> senumerator =
808 do_QueryInterface(enumerator);
809 if (!senumerator) {
810 NS_WARNING("Category enumerator doesn't support nsIUTF8StringEnumerator.");
811 return;
812 }
813
814 bool hasMore;
815 while (NS_SUCCEEDED(senumerator->HasMore(&hasMore)) && hasMore) {
816 // From here on just skip any error we get.
817 nsAutoCString entryString;
818 if (NS_FAILED(senumerator->GetNext(entryString)))
819 continue;
820
821 nsXPIDLCString contractID;
822 rv = categoryManager->GetCategoryEntry(category,entryString.get(),
823 getter_Copies(contractID));
824 if (NS_FAILED(rv))
825 continue;
826
827 nsCOMPtr<nsISupports> instance = do_GetService(contractID);
828 if (!instance) {
829 LogMessage("While creating services from category '%s', could not create service for entry '%s', contract ID '%s'",
830 category, entryString.get(), contractID.get());
831 continue;
832 }
833
834 if (observerTopic) {
835 // try an observer, if it implements it.
836 nsCOMPtr<nsIObserver> observer = do_QueryInterface(instance);
837 if (observer)
838 observer->Observe(origin, observerTopic, EmptyString().get());
839 else
840 LogMessage("While creating services from category '%s', service for entry '%s', contract ID '%s' does not implement nsIObserver.",
841 category, entryString.get(), contractID.get());
842 }
843 }
844 }

mercurial