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
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.
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
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
51 #include "nsISupports.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"
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"
76 #include "nsXPCOMPrivate.h"
77 #include "nsISupportsPrimitives.h"
78 #include "nsIClassInfo.h"
79 #include "nsLocalFile.h"
80 #include "nsReadableUtils.h"
82 #include "nsXPIDLString.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"
89 #include "nsManifestLineReader.h"
91 #include NEW_H // for placement new
95 #include <FindDirectory.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
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)
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 \
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]);
168 nsGetServiceFromCategory::operator()(const nsIID
& aIID
, void** aInstancePtr
) const
171 nsXPIDLCString value
;
172 nsCOMPtr
<nsICategoryManager
> catman
;
173 nsComponentManagerImpl
*compMgr
= nsComponentManagerImpl::gComponentManager
;
175 rv
= NS_ERROR_NOT_INITIALIZED
;
179 if (!mCategory
|| !mEntry
) {
180 // when categories have defaults, use that for null mEntry
181 rv
= NS_ERROR_NULL_POINTER
;
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
;
195 rv
= NS_ERROR_SERVICE_NOT_AVAILABLE
;
200 nsComponentManagerImpl::GetServiceByContractID(value
,
211 ////////////////////////////////////////////////////////////////////////////////
212 // Arena helper functions
213 ////////////////////////////////////////////////////////////////////////////////
215 ArenaStrndup(const char *s
, PRUint32 len
, PLArenaPool
*arena
)
218 // Include trailing null in the len
219 PL_ARENA_ALLOCATE(mem
, arena
, len
+1);
221 memcpy(mem
, s
, len
+1);
222 return static_cast<char *>(mem
);
226 ArenaStrdup(const char *s
, PLArenaPool
*arena
)
228 return ArenaStrndup(s
, strlen(s
), arena
);
231 ////////////////////////////////////////////////////////////////////////////////
232 // Hashtable Callbacks
233 ////////////////////////////////////////////////////////////////////////////////
236 nsFactoryEntry_Destroy(nsHashKey
*aKey
, void *aData
, void* closure
);
239 factory_HashKey(PLDHashTable
*aTable
, const void *aKey
)
241 const nsCID
*cidp
= reinterpret_cast<const nsCID
*>(aKey
);
247 factory_MatchEntry(PLDHashTable
*aTable
, const PLDHashEntryHdr
*aHdr
,
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
);
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
= {
272 PL_DHashMoveEntryStub
,
274 PL_DHashFinalizeStub
,
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
= {
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
,
310 nsISupports
**retval
);
312 class PLDHashTableEnumeratorImpl
: public nsIBidirectionalEnumerator
,
313 public nsISimpleEnumerator
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
; }
326 PLDHashTableEnumeratorImpl(); /* no implementation */
328 ~PLDHashTableEnumeratorImpl();
329 void ReleaseElements();
331 nsVoidArray mElements
;
332 PRInt32 mCount
, mCurrent
;
337 EnumeratorConverter converter
;
339 PLDHashTableEnumeratorImpl
*impl
;
342 static PLDHashOperator
Enumerator(PLDHashTable
*table
,
343 PLDHashEntryHdr
*hdr
,
350 PLDHashTableEnumeratorImpl::Enumerator(PLDHashTable
*table
,
351 PLDHashEntryHdr
*hdr
,
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
,
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
);
385 NS_IMPL_ISUPPORTS3(PLDHashTableEnumeratorImpl
,
386 nsIBidirectionalEnumerator
,
390 PLDHashTableEnumeratorImpl::~PLDHashTableEnumeratorImpl()
396 nsAutoMonitor::DestroyMonitor(mMonitor
);
400 PLDHashTableEnumeratorImpl::ReleaseElements()
402 for (PRInt32 i
= 0; i
< mCount
; i
++) {
403 nsISupports
*supports
= reinterpret_cast<nsISupports
*>
405 NS_IF_RELEASE(supports
);
410 PL_NewDHashTableEnumerator(PLDHashTable
*table
,
411 EnumeratorConverter converter
,
413 PLDHashTableEnumeratorImpl
**retval
)
415 PLDHashTableEnumeratorImpl
*impl
=
416 new PLDHashTableEnumeratorImpl(table
, converter
, converterData
);
419 return NS_ERROR_OUT_OF_MEMORY
;
423 if (impl
->Count() == -1) {
426 return NS_ERROR_FAILURE
;
434 PLDHashTableEnumeratorImpl::First()
437 return NS_ERROR_FAILURE
;
444 PLDHashTableEnumeratorImpl::Last()
447 return NS_ERROR_FAILURE
;
448 mCurrent
= mCount
- 1;
453 PLDHashTableEnumeratorImpl::Prev()
456 return NS_ERROR_FAILURE
;
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
;
473 PLDHashTableEnumeratorImpl::CurrentItem(nsISupports
**retval
)
475 if (!mCount
|| mCurrent
== mCount
)
476 return NS_ERROR_FAILURE
;
478 *retval
= reinterpret_cast<nsISupports
*>(mElements
[mCurrent
]);
486 PLDHashTableEnumeratorImpl::IsDone()
488 if (!mCount
|| (mCurrent
== mCount
))
491 return NS_ENUMERATOR_FALSE
;
495 PLDHashTableEnumeratorImpl::HasMoreElements(PRBool
*_retval
)
497 if (!mCount
|| (mCurrent
>= mCount
- 1))
506 PLDHashTableEnumeratorImpl::GetNext(nsISupports
**_retval
)
508 nsresult rv
= Next();
509 if (NS_FAILED(rv
)) return rv
;
511 return CurrentItem(_retval
);
515 ConvertFactoryEntryToCID(PLDHashTable
*table
,
516 const PLDHashEntryHdr
*hdr
,
517 void *data
, nsISupports
**retval
)
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
);
532 nsFactoryEntry
*fe
= entry
->mFactoryEntry
;
534 wrapper
->SetData(&fe
->mCid
);
545 ConvertContractIDKeyToString(PLDHashTable
*table
,
546 const PLDHashEntryHdr
*hdr
,
547 void *data
, nsISupports
**retval
)
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
));
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
,
587 ////////////////////////////////////////////////////////////////////////////////
588 // nsComponentManagerImpl
589 ////////////////////////////////////////////////////////////////////////////////
592 nsComponentManagerImpl::nsComponentManagerImpl()
595 mShuttingDown(NS_SHUTDOWN_NEVERHAPPENED
),
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
),
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
,
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.
649 PL_DHashTableSetAlphaBounds(&mContractIDs
,
651 PL_DHASH_MIN_ALPHA(&mContractIDs
, 1));
655 if (!mAutoRegEntries
.Init(AUTOREGENTRY_HASHTABLE_INITIAL_SIZE
))
656 return NS_ERROR_OUT_OF_MEMORY
;
658 if (mMon
== nsnull
) {
659 mMon
= nsAutoMonitor::NewMonitor("nsComponentManagerImpl");
661 return NS_ERROR_OUT_OF_MEMORY
;
664 GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_DIR
, getter_AddRefs(mComponentsDir
));
666 return NS_ERROR_OUT_OF_MEMORY
;
668 nsCAutoString componentDescriptor
;
669 nsresult rv
= mComponentsDir
->GetNativePath(componentDescriptor
);
673 mComponentsOffset
= componentDescriptor
.Length();
675 GetLocationFromDirectoryService(NS_GRE_COMPONENT_DIR
, getter_AddRefs(mGREComponentsDir
));
676 if (mGREComponentsDir
) {
677 nsresult rv
= mGREComponentsDir
->GetNativePath(componentDescriptor
);
679 NS_WARNING("No GRE component manager");
682 mGREComponentsOffset
= componentDescriptor
.Length();
685 GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_REGISTRY_FILE
,
686 getter_AddRefs(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();
700 rv
= mStaticModuleLoader
.Init(aStaticModules
, aStaticModuleCount
);
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();
722 PR_LOG(nsComponentManagerLog
, PR_LOG_ERROR
, ("nsComponentManager: Could not write out persistent registry."));
724 printf("Could not write out persistent registry!\n");
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
;
743 // Free staticm modules
744 mStaticModuleLoader
.ReleaseModules();
747 mNativeModuleLoader
.UnloadLibraries();
749 // delete arena for strings and small objects
750 PL_FinishArenaPool(&mArena
);
754 mCategoryManager
= 0;
756 mShuttingDown
= NS_SHUTDOWN_COMPLETE
;
758 PR_LOG(nsComponentManagerLog
, PR_LOG_DEBUG
, ("nsComponentManager: Shutdown complete."));
763 nsComponentManagerImpl::~nsComponentManagerImpl()
765 PR_LOG(nsComponentManagerLog
, PR_LOG_DEBUG
, ("nsComponentManager: Beginning destruction."));
767 if (mShuttingDown
!= NS_SHUTDOWN_COMPLETE
)
771 nsAutoMonitor::DestroyMonitor(mMon
);
773 PR_LOG(nsComponentManagerLog
, PR_LOG_DEBUG
, ("nsComponentManager: Destroyed."));
776 NS_IMPL_THREADSAFE_ISUPPORTS7(nsComponentManagerImpl
,
779 nsISupportsWeakReference
,
780 nsIInterfaceRequestor
,
781 nsIComponentRegistrar
,
782 nsIServiceManagerObsolete
,
783 nsIComponentManagerObsolete
)
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
803 PRBool
ReadSectionHeader(nsManifestLineReader
& reader
, const char *token
)
807 if (*reader
.LinePtr() == '[')
809 char* p
= reader
.LinePtr() + (reader
.LineLength() - 1);
816 if (2 != reader
.ParseLine(values
, lengths
, 1))
819 // ignore the leading '['
820 if (0 != PL_strcmp(values
[0]+1, token
))
826 if (!reader
.NextLine())
833 nsComponentManagerImpl::ReadPersistentRegistry()
835 NS_ASSERTION(mComponentsDir
, "nsComponentManager not initialized.");
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
);
845 nsAutoMonitor
mon(mMon
);
846 nsManifestLineReader reader
;
848 PRFileDesc
* fd
= nsnull
;
851 if (!mRegistryFile
) {
852 return NS_ERROR_FILE_NOT_FOUND
;
855 nsCOMPtr
<nsIFile
> file
;
856 mRegistryFile
->Clone(getter_AddRefs(file
));
858 return NS_ERROR_OUT_OF_MEMORY
;
860 nsCOMPtr
<nsILocalFile
> localFile(do_QueryInterface(file
));
862 rv
= localFile
->OpenNSPRFileDesc(PR_RDONLY
, 0444, &fd
);
867 rv
= localFile
->GetFileSize(&fileSize
);
874 PRInt32 flen
= nsInt64(fileSize
);
878 NS_WARNING("Persistent Registry Empty!");
879 return NS_OK
; // ERROR CONDITION
882 char* registry
= new char[flen
+1];
886 if (flen
> PR_Read(fd
, registry
, flen
))
888 rv
= NS_ERROR_FAILURE
;
891 registry
[flen
] = '\0';
893 reader
.Init(registry
, flen
);
895 if (ReadSectionHeader(reader
, "HEADER"))
898 if (!reader
.NextLine())
904 // VersionLiteral,major,minor
905 if (3 != reader
.ParseLine(values
, lengths
, 3))
909 if (!nsDependentCString(values
[0], lengths
[0]).EqualsLiteral("Version"))
913 if (PERSISTENT_REGISTRY_VERSION_MAJOR
!= atoi(values
[1]))
917 if (PERSISTENT_REGISTRY_VERSION_MINOR
!= atoi(values
[2]))
920 if (ReadSectionHeader(reader
, "COMPONENTS"))
925 if (!reader
.NextLine())
928 //name,last_modification_date[,optionaldata]
929 int parts
= reader
.ParseLine(values
, lengths
, 3);
933 PRInt64 a
= nsCRT::atoll(values
[1]);
935 nsCOMPtr
<nsILocalFile
> lf
;
936 rv
= FileForRegistryLocation(nsDependentCString(values
[0], lengths
[0]),
941 nsCOMPtr
<nsIHashable
> lfhash(do_QueryInterface(lf
));
943 NS_ERROR("nsLocalFile does not implement nsIHashable");
947 mAutoRegEntries
.Put(lfhash
, a
);
950 if (ReadSectionHeader(reader
, "CLASSIDS"))
955 if (!reader
.NextLine())
958 // cid,contract_id,type,class_name,inproc_server
959 if (5 != reader
.ParseLine(values
, lengths
, 5))
963 if (!aClass
.Parse(values
[0]))
966 LoaderType loadertype
= AddLoaderType(values
[2]);
967 if (loadertype
== NS_LOADER_TYPE_INVALID
) {
968 NS_ERROR("Could not create LoaderType");
973 PL_ARENA_ALLOCATE(mem
, &mArena
, sizeof(nsFactoryEntry
));
975 rv
= NS_ERROR_OUT_OF_MEMORY
;
979 nsFactoryEntry
*entry
=
980 new (mem
) nsFactoryEntry(aClass
, loadertype
, values
[4]);
982 if (!entry
->mLocationKey
) {
983 rv
= NS_ERROR_OUT_OF_MEMORY
;
987 nsFactoryTableEntry
* factoryTableEntry
=
988 static_cast<nsFactoryTableEntry
*>
989 (PL_DHashTableOperate(&mFactories
,
993 if (!factoryTableEntry
) {
994 rv
= NS_ERROR_OUT_OF_MEMORY
;
998 factoryTableEntry
->mFactoryEntry
= entry
;
1001 if (ReadSectionHeader(reader
, "CONTRACTIDS"))
1006 if (!reader
.NextLine())
1010 if (2 != reader
.ParseLine(values
, lengths
, 2))
1014 if (!aClass
.Parse(values
[1]))
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
,
1028 if (!contractIDTableEntry
) {
1032 if (!contractIDTableEntry
->mContractID
) {
1033 char *contractID
= ArenaStrndup(values
[0], lengths
[0], &mArena
);
1035 rv
= NS_ERROR_OUT_OF_MEMORY
;
1038 contractIDTableEntry
->mContractID
= contractID
;
1039 contractIDTableEntry
->mContractIDLen
= lengths
[0];
1042 contractIDTableEntry
->mFactoryEntry
= cidEntry
;
1045 if (ReadSectionHeader(reader
, "CATEGORIES"))
1048 mCategoryManager
->SuppressNotifications(PR_TRUE
);
1052 if (!reader
.NextLine())
1056 if (3 != reader
.ParseLine(values
, lengths
, 3))
1059 mCategoryManager
->AddCategoryEntry(values
[0],
1067 mCategoryManager
->SuppressNotifications(PR_FALSE
);
1069 mRegistryDirty
= PR_FALSE
;
1080 struct PersistentWriterArgs
1083 nsTArray
<nsLoaderdata
> *mLoaderData
;
1086 static PLDHashOperator
1087 ContractIDWriter(PLDHashTable
*table
,
1088 PLDHashEntryHdr
*hdr
,
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
,
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
);
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
;
1146 case NS_LOADER_TYPE_NATIVE
:
1147 loaderName
= nativeComponentType
;
1151 loaderName
= loaderData
->ElementAt(factoryEntry
->mLoaderType
).type
.get();
1154 const char* location
= factoryEntry
->mLocationKey
;
1156 // cid,contract_id,type,class_name,inproc_server
1160 (contractID
? contractID
: ""),
1161 (loaderName
? loaderName
: ""),
1162 (className
? className
: ""),
1163 (location
? location
: ""));
1166 PR_Free(contractID
);
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
;
1190 nsComponentManagerImpl::WritePersistentRegistry()
1193 return NS_ERROR_FAILURE
; // this should have been set by Init().
1195 nsCOMPtr
<nsIFile
> file
;
1196 mRegistryFile
->Clone(getter_AddRefs(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
);
1216 if (PR_fprintf(fd
, "Generated File. Do not edit.\n") == (PRUint32
) -1) {
1217 rv
= NS_ERROR_UNEXPECTED
;
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
;
1228 if (PR_fprintf(fd
, "\n[COMPONENTS]\n") == (PRUint32
) -1) {
1229 rv
= NS_ERROR_UNEXPECTED
;
1233 mAutoRegEntries
.Enumerate(AutoRegEntryWriter
, (void*)fd
);
1235 PersistentWriterArgs args
;
1237 args
.mLoaderData
= &mLoaderData
;
1239 if (PR_fprintf(fd
, "\n[CLASSIDS]\n") == (PRUint32
) -1) {
1240 rv
= NS_ERROR_UNEXPECTED
;
1245 PL_DHashTableEnumerate(&mFactories
, ClassIDWriter
, (void*)&args
);
1247 if (PR_fprintf(fd
, "\n[CONTRACTIDS]\n") == (PRUint32
) -1) {
1248 rv
= NS_ERROR_UNEXPECTED
;
1253 PL_DHashTableEnumerate(&mContractIDs
, ContractIDWriter
, (void*)&args
);
1255 if (PR_fprintf(fd
, "\n[CATEGORIES]\n") == (PRUint32
) -1) {
1256 rv
= NS_ERROR_UNEXPECTED
;
1260 NS_ASSERTION(mCategoryManager
, "nsComponentManager used initialized");
1262 rv
= mCategoryManager
->WriteCategoryManagerToRegistry(fd
);
1267 // don't create the file is there was a problem????
1268 NS_ENSURE_SUCCESS(rv
, rv
);
1271 return NS_ERROR_NOT_INITIALIZED
;
1274 if(NS_FAILED(mRegistryFile
->Exists(&exists
)))
1277 if(exists
&& NS_FAILED(mRegistryFile
->Remove(PR_FALSE
)))
1280 nsCOMPtr
<nsIFile
> parent
;
1281 mRegistryFile
->GetParent(getter_AddRefs(parent
));
1283 rv
= localFile
->MoveToNative(parent
, originalLeafName
);
1284 mRegistryDirty
= PR_FALSE
;
1290 ////////////////////////////////////////////////////////////////////////////////
1292 ////////////////////////////////////////////////////////////////////////////////
1294 nsComponentManagerImpl::HashContractID(const char *aContractID
,
1295 PRUint32 aContractIDLen
,
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
,
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
);
1315 return NS_ERROR_OUT_OF_MEMORY
;
1317 contractIDTableEntry
->mContractID
= contractID
;
1318 contractIDTableEntry
->mContractIDLen
= aContractIDLen
;
1321 contractIDTableEntry
->mFactoryEntry
= fe
;
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
,
1340 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry
)) {
1341 fe
= contractIDTableEntry
->mFactoryEntry
;
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
,
1361 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry
)) {
1362 entry
= factoryTableEntry
->mFactoryEntry
;
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.
1380 nsComponentManagerImpl::FindFactory(const nsCID
&aClass
,
1381 nsIFactory
**aFactory
)
1383 PR_ASSERT(aFactory
!= nsnull
);
1385 nsFactoryEntry
*entry
= GetFactoryEntry(aClass
);
1388 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1390 return entry
->GetFactory(aFactory
);
1395 nsComponentManagerImpl::FindFactory(const char *contractID
,
1396 PRUint32 aContractIDLen
,
1397 nsIFactory
**aFactory
)
1399 PR_ASSERT(aFactory
!= nsnull
);
1401 nsFactoryEntry
*entry
= GetFactoryEntry(contractID
, aContractIDLen
);
1404 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1406 return entry
->GetFactory(aFactory
);
1412 * Given a classID, this finds the singleton ClassObject that implements the CID.
1413 * Returns an interface of type aIID off the singleton classobject.
1416 nsComponentManagerImpl::GetClassObject(const nsCID
&aClass
, const nsIID
&aIID
,
1421 nsCOMPtr
<nsIFactory
> factory
;
1424 if (PR_LOG_TEST(nsComponentManagerLog
, PR_LOG_DEBUG
))
1426 char *buf
= aClass
.ToString();
1427 PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf
);
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"));
1448 nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID
,
1454 nsCOMPtr
<nsIFactory
> factory
;
1457 if (PR_LOG_TEST(nsComponentManagerLog
, PR_LOG_DEBUG
))
1459 PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID
);
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"));
1477 * ContractIDToClassID()
1479 * Mapping function from a ContractID to a classID. Directly talks to the registry.
1483 nsComponentManagerImpl::ContractIDToClassID(const char *aContractID
, nsCID
*aClass
)
1485 NS_PRECONDITION(aContractID
!= nsnull
, "null ptr");
1487 return NS_ERROR_NULL_POINTER
;
1489 NS_PRECONDITION(aClass
!= nsnull
, "null ptr");
1491 return NS_ERROR_NULL_POINTER
;
1493 nsresult rv
= NS_ERROR_FACTORY_NOT_REGISTERED
;
1495 nsFactoryEntry
*fe
= GetFactoryEntry(aContractID
, strlen(aContractID
));
1501 if (PR_LOG_TEST(nsComponentManagerLog
, PR_LOG_WARNING
)) {
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]"));
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.
1524 nsComponentManagerImpl::CLSIDToContractID(const nsCID
&aClass
,
1528 NS_WARNING("Need to implement CLSIDToContractID");
1530 nsresult rv
= NS_ERROR_FACTORY_NOT_REGISTERED
;
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]"));
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.
1553 nsComponentManagerImpl::CreateInstance(const nsCID
&aClass
,
1554 nsISupports
*aDelegate
,
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
;
1579 nsFactoryEntry
*entry
= GetFactoryEntry(aClass
);
1582 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1584 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1585 if (entry
->mServiceObject
) {
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());
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
);
1609 // Translate error values
1610 rv
= NS_ERROR_FACTORY_NOT_REGISTERED
;
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"));
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.
1638 nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID
,
1639 nsISupports
*aDelegate
,
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
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
;
1663 nsFactoryEntry
*entry
= GetFactoryEntry(aContractID
, strlen(aContractID
));
1666 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1668 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1669 if (entry
->mServiceObject
) {
1670 nsCAutoString 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());
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
);
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"));
1706 // Service Manager Impl
1709 FreeServiceFactoryEntryEnumerate(PLDHashTable
*aTable
,
1710 PLDHashEntryHdr
*aHdr
,
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
;
1726 FreeServiceContractIDEntryEnumerate(PLDHashTable
*aTable
,
1727 PLDHashEntryHdr
*aHdr
,
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
;
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
);
1761 // This should only ever be called within the monitor!
1762 nsComponentManagerImpl::PendingServiceInfo
*
1763 nsComponentManagerImpl::AddPendingService(const nsCID
& aServiceCID
,
1766 PendingServiceInfo
* newInfo
= mPendingServices
.AppendElement();
1768 newInfo
->cid
= &aServiceCID
;
1769 newInfo
->thread
= aThread
;
1774 // This should only ever be called within the monitor!
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
);
1788 // This should only ever be called within the monitor!
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
)) {
1803 nsComponentManagerImpl::GetService(const nsCID
& aClass
,
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
,
1831 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry
)) {
1832 entry
= factoryTableEntry
->mFactoryEntry
;
1835 if (entry
&& entry
->mServiceObject
) {
1836 nsCOMPtr
<nsISupports
> supports
= entry
->mServiceObject
;
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
;
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
1863 if (!NS_ProcessNextEvent(currentThread
, PR_FALSE
)) {
1864 PR_Sleep(PR_INTERVAL_NO_WAIT
);
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.
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
;
1887 return supports
->QueryInterface(aIID
, result
);
1892 PendingServiceInfo
* newInfo
=
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:
1903 nsresult rv
= CreateInstance(aClass
, nsnull
, aIID
, getter_AddRefs(service
));
1908 pendingPRThread
= GetPendingServiceThread(aClass
);
1909 NS_ASSERTION(pendingPRThread
== currentPRThread
,
1910 "Pending service array has been changed!");
1912 RemovePendingService(aClass
);
1917 if (!entry
) { // second hash lookup for GetService
1918 nsFactoryTableEntry
* factoryTableEntry
=
1919 static_cast<nsFactoryTableEntry
*>
1920 (PL_DHashTableOperate(&mFactories
, &aClass
,
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();
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
)));
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
);
1951 PL_ARENA_ALLOCATE(mem
, &mArena
, sizeof(nsFactoryEntry
));
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
,
1960 if (!factoryTableEntry
)
1961 return NS_ERROR_OUT_OF_MEMORY
;
1963 factoryTableEntry
->mFactoryEntry
= entry
;
1966 if (entry
->mServiceObject
)
1967 return NS_ERROR_FAILURE
;
1970 entry
->mServiceObject
= aService
;
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
,
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
;
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
);
2012 PL_ARENA_ALLOCATE(mem
, &mArena
, sizeof(nsFactoryEntry
));
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
,
2021 if (!contractIDTableEntry
) {
2023 return NS_ERROR_OUT_OF_MEMORY
;
2026 if (!contractIDTableEntry
->mContractID
) {
2027 char *contractID
= ArenaStrndup(aContractID
, contractIDLen
, &mArena
);
2029 return NS_ERROR_OUT_OF_MEMORY
;
2031 contractIDTableEntry
->mContractID
= contractID
;
2032 contractIDTableEntry
->mContractIDLen
= contractIDLen
;
2035 contractIDTableEntry
->mFactoryEntry
= entry
;
2038 if (entry
->mServiceObject
)
2039 return NS_ERROR_FAILURE
;
2042 entry
->mServiceObject
= aService
;
2048 nsComponentManagerImpl::IsServiceInstantiated(const nsCID
& aClass
,
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
,
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
);
2090 NS_IMETHODIMP
nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID
,
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
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
,
2121 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry
)) {
2122 entry
= contractIDTableEntry
->mFactoryEntry
;
2126 if (entry
&& entry
->mServiceObject
) {
2127 nsCOMPtr
<nsISupports
> service
;
2128 rv
= entry
->mServiceObject
->QueryInterface(aIID
, getter_AddRefs(service
));
2129 *result
= (service
!=nsnull
);
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
,
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
;
2160 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID
,
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
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
,
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.
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
;
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
2225 if (!NS_ProcessNextEvent(currentThread
, PR_FALSE
)) {
2226 PR_Sleep(PR_INTERVAL_NO_WAIT
);
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
;
2237 return serviceObject
->QueryInterface(aIID
, result
);
2241 PendingServiceInfo
* newInfo
=
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:
2252 nsresult rv
= CreateInstanceByContractID(aContractID
, nsnull
, aIID
,
2253 getter_AddRefs(service
));
2258 pendingPRThread
= GetPendingServiceThread(entry
->mCid
);
2259 NS_ASSERTION(pendingPRThread
== currentPRThread
,
2260 "Pending service array has been changed!");
2262 RemovePendingService(entry
->mCid
);
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
));
2276 nsComponentManagerImpl::GetService(const nsCID
& aClass
, const nsIID
& aIID
,
2277 nsISupports
* *result
,
2278 nsIShutdownListener
* shutdownListener
)
2280 return GetService(aClass
, aIID
, (void**)result
);
2284 nsComponentManagerImpl::GetService(const char* aContractID
, const nsIID
& aIID
,
2285 nsISupports
* *result
,
2286 nsIShutdownListener
* shutdownListener
)
2288 return GetServiceByContractID(aContractID
, aIID
, (void**)result
);
2293 nsComponentManagerImpl::ReleaseService(const nsCID
& aClass
, nsISupports
* service
,
2294 nsIShutdownListener
* shutdownListener
)
2296 NS_IF_RELEASE(service
);
2301 nsComponentManagerImpl::ReleaseService(const char* aContractID
, nsISupports
* service
,
2302 nsIShutdownListener
* shutdownListener
)
2304 NS_IF_RELEASE(service
);
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
;
2324 nsComponentManagerImpl::RegistryLocationForFile(nsIFile
* aFile
,
2325 nsCString
& aRegistryName
)
2329 if (!mComponentsDir
)
2330 return NS_ERROR_NOT_INITIALIZED
;
2332 // First check to see if this component is in the application
2333 // components directory
2335 mComponentsDir
->Contains(aFile
, PR_TRUE
, &containedIn
);
2337 nsCAutoString nativePathString
;
2340 rv
= aFile
->GetNativePath(nativePathString
);
2344 aRegistryName
.Assign(NS_LITERAL_CSTRING(XPCOM_RELCOMPONENT_PREFIX
) +
2345 Substring(nativePathString
, mComponentsOffset
+ 1));
2349 // Next check to see if this component is in the GRE
2350 // components directory
2352 mGREComponentsDir
->Contains(aFile
, PR_TRUE
, &containedIn
);
2355 rv
= aFile
->GetNativePath(nativePathString
);
2359 aRegistryName
.Assign(NS_LITERAL_CSTRING(XPCOM_GRECOMPONENT_PREFIX
) +
2360 Substring(nativePathString
, mGREComponentsOffset
+ 1));
2364 /* absolute names include volume info on Mac, so persistent descriptor */
2365 rv
= aFile
->GetNativePath(nativePathString
);
2369 aRegistryName
.Assign(NS_LITERAL_CSTRING(XPCOM_ABSCOMPONENT_PREFIX
) +
2375 nsComponentManagerImpl::SpecForRegistryLocation(const char *aLocation
,
2378 return FileForRegistryLocation(nsDependentCString(aLocation
),
2379 (nsILocalFile
**) aSpec
);
2383 nsComponentManagerImpl::FileForRegistryLocation(const nsCString
&aLocation
,
2384 nsILocalFile
**aSpec
)
2386 // i18n: assuming aLocation is encoded for the current locale
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
);
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));
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));
2434 return NS_ERROR_INVALID_ARG
;
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
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.
2454 nsComponentManagerImpl::RegisterFactory(const nsCID
&aClass
,
2455 const char *aClassName
,
2456 const char *aContractID
,
2457 nsIFactory
*aFactory
,
2460 nsAutoMonitor
mon(mMon
);
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)")));
2472 nsFactoryEntry
*entry
= nsnull
;
2473 nsFactoryTableEntry
* factoryTableEntry
= static_cast<nsFactoryTableEntry
*>
2474 (PL_DHashTableOperate(&mFactories
,
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
;
2495 PL_ARENA_ALLOCATE(mem
, &mArena
, sizeof(nsFactoryEntry
));
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
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
));
2514 PR_LOG(nsComponentManagerLog
, PR_LOG_WARNING
,
2515 ("\t\tFactory register succeeded contractid=%s.",
2516 aContractID
? aContractID
: "<none>"));
2522 nsComponentManagerImpl::RegisterComponent(const nsCID
&aClass
,
2523 const char *aClassName
,
2524 const char *aContractID
,
2525 const char *aPersistentDescriptor
,
2529 NS_ENSURE_ARG_POINTER(aPersistentDescriptor
);
2530 return RegisterComponentCommon(aClass
, aClassName
,
2532 aContractID
? strlen(aContractID
) : 0,
2533 aPersistentDescriptor
,
2534 strlen(aPersistentDescriptor
),
2536 nativeComponentType
);
2540 nsComponentManagerImpl::RegisterComponentWithType(const nsCID
&aClass
,
2541 const char *aClassName
,
2542 const char *aContractID
,
2544 const char *aLocation
,
2549 NS_ENSURE_ARG_POINTER(aLocation
);
2550 return RegisterComponentCommon(aClass
, aClassName
,
2552 aContractID
? strlen(aContractID
) : 0,
2560 * Register a component, using whatever they stuck in the nsIFile.
2563 nsComponentManagerImpl::RegisterComponentSpec(const nsCID
&aClass
,
2564 const char *aClassName
,
2565 const char *aContractID
,
2566 nsIFile
*aLibrarySpec
,
2570 nsCAutoString registryName
;
2571 nsresult rv
= RegistryLocationForFile(aLibrarySpec
,
2576 rv
= RegisterComponentWithType(aClass
, aClassName
,
2581 nativeComponentType
);
2586 nsComponentManagerImpl::RegisterComponentLib(const nsCID
&aClass
,
2587 const char *aClassName
,
2588 const char *aContractID
,
2589 const char *aDllName
,
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
2606 nsComponentManagerImpl::RegisterComponentCommon(const nsCID
&aClass
,
2607 const char *aClassName
,
2608 const char *aContractID
,
2609 PRUint32 aContractIDLen
,
2610 const char *aRegistryName
,
2611 PRUint32 aRegistryNameLen
,
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
;
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)",
2632 contractID
? contractID
: "(null)",
2633 aRegistryName
, aType
));
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
;
2649 entry
->ReInit(typeIndex
, aRegistryName
);
2653 // Arena allocate the nsFactoryEntry
2655 PL_ARENA_ALLOCATE(mem
, &mArena
, sizeof(nsFactoryEntry
));
2657 return NS_ERROR_OUT_OF_MEMORY
;
2659 mRegistryDirty
= PR_TRUE
;
2660 entry
= new (mem
) nsFactoryEntry(aClass
,
2663 if (!entry
->mLocationKey
)
2664 return NS_ERROR_OUT_OF_MEMORY
;
2666 nsFactoryTableEntry
* factoryTableEntry
=
2667 static_cast<nsFactoryTableEntry
*>
2668 (PL_DHashTableOperate(&mFactories
, &aClass
,
2671 if (!factoryTableEntry
)
2672 return NS_ERROR_OUT_OF_MEMORY
;
2674 factoryTableEntry
->mFactoryEntry
= entry
;
2677 // Update the ContractID->CLSID Map
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
));
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
)
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());
2712 loader
.swap(mLoaderData
[aType
].loader
);
2715 return mLoaderData
[aType
].loader
;
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
) {
2730 while (NS_SUCCEEDED(loaderStrings
->HasMore(&hasMore
)) && hasMore
) {
2731 nsCAutoString loaderType
;
2732 if (NS_FAILED(loaderStrings
->GetNext(loaderType
)))
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.
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
)
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.
2771 nsComponentManagerImpl::AddLoaderType(const char *typeStr
)
2773 LoaderType typeIndex
= GetLoaderType(typeStr
);
2774 if (typeIndex
!= NS_LOADER_TYPE_INVALID
)
2777 // Add the loader type
2778 nsLoaderdata
*elem
= mLoaderData
.AppendElement();
2780 return NS_LOADER_TYPE_INVALID
;
2782 elem
->type
.Assign(typeStr
);
2783 return mLoaderData
.Length() - 1;
2789 nsIFactory
* factory
;
2790 } UnregisterConditions
;
2792 static PLDHashOperator
2793 DeleteFoundCIDs(PLDHashTable
*aTable
,
2794 PLDHashEntryHdr
*aHdr
,
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
;
2814 nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID
* aClass
, nsIFactory
* factory
)
2816 UnregisterConditions aData
;
2818 aData
.factory
= factory
;
2819 PL_DHashTableEnumerate(&mContractIDs
, DeleteFoundCIDs
, (void*)&aData
);
2823 nsComponentManagerImpl::UnregisterFactory(const nsCID
&aClass
,
2824 nsIFactory
*aFactory
)
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
));
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
);
2852 PR_LOG(nsComponentManagerLog
, PR_LOG_WARNING
,
2853 ("\t\tUnregisterFactory() %s",
2854 NS_SUCCEEDED(rv
) ? "succeeded" : "FAILED"));
2859 nsComponentManagerImpl::UnregisterComponent(const nsCID
&aClass
,
2860 const char *registryName
)
2862 NS_ERROR("Don't call nsIComponentManagerObsolete.unregisterComponent");
2863 return NS_ERROR_NOT_IMPLEMENTED
;
2867 nsComponentManagerImpl::UnregisterComponentSpec(const nsCID
&aClass
,
2868 nsIFile
*aLibrarySpec
)
2870 NS_ERROR("Don't call nsIComponentManagerObsolete.unregisterComponentSpec");
2871 return NS_ERROR_NOT_IMPLEMENTED
;
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
2897 nsComponentManagerImpl::AutoRegister(PRInt32 when
, nsIFile
*inDirSpec
)
2899 return AutoRegister(inDirSpec
);
2903 nsComponentManagerImpl::AutoRegisterImpl(nsIFile
*inDirSpec
,
2904 nsCOMArray
<nsILocalFile
> &aLeftovers
,
2905 nsTArray
<DeferredModule
> &aDeferred
)
2907 NS_ASSERTION(inDirSpec
, "inDirSpec must not be null");
2912 rv
= inDirSpec
->IsDirectory(&isDir
);
2917 return AutoRegisterDirectory(inDirSpec
, aLeftovers
, aDeferred
);
2919 nsCOMPtr
<nsILocalFile
> lf(do_QueryInterface(inDirSpec
));
2921 return NS_NOINTERFACE
;
2923 rv
= AutoRegisterComponent(lf
, aDeferred
);
2925 aLeftovers
.AppendObject(lf
);
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
));
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
));
2946 NS_ERROR("Directory enumerator misbehaving");
2951 rv
= lf
->IsDirectory(&isDir
);
2956 AutoRegisterDirectory(lf
, aLeftovers
, aDeferred
);
2958 rv
= AutoRegisterComponent(lf
, aDeferred
);
2960 aLeftovers
.AppendObject(lf
);
2968 nsComponentManagerImpl::AutoRegisterComponent(PRInt32 unused
,
2971 nsCOMPtr
<nsILocalFile
> lf(do_QueryInterface(component
));
2973 return NS_NOINTERFACE
;
2977 nsTArray
<DeferredModule
> deferred
;
2979 nsresult rv
= AutoRegisterComponent(lf
, deferred
);
2980 if (deferred
.Length())
2981 return NS_ERROR_FACTORY_REGISTER_AGAIN
;
2987 nsComponentManagerImpl::AutoRegisterComponent(nsILocalFile
* aComponentFile
,
2988 nsTArray
<DeferredModule
> &aDeferred
,
2989 LoaderType minLoader
)
2993 NS_ASSERTION(minLoader
< GetLoaderCount(), "Bad minLoader");
2995 nsCAutoString registryLocation
;
2996 rv
= RegistryLocationForFile(aComponentFile
, registryLocation
);
3000 const nsDependentCSubstring extension
= StringTail(registryLocation
, 4);
3001 if (extension
.LowerCaseEqualsLiteral(".dat") ||
3002 extension
.LowerCaseEqualsLiteral(".xpt"))
3005 nsCOMPtr
<nsIHashable
> lfhash(do_QueryInterface(aComponentFile
));
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
)
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
)) {
3028 NS_ERROR("Module loader succeeded without returning a module");
3029 return NS_ERROR_FAILURE
;
3031 registryType
= nativeComponentType
;
3037 if (!registryType
) {
3038 for (; minLoader
< GetLoaderCount(); ++minLoader
) {
3039 nsIModuleLoader
* loader
= LoaderForType(minLoader
);
3043 rv
= loader
->LoadModule(aComponentFile
, getter_AddRefs(module
));
3044 if (NS_SUCCEEDED(rv
)) {
3046 NS_ERROR("Module loader succeeded without returning a module.");
3047 return NS_ERROR_FAILURE
;
3049 registryType
= StringForLoaderType(minLoader
);
3053 if (!registryType
) {
3054 return NS_ERROR_FAILURE
;
3058 rv
= module
->RegisterSelf(this, aComponentFile
, registryLocation
.get(),
3060 if (NS_ERROR_FACTORY_REGISTER_AGAIN
== rv
) {
3061 DeferredModule
*d
= aDeferred
.AppendElement();
3063 return NS_ERROR_OUT_OF_MEMORY
;
3065 d
->type
= registryType
;
3066 d
->file
= aComponentFile
;
3067 d
->location
= registryLocation
;
3069 d
->modTime
= modTime
;
3073 if (NS_SUCCEEDED(rv
) && modTime
!= 0)
3074 mAutoRegEntries
.Put(lfhash
, modTime
);
3080 nsComponentManagerImpl::LoadLeftoverComponents(
3081 nsCOMArray
<nsILocalFile
> &aLeftovers
,
3082 nsTArray
<DeferredModule
> &aDeferred
,
3083 LoaderType minLoader
)
3085 NS_ASSERTION(minLoader
>= GetLoaderCount(), "Corrupted minLoader");
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
)
3094 LoaderType curLoader
= GetLoaderCount();
3096 for (PRInt32 i
= 0; i
< aLeftovers
.Count(); ) {
3097 nsresult rv
= AutoRegisterComponent(aLeftovers
[i
], aDeferred
,
3099 if (NS_SUCCEEDED(rv
)) {
3100 aLeftovers
.RemoveObjectAt(i
);
3106 if (aLeftovers
.Count())
3107 // recursively try this again until there are no new loaders found
3108 LoadLeftoverComponents(aLeftovers
, aDeferred
, curLoader
);
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,
3130 if (NS_SUCCEEDED(rv
) && d
.modTime
!= 0) {
3131 nsCOMPtr
<nsIHashable
> lfhash(do_QueryInterface(d
.file
));
3133 mAutoRegEntries
.Put(lfhash
, d
.modTime
);
3136 if (rv
!= NS_ERROR_FACTORY_REGISTER_AGAIN
) {
3137 aDeferred
.RemoveElementAt(i
);
3147 nsComponentManagerImpl::AutoUnregisterComponent(PRInt32
/* unused */,
3154 nsCAutoString location
;
3155 rv
= RegistryLocationForFile(component
, location
);
3159 nsCOMPtr
<nsILocalFile
> lf(do_QueryInterface(component
));
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
);
3171 if (NS_SUCCEEDED(loader
->LoadModule(lf
, getter_AddRefs(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
);
3190 nsComponentManagerImpl::IsRegistered(const nsCID
&aClass
,
3191 PRBool
*aRegistered
)
3195 NS_ASSERTION(0, "null ptr");
3196 return NS_ERROR_NULL_POINTER
;
3198 *aRegistered
= (nsnull
!= GetFactoryEntry(aClass
));
3203 nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator
** aEnumerator
)
3205 NS_ASSERTION(aEnumerator
!= nsnull
, "null ptr");
3208 return NS_ERROR_NULL_POINTER
;
3210 *aEnumerator
= nsnull
;
3214 PLDHashTableEnumeratorImpl
*aEnum
;
3215 rv
= PL_NewDHashTableEnumerator(&mFactories
,
3216 ConvertFactoryEntryToCID
,
3222 *aEnumerator
= static_cast<nsIEnumerator
*>(aEnum
);
3227 nsComponentManagerImpl::EnumerateContractIDs(nsIEnumerator
** aEnumerator
)
3229 NS_ASSERTION(aEnumerator
!= nsnull
, "null ptr");
3232 return NS_ERROR_NULL_POINTER
;
3235 *aEnumerator
= nsnull
;
3238 PLDHashTableEnumeratorImpl
*aEnum
;
3239 rv
= PL_NewDHashTableEnumerator(&mContractIDs
,
3240 ConvertContractIDKeyToString
,
3246 *aEnumerator
= static_cast<nsIEnumerator
*>(aEnum
);
3250 // nsIComponentRegistrar
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();
3263 d
->type
= staticComponentType
;
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());
3280 nsComponentManagerImpl::AutoRegister(nsIFile
*aSpec
)
3284 if (!mCategoryManager
) {
3285 mCategoryManager
= do_GetService(NS_CATEGORYMANAGER_CONTRACTID
, &rv
);
3292 // Notify observers of xpcom autoregistration start
3293 NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID
,
3296 nsCOMArray
<nsILocalFile
> leftovers
;
3297 nsTArray
<DeferredModule
> deferred
;
3300 mStaticModuleLoader
.EnumerateModules(RegisterStaticModule
,
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.
3309 LoaderType curLoader
= GetLoaderCount();
3312 rv
= AutoRegisterImpl(aSpec
, leftovers
, deferred
);
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
)) &&
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
) {
3340 nsCOMPtr
<nsISupports
> elem
;
3342 while (NS_SUCCEEDED(dirList
->HasMoreElements(&hasMore
)) &&
3344 dirList
->GetNext(getter_AddRefs(elem
));
3345 nsCOMPtr
<nsIFile
> dir(do_QueryInterface(elem
));
3347 AutoRegisterImpl(dir
, leftovers
, deferred
);
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
));
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
,
3381 WritePersistentRegistry();
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
;
3394 aSpec
->IsDirectory(&directory
);
3397 return NS_ERROR_NOT_IMPLEMENTED
;
3399 return AutoUnregisterComponent(0, aSpec
);
3403 nsComponentManagerImpl::RegisterFactory(const nsCID
& aClass
,
3404 const char *aClassName
,
3405 const char *aContractID
,
3406 nsIFactory
*aFactory
)
3408 return RegisterFactory(aClass
,
3416 nsComponentManagerImpl::RegisterFactoryLocation(const nsCID
& aClass
,
3417 const char *aClassName
,
3418 const char *aContractID
,
3420 const char *loaderStr
,
3423 nsCAutoString registryName
;
3427 nsresult rv
= RegistryLocationForFile(aFile
, registryName
);
3433 rv
= RegisterComponentWithType(aClass
,
3437 (loaderStr
? loaderStr
: registryName
.get()),
3440 (aType
? aType
: nativeComponentType
));
3445 nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID
& aClass
,
3448 return UnregisterComponentSpec(aClass
, aFile
);
3452 nsComponentManagerImpl::IsCIDRegistered(const nsCID
& aClass
,
3455 return IsRegistered(aClass
, _retval
);
3459 nsComponentManagerImpl::IsContractIDRegistered(const char *aClass
,
3462 nsFactoryEntry
*entry
= GetFactoryEntry(aClass
, strlen(aClass
));
3467 *_retval
= PR_FALSE
;
3472 nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator
**aEnumerator
)
3474 NS_ASSERTION(aEnumerator
!= nsnull
, "null ptr");
3477 return NS_ERROR_NULL_POINTER
;
3479 *aEnumerator
= nsnull
;
3482 PLDHashTableEnumeratorImpl
*aEnum
;
3483 rv
= PL_NewDHashTableEnumerator(&mFactories
,
3484 ConvertFactoryEntryToCID
,
3490 *aEnumerator
= static_cast<nsISimpleEnumerator
*>(aEnum
);
3495 nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator
**aEnumerator
)
3497 NS_ASSERTION(aEnumerator
!= nsnull
, "null ptr");
3499 return NS_ERROR_NULL_POINTER
;
3501 *aEnumerator
= nsnull
;
3504 PLDHashTableEnumeratorImpl
*aEnum
;
3505 rv
= PL_NewDHashTableEnumerator(&mContractIDs
,
3506 ConvertContractIDKeyToString
,
3512 *aEnumerator
= static_cast<nsISimpleEnumerator
*>(aEnum
);
3517 nsComponentManagerImpl::CIDToContractID(const nsCID
& aClass
,
3520 return CLSIDToContractID(aClass
,
3526 nsComponentManagerImpl::ContractIDToCID(const char *aContractID
,
3529 *_retval
= (nsCID
*) nsMemory::Alloc(sizeof(nsCID
));
3531 return NS_ERROR_OUT_OF_MEMORY
;
3533 nsresult rv
= ContractIDToClassID(aContractID
, *_retval
);
3534 if (NS_FAILED(rv
)) {
3535 nsMemory::Free(*_retval
);
3541 ////////////////////////////////////////////////////////////////////////////////
3543 ////////////////////////////////////////////////////////////////////////////////
3545 nsFactoryEntry::nsFactoryEntry(const nsCID
&aClass
,
3546 LoaderType aLoaderType
,
3547 const char *aLocationKey
,
3548 nsFactoryEntry
*aParent
) :
3550 mLoaderType(aLoaderType
),
3552 ArenaStrdup(aLocationKey
,
3553 &nsComponentManagerImpl::gComponentManager
->mArena
)),
3559 nsFactoryEntry::ReInit(LoaderType aLoaderType
,
3560 const char *aLocationKey
)
3562 mLoaderType
= aLoaderType
;
3564 if (!mLocationKey
|| strcmp(mLocationKey
, aLocationKey
)) {
3566 ArenaStrdup(aLocationKey
,
3567 &nsComponentManagerImpl::gComponentManager
->mArena
);
3572 nsFactoryEntry::GetFactory(nsIFactory
**aFactory
)
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
));
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
);
3599 return NS_ERROR_FAILURE
;
3601 rv
= loader
->LoadModule(moduleFile
,
3602 getter_AddRefs(module
));
3609 NS_ERROR("Module returned success but no module!");
3610 return NS_ERROR_FAILURE
;
3614 GetClassObject(nsComponentManagerImpl::gComponentManager
,
3616 NS_GET_IID(nsIFactory
),
3617 getter_AddRefs(mFactory
));
3621 NS_ASSERTION(mFactory
,
3622 "Loader says it succeeded; got null factory!");
3624 return NS_ERROR_UNEXPECTED
;
3626 *aFactory
= mFactory
.get();
3627 NS_ADDREF(*aFactory
);
3631 nsFactoryEntry::~nsFactoryEntry()
3633 // nsFactoryEntry is arena-allocated. So we don't delete it;
3634 // call the destructor by hand.
3637 mParent
->~nsFactoryEntry();
3640 ////////////////////////////////////////////////////////////////////////////////
3641 // Static Access Functions
3642 ////////////////////////////////////////////////////////////////////////////////
3645 NS_GetComponentManager(nsIComponentManager
* *result
)
3647 if (nsComponentManagerImpl::gComponentManager
== nsnull
)
3649 // XPCOM needs initialization.
3650 nsresult rv
= NS_InitXPCOM2(nsnull
, nsnull
, nsnull
);
3655 *result
= static_cast<nsIComponentManager
*>
3656 (nsComponentManagerImpl::gComponentManager
);
3657 NS_IF_ADDREF(*result
);
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
);
3675 *result
= static_cast<nsIServiceManager
*>
3676 (nsComponentManagerImpl::gComponentManager
);
3677 NS_IF_ADDREF(*result
);
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
);
3696 *result
= static_cast<nsIComponentRegistrar
*>
3697 (nsComponentManagerImpl::gComponentManager
);
3698 NS_IF_ADDREF(*result
);