pfactory.h

Go to the documentation of this file.
00001 /*
00002  * factory.h
00003  *
00004  * Abstract Factory Classes
00005  *
00006  * Portable Windows Library
00007  *
00008  * Copyright (C) 2004 Post Increment
00009  *
00010  * The contents of this file are subject to the Mozilla Public License
00011  * Version 1.0 (the "License"); you may not use this file except in
00012  * compliance with the License. You may obtain a copy of the License at
00013  * http://www.mozilla.org/MPL/
00014  *
00015  * Software distributed under the License is distributed on an "AS IS"
00016  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00017  * the License for the specific language governing rights and limitations
00018  * under the License.
00019  *
00020  * The Original Code is Portable Windows Library.
00021  *
00022  * The Initial Developer of the Original Code is Post Increment
00023  *
00024  * Contributor(s): ______________________________________.
00025  *
00026  * $Log: pfactory.h,v $
00027  * Revision 1.30  2007/09/09 09:42:09  rjongbloed
00028  * Prevent internal factory allocations from being included in memory leaks
00029  *   as they are never deallocated during the life of the program.
00030  *
00031  * Revision 1.29  2007/09/08 11:34:28  rjongbloed
00032  * Improved memory checking (leaks etc), especially when using MSVC debug library.
00033  *
00034  * Revision 1.28  2007/08/07 01:37:05  csoutheren
00035  * Add RegisterAs function to allow registering a factory worker using another key
00036  *
00037  * Revision 1.27  2007/04/18 23:49:50  csoutheren
00038  * Add usage of precompiled headers
00039  *
00040  * Revision 1.26  2007/04/13 07:19:23  rjongbloed
00041  * Removed separate Win32 solution for "plug in static loading" issue,
00042  *   and used the PLOAD_FACTORY() mechanism for everything.
00043  * Slight clean up of the PLOAD_FACTORY macro.
00044  *
00045  * Revision 1.25  2006/11/20 03:18:39  csoutheren
00046  * Using std::string instead of PString avoids problems with key comparisons. Not sure why.....
00047  *
00048  * Revision 1.24  2006/08/11 04:45:36  csoutheren
00049  * Explicitly specify the default key type for PFactory
00050  *
00051  * Revision 1.23  2006/02/20 06:16:38  csoutheren
00052  * Extended factory macros
00053  *
00054  * Revision 1.22  2005/09/18 13:01:40  dominance
00055  * fixed pragma warnings when building with gcc.
00056  *
00057  * Revision 1.21  2005/05/03 11:58:45  csoutheren
00058  * Fixed various problems reported by valgrind
00059  * Thanks to Paul Cadach
00060  *
00061  * Revision 1.20  2005/01/04 07:44:02  csoutheren
00062  * More changes to implement the new configuration methodology, and also to
00063  * attack the global static problem
00064  *
00065  * Revision 1.19  2004/08/16 06:40:59  csoutheren
00066  * Added adapters template to make device plugins available via the abstract factory interface
00067  *
00068  * Revision 1.18  2004/07/12 09:17:20  csoutheren
00069  * Fixed warnings and errors under Linux
00070  *
00071  * Revision 1.17  2004/07/06 10:12:52  csoutheren
00072  * Added static integer o factory template to assist in ensuring factories are instantiated
00073  *
00074  * Revision 1.16  2004/07/06 04:26:44  csoutheren
00075  * Fixed problem when using factory maps with non-standard keys
00076  *
00077  * Revision 1.15  2004/07/02 03:14:47  csoutheren
00078  * Made factories non-singleton, by default
00079  * Added more docs
00080  *
00081  * Revision 1.14  2004/07/01 11:41:28  csoutheren
00082  * Fixed compile and run problems on Linux
00083  *
00084  * Revision 1.13  2004/07/01 04:33:57  csoutheren
00085  * Updated documentation on PFactory classes
00086  *
00087  * Revision 1.12  2004/06/30 12:17:04  rjongbloed
00088  * Rewrite of plug in system to use single global variable for all factories to avoid all sorts
00089  *   of issues with startup orders and Windows DLL multiple instances.
00090  *
00091  * Revision 1.11  2004/06/17 06:35:12  csoutheren
00092  * Use attribute (( constructor )) to guarantee that factories are
00093  * instantiated when loaded from a shared library
00094  *
00095  * Revision 1.10  2004/06/03 13:30:57  csoutheren
00096  * Renamed INSTANTIATE_FACTORY to avoid potential namespace collisions
00097  * Added documentaton on new PINSTANTIATE_FACTORY macro
00098  * Added generic form of PINSTANTIATE_FACTORY
00099  *
00100  * Revision 1.9  2004/06/03 12:47:58  csoutheren
00101  * Decomposed PFactory declarations to hopefully avoid problems with Windows DLLs
00102  *
00103  * Revision 1.8  2004/06/01 05:44:12  csoutheren
00104  * Added typedefs to allow access to types
00105  * Changed singleton class to use new so as to allow full cleanup
00106  *
00107  * Revision 1.7  2004/05/23 12:33:56  rjongbloed
00108  * Made some subtle changes to the way the static variables are instantiated in
00109  *   the factoris to fix problems with DLL's under windows. May not be final solution.
00110  *
00111  * Revision 1.6  2004/05/19 06:48:39  csoutheren
00112  * Added new functions to allow handling of singletons without concrete classes
00113  *
00114  * Revision 1.5  2004/05/18 06:01:06  csoutheren
00115  * Deferred plugin loading until after main has executed by using abstract factory classes
00116  *
00117  * Revision 1.4  2004/05/18 02:32:08  csoutheren
00118  * Fixed linking problems with PGenericFactory classes
00119  *
00120  * Revision 1.3  2004/05/13 15:10:51  csoutheren
00121  * Removed warnings under Windows
00122  *
00123  * Revision 1.2  2004/05/13 14:59:00  csoutheren
00124  * Removed warning under gcc
00125  *
00126  * Revision 1.1  2004/05/13 14:53:35  csoutheren
00127  * Add "abstract factory" template classes
00128  *
00129  */
00130 
00131 #ifndef _PFACTORY_H
00132 #define _PFACTORY_H
00133 
00134 #ifdef P_USE_PRAGMA
00135 #pragma interface
00136 #endif
00137 
00138 #ifndef _PTLIB_H
00139 #include <ptlib.h>
00140 #endif
00141 
00142 #include <string>
00143 #include <map>
00144 #include <vector>
00145 
00146 #if defined(_MSC_VER)
00147 #pragma warning(disable:4786)
00148 #endif
00149 
00201 // this define the default class to be used for keys into PFactories
00202 //typedef PString PDefaultPFactoryKey;
00203 typedef std::string PDefaultPFactoryKey;
00204 
00205 
00213 class PFactoryBase
00214 {
00215   protected:
00216     PFactoryBase()
00217     { }
00218   public:
00219     virtual ~PFactoryBase()
00220     { }
00221 
00222     class FactoryMap : public std::map<std::string, PFactoryBase *>
00223     {
00224       public:
00225         FactoryMap() { }
00226         ~FactoryMap();
00227     };
00228 
00229     static FactoryMap & GetFactories();
00230     static PMutex & GetFactoriesMutex();
00231 
00232     PMutex mutex;
00233 
00234   private:
00235     PFactoryBase(const PFactoryBase &) {}
00236     void operator=(const PFactoryBase &) {}
00237 };
00238 
00239 
00242 template <class _Abstract_T, typename _Key_T = PDefaultPFactoryKey>
00243 class PFactory : PFactoryBase
00244 {
00245   public:
00246     typedef _Key_T      Key_T;
00247     typedef _Abstract_T Abstract_T;
00248 
00249     class WorkerBase
00250     {
00251       protected:
00252         WorkerBase(bool singleton = false)
00253           : isDynamic(false),
00254             isSingleton(singleton),
00255             singletonInstance(NULL),
00256             deleteSingleton(false)
00257         { }
00258         WorkerBase(Abstract_T * instance)
00259           : isDynamic(true),
00260             isSingleton(true),
00261             singletonInstance(instance),
00262             deleteSingleton(true)
00263         { }
00264 
00265         virtual ~WorkerBase()
00266         {
00267           if (deleteSingleton)
00268             delete singletonInstance;
00269         }
00270 
00271         Abstract_T * CreateInstance(const Key_T & key)
00272         {
00273           if (!isSingleton)
00274             return Create(key);
00275 
00276           if (singletonInstance == NULL)
00277             singletonInstance = Create(key);
00278           return singletonInstance;
00279         }
00280 
00281         virtual Abstract_T * Create(const Key_T & /*key*/) const { return singletonInstance; }
00282 
00283         bool         isDynamic;
00284         bool         isSingleton;
00285         Abstract_T * singletonInstance;
00286         bool         deleteSingleton;
00287 
00288       friend class PFactory<_Abstract_T, _Key_T>;
00289     };
00290 
00291     template <class _Concrete_T>
00292     class Worker : WorkerBase
00293     {
00294       public:
00295         Worker(const Key_T & key, bool singleton = false)
00296           : WorkerBase(singleton)
00297         {
00298           PMEMORY_IGNORE_ALLOCATIONS_FOR_SCOPE;
00299           PFactory<_Abstract_T, _Key_T>::Register(key, this);   // here
00300         }
00301 
00302       protected:
00303         virtual Abstract_T * Create(const Key_T & /*key*/) const
00304         {
00305 #if PMEMORY_HEAP
00306           // Singletons are never deallocated, so make sure they arenot reported as a leak
00307           BOOL previousIgnoreAllocations = PMemoryHeap::SetIgnoreAllocations(isSingleton);
00308 #endif
00309           Abstract_T * instance = new _Concrete_T;
00310 #if PMEMORY_HEAP
00311           PMemoryHeap::SetIgnoreAllocations(previousIgnoreAllocations);
00312 #endif
00313           return instance;
00314         }
00315     };
00316 
00317     typedef std::map<_Key_T, WorkerBase *> KeyMap_T;
00318     typedef std::vector<_Key_T> KeyList_T;
00319 
00320     static void Register(const _Key_T & key, WorkerBase * worker)
00321     {
00322       GetInstance().Register_Internal(key, worker);
00323     }
00324 
00325     static void Register(const _Key_T & key, Abstract_T * instance)
00326     {
00327       GetInstance().Register_Internal(key, PNEW WorkerBase(instance));
00328     }
00329 
00330     static BOOL RegisterAs(const _Key_T & newKey, const _Key_T & oldKey)
00331     {
00332       return GetInstance().RegisterAs_Internal(newKey, oldKey);
00333     }
00334 
00335     static void Unregister(const _Key_T & key)
00336     {
00337       GetInstance().Unregister_Internal(key);
00338     }
00339 
00340     static void UnregisterAll()
00341     {
00342       GetInstance().UnregisterAll_Internal();
00343     }
00344 
00345     static bool IsRegistered(const _Key_T & key)
00346     {
00347       return GetInstance().IsRegistered_Internal(key);
00348     }
00349 
00350     static _Abstract_T * CreateInstance(const _Key_T & key)
00351     {
00352       return GetInstance().CreateInstance_Internal(key);
00353     }
00354 
00355     static BOOL IsSingleton(const _Key_T & key)
00356     {
00357       return GetInstance().IsSingleton_Internal(key);
00358     }
00359 
00360     static KeyList_T GetKeyList()
00361     { 
00362       return GetInstance().GetKeyList_Internal();
00363     }
00364 
00365     static KeyMap_T & GetKeyMap()
00366     { 
00367       return GetInstance().keyMap;
00368     }
00369 
00370     static PMutex & GetMutex()
00371     {
00372       return GetInstance().mutex;
00373     }
00374 
00375   protected:
00376     PFactory()
00377     { }
00378 
00379     ~PFactory()
00380     {
00381       typename KeyMap_T::const_iterator entry;
00382       for (entry = keyMap.begin(); entry != keyMap.end(); ++entry) {
00383         if (entry->second->isDynamic)
00384           delete entry->second;
00385       }
00386     }
00387 
00388     static PFactory & GetInstance()
00389     {
00390       std::string className = typeid(PFactory).name();
00391       PWaitAndSignal m(GetFactoriesMutex());
00392       FactoryMap & factories = GetFactories();
00393       FactoryMap::const_iterator entry = factories.find(className);
00394       if (entry != factories.end()) {
00395         PAssert(entry->second != NULL, "Factory map returned NULL for existing key");
00396         PFactoryBase * b = entry->second;
00397         // don't use the following dynamic cast, because gcc does not like it
00398         //PFactory * f = dynamic_cast<PFactory*>(b);
00399         return *(PFactory *)b;
00400       }
00401 
00402       PMEMORY_IGNORE_ALLOCATIONS_FOR_SCOPE;
00403       PFactory * factory = new PFactory;
00404       factories[className] = factory;
00405       return *factory;
00406     }
00407 
00408 
00409     void Register_Internal(const _Key_T & key, WorkerBase * worker)
00410     {
00411       PWaitAndSignal m(mutex);
00412       if (keyMap.find(key) == keyMap.end())
00413         keyMap[key] = worker;
00414     }
00415 
00416     BOOL RegisterAs_Internal(const _Key_T & newKey, const _Key_T & oldKey)
00417     {
00418       PWaitAndSignal m(mutex);
00419       if (keyMap.find(oldKey) == keyMap.end())
00420         return FALSE;
00421       keyMap[newKey] = keyMap[oldKey];
00422       return TRUE;
00423     }
00424 
00425     void Unregister_Internal(const _Key_T & key)
00426     {
00427       PWaitAndSignal m(mutex);
00428       keyMap.erase(key);
00429     }
00430 
00431     void UnregisterAll_Internal()
00432     {
00433       PWaitAndSignal m(mutex);
00434       keyMap.erase(keyMap.begin(), keyMap.end());
00435     }
00436 
00437     bool IsRegistered_Internal(const _Key_T & key)
00438     {
00439       PWaitAndSignal m(mutex);
00440       return keyMap.find(key) != keyMap.end();
00441     }
00442 
00443     _Abstract_T * CreateInstance_Internal(const _Key_T & key)
00444     {
00445       PWaitAndSignal m(mutex);
00446       typename KeyMap_T::const_iterator entry = keyMap.find(key);
00447       if (entry != keyMap.end())
00448         return entry->second->CreateInstance(key);
00449       return NULL;
00450     }
00451 
00452     bool IsSingleton_Internal(const _Key_T & key)
00453     {
00454       PWaitAndSignal m(mutex);
00455       if (keyMap.find(key) == keyMap.end())
00456         return false;
00457       return keyMap[key]->isSingleton;
00458     }
00459 
00460     KeyList_T GetKeyList_Internal()
00461     { 
00462       PWaitAndSignal m(mutex);
00463       KeyList_T list;
00464       typename KeyMap_T::const_iterator entry;
00465       for (entry = keyMap.begin(); entry != keyMap.end(); ++entry)
00466         list.push_back(entry->first);
00467       return list;
00468     }
00469 
00470     KeyMap_T keyMap;
00471 
00472   private:
00473     PFactory(const PFactory &) {}
00474     void operator=(const PFactory &) {}
00475 };
00476 
00477 //
00478 //  this macro is used to initialise the static member variable used to force factories to instantiate
00479 //
00480 #define PLOAD_FACTORY(AbstractType, KeyType) \
00481   namespace PWLibFactoryLoader { \
00482     extern int AbstractType##_##KeyType##_loader; \
00483     static int AbstractType##_##KeyType##_loader_instance = AbstractType##_##KeyType##_loader; \
00484   };
00485 
00486 
00487 //
00488 //  this macro is used to instantiate a static variable that accesses the static member variable 
00489 //  in a factory forcing it to load
00490 //
00491 #define PINSTANTIATE_FACTORY(AbstractType, KeyType) \
00492   namespace PWLibFactoryLoader { int AbstractType##_##KeyType##_loader; }
00493 
00494 
00495 #endif // _PFACTORY_H

Generated on Fri Mar 7 06:25:02 2008 for PTLib by  doxygen 1.5.1