Bug 464947 - Clear Recent History dialog should clear form data by timespan. r=mconnor
[wine-gecko.git] / xpcom / components / nsComponentManager.cpp
blobe81187f0f0d601389133a11706d95162d548fa46
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK *****
38 * This Original Code has been modified by IBM Corporation.
39 * Modifications made by IBM described herein are
40 * Copyright (c) International Business Machines
41 * Corporation, 2000
43 * Modifications to Mozilla code or documentation
44 * identified per MPL Section 3.3
46 * Date Modified by Description of modification
47 * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
49 #include <stdlib.h>
50 #include "nscore.h"
51 #include "nsISupports.h"
52 #include "nspr.h"
53 #include "nsCRT.h" // for atoll
54 // Arena used by component manager for storing contractid string, dll
55 // location strings and small objects
56 // CAUTION: Arena align mask needs to be defined before including plarena.h
57 // currently from nsComponentManager.h
58 #define PL_ARENA_CONST_ALIGN_MASK 7
59 #define NS_CM_BLOCK_SIZE (1024 * 8)
61 #include "nsAutoLock.h"
62 #include "nsCOMPtr.h"
63 #include "nsComponentManager.h"
64 #include "nsDirectoryService.h"
65 #include "nsDirectoryServiceDefs.h"
66 #include "nsCategoryManager.h"
67 #include "nsCategoryManagerUtils.h"
68 #include "nsIEnumerator.h"
69 #include "xptiprivate.h"
70 #include "nsIConsoleService.h"
71 #include "nsIModule.h"
72 #include "nsIObserverService.h"
73 #include "nsISimpleEnumerator.h"
74 #include "nsIStringEnumerator.h"
75 #include "nsXPCOM.h"
76 #include "nsXPCOMPrivate.h"
77 #include "nsISupportsPrimitives.h"
78 #include "nsIClassInfo.h"
79 #include "nsLocalFile.h"
80 #include "nsReadableUtils.h"
81 #include "nsString.h"
82 #include "nsXPIDLString.h"
83 #include "prcmon.h"
84 #include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself...
85 #include "nsThreadUtils.h"
86 #include "prthread.h"
88 #include "nsInt64.h"
89 #include "nsManifestLineReader.h"
91 #include NEW_H // for placement new
94 #ifdef XP_BEOS
95 #include <FindDirectory.h>
96 #include <Path.h>
97 #endif
99 #include "prlog.h"
101 NS_COM PRLogModuleInfo* nsComponentManagerLog = nsnull;
103 #if 0 || defined (DEBUG_timeless)
104 #define SHOW_DENIED_ON_SHUTDOWN
105 #define SHOW_CI_ON_EXISTING_SERVICE
106 #endif
108 // Bloated registry buffer size to improve startup performance -- needs to
109 // be big enough to fit the entire file into memory or it'll thrash.
110 // 512K is big enough to allow for some future growth in the registry.
111 #define BIG_REGISTRY_BUFLEN (512*1024)
113 // Common Key Names
114 const char classIDKeyName[]="classID";
115 const char classesKeyName[]="contractID";
116 const char componentsKeyName[]="components";
117 const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components";
118 const char xpcomKeyName[]="software/mozilla/XPCOM";
120 // Common Value Names
121 const char classIDValueName[]="ClassID";
122 const char classNameValueName[]="ClassName";
123 const char componentCountValueName[]="ComponentsCount";
124 const char componentTypeValueName[]="ComponentType";
125 const char contractIDValueName[]="ContractID";
126 const char fileSizeValueName[]="FileSize";
127 const char inprocServerValueName[]="InprocServer";
128 const char lastModValueName[]="LastModTimeStamp";
129 const char nativeComponentType[]="application/x-mozilla-native";
130 const char staticComponentType[]="application/x-mozilla-static";
131 const char versionValueName[]="VersionString";
133 const static char XPCOM_ABSCOMPONENT_PREFIX[] = "abs:";
134 const static char XPCOM_RELCOMPONENT_PREFIX[] = "rel:";
135 const static char XPCOM_GRECOMPONENT_PREFIX[] = "gre:";
137 static const char gIDFormat[] =
138 "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
141 #define NS_EMPTY_IID \
143 0x00000000, \
144 0x0000, \
145 0x0000, \
146 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \
149 NS_DEFINE_CID(kEmptyCID, NS_EMPTY_IID);
150 NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID);
152 #define UID_STRING_LENGTH 39
154 // Set to true from NS_ShutdownXPCOM.
155 extern PRBool gXPCOMShuttingDown;
157 static void GetIDString(const nsID& aCID, char buf[UID_STRING_LENGTH])
159 PR_snprintf(buf, UID_STRING_LENGTH, gIDFormat,
160 aCID.m0, (PRUint32) aCID.m1, (PRUint32) aCID.m2,
161 (PRUint32) aCID.m3[0], (PRUint32) aCID.m3[1],
162 (PRUint32) aCID.m3[2], (PRUint32) aCID.m3[3],
163 (PRUint32) aCID.m3[4], (PRUint32) aCID.m3[5],
164 (PRUint32) aCID.m3[6], (PRUint32) aCID.m3[7]);
167 nsresult
168 nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
170 nsresult rv;
171 nsXPIDLCString value;
172 nsCOMPtr<nsICategoryManager> catman;
173 nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager;
174 if (!compMgr) {
175 rv = NS_ERROR_NOT_INITIALIZED;
176 goto error;
179 if (!mCategory || !mEntry) {
180 // when categories have defaults, use that for null mEntry
181 rv = NS_ERROR_NULL_POINTER;
182 goto error;
185 rv = compMgr->nsComponentManagerImpl::GetService(kCategoryManagerCID,
186 NS_GET_IID(nsICategoryManager),
187 getter_AddRefs(catman));
188 if (NS_FAILED(rv)) goto error;
190 /* find the contractID for category.entry */
191 rv = catman->GetCategoryEntry(mCategory, mEntry,
192 getter_Copies(value));
193 if (NS_FAILED(rv)) goto error;
194 if (!value) {
195 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
196 goto error;
199 rv = compMgr->
200 nsComponentManagerImpl::GetServiceByContractID(value,
201 aIID, aInstancePtr);
202 if (NS_FAILED(rv)) {
203 error:
204 *aInstancePtr = 0;
206 if (mErrorPtr)
207 *mErrorPtr = rv;
208 return rv;
211 ////////////////////////////////////////////////////////////////////////////////
212 // Arena helper functions
213 ////////////////////////////////////////////////////////////////////////////////
214 char *
215 ArenaStrndup(const char *s, PRUint32 len, PLArenaPool *arena)
217 void *mem;
218 // Include trailing null in the len
219 PL_ARENA_ALLOCATE(mem, arena, len+1);
220 if (mem)
221 memcpy(mem, s, len+1);
222 return static_cast<char *>(mem);
225 char*
226 ArenaStrdup(const char *s, PLArenaPool *arena)
228 return ArenaStrndup(s, strlen(s), arena);
231 ////////////////////////////////////////////////////////////////////////////////
232 // Hashtable Callbacks
233 ////////////////////////////////////////////////////////////////////////////////
235 PRBool
236 nsFactoryEntry_Destroy(nsHashKey *aKey, void *aData, void* closure);
238 static PLDHashNumber
239 factory_HashKey(PLDHashTable *aTable, const void *aKey)
241 const nsCID *cidp = reinterpret_cast<const nsCID*>(aKey);
243 return cidp->m0;
246 static PRBool
247 factory_MatchEntry(PLDHashTable *aTable, const PLDHashEntryHdr *aHdr,
248 const void *aKey)
250 const nsFactoryTableEntry* entry =
251 static_cast<const nsFactoryTableEntry*>(aHdr);
252 const nsCID *cidp = reinterpret_cast<const nsCID*>(aKey);
254 return (entry->mFactoryEntry->mCid).Equals(*cidp);
257 static void
258 factory_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
260 nsFactoryTableEntry* entry = static_cast<nsFactoryTableEntry*>(aHdr);
261 // nsFactoryEntry is arena allocated. So we don't delete it.
262 // We call the destructor by hand.
263 entry->mFactoryEntry->~nsFactoryEntry();
264 PL_DHashClearEntryStub(aTable, aHdr);
267 static const PLDHashTableOps factory_DHashTableOps = {
268 PL_DHashAllocTable,
269 PL_DHashFreeTable,
270 factory_HashKey,
271 factory_MatchEntry,
272 PL_DHashMoveEntryStub,
273 factory_ClearEntry,
274 PL_DHashFinalizeStub,
277 static void
278 contractID_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
280 nsContractIDTableEntry* entry = static_cast<nsContractIDTableEntry*>(aHdr);
281 if (entry->mFactoryEntry->mLoaderType == NS_LOADER_TYPE_INVALID &&
282 entry->mFactoryEntry->mCid.Equals(kEmptyCID)) {
283 // this object is owned by the hash.
284 // nsFactoryEntry is arena allocated. So we don't delete it.
285 // We call the destructor by hand.
286 entry->mFactoryEntry->~nsFactoryEntry();
289 // contractIDs are arena allocated. No need to free them.
291 PL_DHashClearEntryStub(aTable, aHdr);
294 static const PLDHashTableOps contractID_DHashTableOps = {
295 PL_DHashAllocTable,
296 PL_DHashFreeTable,
297 PL_DHashStringKey,
298 PL_DHashMatchStringKey,
299 PL_DHashMoveEntryStub,
300 contractID_ClearEntry,
301 PL_DHashFinalizeStub,
304 ////////////////////////////////////////////////////////////////////////////////
305 // Hashtable Enumeration
306 ////////////////////////////////////////////////////////////////////////////////
307 typedef NS_CALLBACK(EnumeratorConverter)(PLDHashTable *table,
308 const PLDHashEntryHdr *hdr,
309 void *data,
310 nsISupports **retval);
312 class PLDHashTableEnumeratorImpl : public nsIBidirectionalEnumerator,
313 public nsISimpleEnumerator
315 public:
316 NS_DECL_ISUPPORTS
317 NS_DECL_NSIENUMERATOR
318 NS_DECL_NSIBIDIRECTIONALENUMERATOR
319 NS_DECL_NSISIMPLEENUMERATOR
321 PLDHashTableEnumeratorImpl(PLDHashTable *table,
322 EnumeratorConverter converter,
323 void *converterData);
324 PRInt32 Count() { return mCount; }
325 private:
326 PLDHashTableEnumeratorImpl(); /* no implementation */
328 ~PLDHashTableEnumeratorImpl();
329 void ReleaseElements();
331 nsVoidArray mElements;
332 PRInt32 mCount, mCurrent;
333 PRMonitor* mMonitor;
335 struct Closure {
336 PRBool succeeded;
337 EnumeratorConverter converter;
338 void *data;
339 PLDHashTableEnumeratorImpl *impl;
342 static PLDHashOperator Enumerator(PLDHashTable *table,
343 PLDHashEntryHdr *hdr,
344 PRUint32 number,
345 void *data);
348 // static
349 PLDHashOperator
350 PLDHashTableEnumeratorImpl::Enumerator(PLDHashTable *table,
351 PLDHashEntryHdr *hdr,
352 PRUint32 number,
353 void *data)
355 Closure *c = reinterpret_cast<Closure *>(data);
356 nsISupports *converted;
357 if (NS_FAILED(c->converter(table, hdr, c->data, &converted)) ||
358 !c->impl->mElements.AppendElement(converted)) {
359 c->succeeded = PR_FALSE;
360 return PL_DHASH_STOP;
363 c->succeeded = PR_TRUE;
364 return PL_DHASH_NEXT;
367 PLDHashTableEnumeratorImpl::PLDHashTableEnumeratorImpl(PLDHashTable *table,
368 EnumeratorConverter converter,
369 void *converterData)
370 : mCurrent(0)
372 mMonitor = nsAutoMonitor::NewMonitor("PLDHashTableEnumeratorImpl");
373 NS_ASSERTION(mMonitor, "NULL Monitor");
375 nsAutoMonitor mon(mMonitor);
377 Closure c = { PR_FALSE, converter, converterData, this };
378 mCount = PL_DHashTableEnumerate(table, Enumerator, &c);
379 if (!c.succeeded) {
380 ReleaseElements();
381 mCount = 0;
385 NS_IMPL_ISUPPORTS3(PLDHashTableEnumeratorImpl,
386 nsIBidirectionalEnumerator,
387 nsIEnumerator,
388 nsISimpleEnumerator)
390 PLDHashTableEnumeratorImpl::~PLDHashTableEnumeratorImpl()
392 ReleaseElements();
394 // Destroy the Lock
395 if (mMonitor)
396 nsAutoMonitor::DestroyMonitor(mMonitor);
399 void
400 PLDHashTableEnumeratorImpl::ReleaseElements()
402 for (PRInt32 i = 0; i < mCount; i++) {
403 nsISupports *supports = reinterpret_cast<nsISupports *>
404 (mElements[i]);
405 NS_IF_RELEASE(supports);
409 NS_IMETHODIMP
410 PL_NewDHashTableEnumerator(PLDHashTable *table,
411 EnumeratorConverter converter,
412 void *converterData,
413 PLDHashTableEnumeratorImpl **retval)
415 PLDHashTableEnumeratorImpl *impl =
416 new PLDHashTableEnumeratorImpl(table, converter, converterData);
418 if (!impl)
419 return NS_ERROR_OUT_OF_MEMORY;
421 NS_ADDREF(impl);
423 if (impl->Count() == -1) {
424 // conversion failed
425 NS_RELEASE(impl);
426 return NS_ERROR_FAILURE;
429 *retval = impl;
430 return NS_OK;
433 NS_IMETHODIMP
434 PLDHashTableEnumeratorImpl::First()
436 if (!mCount)
437 return NS_ERROR_FAILURE;
439 mCurrent = 0;
440 return NS_OK;
443 NS_IMETHODIMP
444 PLDHashTableEnumeratorImpl::Last()
446 if (!mCount)
447 return NS_ERROR_FAILURE;
448 mCurrent = mCount - 1;
449 return NS_OK;
452 NS_IMETHODIMP
453 PLDHashTableEnumeratorImpl::Prev()
455 if (!mCurrent)
456 return NS_ERROR_FAILURE;
458 mCurrent--;
459 return NS_OK;
462 NS_IMETHODIMP
463 PLDHashTableEnumeratorImpl::Next()
465 // If empty or we're past the end, or we are at the end return error
466 if (!mCount || (mCurrent == mCount) || (++mCurrent == mCount))
467 return NS_ERROR_FAILURE;
469 return NS_OK;
472 NS_IMETHODIMP
473 PLDHashTableEnumeratorImpl::CurrentItem(nsISupports **retval)
475 if (!mCount || mCurrent == mCount)
476 return NS_ERROR_FAILURE;
478 *retval = reinterpret_cast<nsISupports *>(mElements[mCurrent]);
479 if (*retval)
480 NS_ADDREF(*retval);
482 return NS_OK;
485 NS_IMETHODIMP
486 PLDHashTableEnumeratorImpl::IsDone()
488 if (!mCount || (mCurrent == mCount))
489 return NS_OK;
491 return NS_ENUMERATOR_FALSE;
494 NS_IMETHODIMP
495 PLDHashTableEnumeratorImpl::HasMoreElements(PRBool *_retval)
497 if (!mCount || (mCurrent >= mCount - 1))
498 *_retval = PR_FALSE;
499 else
500 *_retval = PR_TRUE;
502 return NS_OK;
505 NS_IMETHODIMP
506 PLDHashTableEnumeratorImpl::GetNext(nsISupports **_retval)
508 nsresult rv = Next();
509 if (NS_FAILED(rv)) return rv;
511 return CurrentItem(_retval);
514 static NS_IMETHODIMP
515 ConvertFactoryEntryToCID(PLDHashTable *table,
516 const PLDHashEntryHdr *hdr,
517 void *data, nsISupports **retval)
519 nsresult rv;
520 nsCOMPtr<nsISupportsID> wrapper;
522 nsComponentManagerImpl *cm = static_cast<nsComponentManagerImpl *>(data);
524 rv = cm->CreateInstanceByContractID(NS_SUPPORTS_ID_CONTRACTID, nsnull,
525 NS_GET_IID(nsISupportsID), getter_AddRefs(wrapper));
527 NS_ENSURE_SUCCESS(rv, rv);
529 const nsFactoryTableEntry *entry =
530 reinterpret_cast<const nsFactoryTableEntry *>(hdr);
531 if (entry) {
532 nsFactoryEntry *fe = entry->mFactoryEntry;
534 wrapper->SetData(&fe->mCid);
535 *retval = wrapper;
536 NS_ADDREF(*retval);
537 return NS_OK;
539 *retval = nsnull;
541 return rv;
544 static NS_IMETHODIMP
545 ConvertContractIDKeyToString(PLDHashTable *table,
546 const PLDHashEntryHdr *hdr,
547 void *data, nsISupports **retval)
549 nsresult rv;
550 nsCOMPtr<nsISupportsCString> wrapper;
552 nsComponentManagerImpl *cm = static_cast<nsComponentManagerImpl *>(data);
554 rv = cm->CreateInstanceByContractID(NS_SUPPORTS_CSTRING_CONTRACTID, nsnull,
555 NS_GET_IID(nsISupportsCString), getter_AddRefs(wrapper));
557 NS_ENSURE_SUCCESS(rv, rv);
559 const nsContractIDTableEntry *entry =
560 reinterpret_cast<const nsContractIDTableEntry *>(hdr);
562 wrapper->SetData(nsDependentCString(entry->mContractID,
563 entry->mContractIDLen));
564 *retval = wrapper;
565 NS_ADDREF(*retval);
566 return NS_OK;
569 // this is safe to call during InitXPCOM
570 static nsresult GetLocationFromDirectoryService(const char* prop,
571 nsIFile** aDirectory)
573 nsCOMPtr<nsIProperties> directoryService;
574 nsDirectoryService::Create(nsnull,
575 NS_GET_IID(nsIProperties),
576 getter_AddRefs(directoryService));
578 if (!directoryService)
579 return NS_ERROR_FAILURE;
581 return directoryService->Get(prop,
582 NS_GET_IID(nsIFile),
583 (void**)aDirectory);
587 ////////////////////////////////////////////////////////////////////////////////
588 // nsComponentManagerImpl
589 ////////////////////////////////////////////////////////////////////////////////
592 nsComponentManagerImpl::nsComponentManagerImpl()
594 mMon(NULL),
595 mShuttingDown(NS_SHUTDOWN_NEVERHAPPENED),
596 mLoaderData(4),
597 mRegistryDirty(PR_FALSE)
599 mFactories.ops = nsnull;
600 mContractIDs.ops = nsnull;
603 #define CONTRACTID_HASHTABLE_INITIAL_SIZE 2048
604 #define AUTOREGENTRY_HASHTABLE_INITIAL_SIZE 256
606 nsresult nsComponentManagerImpl::Init(nsStaticModuleInfo const *aStaticModules,
607 PRUint32 aStaticModuleCount)
609 PR_ASSERT(mShuttingDown != NS_SHUTDOWN_INPROGRESS);
610 if (mShuttingDown == NS_SHUTDOWN_INPROGRESS)
611 return NS_ERROR_FAILURE;
613 mShuttingDown = NS_SHUTDOWN_NEVERHAPPENED;
615 if (nsComponentManagerLog == nsnull)
617 nsComponentManagerLog = PR_NewLogModule("nsComponentManager");
620 // Initialize our arena
621 PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);
623 if (!mFactories.ops) {
624 if (!PL_DHashTableInit(&mFactories, &factory_DHashTableOps,
625 0, sizeof(nsFactoryTableEntry),
626 1024)) {
627 mFactories.ops = nsnull;
628 return NS_ERROR_OUT_OF_MEMORY;
631 // Minimum alpha uses k=2 because nsFactoryTableEntry saves two
632 // words compared to what a chained hash table requires.
633 PL_DHashTableSetAlphaBounds(&mFactories,
634 0.875,
635 PL_DHASH_MIN_ALPHA(&mFactories, 2));
638 if (!mContractIDs.ops) {
639 if (!PL_DHashTableInit(&mContractIDs, &contractID_DHashTableOps,
640 0, sizeof(nsContractIDTableEntry),
641 CONTRACTID_HASHTABLE_INITIAL_SIZE)) {
642 mContractIDs.ops = nsnull;
643 return NS_ERROR_OUT_OF_MEMORY;
646 // Minimum alpha uses k=1 because nsContractIDTableEntry saves one
647 // word compared to what a chained hash table requires.
648 #if 0
649 PL_DHashTableSetAlphaBounds(&mContractIDs,
650 0.875,
651 PL_DHASH_MIN_ALPHA(&mContractIDs, 1));
652 #endif
655 if (!mAutoRegEntries.Init(AUTOREGENTRY_HASHTABLE_INITIAL_SIZE))
656 return NS_ERROR_OUT_OF_MEMORY;
658 if (mMon == nsnull) {
659 mMon = nsAutoMonitor::NewMonitor("nsComponentManagerImpl");
660 if (mMon == nsnull)
661 return NS_ERROR_OUT_OF_MEMORY;
664 GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_DIR, getter_AddRefs(mComponentsDir));
665 if (!mComponentsDir)
666 return NS_ERROR_OUT_OF_MEMORY;
668 nsCAutoString componentDescriptor;
669 nsresult rv = mComponentsDir->GetNativePath(componentDescriptor);
670 if (NS_FAILED(rv))
671 return rv;
673 mComponentsOffset = componentDescriptor.Length();
675 GetLocationFromDirectoryService(NS_GRE_COMPONENT_DIR, getter_AddRefs(mGREComponentsDir));
676 if (mGREComponentsDir) {
677 nsresult rv = mGREComponentsDir->GetNativePath(componentDescriptor);
678 if (NS_FAILED(rv)) {
679 NS_WARNING("No GRE component manager");
680 return rv;
682 mGREComponentsOffset = componentDescriptor.Length();
685 GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_REGISTRY_FILE,
686 getter_AddRefs(mRegistryFile));
688 if(!mRegistryFile) {
689 NS_WARNING("No Component Registry file was found in the directory service");
690 return NS_ERROR_FAILURE;
693 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
694 ("nsComponentManager: Initialized."));
696 rv = mNativeModuleLoader.Init();
697 if (NS_FAILED(rv))
698 return rv;
700 rv = mStaticModuleLoader.Init(aStaticModules, aStaticModuleCount);
701 if (NS_FAILED(rv))
702 return rv;
704 return NS_OK;
707 nsresult nsComponentManagerImpl::Shutdown(void)
709 PR_ASSERT(mShuttingDown == NS_SHUTDOWN_NEVERHAPPENED);
710 if (mShuttingDown != NS_SHUTDOWN_NEVERHAPPENED)
711 return NS_ERROR_FAILURE;
713 mShuttingDown = NS_SHUTDOWN_INPROGRESS;
715 // Shutdown the component manager
716 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown."));
718 // Write out our component data file.
719 if (mRegistryDirty) {
720 nsresult rv = WritePersistentRegistry();
721 if (NS_FAILED(rv)) {
722 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: Could not write out persistent registry."));
723 #ifdef DEBUG
724 printf("Could not write out persistent registry!\n");
725 #endif
729 mAutoRegEntries.Clear();
731 // Release all cached factories
732 if (mContractIDs.ops) {
733 PL_DHashTableFinish(&mContractIDs);
734 mContractIDs.ops = nsnull;
736 if (mFactories.ops) {
737 PL_DHashTableFinish(&mFactories);
738 mFactories.ops = nsnull;
741 mLoaderData.Clear();
743 // Free staticm modules
744 mStaticModuleLoader.ReleaseModules();
746 // Unload libraries
747 mNativeModuleLoader.UnloadLibraries();
749 // delete arena for strings and small objects
750 PL_FinishArenaPool(&mArena);
752 mComponentsDir = 0;
754 mCategoryManager = 0;
756 mShuttingDown = NS_SHUTDOWN_COMPLETE;
758 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Shutdown complete."));
760 return NS_OK;
763 nsComponentManagerImpl::~nsComponentManagerImpl()
765 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction."));
767 if (mShuttingDown != NS_SHUTDOWN_COMPLETE)
768 Shutdown();
770 if (mMon) {
771 nsAutoMonitor::DestroyMonitor(mMon);
773 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed."));
776 NS_IMPL_THREADSAFE_ISUPPORTS7(nsComponentManagerImpl,
777 nsIComponentManager,
778 nsIServiceManager,
779 nsISupportsWeakReference,
780 nsIInterfaceRequestor,
781 nsIComponentRegistrar,
782 nsIServiceManagerObsolete,
783 nsIComponentManagerObsolete)
786 nsresult
787 nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result)
789 NS_WARNING("This isn't supported");
790 // fall through to QI as anything QIable is a superset of what can be
791 // got via the GetInterface()
792 return QueryInterface(uuid, result);
795 ////////////////////////////////////////////////////////////////////////////////
796 // nsComponentManagerImpl: Platform methods
797 ////////////////////////////////////////////////////////////////////////////////
799 #define PERSISTENT_REGISTRY_VERSION_MINOR 5
800 #define PERSISTENT_REGISTRY_VERSION_MAJOR 0
802 static
803 PRBool ReadSectionHeader(nsManifestLineReader& reader, const char *token)
805 while (1)
807 if (*reader.LinePtr() == '[')
809 char* p = reader.LinePtr() + (reader.LineLength() - 1);
810 if (*p != ']')
811 break;
812 *p = 0;
814 char* values[1];
815 int lengths[1];
816 if (2 != reader.ParseLine(values, lengths, 1))
817 break;
819 // ignore the leading '['
820 if (0 != PL_strcmp(values[0]+1, token))
821 break;
823 return PR_TRUE;
826 if (!reader.NextLine())
827 break;
829 return PR_FALSE;
832 nsresult
833 nsComponentManagerImpl::ReadPersistentRegistry()
835 NS_ASSERTION(mComponentsDir, "nsComponentManager not initialized.");
837 nsresult rv;
839 // populate Category Manager. need to get this early so that we don't get
840 // skipped by 'goto out'
841 mCategoryManager = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
842 if (NS_FAILED(rv))
843 return rv;
845 nsAutoMonitor mon(mMon);
846 nsManifestLineReader reader;
848 PRFileDesc* fd = nsnull;
850 // Set From Init
851 if (!mRegistryFile) {
852 return NS_ERROR_FILE_NOT_FOUND;
855 nsCOMPtr<nsIFile> file;
856 mRegistryFile->Clone(getter_AddRefs(file));
857 if (!file)
858 return NS_ERROR_OUT_OF_MEMORY;
860 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
862 rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
863 if (NS_FAILED(rv))
864 return rv;
866 PRInt64 fileSize;
867 rv = localFile->GetFileSize(&fileSize);
868 if (NS_FAILED(rv))
870 PR_Close(fd);
871 return rv;
874 PRInt32 flen = nsInt64(fileSize);
875 if (flen == 0)
877 PR_Close(fd);
878 NS_WARNING("Persistent Registry Empty!");
879 return NS_OK; // ERROR CONDITION
882 char* registry = new char[flen+1];
883 if (!registry)
884 goto out;
886 if (flen > PR_Read(fd, registry, flen))
888 rv = NS_ERROR_FAILURE;
889 goto out;
891 registry[flen] = '\0';
893 reader.Init(registry, flen);
895 if (ReadSectionHeader(reader, "HEADER"))
896 goto out;
898 if (!reader.NextLine())
899 goto out;
901 char* values[6];
902 int lengths[6];
904 // VersionLiteral,major,minor
905 if (3 != reader.ParseLine(values, lengths, 3))
906 goto out;
908 // VersionLiteral
909 if (!nsDependentCString(values[0], lengths[0]).EqualsLiteral("Version"))
910 goto out;
912 // major
913 if (PERSISTENT_REGISTRY_VERSION_MAJOR != atoi(values[1]))
914 goto out;
916 // minor
917 if (PERSISTENT_REGISTRY_VERSION_MINOR != atoi(values[2]))
918 goto out;
920 if (ReadSectionHeader(reader, "COMPONENTS"))
921 goto out;
923 while (1)
925 if (!reader.NextLine())
926 break;
928 //name,last_modification_date[,optionaldata]
929 int parts = reader.ParseLine(values, lengths, 3);
930 if (2 != parts)
931 break;
933 PRInt64 a = nsCRT::atoll(values[1]);
935 nsCOMPtr<nsILocalFile> lf;
936 rv = FileForRegistryLocation(nsDependentCString(values[0], lengths[0]),
937 getter_AddRefs(lf));
938 if (NS_FAILED(rv))
939 continue;
941 nsCOMPtr<nsIHashable> lfhash(do_QueryInterface(lf));
942 if (!lf) {
943 NS_ERROR("nsLocalFile does not implement nsIHashable");
944 continue;
947 mAutoRegEntries.Put(lfhash, a);
950 if (ReadSectionHeader(reader, "CLASSIDS"))
951 goto out;
953 while (1)
955 if (!reader.NextLine())
956 break;
958 // cid,contract_id,type,class_name,inproc_server
959 if (5 != reader.ParseLine(values, lengths, 5))
960 break;
962 nsCID aClass;
963 if (!aClass.Parse(values[0]))
964 continue;
966 LoaderType loadertype = AddLoaderType(values[2]);
967 if (loadertype == NS_LOADER_TYPE_INVALID) {
968 NS_ERROR("Could not create LoaderType");
969 continue;
972 void *mem;
973 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
974 if (!mem) {
975 rv = NS_ERROR_OUT_OF_MEMORY;
976 goto out;
979 nsFactoryEntry *entry =
980 new (mem) nsFactoryEntry(aClass, loadertype, values[4]);
982 if (!entry->mLocationKey) {
983 rv = NS_ERROR_OUT_OF_MEMORY;
984 goto out;
987 nsFactoryTableEntry* factoryTableEntry =
988 static_cast<nsFactoryTableEntry*>
989 (PL_DHashTableOperate(&mFactories,
990 &aClass,
991 PL_DHASH_ADD));
993 if (!factoryTableEntry) {
994 rv = NS_ERROR_OUT_OF_MEMORY;
995 goto out;
998 factoryTableEntry->mFactoryEntry = entry;
1001 if (ReadSectionHeader(reader, "CONTRACTIDS"))
1002 goto out;
1004 while (1)
1006 if (!reader.NextLine())
1007 break;
1009 //contractID,cid
1010 if (2 != reader.ParseLine(values, lengths, 2))
1011 break;
1013 nsCID aClass;
1014 if (!aClass.Parse(values[1]))
1015 continue;
1018 //need to find the location for this cid.
1019 nsFactoryEntry *cidEntry = GetFactoryEntry(aClass);
1020 if (!cidEntry || cidEntry->mLoaderType == NS_LOADER_TYPE_INVALID)
1021 continue; //what should we really do?
1023 nsContractIDTableEntry* contractIDTableEntry =
1024 static_cast<nsContractIDTableEntry*>
1025 (PL_DHashTableOperate(&mContractIDs,
1026 values[0],
1027 PL_DHASH_ADD));
1028 if (!contractIDTableEntry) {
1029 continue;
1032 if (!contractIDTableEntry->mContractID) {
1033 char *contractID = ArenaStrndup(values[0], lengths[0], &mArena);
1034 if (!contractID) {
1035 rv = NS_ERROR_OUT_OF_MEMORY;
1036 goto out;
1038 contractIDTableEntry->mContractID = contractID;
1039 contractIDTableEntry->mContractIDLen = lengths[0];
1042 contractIDTableEntry->mFactoryEntry = cidEntry;
1045 if (ReadSectionHeader(reader, "CATEGORIES"))
1046 goto out;
1048 mCategoryManager->SuppressNotifications(PR_TRUE);
1050 while (1)
1052 if (!reader.NextLine())
1053 break;
1055 //type,name,value
1056 if (3 != reader.ParseLine(values, lengths, 3))
1057 break;
1059 mCategoryManager->AddCategoryEntry(values[0],
1060 values[1],
1061 values[2],
1062 PR_TRUE,
1063 PR_TRUE,
1067 mCategoryManager->SuppressNotifications(PR_FALSE);
1069 mRegistryDirty = PR_FALSE;
1070 out:
1071 if (fd)
1072 PR_Close(fd);
1074 if (registry)
1075 delete [] registry;
1077 return rv;
1080 struct PersistentWriterArgs
1082 PRFileDesc *mFD;
1083 nsTArray<nsLoaderdata> *mLoaderData;
1086 static PLDHashOperator
1087 ContractIDWriter(PLDHashTable *table,
1088 PLDHashEntryHdr *hdr,
1089 PRUint32 number,
1090 void *arg)
1092 char *contractID = ((nsContractIDTableEntry*)hdr)->mContractID;
1093 nsFactoryEntry *factoryEntry = ((nsContractIDTableEntry*)hdr)->mFactoryEntry;
1095 // for now, we only save out the top most parent.
1096 while (factoryEntry->mParent)
1097 factoryEntry = factoryEntry->mParent;
1099 if (factoryEntry->mLoaderType == NS_LOADER_TYPE_INVALID)
1100 return PL_DHASH_NEXT;
1102 PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD;
1104 char cidString[UID_STRING_LENGTH];
1105 GetIDString(factoryEntry->mCid, cidString);
1106 PR_fprintf(fd, "%s,%s\n", contractID, cidString); // what if this fails?
1107 return PL_DHASH_NEXT;
1110 static PLDHashOperator
1111 ClassIDWriter(PLDHashTable *table,
1112 PLDHashEntryHdr *hdr,
1113 PRUint32 number,
1114 void *arg)
1116 nsFactoryEntry *factoryEntry = ((nsFactoryTableEntry*)hdr)->mFactoryEntry;
1117 PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD;
1118 nsTArray<nsLoaderdata> *loaderData = ((PersistentWriterArgs*)arg)->mLoaderData;
1120 // for now, we only save out the top most parent.
1121 while (factoryEntry->mParent)
1122 factoryEntry = factoryEntry->mParent;
1124 if (factoryEntry->mLoaderType == NS_LOADER_TYPE_INVALID) {
1125 return PL_DHASH_NEXT;
1128 char cidString[UID_STRING_LENGTH];
1129 GetIDString(factoryEntry->mCid, cidString);
1131 char *contractID = nsnull, *className = nsnull;
1133 nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(factoryEntry->mFactory);
1134 if (classInfo)
1136 classInfo->GetContractID(&contractID);
1137 classInfo->GetClassDescription(&className);
1140 const char *loaderName;
1141 switch (factoryEntry->mLoaderType) {
1142 case NS_LOADER_TYPE_STATIC:
1143 loaderName = staticComponentType;
1144 break;
1146 case NS_LOADER_TYPE_NATIVE:
1147 loaderName = nativeComponentType;
1148 break;
1150 default:
1151 loaderName = loaderData->ElementAt(factoryEntry->mLoaderType).type.get();
1154 const char* location = factoryEntry->mLocationKey;
1156 // cid,contract_id,type,class_name,inproc_server
1157 PR_fprintf(fd,
1158 "%s,%s,%s,%s,%s\n",
1159 cidString,
1160 (contractID ? contractID : ""),
1161 (loaderName ? loaderName : ""),
1162 (className ? className : ""),
1163 (location ? location : ""));
1165 if (contractID)
1166 PR_Free(contractID);
1167 if (className)
1168 PR_Free(className);
1170 return PL_DHASH_NEXT;
1173 static PLDHashOperator
1174 AutoRegEntryWriter(nsIHashable *aKey, PRInt64 &aTimestamp, void* aClosure)
1176 PRFileDesc* fd = (PRFileDesc*) aClosure;
1178 nsCOMPtr<nsILocalFile> lf(do_QueryInterface(aKey));
1180 nsCAutoString location;
1181 nsComponentManagerImpl::gComponentManager->
1182 RegistryLocationForFile(lf, location);
1184 PR_fprintf(fd, "%s,%lld\n", location.get(), (PRInt64) aTimestamp);
1186 return PL_DHASH_NEXT;
1189 nsresult
1190 nsComponentManagerImpl::WritePersistentRegistry()
1192 if (!mRegistryFile)
1193 return NS_ERROR_FAILURE; // this should have been set by Init().
1195 nsCOMPtr<nsIFile> file;
1196 mRegistryFile->Clone(getter_AddRefs(file));
1197 if (!file)
1198 return NS_ERROR_OUT_OF_MEMORY;
1200 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
1202 nsCAutoString originalLeafName;
1203 localFile->GetNativeLeafName(originalLeafName);
1205 nsCAutoString leafName;
1206 leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp"));
1208 localFile->SetNativeLeafName(leafName);
1210 PRFileDesc* fd = nsnull;
1211 // Owner and group can setup components, everyone else should be able to see but not poison them.
1212 nsresult rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0664, &fd);
1213 if (NS_FAILED(rv))
1214 return rv;
1216 if (PR_fprintf(fd, "Generated File. Do not edit.\n") == (PRUint32) -1) {
1217 rv = NS_ERROR_UNEXPECTED;
1218 goto out;
1221 if (PR_fprintf(fd, "\n[HEADER]\nVersion,%d,%d\n",
1222 PERSISTENT_REGISTRY_VERSION_MAJOR,
1223 PERSISTENT_REGISTRY_VERSION_MINOR) == (PRUint32) -1) {
1224 rv = NS_ERROR_UNEXPECTED;
1225 goto out;
1228 if (PR_fprintf(fd, "\n[COMPONENTS]\n") == (PRUint32) -1) {
1229 rv = NS_ERROR_UNEXPECTED;
1230 goto out;
1233 mAutoRegEntries.Enumerate(AutoRegEntryWriter, (void*)fd);
1235 PersistentWriterArgs args;
1236 args.mFD = fd;
1237 args.mLoaderData = &mLoaderData;
1239 if (PR_fprintf(fd, "\n[CLASSIDS]\n") == (PRUint32) -1) {
1240 rv = NS_ERROR_UNEXPECTED;
1241 goto out;
1245 PL_DHashTableEnumerate(&mFactories, ClassIDWriter, (void*)&args);
1247 if (PR_fprintf(fd, "\n[CONTRACTIDS]\n") == (PRUint32) -1) {
1248 rv = NS_ERROR_UNEXPECTED;
1249 goto out;
1253 PL_DHashTableEnumerate(&mContractIDs, ContractIDWriter, (void*)&args);
1255 if (PR_fprintf(fd, "\n[CATEGORIES]\n") == (PRUint32) -1) {
1256 rv = NS_ERROR_UNEXPECTED;
1257 goto out;
1260 NS_ASSERTION(mCategoryManager, "nsComponentManager used initialized");
1262 rv = mCategoryManager->WriteCategoryManagerToRegistry(fd);
1264 out:
1265 PR_Close(fd);
1267 // don't create the file is there was a problem????
1268 NS_ENSURE_SUCCESS(rv, rv);
1270 if (!mRegistryFile)
1271 return NS_ERROR_NOT_INITIALIZED;
1273 PRBool exists;
1274 if(NS_FAILED(mRegistryFile->Exists(&exists)))
1275 return PR_FALSE;
1277 if(exists && NS_FAILED(mRegistryFile->Remove(PR_FALSE)))
1278 return PR_FALSE;
1280 nsCOMPtr<nsIFile> parent;
1281 mRegistryFile->GetParent(getter_AddRefs(parent));
1283 rv = localFile->MoveToNative(parent, originalLeafName);
1284 mRegistryDirty = PR_FALSE;
1286 return rv;
1290 ////////////////////////////////////////////////////////////////////////////////
1291 // Hash Functions
1292 ////////////////////////////////////////////////////////////////////////////////
1293 nsresult
1294 nsComponentManagerImpl::HashContractID(const char *aContractID,
1295 PRUint32 aContractIDLen,
1296 nsFactoryEntry *fe)
1298 if(!aContractID || !aContractIDLen)
1299 return NS_ERROR_NULL_POINTER;
1301 nsAutoMonitor mon(mMon);
1303 nsContractIDTableEntry* contractIDTableEntry =
1304 static_cast<nsContractIDTableEntry*>
1305 (PL_DHashTableOperate(&mContractIDs, aContractID,
1306 PL_DHASH_ADD));
1307 if (!contractIDTableEntry)
1308 return NS_ERROR_OUT_OF_MEMORY;
1310 NS_ASSERTION(!contractIDTableEntry->mContractID || !strcmp(contractIDTableEntry->mContractID, aContractID), "contractid conflict");
1312 if (!contractIDTableEntry->mContractID) {
1313 char *contractID = ArenaStrndup(aContractID, aContractIDLen, &mArena);
1314 if (!contractID)
1315 return NS_ERROR_OUT_OF_MEMORY;
1317 contractIDTableEntry->mContractID = contractID;
1318 contractIDTableEntry->mContractIDLen = aContractIDLen;
1321 contractIDTableEntry->mFactoryEntry = fe;
1323 return NS_OK;
1326 nsFactoryEntry *
1327 nsComponentManagerImpl::GetFactoryEntry(const char *aContractID,
1328 PRUint32 aContractIDLen)
1330 nsFactoryEntry *fe = nsnull;
1332 nsAutoMonitor mon(mMon);
1334 nsContractIDTableEntry* contractIDTableEntry =
1335 static_cast<nsContractIDTableEntry*>
1336 (PL_DHashTableOperate(&mContractIDs, aContractID,
1337 PL_DHASH_LOOKUP));
1340 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
1341 fe = contractIDTableEntry->mFactoryEntry;
1343 } //exit monitor
1345 return fe;
1349 nsFactoryEntry *
1350 nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass)
1352 nsFactoryEntry *entry = nsnull;
1354 nsAutoMonitor mon(mMon);
1356 nsFactoryTableEntry* factoryTableEntry =
1357 static_cast<nsFactoryTableEntry*>
1358 (PL_DHashTableOperate(&mFactories, &aClass,
1359 PL_DHASH_LOOKUP));
1361 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
1362 entry = factoryTableEntry->mFactoryEntry;
1364 } // exit monitor
1366 return entry;
1371 * FindFactory()
1373 * Given a classID, this finds the factory for this CID by first searching the
1374 * local CID<->factory mapping. Next it searches for a Dll that implements
1375 * this classID and calls LoadFactory() to create the factory.
1377 * Again, no attempt is made at storing the factory.
1379 NS_IMETHODIMP
1380 nsComponentManagerImpl::FindFactory(const nsCID &aClass,
1381 nsIFactory **aFactory)
1383 PR_ASSERT(aFactory != nsnull);
1385 nsFactoryEntry *entry = GetFactoryEntry(aClass);
1387 if (!entry)
1388 return NS_ERROR_FACTORY_NOT_REGISTERED;
1390 return entry->GetFactory(aFactory);
1394 nsresult
1395 nsComponentManagerImpl::FindFactory(const char *contractID,
1396 PRUint32 aContractIDLen,
1397 nsIFactory **aFactory)
1399 PR_ASSERT(aFactory != nsnull);
1401 nsFactoryEntry *entry = GetFactoryEntry(contractID, aContractIDLen);
1403 if (!entry)
1404 return NS_ERROR_FACTORY_NOT_REGISTERED;
1406 return entry->GetFactory(aFactory);
1410 * GetClassObject()
1412 * Given a classID, this finds the singleton ClassObject that implements the CID.
1413 * Returns an interface of type aIID off the singleton classobject.
1415 NS_IMETHODIMP
1416 nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID,
1417 void **aResult)
1419 nsresult rv;
1421 nsCOMPtr<nsIFactory> factory;
1423 #ifdef PR_LOGGING
1424 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG))
1426 char *buf = aClass.ToString();
1427 PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
1428 if (buf)
1429 PR_Free(buf);
1431 #endif
1433 PR_ASSERT(aResult != nsnull);
1435 rv = FindFactory(aClass, getter_AddRefs(factory));
1436 if (NS_FAILED(rv)) return rv;
1438 rv = factory->QueryInterface(aIID, aResult);
1440 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1441 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1443 return rv;
1447 NS_IMETHODIMP
1448 nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID,
1449 const nsIID &aIID,
1450 void **aResult)
1452 nsresult rv;
1454 nsCOMPtr<nsIFactory> factory;
1456 #ifdef PR_LOGGING
1457 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG))
1459 PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID);
1461 #endif
1463 PR_ASSERT(aResult != nsnull);
1465 rv = FindFactory(contractID, strlen(contractID), getter_AddRefs(factory));
1466 if (NS_FAILED(rv)) return rv;
1468 rv = factory->QueryInterface(aIID, aResult);
1470 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1471 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1473 return rv;
1477 * ContractIDToClassID()
1479 * Mapping function from a ContractID to a classID. Directly talks to the registry.
1482 NS_IMETHODIMP
1483 nsComponentManagerImpl::ContractIDToClassID(const char *aContractID, nsCID *aClass)
1485 NS_PRECONDITION(aContractID != nsnull, "null ptr");
1486 if (!aContractID)
1487 return NS_ERROR_NULL_POINTER;
1489 NS_PRECONDITION(aClass != nsnull, "null ptr");
1490 if (!aClass)
1491 return NS_ERROR_NULL_POINTER;
1493 nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1495 nsFactoryEntry *fe = GetFactoryEntry(aContractID, strlen(aContractID));
1496 if (fe) {
1497 *aClass = fe->mCid;
1498 rv = NS_OK;
1500 #ifdef PR_LOGGING
1501 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) {
1502 char *buf = 0;
1503 if (NS_SUCCEEDED(rv))
1504 buf = aClass->ToString();
1505 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1506 ("nsComponentManager: ContractIDToClassID(%s)->%s", aContractID,
1507 NS_SUCCEEDED(rv) ? buf : "[FAILED]"));
1508 if (buf)
1509 PR_Free(buf);
1511 #endif
1512 return rv;
1516 * CLSIDToContractID()
1518 * Translates a classID to a {ContractID, Class Name}. Does direct registry
1519 * access to do the translation.
1521 * NOTE: Since this isn't heavily used, we aren't caching this.
1523 NS_IMETHODIMP
1524 nsComponentManagerImpl::CLSIDToContractID(const nsCID &aClass,
1525 char* *aClassName,
1526 char* *aContractID)
1528 NS_WARNING("Need to implement CLSIDToContractID");
1530 nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1531 #ifdef PR_LOGGING
1532 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
1534 char *buf = aClass.ToString();
1535 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1536 ("nsComponentManager: CLSIDToContractID(%s)->%s", buf,
1537 NS_SUCCEEDED(rv) ? *aContractID : "[FAILED]"));
1538 if (buf)
1539 PR_Free(buf);
1541 #endif
1542 return rv;
1546 * CreateInstance()
1548 * Create an instance of an object that implements an interface and belongs
1549 * to the implementation aClass using the factory. The factory is immediately
1550 * released and not held onto for any longer.
1552 NS_IMETHODIMP
1553 nsComponentManagerImpl::CreateInstance(const nsCID &aClass,
1554 nsISupports *aDelegate,
1555 const nsIID &aIID,
1556 void **aResult)
1558 // test this first, since there's no point in creating a component during
1559 // shutdown -- whether it's available or not would depend on the order it
1560 // occurs in the list
1561 if (gXPCOMShuttingDown) {
1562 // When processing shutdown, don't process new GetService() requests
1563 #ifdef SHOW_DENIED_ON_SHUTDOWN
1564 nsXPIDLCString cid, iid;
1565 cid.Adopt(aClass.ToString());
1566 iid.Adopt(aIID.ToString());
1567 fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
1568 " CID: %s\n IID: %s\n", cid.get(), iid.get());
1569 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1570 return NS_ERROR_UNEXPECTED;
1573 if (aResult == nsnull)
1575 return NS_ERROR_NULL_POINTER;
1577 *aResult = nsnull;
1579 nsFactoryEntry *entry = GetFactoryEntry(aClass);
1581 if (!entry)
1582 return NS_ERROR_FACTORY_NOT_REGISTERED;
1584 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1585 if (entry->mServiceObject) {
1586 nsXPIDLCString cid;
1587 cid.Adopt(aClass.ToString());
1588 nsCAutoString message;
1589 message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1590 cid + NS_LITERAL_CSTRING("\" when a service for this CID already exists!");
1591 NS_ERROR(message.get());
1593 #endif
1595 nsIFactory *factory = nsnull;
1596 nsresult rv = entry->GetFactory(&factory);
1598 if (NS_SUCCEEDED(rv))
1600 rv = factory->CreateInstance(aDelegate, aIID, aResult);
1601 if (NS_SUCCEEDED(rv) && !*aResult) {
1602 NS_ERROR("Factory did not return an object but returned success!");
1603 rv = NS_ERROR_SERVICE_NOT_FOUND;
1605 NS_RELEASE(factory);
1607 else
1609 // Translate error values
1610 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1613 #ifdef PR_LOGGING
1614 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
1616 char *buf = aClass.ToString();
1617 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1618 ("nsComponentManager: CreateInstance(%s) %s", buf,
1619 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1620 if (buf)
1621 PR_Free(buf);
1623 #endif
1625 return rv;
1629 * CreateInstanceByContractID()
1631 * A variant of CreateInstance() that creates an instance of the object that
1632 * implements the interface aIID and whose implementation has a contractID aContractID.
1634 * This is only a convenience routine that turns around can calls the
1635 * CreateInstance() with classid and iid.
1637 NS_IMETHODIMP
1638 nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID,
1639 nsISupports *aDelegate,
1640 const nsIID &aIID,
1641 void **aResult)
1643 // test this first, since there's no point in creating a component during
1644 // shutdown -- whether it's available or not would depend on the order it
1645 // occurs in the list
1646 if (gXPCOMShuttingDown) {
1647 // When processing shutdown, don't process new GetService() requests
1648 #ifdef SHOW_DENIED_ON_SHUTDOWN
1649 nsXPIDLCString iid;
1650 iid.Adopt(aIID.ToString());
1651 fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
1652 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
1653 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1654 return NS_ERROR_UNEXPECTED;
1657 if (aResult == nsnull)
1659 return NS_ERROR_NULL_POINTER;
1661 *aResult = nsnull;
1663 nsFactoryEntry *entry = GetFactoryEntry(aContractID, strlen(aContractID));
1665 if (!entry)
1666 return NS_ERROR_FACTORY_NOT_REGISTERED;
1668 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1669 if (entry->mServiceObject) {
1670 nsCAutoString message;
1671 message =
1672 NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1673 nsDependentCString(aContractID) +
1674 NS_LITERAL_CSTRING("\" when a service for this CID already exists! "
1675 "Add it to abusedContracts to track down the service consumer.");
1676 NS_ERROR(message.get());
1678 #endif
1680 nsIFactory *factory = nsnull;
1681 nsresult rv = entry->GetFactory(&factory);
1683 if (NS_SUCCEEDED(rv))
1686 rv = factory->CreateInstance(aDelegate, aIID, aResult);
1687 if (NS_SUCCEEDED(rv) && !*aResult) {
1688 NS_ERROR("Factory did not return an object but returned success!");
1689 rv = NS_ERROR_SERVICE_NOT_FOUND;
1691 NS_RELEASE(factory);
1693 else
1695 // Translate error values
1696 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1699 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1700 ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
1701 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1703 return rv;
1706 // Service Manager Impl
1707 static
1708 PLDHashOperator
1709 FreeServiceFactoryEntryEnumerate(PLDHashTable *aTable,
1710 PLDHashEntryHdr *aHdr,
1711 PRUint32 aNumber,
1712 void *aData)
1714 nsFactoryTableEntry* entry = static_cast<nsFactoryTableEntry*>(aHdr);
1716 if (!entry->mFactoryEntry)
1717 return PL_DHASH_NEXT;
1719 nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
1720 factoryEntry->mServiceObject = nsnull;
1721 return PL_DHASH_NEXT;
1724 static
1725 PLDHashOperator
1726 FreeServiceContractIDEntryEnumerate(PLDHashTable *aTable,
1727 PLDHashEntryHdr *aHdr,
1728 PRUint32 aNumber,
1729 void *aData)
1731 nsContractIDTableEntry* entry = static_cast<nsContractIDTableEntry*>(aHdr);
1733 if (!entry->mFactoryEntry)
1734 return PL_DHASH_NEXT;
1736 nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
1737 factoryEntry->mServiceObject = nsnull;
1738 return PL_DHASH_NEXT;
1741 nsresult
1742 nsComponentManagerImpl::FreeServices()
1744 NS_ASSERTION(gXPCOMShuttingDown, "Must be shutting down in order to free all services");
1746 if (!gXPCOMShuttingDown)
1747 return NS_ERROR_FAILURE;
1749 if (mContractIDs.ops) {
1750 PL_DHashTableEnumerate(&mContractIDs, FreeServiceContractIDEntryEnumerate, nsnull);
1754 if (mFactories.ops) {
1755 PL_DHashTableEnumerate(&mFactories, FreeServiceFactoryEntryEnumerate, nsnull);
1758 return NS_OK;
1761 // This should only ever be called within the monitor!
1762 nsComponentManagerImpl::PendingServiceInfo*
1763 nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID,
1764 PRThread* aThread)
1766 PendingServiceInfo* newInfo = mPendingServices.AppendElement();
1767 if (newInfo) {
1768 newInfo->cid = &aServiceCID;
1769 newInfo->thread = aThread;
1771 return newInfo;
1774 // This should only ever be called within the monitor!
1775 void
1776 nsComponentManagerImpl::RemovePendingService(const nsCID& aServiceCID)
1778 PRUint32 pendingCount = mPendingServices.Length();
1779 for (PRUint32 index = 0; index < pendingCount; ++index) {
1780 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
1781 if (info.cid->Equals(aServiceCID)) {
1782 mPendingServices.RemoveElementAt(index);
1783 return;
1788 // This should only ever be called within the monitor!
1789 PRThread*
1790 nsComponentManagerImpl::GetPendingServiceThread(const nsCID& aServiceCID) const
1792 PRUint32 pendingCount = mPendingServices.Length();
1793 for (PRUint32 index = 0; index < pendingCount; ++index) {
1794 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
1795 if (info.cid->Equals(aServiceCID)) {
1796 return info.thread;
1799 return nsnull;
1802 NS_IMETHODIMP
1803 nsComponentManagerImpl::GetService(const nsCID& aClass,
1804 const nsIID& aIID,
1805 void* *result)
1807 // test this first, since there's no point in returning a service during
1808 // shutdown -- whether it's available or not would depend on the order it
1809 // occurs in the list
1810 if (gXPCOMShuttingDown) {
1811 // When processing shutdown, don't process new GetService() requests
1812 #ifdef SHOW_DENIED_ON_SHUTDOWN
1813 nsXPIDLCString cid, iid;
1814 cid.Adopt(aClass.ToString());
1815 iid.Adopt(aIID.ToString());
1816 fprintf(stderr, "Getting service on shutdown. Denied.\n"
1817 " CID: %s\n IID: %s\n", cid.get(), iid.get());
1818 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1819 return NS_ERROR_UNEXPECTED;
1822 nsAutoMonitor mon(mMon);
1824 nsIDKey key(aClass);
1825 nsFactoryEntry* entry = nsnull;
1826 nsFactoryTableEntry* factoryTableEntry =
1827 static_cast<nsFactoryTableEntry*>
1828 (PL_DHashTableOperate(&mFactories, &aClass,
1829 PL_DHASH_LOOKUP));
1831 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
1832 entry = factoryTableEntry->mFactoryEntry;
1835 if (entry && entry->mServiceObject) {
1836 nsCOMPtr<nsISupports> supports = entry->mServiceObject;
1837 mon.Exit();
1838 return supports->QueryInterface(aIID, result);
1841 PRThread* currentPRThread = PR_GetCurrentThread();
1842 NS_ASSERTION(currentPRThread, "This should never be null!");
1844 // Needed to optimize the event loop below.
1845 nsIThread* currentThread = nsnull;
1847 PRThread* pendingPRThread;
1848 while ((pendingPRThread = GetPendingServiceThread(aClass))) {
1849 if (pendingPRThread == currentPRThread) {
1850 NS_ERROR("Recursive GetService!");
1851 return NS_ERROR_NOT_AVAILABLE;
1854 mon.Exit();
1856 if (!currentThread) {
1857 currentThread = NS_GetCurrentThread();
1858 NS_ASSERTION(currentThread, "This should never be null!");
1861 // This will process a single event or yield the thread if no event is
1862 // pending.
1863 if (!NS_ProcessNextEvent(currentThread, PR_FALSE)) {
1864 PR_Sleep(PR_INTERVAL_NO_WAIT);
1867 mon.Enter();
1870 if (currentThread) {
1871 // If we have a currentThread then we must have waited on another thread
1872 // to create the service. Grab it now if that succeeded.
1873 if (!entry) {
1874 factoryTableEntry = static_cast<nsFactoryTableEntry*>
1875 (PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_LOOKUP));
1877 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
1878 entry = factoryTableEntry->mFactoryEntry;
1882 // It's still possible that the other thread failed to create the
1883 // service so we're not guaranteed to have an entry or service yet.
1884 if (entry && entry->mServiceObject) {
1885 nsCOMPtr<nsISupports> supports = entry->mServiceObject;
1886 mon.Exit();
1887 return supports->QueryInterface(aIID, result);
1891 #ifdef DEBUG
1892 PendingServiceInfo* newInfo =
1893 #endif
1894 AddPendingService(aClass, currentPRThread);
1895 NS_ASSERTION(newInfo, "Failed to add info to the array!");
1897 nsCOMPtr<nsISupports> service;
1898 // We need to not be holding the service manager's monitor while calling
1899 // CreateInstance, because it invokes user code which could try to re-enter
1900 // the service manager:
1901 mon.Exit();
1903 nsresult rv = CreateInstance(aClass, nsnull, aIID, getter_AddRefs(service));
1905 mon.Enter();
1907 #ifdef DEBUG
1908 pendingPRThread = GetPendingServiceThread(aClass);
1909 NS_ASSERTION(pendingPRThread == currentPRThread,
1910 "Pending service array has been changed!");
1911 #endif
1912 RemovePendingService(aClass);
1914 if (NS_FAILED(rv))
1915 return rv;
1917 if (!entry) { // second hash lookup for GetService
1918 nsFactoryTableEntry* factoryTableEntry =
1919 static_cast<nsFactoryTableEntry*>
1920 (PL_DHashTableOperate(&mFactories, &aClass,
1921 PL_DHASH_LOOKUP));
1922 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
1923 entry = factoryTableEntry->mFactoryEntry;
1925 NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
1926 if (!entry) return NS_ERROR_FAILURE;
1929 NS_ASSERTION(!entry->mServiceObject, "Created two instances of a service!");
1931 entry->mServiceObject = service;
1932 *result = service.get();
1933 if (!*result) {
1934 NS_ERROR("Factory did not return an object but returned success!");
1935 return NS_ERROR_SERVICE_NOT_FOUND;
1937 NS_ADDREF(static_cast<nsISupports*>((*result)));
1938 return rv;
1941 NS_IMETHODIMP
1942 nsComponentManagerImpl::RegisterService(const nsCID& aClass, nsISupports* aService)
1944 nsAutoMonitor mon(mMon);
1946 // check to see if we have a factory entry for the service
1947 nsFactoryEntry *entry = GetFactoryEntry(aClass);
1949 if (!entry) {
1950 void *mem;
1951 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
1952 if (!mem)
1953 return NS_ERROR_OUT_OF_MEMORY;
1954 entry = new (mem) nsFactoryEntry(aClass, (nsIFactory*) nsnull);
1956 nsFactoryTableEntry* factoryTableEntry =
1957 static_cast<nsFactoryTableEntry*>
1958 (PL_DHashTableOperate(&mFactories, &aClass,
1959 PL_DHASH_ADD));
1960 if (!factoryTableEntry)
1961 return NS_ERROR_OUT_OF_MEMORY;
1963 factoryTableEntry->mFactoryEntry = entry;
1965 else {
1966 if (entry->mServiceObject)
1967 return NS_ERROR_FAILURE;
1970 entry->mServiceObject = aService;
1971 return NS_OK;
1974 NS_IMETHODIMP
1975 nsComponentManagerImpl::UnregisterService(const nsCID& aClass)
1977 nsresult rv = NS_OK;
1979 nsFactoryEntry* entry = nsnull;
1981 nsAutoMonitor mon(mMon);
1983 nsFactoryTableEntry* factoryTableEntry =
1984 static_cast<nsFactoryTableEntry*>
1985 (PL_DHashTableOperate(&mFactories, &aClass,
1986 PL_DHASH_LOOKUP));
1988 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
1989 entry = factoryTableEntry->mFactoryEntry;
1992 if (!entry || !entry->mServiceObject)
1993 return NS_ERROR_SERVICE_NOT_AVAILABLE;
1995 entry->mServiceObject = nsnull;
1996 return rv;
1999 NS_IMETHODIMP
2000 nsComponentManagerImpl::RegisterService(const char* aContractID,
2001 nsISupports* aService)
2004 nsAutoMonitor mon(mMon);
2006 // check to see if we have a factory entry for the service
2007 PRUint32 contractIDLen = strlen(aContractID);
2008 nsFactoryEntry *entry = GetFactoryEntry(aContractID, contractIDLen);
2010 if (!entry) {
2011 void *mem;
2012 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2013 if (!mem)
2014 return NS_ERROR_OUT_OF_MEMORY;
2015 entry = new (mem) nsFactoryEntry(kEmptyCID, (nsIFactory*) nsnull);
2017 nsContractIDTableEntry* contractIDTableEntry =
2018 static_cast<nsContractIDTableEntry*>
2019 (PL_DHashTableOperate(&mContractIDs, aContractID,
2020 PL_DHASH_ADD));
2021 if (!contractIDTableEntry) {
2022 delete entry;
2023 return NS_ERROR_OUT_OF_MEMORY;
2026 if (!contractIDTableEntry->mContractID) {
2027 char *contractID = ArenaStrndup(aContractID, contractIDLen, &mArena);
2028 if (!contractID)
2029 return NS_ERROR_OUT_OF_MEMORY;
2031 contractIDTableEntry->mContractID = contractID;
2032 contractIDTableEntry->mContractIDLen = contractIDLen;
2035 contractIDTableEntry->mFactoryEntry = entry;
2037 else {
2038 if (entry->mServiceObject)
2039 return NS_ERROR_FAILURE;
2042 entry->mServiceObject = aService;
2043 return NS_OK;
2047 NS_IMETHODIMP
2048 nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass,
2049 const nsIID& aIID,
2050 PRBool *result)
2052 // Now we want to get the service if we already got it. If not, we don't want
2053 // to create an instance of it. mmh!
2055 // test this first, since there's no point in returning a service during
2056 // shutdown -- whether it's available or not would depend on the order it
2057 // occurs in the list
2058 if (gXPCOMShuttingDown) {
2059 // When processing shutdown, don't process new GetService() requests
2060 #ifdef SHOW_DENIED_ON_SHUTDOWN
2061 nsXPIDLCString cid, iid;
2062 cid.Adopt(aClass.ToString());
2063 iid.Adopt(aIID.ToString());
2064 fprintf(stderr, "Checking for service on shutdown. Denied.\n"
2065 " CID: %s\n IID: %s\n", cid.get(), iid.get());
2066 #endif /* SHOW_DENIED_ON_SHUTDOWN */
2067 return NS_ERROR_UNEXPECTED;
2070 nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
2071 nsFactoryEntry* entry = nsnull;
2072 nsFactoryTableEntry* factoryTableEntry =
2073 static_cast<nsFactoryTableEntry*>
2074 (PL_DHashTableOperate(&mFactories, &aClass,
2075 PL_DHASH_LOOKUP));
2077 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2078 entry = factoryTableEntry->mFactoryEntry;
2081 if (entry && entry->mServiceObject) {
2082 nsCOMPtr<nsISupports> service;
2083 rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
2084 *result = (service!=nsnull);
2086 return rv;
2090 NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID,
2091 const nsIID& aIID,
2092 PRBool *result)
2094 // Now we want to get the service if we already got it. If not, we don't want
2095 // to create an instance of it. mmh!
2097 // test this first, since there's no point in returning a service during
2098 // shutdown -- whether it's available or not would depend on the order it
2099 // occurs in the list
2100 if (gXPCOMShuttingDown) {
2101 // When processing shutdown, don't process new GetService() requests
2102 #ifdef SHOW_DENIED_ON_SHUTDOWN
2103 nsXPIDLCString iid;
2104 iid.Adopt(aIID.ToString());
2105 fprintf(stderr, "Checking for service on shutdown. Denied.\n"
2106 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
2107 #endif /* SHOW_DENIED_ON_SHUTDOWN */
2108 return NS_ERROR_UNEXPECTED;
2111 nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
2112 nsFactoryEntry *entry = nsnull;
2114 nsAutoMonitor mon(mMon);
2116 nsContractIDTableEntry* contractIDTableEntry =
2117 static_cast<nsContractIDTableEntry*>
2118 (PL_DHashTableOperate(&mContractIDs, aContractID,
2119 PL_DHASH_LOOKUP));
2121 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
2122 entry = contractIDTableEntry->mFactoryEntry;
2124 } // exit monitor
2126 if (entry && entry->mServiceObject) {
2127 nsCOMPtr<nsISupports> service;
2128 rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
2129 *result = (service!=nsnull);
2131 return rv;
2135 NS_IMETHODIMP
2136 nsComponentManagerImpl::UnregisterService(const char* aContractID)
2138 nsresult rv = NS_OK;
2140 nsAutoMonitor mon(mMon);
2142 nsFactoryEntry *entry = nsnull;
2143 nsContractIDTableEntry* contractIDTableEntry =
2144 static_cast<nsContractIDTableEntry*>
2145 (PL_DHashTableOperate(&mContractIDs, aContractID,
2146 PL_DHASH_LOOKUP));
2148 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
2149 entry = contractIDTableEntry->mFactoryEntry;
2152 if (!entry || !entry->mServiceObject)
2153 return NS_ERROR_SERVICE_NOT_AVAILABLE;
2155 entry->mServiceObject = nsnull;
2156 return rv;
2159 NS_IMETHODIMP
2160 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
2161 const nsIID& aIID,
2162 void* *result)
2164 // test this first, since there's no point in returning a service during
2165 // shutdown -- whether it's available or not would depend on the order it
2166 // occurs in the list
2167 if (gXPCOMShuttingDown) {
2168 // When processing shutdown, don't process new GetService() requests
2169 #ifdef SHOW_DENIED_ON_SHUTDOWN
2170 nsXPIDLCString iid;
2171 iid.Adopt(aIID.ToString());
2172 fprintf(stderr, "Getting service on shutdown. Denied.\n"
2173 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
2174 #endif /* SHOW_DENIED_ON_SHUTDOWN */
2175 return NS_ERROR_UNEXPECTED;
2178 nsAutoMonitor mon(mMon);
2180 nsFactoryEntry *entry = nsnull;
2181 nsContractIDTableEntry* contractIDTableEntry =
2182 static_cast<nsContractIDTableEntry*>
2183 (PL_DHashTableOperate(&mContractIDs, aContractID,
2184 PL_DHASH_LOOKUP));
2186 if (!PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry))
2187 return NS_ERROR_FACTORY_NOT_REGISTERED;
2189 entry = contractIDTableEntry->mFactoryEntry;
2190 NS_ASSERTION(entry, "This should never be null!");
2192 if (entry->mServiceObject) {
2193 nsCOMPtr<nsISupports> serviceObject = entry->mServiceObject;
2195 // We need to not be holding the service manager's monitor while calling
2196 // QueryInterface, because it invokes user code which could try to re-enter
2197 // the service manager, or try to grab some other lock/monitor/condvar
2198 // and deadlock, e.g. bug 282743.
2199 mon.Exit();
2200 return serviceObject->QueryInterface(aIID, result);
2203 PRThread* currentPRThread = PR_GetCurrentThread();
2204 NS_ASSERTION(currentPRThread, "This should never be null!");
2206 // Needed to optimize the event loop below.
2207 nsIThread* currentThread = nsnull;
2209 PRThread* pendingPRThread;
2210 while ((pendingPRThread = GetPendingServiceThread(entry->mCid))) {
2211 if (pendingPRThread == currentPRThread) {
2212 NS_ERROR("Recursive GetService!");
2213 return NS_ERROR_NOT_AVAILABLE;
2216 mon.Exit();
2218 if (!currentThread) {
2219 currentThread = NS_GetCurrentThread();
2220 NS_ASSERTION(currentThread, "This should never be null!");
2223 // This will process a single event or yield the thread if no event is
2224 // pending.
2225 if (!NS_ProcessNextEvent(currentThread, PR_FALSE)) {
2226 PR_Sleep(PR_INTERVAL_NO_WAIT);
2229 mon.Enter();
2232 if (currentThread && entry->mServiceObject) {
2233 // If we have a currentThread then we must have waited on another thread
2234 // to create the service. Grab it now if that succeeded.
2235 nsCOMPtr<nsISupports> serviceObject = entry->mServiceObject;
2236 mon.Exit();
2237 return serviceObject->QueryInterface(aIID, result);
2240 #ifdef DEBUG
2241 PendingServiceInfo* newInfo =
2242 #endif
2243 AddPendingService(entry->mCid, currentPRThread);
2244 NS_ASSERTION(newInfo, "Failed to add info to the array!");
2246 nsCOMPtr<nsISupports> service;
2247 // We need to not be holding the service manager's monitor while calling
2248 // CreateInstance, because it invokes user code which could try to re-enter
2249 // the service manager:
2250 mon.Exit();
2252 nsresult rv = CreateInstanceByContractID(aContractID, nsnull, aIID,
2253 getter_AddRefs(service));
2255 mon.Enter();
2257 #ifdef DEBUG
2258 pendingPRThread = GetPendingServiceThread(entry->mCid);
2259 NS_ASSERTION(pendingPRThread == currentPRThread,
2260 "Pending service array has been changed!");
2261 #endif
2262 RemovePendingService(entry->mCid);
2264 if (NS_FAILED(rv))
2265 return rv;
2267 NS_ASSERTION(!entry->mServiceObject, "Created two instances of a service!");
2269 entry->mServiceObject = service;
2270 *result = service.get();
2271 NS_ADDREF(static_cast<nsISupports*>(*result));
2272 return rv;
2275 NS_IMETHODIMP
2276 nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
2277 nsISupports* *result,
2278 nsIShutdownListener* shutdownListener)
2280 return GetService(aClass, aIID, (void**)result);
2283 NS_IMETHODIMP
2284 nsComponentManagerImpl::GetService(const char* aContractID, const nsIID& aIID,
2285 nsISupports* *result,
2286 nsIShutdownListener* shutdownListener)
2288 return GetServiceByContractID(aContractID, aIID, (void**)result);
2292 NS_IMETHODIMP
2293 nsComponentManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service,
2294 nsIShutdownListener* shutdownListener)
2296 NS_IF_RELEASE(service);
2297 return NS_OK;
2300 NS_IMETHODIMP
2301 nsComponentManagerImpl::ReleaseService(const char* aContractID, nsISupports* service,
2302 nsIShutdownListener* shutdownListener)
2304 NS_IF_RELEASE(service);
2305 return NS_OK;
2308 NS_IMETHODIMP
2309 nsComponentManagerImpl::RegistryLocationForSpec(nsIFile *aSpec,
2310 char **aRegistryName)
2312 nsCAutoString location;
2313 nsresult rv = RegistryLocationForFile(aSpec, location);
2314 if (NS_SUCCEEDED(rv)) {
2315 *aRegistryName = ToNewCString(location);
2316 if (!*aRegistryName)
2317 return NS_ERROR_OUT_OF_MEMORY;
2320 return rv;
2323 nsresult
2324 nsComponentManagerImpl::RegistryLocationForFile(nsIFile* aFile,
2325 nsCString& aRegistryName)
2327 nsresult rv;
2329 if (!mComponentsDir)
2330 return NS_ERROR_NOT_INITIALIZED;
2332 // First check to see if this component is in the application
2333 // components directory
2334 PRBool containedIn;
2335 mComponentsDir->Contains(aFile, PR_TRUE, &containedIn);
2337 nsCAutoString nativePathString;
2339 if (containedIn){
2340 rv = aFile->GetNativePath(nativePathString);
2341 if (NS_FAILED(rv))
2342 return rv;
2344 aRegistryName.Assign(NS_LITERAL_CSTRING(XPCOM_RELCOMPONENT_PREFIX) +
2345 Substring(nativePathString, mComponentsOffset + 1));
2346 return NS_OK;
2349 // Next check to see if this component is in the GRE
2350 // components directory
2352 mGREComponentsDir->Contains(aFile, PR_TRUE, &containedIn);
2354 if (containedIn){
2355 rv = aFile->GetNativePath(nativePathString);
2356 if (NS_FAILED(rv))
2357 return rv;
2359 aRegistryName.Assign(NS_LITERAL_CSTRING(XPCOM_GRECOMPONENT_PREFIX) +
2360 Substring(nativePathString, mGREComponentsOffset + 1));
2361 return NS_OK;
2364 /* absolute names include volume info on Mac, so persistent descriptor */
2365 rv = aFile->GetNativePath(nativePathString);
2366 if (NS_FAILED(rv))
2367 return rv;
2369 aRegistryName.Assign(NS_LITERAL_CSTRING(XPCOM_ABSCOMPONENT_PREFIX) +
2370 nativePathString);
2371 return NS_OK;
2374 NS_IMETHODIMP
2375 nsComponentManagerImpl::SpecForRegistryLocation(const char *aLocation,
2376 nsIFile **aSpec)
2378 return FileForRegistryLocation(nsDependentCString(aLocation),
2379 (nsILocalFile**) aSpec);
2382 nsresult
2383 nsComponentManagerImpl::FileForRegistryLocation(const nsCString &aLocation,
2384 nsILocalFile **aSpec)
2386 // i18n: assuming aLocation is encoded for the current locale
2388 nsresult rv;
2390 const nsDependentCSubstring prefix = Substring(aLocation, 0, 4);
2392 /* abs:/full/path/to/libcomponent.so */
2393 if (prefix.EqualsLiteral(XPCOM_ABSCOMPONENT_PREFIX)) {
2395 nsLocalFile* file = new nsLocalFile;
2396 if (!file) return NS_ERROR_FAILURE;
2398 rv = file->InitWithNativePath(Substring(aLocation, 4));
2399 file->QueryInterface(NS_GET_IID(nsILocalFile), (void**)aSpec);
2400 return rv;
2403 if (prefix.EqualsLiteral(XPCOM_RELCOMPONENT_PREFIX)) {
2405 if (!mComponentsDir)
2406 return NS_ERROR_NOT_INITIALIZED;
2408 nsILocalFile* file = nsnull;
2409 rv = mComponentsDir->Clone((nsIFile**)&file);
2411 if (NS_FAILED(rv)) return rv;
2413 rv = file->AppendRelativeNativePath(Substring(aLocation, 4));
2414 *aSpec = file;
2415 return rv;
2418 if (prefix.EqualsLiteral(XPCOM_GRECOMPONENT_PREFIX)) {
2420 if (!mGREComponentsDir)
2421 return NS_ERROR_NOT_INITIALIZED;
2423 nsILocalFile* file = nsnull;
2424 rv = mGREComponentsDir->Clone((nsIFile**)&file);
2426 if (NS_FAILED(rv)) return rv;
2428 rv = file->AppendRelativeNativePath(Substring(aLocation, 4));
2429 *aSpec = file;
2430 return rv;
2433 *aSpec = nsnull;
2434 return NS_ERROR_INVALID_ARG;
2438 * RegisterFactory()
2440 * Register a factory to be responsible for creation of implementation of
2441 * classID aClass. Plus creates as association of aClassName and aContractID
2442 * to the classID. If replace is PR_TRUE, we replace any existing registrations
2443 * with this one.
2445 * Once registration is complete, we add the class to the factories cache
2446 * that we maintain. The factories cache is the ONLY place where these
2447 * registrations are ever kept.
2449 * The other RegisterFunctions create a loader mapping and persistent
2450 * location, but we just slam it into the cache here. And we don't call the
2451 * loader's OnRegister function, either.
2453 NS_IMETHODIMP
2454 nsComponentManagerImpl::RegisterFactory(const nsCID &aClass,
2455 const char *aClassName,
2456 const char *aContractID,
2457 nsIFactory *aFactory,
2458 PRBool aReplace)
2460 nsAutoMonitor mon(mMon);
2461 #ifdef PR_LOGGING
2462 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
2464 char *buf = aClass.ToString();
2465 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2466 ("nsComponentManager: RegisterFactory(%s, %s)", buf,
2467 (aContractID ? aContractID : "(null)")));
2468 if (buf)
2469 PR_Free(buf);
2471 #endif
2472 nsFactoryEntry *entry = nsnull;
2473 nsFactoryTableEntry* factoryTableEntry = static_cast<nsFactoryTableEntry*>
2474 (PL_DHashTableOperate(&mFactories,
2475 &aClass,
2476 PL_DHASH_ADD));
2478 if (!factoryTableEntry)
2479 return NS_ERROR_OUT_OF_MEMORY;
2482 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2483 entry = factoryTableEntry->mFactoryEntry;
2486 if (entry && !aReplace)
2488 // Already registered
2489 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
2490 ("\t\tFactory already registered."));
2491 return NS_ERROR_FACTORY_EXISTS;
2494 void *mem;
2495 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2496 if (!mem)
2497 return NS_ERROR_OUT_OF_MEMORY;
2499 entry = new (mem) nsFactoryEntry(aClass, aFactory, entry);
2501 factoryTableEntry->mFactoryEntry = entry;
2503 // Update the ContractID->CLSID Map
2504 if (aContractID) {
2505 nsresult rv = HashContractID(aContractID, strlen(aContractID), entry);
2506 if (NS_FAILED(rv)) {
2507 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2508 ("\t\tFactory register succeeded. "
2509 "Hashing contractid (%s) FAILED.", aContractID));
2510 return rv;
2514 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2515 ("\t\tFactory register succeeded contractid=%s.",
2516 aContractID ? aContractID : "<none>"));
2518 return NS_OK;
2521 NS_IMETHODIMP
2522 nsComponentManagerImpl::RegisterComponent(const nsCID &aClass,
2523 const char *aClassName,
2524 const char *aContractID,
2525 const char *aPersistentDescriptor,
2526 PRBool aReplace,
2527 PRBool aPersist)
2529 NS_ENSURE_ARG_POINTER(aPersistentDescriptor);
2530 return RegisterComponentCommon(aClass, aClassName,
2531 aContractID,
2532 aContractID ? strlen(aContractID) : 0,
2533 aPersistentDescriptor,
2534 strlen(aPersistentDescriptor),
2535 aReplace, aPersist,
2536 nativeComponentType);
2539 NS_IMETHODIMP
2540 nsComponentManagerImpl::RegisterComponentWithType(const nsCID &aClass,
2541 const char *aClassName,
2542 const char *aContractID,
2543 nsIFile *aSpec,
2544 const char *aLocation,
2545 PRBool aReplace,
2546 PRBool aPersist,
2547 const char *aType)
2549 NS_ENSURE_ARG_POINTER(aLocation);
2550 return RegisterComponentCommon(aClass, aClassName,
2551 aContractID,
2552 aContractID ? strlen(aContractID) : 0,
2553 aLocation,
2554 strlen(aLocation),
2555 aReplace, aPersist,
2556 aType);
2560 * Register a component, using whatever they stuck in the nsIFile.
2562 NS_IMETHODIMP
2563 nsComponentManagerImpl::RegisterComponentSpec(const nsCID &aClass,
2564 const char *aClassName,
2565 const char *aContractID,
2566 nsIFile *aLibrarySpec,
2567 PRBool aReplace,
2568 PRBool aPersist)
2570 nsCAutoString registryName;
2571 nsresult rv = RegistryLocationForFile(aLibrarySpec,
2572 registryName);
2573 if (NS_FAILED(rv))
2574 return rv;
2576 rv = RegisterComponentWithType(aClass, aClassName,
2577 aContractID,
2578 aLibrarySpec,
2579 registryName.get(),
2580 aReplace, aPersist,
2581 nativeComponentType);
2582 return rv;
2585 NS_IMETHODIMP
2586 nsComponentManagerImpl::RegisterComponentLib(const nsCID &aClass,
2587 const char *aClassName,
2588 const char *aContractID,
2589 const char *aDllName,
2590 PRBool aReplace,
2591 PRBool aPersist)
2593 // deprecated and obsolete.
2594 return NS_ERROR_NOT_IMPLEMENTED;
2598 * Add a component to the known universe of components.
2600 * Once we enter this function, we own aRegistryName, and must free it
2601 * or hand it to nsFactoryEntry. Common exit point ``out'' helps keep us
2602 * sane.
2605 nsresult
2606 nsComponentManagerImpl::RegisterComponentCommon(const nsCID &aClass,
2607 const char *aClassName,
2608 const char *aContractID,
2609 PRUint32 aContractIDLen,
2610 const char *aRegistryName,
2611 PRUint32 aRegistryNameLen,
2612 PRBool aReplace,
2613 PRBool aPersist,
2614 const char *aType)
2616 nsresult rv;
2618 nsIDKey key(aClass);
2619 nsAutoMonitor mon(mMon);
2621 nsFactoryEntry *entry = GetFactoryEntry(aClass);
2623 // Normalize proid and classname
2624 const char *contractID = (aContractID && *aContractID) ? aContractID : nsnull;
2625 #ifdef PR_LOGGING
2626 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
2628 char *buf = aClass.ToString();
2629 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2630 ("nsComponentManager: RegisterComponentCommon(%s, %s, %s, %s)",
2631 buf,
2632 contractID ? contractID : "(null)",
2633 aRegistryName, aType));
2634 if (buf)
2635 PR_Free(buf);
2637 #endif
2638 if (entry && !aReplace) {
2639 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
2640 ("\t\tFactory already registered."));
2641 return NS_ERROR_FACTORY_EXISTS;
2644 int typeIndex = GetLoaderType(aType);
2645 if (typeIndex == NS_LOADER_TYPE_INVALID)
2646 return NS_ERROR_OUT_OF_MEMORY;
2648 if (entry) {
2649 entry->ReInit(typeIndex, aRegistryName);
2651 else {
2653 // Arena allocate the nsFactoryEntry
2654 void *mem;
2655 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2656 if (!mem)
2657 return NS_ERROR_OUT_OF_MEMORY;
2659 mRegistryDirty = PR_TRUE;
2660 entry = new (mem) nsFactoryEntry(aClass,
2661 typeIndex,
2662 aRegistryName);
2663 if (!entry->mLocationKey)
2664 return NS_ERROR_OUT_OF_MEMORY;
2666 nsFactoryTableEntry* factoryTableEntry =
2667 static_cast<nsFactoryTableEntry*>
2668 (PL_DHashTableOperate(&mFactories, &aClass,
2669 PL_DHASH_ADD));
2671 if (!factoryTableEntry)
2672 return NS_ERROR_OUT_OF_MEMORY;
2674 factoryTableEntry->mFactoryEntry = entry;
2677 // Update the ContractID->CLSID Map
2678 if (contractID) {
2679 rv = HashContractID(contractID, aContractIDLen, entry);
2680 if (NS_FAILED(rv)) {
2681 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
2682 ("\t\tHashContractID(%s) FAILED\n", contractID));
2683 return rv;
2686 return NS_OK;
2690 nsIModuleLoader*
2691 nsComponentManagerImpl::LoaderForType(LoaderType aType)
2693 NS_ASSERTION(aType != NS_LOADER_TYPE_STATIC,
2694 "Static component loader is special");
2696 if (aType == NS_LOADER_TYPE_INVALID)
2697 return nsnull;
2699 if (aType == NS_LOADER_TYPE_NATIVE)
2700 return &mNativeModuleLoader;
2702 NS_ASSERTION(aType >= 0 && aType < mLoaderData.Length(),
2703 "LoaderType out of range");
2705 if (!mLoaderData[aType].loader) {
2706 nsCOMPtr<nsIModuleLoader> loader;
2707 loader = do_GetServiceFromCategory("module-loader",
2708 mLoaderData[aType].type.get());
2709 if (!loader)
2710 return nsnull;
2712 loader.swap(mLoaderData[aType].loader);
2715 return mLoaderData[aType].loader;
2718 void
2719 nsComponentManagerImpl::GetAllLoaders()
2721 NS_ASSERTION(mCategoryManager, "nsComponentManager used uninitialized");
2723 nsCOMPtr<nsISimpleEnumerator> loaderEnum;
2724 mCategoryManager->EnumerateCategory("module-loader",
2725 getter_AddRefs(loaderEnum));
2726 nsCOMPtr<nsIUTF8StringEnumerator>
2727 loaderStrings(do_QueryInterface(loaderEnum));
2728 if (loaderStrings) {
2729 PRBool hasMore;
2730 while (NS_SUCCEEDED(loaderStrings->HasMore(&hasMore)) && hasMore) {
2731 nsCAutoString loaderType;
2732 if (NS_FAILED(loaderStrings->GetNext(loaderType)))
2733 continue;
2735 // We depend on the loader being created. Add the loader type and
2736 // create the loader object too.
2737 (void) LoaderForType(AddLoaderType(loaderType.get()));
2742 // Convert a loader type string into an index into the component data
2743 // array. Empty loader types are converted to NATIVE.
2744 LoaderType
2745 nsComponentManagerImpl::GetLoaderType(const char *typeStr)
2747 if (!typeStr || !*typeStr) {
2748 // Empty type strings are NATIVE
2749 return NS_LOADER_TYPE_NATIVE;
2752 if (!strcmp(typeStr, staticComponentType))
2753 return NS_LOADER_TYPE_STATIC;
2755 if (!strcmp(typeStr, nativeComponentType))
2756 return NS_LOADER_TYPE_NATIVE;
2758 const nsDependentCString type(typeStr);
2760 for (unsigned int i = 0; i < mLoaderData.Length(); ++i) {
2761 if (mLoaderData[i].type == type)
2762 return i;
2765 return NS_LOADER_TYPE_INVALID;
2768 // Add a loader type if not already known. Out the typeIndex
2769 // if the loader type is either added or already there.
2770 LoaderType
2771 nsComponentManagerImpl::AddLoaderType(const char *typeStr)
2773 LoaderType typeIndex = GetLoaderType(typeStr);
2774 if (typeIndex != NS_LOADER_TYPE_INVALID)
2775 return typeIndex;
2777 // Add the loader type
2778 nsLoaderdata *elem = mLoaderData.AppendElement();
2779 if (!elem)
2780 return NS_LOADER_TYPE_INVALID;
2782 elem->type.Assign(typeStr);
2783 return mLoaderData.Length() - 1;
2786 typedef struct
2788 const nsCID* cid;
2789 nsIFactory* factory;
2790 } UnregisterConditions;
2792 static PLDHashOperator
2793 DeleteFoundCIDs(PLDHashTable *aTable,
2794 PLDHashEntryHdr *aHdr,
2795 PRUint32 aNumber,
2796 void *aData)
2798 nsContractIDTableEntry* entry = static_cast<nsContractIDTableEntry*>(aHdr);
2800 if (!entry->mFactoryEntry)
2801 return PL_DHASH_NEXT;
2803 UnregisterConditions* data = (UnregisterConditions*)aData;
2805 nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
2806 if (data->cid->Equals(factoryEntry->mCid) &&
2807 data->factory == factoryEntry->mFactory.get())
2808 return PL_DHASH_REMOVE;
2810 return PL_DHASH_NEXT;
2813 void
2814 nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, nsIFactory* factory)
2816 UnregisterConditions aData;
2817 aData.cid = aClass;
2818 aData.factory = factory;
2819 PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData);
2822 nsresult
2823 nsComponentManagerImpl::UnregisterFactory(const nsCID &aClass,
2824 nsIFactory *aFactory)
2826 #ifdef PR_LOGGING
2827 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
2829 char *buf = aClass.ToString();
2830 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2831 ("nsComponentManager: UnregisterFactory(%s)", buf));
2832 if (buf)
2833 PR_Free(buf);
2835 #endif
2836 nsFactoryEntry *old;
2838 // first delete all contract id entries that are registered with this cid.
2839 DeleteContractIDEntriesByCID(&aClass, aFactory);
2841 // next check to see if there is a CID registered
2842 nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
2843 old = GetFactoryEntry(aClass);
2845 if (old && (old->mFactory.get() == aFactory))
2847 nsAutoMonitor mon(mMon);
2848 PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE);
2849 rv = NS_OK;
2852 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2853 ("\t\tUnregisterFactory() %s",
2854 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
2855 return rv;
2858 NS_IMETHODIMP
2859 nsComponentManagerImpl::UnregisterComponent(const nsCID &aClass,
2860 const char *registryName)
2862 NS_ERROR("Don't call nsIComponentManagerObsolete.unregisterComponent");
2863 return NS_ERROR_NOT_IMPLEMENTED;
2866 NS_IMETHODIMP
2867 nsComponentManagerImpl::UnregisterComponentSpec(const nsCID &aClass,
2868 nsIFile *aLibrarySpec)
2870 NS_ERROR("Don't call nsIComponentManagerObsolete.unregisterComponentSpec");
2871 return NS_ERROR_NOT_IMPLEMENTED;
2874 NS_IMETHODIMP
2875 nsComponentManagerImpl::FreeLibraries(void)
2877 return NS_ERROR_NOT_IMPLEMENTED;
2881 * AutoRegister(RegistrationInstant, const char *directory)
2883 * Given a directory in the following format, this will ensure proper registration
2884 * of all components. No default directory is looked at.
2886 * Directory and fullname are what NSPR will accept. For eg.
2887 * WIN y:/home/dp/mozilla/dist/bin
2888 * UNIX /home/dp/mozilla/dist/bin
2889 * MAC /Hard drive/mozilla/dist/apprunner
2891 * This will take care not loading already registered dlls, finding and
2892 * registering new dlls, re-registration of modified dlls
2896 NS_IMETHODIMP
2897 nsComponentManagerImpl::AutoRegister(PRInt32 when, nsIFile *inDirSpec)
2899 return AutoRegister(inDirSpec);
2902 nsresult
2903 nsComponentManagerImpl::AutoRegisterImpl(nsIFile *inDirSpec,
2904 nsCOMArray<nsILocalFile> &aLeftovers,
2905 nsTArray<DeferredModule> &aDeferred)
2907 NS_ASSERTION(inDirSpec, "inDirSpec must not be null");
2909 nsresult rv;
2911 PRBool isDir;
2912 rv = inDirSpec->IsDirectory(&isDir);
2913 if (NS_FAILED(rv))
2914 return rv;
2916 if (isDir)
2917 return AutoRegisterDirectory(inDirSpec, aLeftovers, aDeferred);
2919 nsCOMPtr<nsILocalFile> lf(do_QueryInterface(inDirSpec));
2920 if (!lf)
2921 return NS_NOINTERFACE;
2923 rv = AutoRegisterComponent(lf, aDeferred);
2924 if (NS_FAILED(rv))
2925 aLeftovers.AppendObject(lf);
2926 return rv;
2929 nsresult
2930 nsComponentManagerImpl::AutoRegisterDirectory(nsIFile *inDirSpec,
2931 nsCOMArray<nsILocalFile> &aLeftovers,
2932 nsTArray<DeferredModule> &aDeferred)
2934 nsCOMPtr<nsISimpleEnumerator> entries;
2935 nsresult rv = inDirSpec->GetDirectoryEntries(getter_AddRefs(entries));
2936 if (NS_FAILED(rv))
2937 return rv;
2939 PRBool hasMore;
2940 nsCOMPtr<nsISupports> elem;
2942 while (NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) {
2943 entries->GetNext(getter_AddRefs(elem));
2944 nsCOMPtr<nsILocalFile> lf(do_QueryInterface(elem));
2945 if (!lf) {
2946 NS_ERROR("Directory enumerator misbehaving");
2947 continue;
2950 PRBool isDir;
2951 rv = lf->IsDirectory(&isDir);
2952 if (NS_FAILED(rv))
2953 continue;
2955 if (isDir)
2956 AutoRegisterDirectory(lf, aLeftovers, aDeferred);
2957 else {
2958 rv = AutoRegisterComponent(lf, aDeferred);
2959 if (NS_FAILED(rv))
2960 aLeftovers.AppendObject(lf);
2964 return NS_OK;
2967 nsresult
2968 nsComponentManagerImpl::AutoRegisterComponent(PRInt32 unused,
2969 nsIFile *component)
2971 nsCOMPtr<nsILocalFile> lf(do_QueryInterface(component));
2972 if (!lf)
2973 return NS_NOINTERFACE;
2975 GetAllLoaders();
2977 nsTArray<DeferredModule> deferred;
2979 nsresult rv = AutoRegisterComponent(lf, deferred);
2980 if (deferred.Length())
2981 return NS_ERROR_FACTORY_REGISTER_AGAIN;
2983 return rv;
2986 nsresult
2987 nsComponentManagerImpl::AutoRegisterComponent(nsILocalFile* aComponentFile,
2988 nsTArray<DeferredModule> &aDeferred,
2989 LoaderType minLoader)
2991 nsresult rv;
2993 NS_ASSERTION(minLoader < GetLoaderCount(), "Bad minLoader");
2995 nsCAutoString registryLocation;
2996 rv = RegistryLocationForFile(aComponentFile, registryLocation);
2997 if (NS_FAILED(rv))
2998 return rv;
3000 const nsDependentCSubstring extension = StringTail(registryLocation, 4);
3001 if (extension.LowerCaseEqualsLiteral(".dat") ||
3002 extension.LowerCaseEqualsLiteral(".xpt"))
3003 return NS_OK;
3005 nsCOMPtr<nsIHashable> lfhash(do_QueryInterface(aComponentFile));
3006 if (!lfhash) {
3007 NS_ERROR("localfile not implementing nsIHashable!");
3008 return NS_NOINTERFACE;
3011 PRInt64 modTime = 0;
3012 if (NS_SUCCEEDED(aComponentFile->GetLastModifiedTime(&modTime))) {
3013 PRInt64 cachedModTime;
3014 if (mAutoRegEntries.Get(lfhash, &cachedModTime) &&
3015 cachedModTime == modTime)
3016 return NS_OK;
3019 const char *registryType = nsnull;
3021 nsCOMPtr<nsIModule> module;
3023 if (minLoader == NS_LOADER_TYPE_NATIVE) {
3024 rv = mNativeModuleLoader.LoadModule(aComponentFile,
3025 getter_AddRefs(module));
3026 if (NS_SUCCEEDED(rv)) {
3027 if (!module) {
3028 NS_ERROR("Module loader succeeded without returning a module");
3029 return NS_ERROR_FAILURE;
3031 registryType = nativeComponentType;
3034 minLoader = 0;
3037 if (!registryType) {
3038 for (; minLoader < GetLoaderCount(); ++minLoader) {
3039 nsIModuleLoader* loader = LoaderForType(minLoader);
3040 if (!loader)
3041 continue;
3043 rv = loader->LoadModule(aComponentFile, getter_AddRefs(module));
3044 if (NS_SUCCEEDED(rv)) {
3045 if (!module) {
3046 NS_ERROR("Module loader succeeded without returning a module.");
3047 return NS_ERROR_FAILURE;
3049 registryType = StringForLoaderType(minLoader);
3050 break;
3053 if (!registryType) {
3054 return NS_ERROR_FAILURE;
3058 rv = module->RegisterSelf(this, aComponentFile, registryLocation.get(),
3059 registryType);
3060 if (NS_ERROR_FACTORY_REGISTER_AGAIN == rv) {
3061 DeferredModule *d = aDeferred.AppendElement();
3062 if (!d)
3063 return NS_ERROR_OUT_OF_MEMORY;
3065 d->type = registryType;
3066 d->file = aComponentFile;
3067 d->location = registryLocation;
3068 d->module = module;
3069 d->modTime = modTime;
3070 return NS_OK;
3073 if (NS_SUCCEEDED(rv) && modTime != 0)
3074 mAutoRegEntries.Put(lfhash, modTime);
3076 return rv;
3079 void
3080 nsComponentManagerImpl::LoadLeftoverComponents(
3081 nsCOMArray<nsILocalFile> &aLeftovers,
3082 nsTArray<DeferredModule> &aDeferred,
3083 LoaderType minLoader)
3085 NS_ASSERTION(minLoader >= GetLoaderCount(), "Corrupted minLoader");
3087 GetAllLoaders();
3089 // If there aren't any new loaders found since we tried this last, there's
3090 // nothing left to do.
3091 if (GetLoaderCount() == minLoader)
3092 return;
3094 LoaderType curLoader = GetLoaderCount();
3096 for (PRInt32 i = 0; i < aLeftovers.Count(); ) {
3097 nsresult rv = AutoRegisterComponent(aLeftovers[i], aDeferred,
3098 minLoader);
3099 if (NS_SUCCEEDED(rv)) {
3100 aLeftovers.RemoveObjectAt(i);
3102 else {
3103 ++i;
3106 if (aLeftovers.Count())
3107 // recursively try this again until there are no new loaders found
3108 LoadLeftoverComponents(aLeftovers, aDeferred, curLoader);
3111 void
3112 nsComponentManagerImpl::LoadDeferredModules(nsTArray<DeferredModule> &aDeferred)
3114 // We keep looping through deferred components until one of
3115 // 1) they're all gone
3116 // 2) we loop through and none of them succeed
3118 PRUint32 lastCount = PR_UINT32_MAX;
3119 while (aDeferred.Length() > 0 &&
3120 lastCount > aDeferred.Length()) {
3122 lastCount = aDeferred.Length();
3124 for (PRInt32 i = 0; i < aDeferred.Length(); ) {
3125 DeferredModule &d = aDeferred[i];
3126 nsresult rv = d.module->RegisterSelf(this,
3127 d.file,
3128 d.location.get(),
3129 d.type);
3130 if (NS_SUCCEEDED(rv) && d.modTime != 0) {
3131 nsCOMPtr<nsIHashable> lfhash(do_QueryInterface(d.file));
3132 if (lfhash)
3133 mAutoRegEntries.Put(lfhash, d.modTime);
3136 if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) {
3137 aDeferred.RemoveElementAt(i);
3139 else {
3140 ++i;
3146 NS_IMETHODIMP
3147 nsComponentManagerImpl::AutoUnregisterComponent(PRInt32 /* unused */,
3148 nsIFile *component)
3150 nsresult rv;
3152 GetAllLoaders();
3154 nsCAutoString location;
3155 rv = RegistryLocationForFile(component, location);
3156 if (NS_FAILED(rv))
3157 return rv;
3159 nsCOMPtr<nsILocalFile> lf(do_QueryInterface(component));
3160 if (!lf)
3161 return NS_NOINTERFACE;
3163 nsCOMPtr<nsIModule> module;
3164 rv = mNativeModuleLoader.LoadModule(lf, getter_AddRefs(module));
3165 if (NS_FAILED(rv)) {
3166 for (LoaderType i = 0; i < mLoaderData.Length(); ++i) {
3167 nsIModuleLoader* loader = LoaderForType(i);
3168 if (!loader)
3169 continue;
3171 if (NS_SUCCEEDED(loader->LoadModule(lf, getter_AddRefs(module))) &&
3172 module) {
3173 break;
3178 if (!module)
3179 return NS_ERROR_FAILURE;
3181 rv = module->UnregisterSelf(this, lf, location.get());
3183 nsCOMPtr<nsIHashable> lfhash(do_QueryInterface(lf));
3184 mAutoRegEntries.Remove(lfhash);
3186 return rv;
3189 NS_IMETHODIMP
3190 nsComponentManagerImpl::IsRegistered(const nsCID &aClass,
3191 PRBool *aRegistered)
3193 if (!aRegistered)
3195 NS_ASSERTION(0, "null ptr");
3196 return NS_ERROR_NULL_POINTER;
3198 *aRegistered = (nsnull != GetFactoryEntry(aClass));
3199 return NS_OK;
3202 NS_IMETHODIMP
3203 nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator** aEnumerator)
3205 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3206 if (!aEnumerator)
3208 return NS_ERROR_NULL_POINTER;
3210 *aEnumerator = nsnull;
3212 nsresult rv;
3214 PLDHashTableEnumeratorImpl *aEnum;
3215 rv = PL_NewDHashTableEnumerator(&mFactories,
3216 ConvertFactoryEntryToCID,
3217 (void*)this,
3218 &aEnum);
3219 if (NS_FAILED(rv))
3220 return rv;
3222 *aEnumerator = static_cast<nsIEnumerator*>(aEnum);
3223 return NS_OK;
3226 NS_IMETHODIMP
3227 nsComponentManagerImpl::EnumerateContractIDs(nsIEnumerator** aEnumerator)
3229 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3230 if (!aEnumerator)
3232 return NS_ERROR_NULL_POINTER;
3235 *aEnumerator = nsnull;
3237 nsresult rv;
3238 PLDHashTableEnumeratorImpl *aEnum;
3239 rv = PL_NewDHashTableEnumerator(&mContractIDs,
3240 ConvertContractIDKeyToString,
3241 (void*)this,
3242 &aEnum);
3243 if (NS_FAILED(rv))
3244 return rv;
3246 *aEnumerator = static_cast<nsIEnumerator*>(aEnum);
3247 return NS_OK;
3250 // nsIComponentRegistrar
3252 static void
3253 RegisterStaticModule(const char *key, nsIModule* module,
3254 nsTArray<DeferredModule> &deferred)
3256 nsresult rv = module->
3257 RegisterSelf(nsComponentManagerImpl::gComponentManager,
3258 nsnull, key, staticComponentType);
3260 if (NS_ERROR_FACTORY_REGISTER_AGAIN == rv) {
3261 DeferredModule *d = deferred.AppendElement();
3262 if (d) {
3263 d->type = staticComponentType;
3264 d->location = key;
3269 static void
3270 ReportLoadFailure(nsIFile* aFile, nsIConsoleService* aCS)
3272 nsAutoString message;
3273 aFile->GetPath(message);
3274 message.Insert(NS_LITERAL_STRING("Failed to load XPCOM component: "), 0);
3276 aCS->LogStringMessage(message.get());
3279 NS_IMETHODIMP
3280 nsComponentManagerImpl::AutoRegister(nsIFile *aSpec)
3282 nsresult rv;
3284 if (!mCategoryManager) {
3285 mCategoryManager = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
3286 if (NS_FAILED(rv))
3287 return rv;
3290 GetAllLoaders();
3292 // Notify observers of xpcom autoregistration start
3293 NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
3294 aSpec, "start");
3296 nsCOMArray<nsILocalFile> leftovers;
3297 nsTArray<DeferredModule> deferred;
3299 if (!aSpec) {
3300 mStaticModuleLoader.EnumerateModules(RegisterStaticModule,
3301 deferred);
3303 // Builtin component loaders (xpconnect!) can be static modules.
3304 // Set them up now, so that JS components don't go into
3305 // the leftovers list.
3306 GetAllLoaders();
3309 LoaderType curLoader = GetLoaderCount();
3311 if (aSpec) {
3312 rv = AutoRegisterImpl(aSpec, leftovers, deferred);
3314 else {
3315 // register static components, then GRE components, then
3316 // NS_XPCOM_COMPONENT_DIR, then NS_XPCOM_COMPONENT_DIR_LIST
3318 PRBool equals = PR_FALSE;
3320 if (mGREComponentsDir &&
3321 NS_SUCCEEDED(mGREComponentsDir->Equals(mComponentsDir, &equals)) &&
3322 !equals) {
3323 rv = AutoRegisterImpl(mGREComponentsDir, leftovers, deferred);
3324 if (NS_FAILED(rv)) {
3325 NS_WARNING("Couldn't register mGREComponentsDir");
3329 rv = AutoRegisterImpl(mComponentsDir, leftovers, deferred);
3330 if (NS_FAILED(rv)) {
3331 NS_WARNING("Couldn't register mComponentsDir");
3334 nsCOMPtr<nsISimpleEnumerator> dirList;
3335 rv = nsDirectoryService::gService->Get(NS_XPCOM_COMPONENT_DIR_LIST,
3336 NS_GET_IID(nsISimpleEnumerator),
3337 getter_AddRefs(dirList));
3338 if (NS_SUCCEEDED(rv) && dirList) {
3339 PRBool hasMore;
3340 nsCOMPtr<nsISupports> elem;
3342 while (NS_SUCCEEDED(dirList->HasMoreElements(&hasMore)) &&
3343 hasMore) {
3344 dirList->GetNext(getter_AddRefs(elem));
3345 nsCOMPtr<nsIFile> dir(do_QueryInterface(elem));
3346 if (dir) {
3347 AutoRegisterImpl(dir, leftovers, deferred);
3352 rv = NS_OK;
3355 if (NS_SUCCEEDED(rv)) {
3356 // We may have found new component loaders in the meantime, try to go
3357 // back and load the leftovers.
3358 if (leftovers.Count())
3359 LoadLeftoverComponents(leftovers, deferred, curLoader);
3361 // If a module said its loading should be deferred, register it now
3362 if (deferred.Length())
3363 LoadDeferredModules(deferred);
3365 nsCOMPtr<nsIConsoleService>
3366 cs(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
3368 if (cs) {
3369 for (PRInt32 i = 0; i < leftovers.Count(); ++i) {
3370 ReportLoadFailure(leftovers[i], cs);
3375 // Notify observers of xpcom autoregistration completion
3376 NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
3377 aSpec,
3378 "end");
3380 if (mRegistryDirty)
3381 WritePersistentRegistry();
3383 return rv;
3386 NS_IMETHODIMP
3387 nsComponentManagerImpl::AutoUnregister(nsIFile *aSpec)
3389 // unregistering a complete directory is not implmeneted yet...FIX
3390 if (aSpec == nsnull)
3391 return NS_ERROR_NOT_IMPLEMENTED;
3393 PRBool directory;
3394 aSpec->IsDirectory(&directory);
3396 if (directory)
3397 return NS_ERROR_NOT_IMPLEMENTED;
3399 return AutoUnregisterComponent(0, aSpec);
3402 NS_IMETHODIMP
3403 nsComponentManagerImpl::RegisterFactory(const nsCID & aClass,
3404 const char *aClassName,
3405 const char *aContractID,
3406 nsIFactory *aFactory)
3408 return RegisterFactory(aClass,
3409 aClassName,
3410 aContractID,
3411 aFactory,
3412 PR_TRUE);
3415 NS_IMETHODIMP
3416 nsComponentManagerImpl::RegisterFactoryLocation(const nsCID & aClass,
3417 const char *aClassName,
3418 const char *aContractID,
3419 nsIFile *aFile,
3420 const char *loaderStr,
3421 const char *aType)
3423 nsCAutoString registryName;
3425 if (!loaderStr)
3427 nsresult rv = RegistryLocationForFile(aFile, registryName);
3428 if (NS_FAILED(rv))
3429 return rv;
3432 nsresult rv;
3433 rv = RegisterComponentWithType(aClass,
3434 aClassName,
3435 aContractID,
3436 aFile,
3437 (loaderStr ? loaderStr : registryName.get()),
3438 PR_TRUE,
3439 PR_TRUE,
3440 (aType ? aType : nativeComponentType));
3441 return rv;
3444 NS_IMETHODIMP
3445 nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID & aClass,
3446 nsIFile *aFile)
3448 return UnregisterComponentSpec(aClass, aFile);
3451 NS_IMETHODIMP
3452 nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass,
3453 PRBool *_retval)
3455 return IsRegistered(aClass, _retval);
3458 NS_IMETHODIMP
3459 nsComponentManagerImpl::IsContractIDRegistered(const char *aClass,
3460 PRBool *_retval)
3462 nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass));
3464 if (entry)
3465 *_retval = PR_TRUE;
3466 else
3467 *_retval = PR_FALSE;
3468 return NS_OK;
3471 NS_IMETHODIMP
3472 nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator)
3474 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3476 if (!aEnumerator)
3477 return NS_ERROR_NULL_POINTER;
3479 *aEnumerator = nsnull;
3481 nsresult rv;
3482 PLDHashTableEnumeratorImpl *aEnum;
3483 rv = PL_NewDHashTableEnumerator(&mFactories,
3484 ConvertFactoryEntryToCID,
3485 (void*)this,
3486 &aEnum);
3487 if (NS_FAILED(rv))
3488 return rv;
3490 *aEnumerator = static_cast<nsISimpleEnumerator*>(aEnum);
3491 return NS_OK;
3494 NS_IMETHODIMP
3495 nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator)
3497 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3498 if (!aEnumerator)
3499 return NS_ERROR_NULL_POINTER;
3501 *aEnumerator = nsnull;
3503 nsresult rv;
3504 PLDHashTableEnumeratorImpl *aEnum;
3505 rv = PL_NewDHashTableEnumerator(&mContractIDs,
3506 ConvertContractIDKeyToString,
3507 (void*)this,
3508 &aEnum);
3509 if (NS_FAILED(rv))
3510 return rv;
3512 *aEnumerator = static_cast<nsISimpleEnumerator*>(aEnum);
3513 return NS_OK;
3516 NS_IMETHODIMP
3517 nsComponentManagerImpl::CIDToContractID(const nsCID & aClass,
3518 char **_retval)
3520 return CLSIDToContractID(aClass,
3521 nsnull,
3522 _retval);
3525 NS_IMETHODIMP
3526 nsComponentManagerImpl::ContractIDToCID(const char *aContractID,
3527 nsCID * *_retval)
3529 *_retval = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
3530 if (!*_retval)
3531 return NS_ERROR_OUT_OF_MEMORY;
3533 nsresult rv = ContractIDToClassID(aContractID, *_retval);
3534 if (NS_FAILED(rv)) {
3535 nsMemory::Free(*_retval);
3536 *_retval = nsnull;
3538 return rv;
3541 ////////////////////////////////////////////////////////////////////////////////
3542 // nsFactoryEntry
3543 ////////////////////////////////////////////////////////////////////////////////
3545 nsFactoryEntry::nsFactoryEntry(const nsCID &aClass,
3546 LoaderType aLoaderType,
3547 const char *aLocationKey,
3548 nsFactoryEntry *aParent) :
3549 mCid(aClass),
3550 mLoaderType(aLoaderType),
3551 mLocationKey(
3552 ArenaStrdup(aLocationKey,
3553 &nsComponentManagerImpl::gComponentManager->mArena)),
3554 mParent(aParent)
3558 void
3559 nsFactoryEntry::ReInit(LoaderType aLoaderType,
3560 const char *aLocationKey)
3562 mLoaderType = aLoaderType;
3564 if (!mLocationKey || strcmp(mLocationKey, aLocationKey)) {
3565 mLocationKey =
3566 ArenaStrdup(aLocationKey,
3567 &nsComponentManagerImpl::gComponentManager->mArena);
3571 nsresult
3572 nsFactoryEntry::GetFactory(nsIFactory **aFactory)
3574 if (!mFactory) {
3575 nsresult rv;
3577 if (mLoaderType == NS_LOADER_TYPE_INVALID)
3578 return NS_ERROR_FAILURE;
3580 nsCOMPtr<nsIModule> module;
3582 if (mLoaderType == NS_LOADER_TYPE_STATIC) {
3583 rv = nsComponentManagerImpl::gComponentManager->
3584 mStaticModuleLoader.
3585 GetModuleFor(mLocationKey,
3586 getter_AddRefs(module));
3588 else {
3589 nsCOMPtr<nsILocalFile> moduleFile;
3590 rv = nsComponentManagerImpl::gComponentManager->
3591 FileForRegistryLocation(nsDependentCString(mLocationKey),
3592 getter_AddRefs(moduleFile));
3593 NS_ENSURE_SUCCESS(rv, rv);
3595 nsIModuleLoader* loader =
3596 nsComponentManagerImpl::gComponentManager->
3597 LoaderForType(mLoaderType);
3598 if (!loader)
3599 return NS_ERROR_FAILURE;
3601 rv = loader->LoadModule(moduleFile,
3602 getter_AddRefs(module));
3605 if (NS_FAILED(rv))
3606 return rv;
3608 if (!module) {
3609 NS_ERROR("Module returned success but no module!");
3610 return NS_ERROR_FAILURE;
3613 rv = module->
3614 GetClassObject(nsComponentManagerImpl::gComponentManager,
3615 mCid,
3616 NS_GET_IID(nsIFactory),
3617 getter_AddRefs(mFactory));
3618 if (NS_FAILED(rv))
3619 return rv;
3621 NS_ASSERTION(mFactory,
3622 "Loader says it succeeded; got null factory!");
3623 if (!mFactory)
3624 return NS_ERROR_UNEXPECTED;
3626 *aFactory = mFactory.get();
3627 NS_ADDREF(*aFactory);
3628 return NS_OK;
3631 nsFactoryEntry::~nsFactoryEntry()
3633 // nsFactoryEntry is arena-allocated. So we don't delete it;
3634 // call the destructor by hand.
3636 if (mParent)
3637 mParent->~nsFactoryEntry();
3640 ////////////////////////////////////////////////////////////////////////////////
3641 // Static Access Functions
3642 ////////////////////////////////////////////////////////////////////////////////
3644 NS_COM nsresult
3645 NS_GetComponentManager(nsIComponentManager* *result)
3647 if (nsComponentManagerImpl::gComponentManager == nsnull)
3649 // XPCOM needs initialization.
3650 nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3651 if (NS_FAILED(rv))
3652 return rv;
3655 *result = static_cast<nsIComponentManager*>
3656 (nsComponentManagerImpl::gComponentManager);
3657 NS_IF_ADDREF(*result);
3658 return NS_OK;
3661 NS_COM nsresult
3662 NS_GetServiceManager(nsIServiceManager* *result)
3664 nsresult rv = NS_OK;
3666 if (nsComponentManagerImpl::gComponentManager == nsnull)
3668 // XPCOM needs initialization.
3669 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3672 if (NS_FAILED(rv))
3673 return rv;
3675 *result = static_cast<nsIServiceManager*>
3676 (nsComponentManagerImpl::gComponentManager);
3677 NS_IF_ADDREF(*result);
3678 return NS_OK;
3682 NS_COM nsresult
3683 NS_GetComponentRegistrar(nsIComponentRegistrar* *result)
3685 nsresult rv = NS_OK;
3687 if (nsComponentManagerImpl::gComponentManager == nsnull)
3689 // XPCOM needs initialization.
3690 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3693 if (NS_FAILED(rv))
3694 return rv;
3696 *result = static_cast<nsIComponentRegistrar*>
3697 (nsComponentManagerImpl::gComponentManager);
3698 NS_IF_ADDREF(*result);
3699 return NS_OK;