Back to index

lightning-sunbird  0.9+nobinonly
nsGenericFactory.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 
00040 // DO NOT COPY THIS CODE INTO YOUR SOURCE!  USE NS_IMPL_NSGETMODULE()
00041 
00042 #include "nsGenericFactory.h"
00043 #include "nsMemory.h"
00044 #include "nsCOMPtr.h"
00045 #include "nsIComponentManager.h"
00046 #include "nsIComponentRegistrar.h"
00047 
00048 #ifdef XPCOM_GLUE
00049 #include "nsXPCOMGlue.h"
00050 #include "nsXPCOMPrivate.h"
00051 #endif
00052 
00053 nsGenericFactory::nsGenericFactory(const nsModuleComponentInfo *info)
00054     : mInfo(info)
00055 {
00056     if (mInfo && mInfo->mClassInfoGlobal)
00057         *mInfo->mClassInfoGlobal = NS_STATIC_CAST(nsIClassInfo *, this);
00058 }
00059 
00060 nsGenericFactory::~nsGenericFactory()
00061 {
00062     if (mInfo) {
00063         if (mInfo->mFactoryDestructor)
00064             mInfo->mFactoryDestructor();
00065         if (mInfo->mClassInfoGlobal)
00066             *mInfo->mClassInfoGlobal = 0;
00067     }
00068 }
00069 
00070 NS_IMPL_THREADSAFE_ISUPPORTS3(nsGenericFactory,
00071                               nsIGenericFactory, 
00072                               nsIFactory,
00073                               nsIClassInfo)
00074 
00075 NS_IMETHODIMP nsGenericFactory::CreateInstance(nsISupports *aOuter,
00076                                                REFNSIID aIID, void **aResult)
00077 {
00078     if (mInfo->mConstructor) {
00079         return mInfo->mConstructor(aOuter, aIID, aResult);
00080     }
00081 
00082     return NS_ERROR_FACTORY_NOT_REGISTERED;
00083 }
00084 
00085 NS_IMETHODIMP nsGenericFactory::LockFactory(PRBool aLock)
00086 {
00087     // XXX do we care if (mInfo->mFlags & THREADSAFE)?
00088     return NS_OK;
00089 }
00090 
00091 NS_IMETHODIMP nsGenericFactory::GetInterfaces(PRUint32 *countp,
00092                                               nsIID* **array)
00093 {
00094     if (!mInfo->mGetInterfacesProc) {
00095         *countp = 0;
00096         *array = nsnull;
00097         return NS_OK;
00098     }
00099     return mInfo->mGetInterfacesProc(countp, array);
00100 }
00101 
00102 NS_IMETHODIMP nsGenericFactory::GetHelperForLanguage(PRUint32 language,
00103                                                      nsISupports **helper)
00104 {
00105     if (mInfo->mGetLanguageHelperProc)
00106         return mInfo->mGetLanguageHelperProc(language, helper);
00107     *helper = nsnull;
00108     return NS_OK;
00109 }
00110 
00111 NS_IMETHODIMP nsGenericFactory::GetContractID(char **aContractID)
00112 {
00113     if (mInfo->mContractID) {
00114         *aContractID = (char *)nsMemory::Alloc(strlen(mInfo->mContractID) + 1);
00115         if (!*aContractID)
00116             return NS_ERROR_OUT_OF_MEMORY;
00117         strcpy(*aContractID, mInfo->mContractID);
00118     } else {
00119         *aContractID = nsnull;
00120     }
00121     return NS_OK;
00122 }
00123 
00124 NS_IMETHODIMP nsGenericFactory::GetClassDescription(char * *aClassDescription)
00125 {
00126     if (mInfo->mDescription) {
00127         *aClassDescription = (char *)
00128             nsMemory::Alloc(strlen(mInfo->mDescription) + 1);
00129         if (!*aClassDescription)
00130             return NS_ERROR_OUT_OF_MEMORY;
00131         strcpy(*aClassDescription, mInfo->mDescription);
00132     } else {
00133         *aClassDescription = nsnull;
00134     }
00135     return NS_OK;
00136 }
00137 
00138 NS_IMETHODIMP nsGenericFactory::GetClassID(nsCID * *aClassID)
00139 {
00140     *aClassID =
00141         NS_REINTERPRET_CAST(nsCID*,
00142                             nsMemory::Clone(&mInfo->mCID, sizeof mInfo->mCID));
00143     if (! *aClassID)
00144         return NS_ERROR_OUT_OF_MEMORY;
00145     return NS_OK;
00146 }
00147 
00148 NS_IMETHODIMP nsGenericFactory::GetClassIDNoAlloc(nsCID *aClassID)
00149 {
00150     *aClassID = mInfo->mCID;
00151     return NS_OK;
00152 }
00153 
00154 NS_IMETHODIMP nsGenericFactory::GetImplementationLanguage(PRUint32 *langp)
00155 {
00156     *langp = nsIProgrammingLanguage::CPLUSPLUS;
00157     return NS_OK;
00158 }
00159 
00160 NS_IMETHODIMP nsGenericFactory::GetFlags(PRUint32 *flagsp)
00161 {
00162     *flagsp = mInfo->mFlags;
00163     return NS_OK;
00164 }
00165 
00166 // nsIGenericFactory: component-info accessors
00167 NS_IMETHODIMP nsGenericFactory::SetComponentInfo(const nsModuleComponentInfo *info)
00168 {
00169     if (mInfo && mInfo->mClassInfoGlobal)
00170         *mInfo->mClassInfoGlobal = 0;
00171     mInfo = info;
00172     if (mInfo && mInfo->mClassInfoGlobal)
00173         *mInfo->mClassInfoGlobal = NS_STATIC_CAST(nsIClassInfo *, this);
00174     return NS_OK;
00175 }
00176 
00177 NS_IMETHODIMP nsGenericFactory::GetComponentInfo(const nsModuleComponentInfo **infop)
00178 {
00179     *infop = mInfo;
00180     return NS_OK;
00181 }
00182 
00183 NS_METHOD nsGenericFactory::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
00184 {
00185     // sorry, aggregation not spoken here.
00186     nsresult res = NS_ERROR_NO_AGGREGATION;
00187     if (outer == NULL) {
00188         nsGenericFactory* factory = new nsGenericFactory;
00189         if (factory != NULL) {
00190             res = factory->QueryInterface(aIID, aInstancePtr);
00191             if (res != NS_OK)
00192                 delete factory;
00193         } else {
00194             res = NS_ERROR_OUT_OF_MEMORY;
00195         }
00196     }
00197     return res;
00198 }
00199 
00200 NS_COM_GLUE nsresult
00201 NS_NewGenericFactory(nsIGenericFactory* *result,
00202                      const nsModuleComponentInfo *info)
00203 {
00204     nsresult rv;
00205     nsIGenericFactory* fact;
00206     rv = nsGenericFactory::Create(NULL, NS_GET_IID(nsIGenericFactory), (void**)&fact);
00207     if (NS_FAILED(rv)) return rv;
00208     rv = fact->SetComponentInfo(info);
00209     if (NS_FAILED(rv)) goto error;
00210     *result = fact;
00211     return rv;
00212 
00213   error:
00214     NS_RELEASE(fact);
00215     return rv;
00216 }
00217 
00219 
00220 nsGenericModule::nsGenericModule(const char* moduleName, PRUint32 componentCount,
00221                                  const nsModuleComponentInfo* components,
00222                                  nsModuleConstructorProc ctor,
00223                                  nsModuleDestructorProc dtor)
00224     : mInitialized(PR_FALSE), 
00225       mModuleName(moduleName),
00226       mComponentCount(componentCount),
00227       mComponents(components),
00228       mFactoriesNotToBeRegistered(nsnull),
00229       mCtor(ctor),
00230       mDtor(dtor)
00231 {
00232 }
00233 
00234 nsGenericModule::~nsGenericModule()
00235 {
00236     Shutdown();
00237 
00238 #ifdef XPCOM_GLUE
00239    XPCOMGlueShutdown();
00240 #endif
00241 
00242 }
00243 
00244 NS_IMPL_THREADSAFE_ISUPPORTS1(nsGenericModule, nsIModule)
00245 
00246 nsresult 
00247 nsGenericModule::AddFactoryNode(nsIGenericFactory* fact)
00248 {
00249     if (!fact)
00250         return NS_ERROR_FAILURE;
00251 
00252     FactoryNode *node = new FactoryNode(fact, mFactoriesNotToBeRegistered);
00253     if (!node)
00254         return NS_ERROR_OUT_OF_MEMORY;
00255     
00256     mFactoriesNotToBeRegistered = node;
00257     return NS_OK;
00258 }
00259 
00260 
00261 // Perform our one-time intialization for this module
00262 nsresult
00263 nsGenericModule::Initialize(nsIComponentManager *compMgr)
00264 {
00265     nsresult rv;
00266 
00267     if (mInitialized) {
00268         return NS_OK;
00269     }
00270 
00271     if (mCtor) {
00272         rv = mCtor(this);
00273         if (NS_FAILED(rv))
00274             return rv;
00275     }
00276 
00277 
00278 #ifdef XPCOM_GLUE
00279     rv = XPCOMGlueStartup(".");
00280     if (NS_FAILED(rv))
00281         return rv;
00282 #endif
00283 
00284     nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(compMgr, &rv);
00285     if (NS_FAILED(rv))
00286         return rv;
00287 
00288     // Eagerly populate factory/class object hash for entries
00289     // without constructors. If we didn't, the class object would
00290     // never get created. Also create the factory, which doubles
00291     // as the class object, if the EAGER_CLASSINFO flag was given.
00292     // This allows objects to be created (within their modules)
00293     // via operator new rather than CreateInstance, yet still be
00294     // QI'able to nsIClassInfo.
00295     const nsModuleComponentInfo* desc = mComponents;
00296     for (PRUint32 i = 0; i < mComponentCount; i++) {
00297         if (!desc->mConstructor ||
00298             (desc->mFlags & nsIClassInfo::EAGER_CLASSINFO)) {
00299             nsCOMPtr<nsIGenericFactory> fact;
00300             nsresult rv = NS_NewGenericFactory(getter_AddRefs(fact), desc);
00301             if (NS_FAILED(rv)) return rv;
00302 
00303             // if we don't have a mConstructor, then we should not populate
00304             // the component manager.
00305             if (!desc->mConstructor) {
00306                 rv = AddFactoryNode(fact);
00307             } else {
00308                 rv = registrar->RegisterFactory(desc->mCID, 
00309                                                 desc->mDescription,
00310                                                 desc->mContractID, 
00311                                                 fact);
00312             }
00313             if (NS_FAILED(rv)) return rv;
00314         }
00315         desc++;
00316     }
00317 
00318     mInitialized = PR_TRUE;
00319     return NS_OK;
00320 }
00321 
00322 // Shutdown this module, releasing all of the module resources
00323 void
00324 nsGenericModule::Shutdown()
00325 {
00326     // Free cached factories that were not registered.
00327     FactoryNode* node;
00328     while (mFactoriesNotToBeRegistered)
00329     {
00330         node = mFactoriesNotToBeRegistered->mNext;
00331         delete mFactoriesNotToBeRegistered;
00332         mFactoriesNotToBeRegistered = node;
00333     }
00334 
00335     if (mInitialized) {
00336         mInitialized = PR_FALSE;
00337 
00338         if (mDtor)
00339             mDtor(this);
00340     }
00341 }
00342 
00343 // Create a factory object for creating instances of aClass.
00344 NS_IMETHODIMP
00345 nsGenericModule::GetClassObject(nsIComponentManager *aCompMgr,
00346                                 const nsCID& aClass,
00347                                 const nsIID& aIID,
00348                                 void** r_classObj)
00349 {
00350     nsresult rv;
00351 
00352     // Defensive programming: Initialize *r_classObj in case of error below
00353     if (!r_classObj) {
00354         return NS_ERROR_INVALID_POINTER;
00355     }
00356     *r_classObj = NULL;
00357 
00358     // Do one-time-only initialization if necessary
00359     if (!mInitialized) {
00360         rv = Initialize(aCompMgr);
00361         if (NS_FAILED(rv)) {
00362             // Initialization failed! yikes!
00363             return rv;
00364         }
00365     }
00366 
00367     // Choose the appropriate factory, based on the desired instance
00368     // class type (aClass).
00369     const nsModuleComponentInfo* desc = mComponents;
00370     for (PRUint32 i = 0; i < mComponentCount; i++) {
00371         if (desc->mCID.Equals(aClass)) {
00372             nsCOMPtr<nsIGenericFactory> fact;
00373             rv = NS_NewGenericFactory(getter_AddRefs(fact), desc);
00374             if (NS_FAILED(rv)) return rv;
00375             return fact->QueryInterface(aIID, r_classObj);
00376         }
00377         desc++;
00378     }
00379     // not found in descriptions
00380     return NS_ERROR_FACTORY_NOT_REGISTERED;
00381 }
00382 
00383 NS_IMETHODIMP
00384 nsGenericModule::RegisterSelf(nsIComponentManager *aCompMgr,
00385                               nsIFile* aPath,
00386                               const char* registryLocation,
00387                               const char* componentType)
00388 {
00389     nsresult rv = NS_OK;
00390 
00391 #ifdef DEBUG
00392     fprintf(stderr, "*** Registering %s components (all right -- a generic module!)\n", mModuleName);
00393 #endif
00394 
00395     const nsModuleComponentInfo* cp = mComponents;
00396     for (PRUint32 i = 0; i < mComponentCount; i++) {
00397         // Register the component only if it has a constructor
00398         if (cp->mConstructor) {
00399             nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(aCompMgr, &rv);
00400             if (registrar)
00401                 rv = registrar->RegisterFactoryLocation(cp->mCID, 
00402                                                         cp->mDescription,
00403                                                         cp->mContractID, 
00404                                                         aPath,
00405                                                         registryLocation,
00406                                                         componentType);
00407             if (NS_FAILED(rv)) {
00408 #ifdef DEBUG
00409                 fprintf(stderr, "nsGenericModule %s: unable to register %s component => %x\n",
00410                        mModuleName?mModuleName:"(null)", cp->mDescription?cp->mDescription:"(null)", rv);
00411 #endif
00412                 break;
00413             }
00414         }
00415         // Call the registration hook of the component, if any
00416         if (cp->mRegisterSelfProc)
00417         {
00418             rv = cp->mRegisterSelfProc(aCompMgr, aPath, registryLocation,
00419                                        componentType, cp);
00420             if (NS_FAILED(rv)) {
00421 #ifdef DEBUG
00422                 fprintf(stderr, "nsGenericModule %s: Register hook for %s component returned error => %x\n",
00423                        mModuleName?mModuleName:"(null)", cp->mDescription?cp->mDescription:"(null)", rv);
00424 #endif
00425                 break;
00426             }
00427         }
00428         cp++;
00429     }
00430 
00431     return rv;
00432 }
00433 
00434 NS_IMETHODIMP
00435 nsGenericModule::UnregisterSelf(nsIComponentManager* aCompMgr,
00436                             nsIFile* aPath,
00437                             const char* registryLocation)
00438 {
00439 #ifdef DEBUG
00440     fprintf(stderr, "*** Unregistering %s components (all right -- a generic module!)\n", mModuleName);
00441 #endif
00442     const nsModuleComponentInfo* cp = mComponents;
00443     for (PRUint32 i = 0; i < mComponentCount; i++) {
00444         // Call the unregistration hook of the component, if any
00445         if (cp->mUnregisterSelfProc)
00446         {
00447             cp->mUnregisterSelfProc(aCompMgr, aPath, registryLocation, cp);
00448         }
00449 
00450         // Unregister the component
00451         nsresult rv; 
00452         nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(aCompMgr, &rv);
00453         if (registrar)
00454              rv = registrar->UnregisterFactoryLocation(cp->mCID, aPath);
00455         if (NS_FAILED(rv)) {
00456 #ifdef DEBUG
00457             fprintf(stderr, "nsGenericModule %s: unable to unregister %s component => %x\n",
00458                    mModuleName, cp->mDescription, rv);
00459 #endif
00460         }
00461         cp++;
00462     }
00463 
00464     return NS_OK;
00465 }
00466 
00467 NS_IMETHODIMP
00468 nsGenericModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload)
00469 {
00470     if (!okToUnload) {
00471         return NS_ERROR_INVALID_POINTER;
00472     }
00473     *okToUnload = PR_FALSE;
00474     return NS_ERROR_FAILURE;
00475 }
00476 
00477 NS_COM_GLUE nsresult
00478 NS_NewGenericModule2(nsModuleInfo const *info, nsIModule* *result)
00479 {
00480     nsresult rv = NS_OK;
00481 
00482     // Create and initialize the module instance
00483     nsGenericModule *m = 
00484         new nsGenericModule(info->mModuleName, info->mCount, info->mComponents,
00485                             info->mCtor, info->mDtor);
00486 
00487     if (!m)
00488         return NS_ERROR_OUT_OF_MEMORY;
00489 
00490     // Increase refcnt and store away nsIModule interface to m in result
00491     NS_ADDREF(*result = m);
00492     return rv;
00493 }
00494 
00495 NS_COM_GLUE nsresult
00496 NS_NewGenericModule(const char* moduleName,
00497                     PRUint32 componentCount,
00498                     nsModuleComponentInfo* components,
00499                     nsModuleDestructorProc dtor,
00500                     nsIModule* *result)
00501 {
00502     nsModuleInfo info;
00503     memset(&info, 0, sizeof(info));
00504 
00505     info.mVersion    = NS_MODULEINFO_VERSION;
00506     info.mModuleName = moduleName;
00507     info.mComponents = components;
00508     info.mCount      = componentCount;
00509     info.mDtor       = dtor;
00510 
00511     return NS_NewGenericModule2(&info, result);
00512 }
00513