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.25  2006/11/20 03:18:39  csoutheren
00028  * Using std::string instead of PString avoids problems with key comparisons. Not sure why.....
00029  *
00030  * Revision 1.24  2006/08/11 04:45:36  csoutheren
00031  * Explicitly specify the default key type for PFactory
00032  *
00033  * Revision 1.23  2006/02/20 06:16:38  csoutheren
00034  * Extended factory macros
00035  *
00036  * Revision 1.22  2005/09/18 13:01:40  dominance
00037  * fixed pragma warnings when building with gcc.
00038  *
00039  * Revision 1.21  2005/05/03 11:58:45  csoutheren
00040  * Fixed various problems reported by valgrind
00041  * Thanks to Paul Cadach
00042  *
00043  * Revision 1.20  2005/01/04 07:44:02  csoutheren
00044  * More changes to implement the new configuration methodology, and also to
00045  * attack the global static problem
00046  *
00047  * Revision 1.19  2004/08/16 06:40:59  csoutheren
00048  * Added adapters template to make device plugins available via the abstract factory interface
00049  *
00050  * Revision 1.18  2004/07/12 09:17:20  csoutheren
00051  * Fixed warnings and errors under Linux
00052  *
00053  * Revision 1.17  2004/07/06 10:12:52  csoutheren
00054  * Added static integer o factory template to assist in ensuring factories are instantiated
00055  *
00056  * Revision 1.16  2004/07/06 04:26:44  csoutheren
00057  * Fixed problem when using factory maps with non-standard keys
00058  *
00059  * Revision 1.15  2004/07/02 03:14:47  csoutheren
00060  * Made factories non-singleton, by default
00061  * Added more docs
00062  *
00063  * Revision 1.14  2004/07/01 11:41:28  csoutheren
00064  * Fixed compile and run problems on Linux
00065  *
00066  * Revision 1.13  2004/07/01 04:33:57  csoutheren
00067  * Updated documentation on PFactory classes
00068  *
00069  * Revision 1.12  2004/06/30 12:17:04  rjongbloed
00070  * Rewrite of plug in system to use single global variable for all factories to avoid all sorts
00071  *   of issues with startup orders and Windows DLL multiple instances.
00072  *
00073  * Revision 1.11  2004/06/17 06:35:12  csoutheren
00074  * Use attribute (( constructor )) to guarantee that factories are
00075  * instantiated when loaded from a shared library
00076  *
00077  * Revision 1.10  2004/06/03 13:30:57  csoutheren
00078  * Renamed INSTANTIATE_FACTORY to avoid potential namespace collisions
00079  * Added documentaton on new PINSTANTIATE_FACTORY macro
00080  * Added generic form of PINSTANTIATE_FACTORY
00081  *
00082  * Revision 1.9  2004/06/03 12:47:58  csoutheren
00083  * Decomposed PFactory declarations to hopefully avoid problems with Windows DLLs
00084  *
00085  * Revision 1.8  2004/06/01 05:44:12  csoutheren
00086  * Added typedefs to allow access to types
00087  * Changed singleton class to use new so as to allow full cleanup
00088  *
00089  * Revision 1.7  2004/05/23 12:33:56  rjongbloed
00090  * Made some subtle changes to the way the static variables are instantiated in
00091  *   the factoris to fix problems with DLL's under windows. May not be final solution.
00092  *
00093  * Revision 1.6  2004/05/19 06:48:39  csoutheren
00094  * Added new functions to allow handling of singletons without concrete classes
00095  *
00096  * Revision 1.5  2004/05/18 06:01:06  csoutheren
00097  * Deferred plugin loading until after main has executed by using abstract factory classes
00098  *
00099  * Revision 1.4  2004/05/18 02:32:08  csoutheren
00100  * Fixed linking problems with PGenericFactory classes
00101  *
00102  * Revision 1.3  2004/05/13 15:10:51  csoutheren
00103  * Removed warnings under Windows
00104  *
00105  * Revision 1.2  2004/05/13 14:59:00  csoutheren
00106  * Removed warning under gcc
00107  *
00108  * Revision 1.1  2004/05/13 14:53:35  csoutheren
00109  * Add "abstract factory" template classes
00110  *
00111  */
00112 
00113 #ifndef _PFACTORY_H
00114 #define _PFACTORY_H
00115 
00116 #ifdef P_USE_PRAGMA
00117 #pragma interface
00118 #endif
00119 
00120 #include <ptlib.h>
00121 #include <string>
00122 #include <map>
00123 #include <vector>
00124 
00125 #if defined(_MSC_VER)
00126 #pragma warning(disable:4786)
00127 #endif
00128 
00180 // this define the default class to be used for keys into PFactories
00181 //typedef PString PDefaultPFactoryKey;
00182 typedef std::string PDefaultPFactoryKey;
00183 
00184 
00192 class PFactoryBase
00193 {
00194   protected:
00195     PFactoryBase()
00196     { }
00197   public:
00198     virtual ~PFactoryBase()
00199     { }
00200 
00201     class FactoryMap : public std::map<std::string, PFactoryBase *>
00202     {
00203       public:
00204         FactoryMap() { }
00205         ~FactoryMap();
00206     };
00207 
00208     static FactoryMap & GetFactories();
00209     static PMutex & GetFactoriesMutex();
00210 
00211     PMutex mutex;
00212 
00213   private:
00214     PFactoryBase(const PFactoryBase &) {}
00215     void operator=(const PFactoryBase &) {}
00216 };
00217 
00218 
00221 template <class _Abstract_T, typename _Key_T = PDefaultPFactoryKey>
00222 class PFactory : PFactoryBase
00223 {
00224   public:
00225     typedef _Key_T      Key_T;
00226     typedef _Abstract_T Abstract_T;
00227 
00228     class WorkerBase
00229     {
00230       protected:
00231         WorkerBase(bool singleton = false)
00232           : isDynamic(false),
00233             isSingleton(singleton),
00234             singletonInstance(NULL),
00235             deleteSingleton(false)
00236         { }
00237         WorkerBase(Abstract_T * instance)
00238           : isDynamic(true),
00239             isSingleton(true),
00240             singletonInstance(instance),
00241             deleteSingleton(true)
00242         { }
00243 
00244         virtual ~WorkerBase()
00245         {
00246           if (deleteSingleton)
00247             delete singletonInstance;
00248         }
00249 
00250         Abstract_T * CreateInstance(const Key_T & key)
00251         {
00252           if (!isSingleton)
00253             return Create(key);
00254 
00255           if (singletonInstance == NULL)
00256             singletonInstance = Create(key);
00257           return singletonInstance;
00258         }
00259 
00260         virtual Abstract_T * Create(const Key_T & /*key*/) const { return singletonInstance; }
00261 
00262         bool         isDynamic;
00263         bool         isSingleton;
00264         Abstract_T * singletonInstance;
00265         bool         deleteSingleton;
00266 
00267       friend class PFactory<_Abstract_T, _Key_T>;
00268     };
00269 
00270     template <class _Concrete_T>
00271     class Worker : WorkerBase
00272     {
00273       public:
00274         Worker(const Key_T & key, bool singleton = false)
00275           : WorkerBase(singleton)
00276         {
00277           PFactory<_Abstract_T, _Key_T>::Register(key, this);   // here
00278         }
00279 
00280       protected:
00281         virtual Abstract_T * Create(const Key_T & /*key*/) const { return new _Concrete_T; }
00282     };
00283 
00284     typedef std::map<_Key_T, WorkerBase *> KeyMap_T;
00285     typedef std::vector<_Key_T> KeyList_T;
00286 
00287     static void Register(const _Key_T & key, WorkerBase * worker)
00288     {
00289       GetInstance().Register_Internal(key, worker);
00290     }
00291 
00292     static void Register(const _Key_T & key, Abstract_T * instance)
00293     {
00294       GetInstance().Register_Internal(key, new WorkerBase(instance));
00295     }
00296 
00297     static void Unregister(const _Key_T & key)
00298     {
00299       GetInstance().Unregister_Internal(key);
00300     }
00301 
00302     static void UnregisterAll()
00303     {
00304       GetInstance().UnregisterAll_Internal();
00305     }
00306 
00307     static bool IsRegistered(const _Key_T & key)
00308     {
00309       return GetInstance().IsRegistered_Internal(key);
00310     }
00311 
00312     static _Abstract_T * CreateInstance(const _Key_T & key)
00313     {
00314       return GetInstance().CreateInstance_Internal(key);
00315     }
00316 
00317     static BOOL IsSingleton(const _Key_T & key)
00318     {
00319       return GetInstance().IsSingleton_Internal(key);
00320     }
00321 
00322     static KeyList_T GetKeyList()
00323     { 
00324       return GetInstance().GetKeyList_Internal();
00325     }
00326 
00327     static KeyMap_T & GetKeyMap()
00328     { 
00329       return GetInstance().keyMap;
00330     }
00331 
00332     static PMutex & GetMutex()
00333     {
00334       return GetInstance().mutex;
00335     }
00336 
00337   protected:
00338     PFactory()
00339     { }
00340 
00341     ~PFactory()
00342     {
00343       typename KeyMap_T::const_iterator entry;
00344       for (entry = keyMap.begin(); entry != keyMap.end(); ++entry) {
00345         if (entry->second->isDynamic)
00346           delete entry->second;
00347       }
00348     }
00349 
00350     static PFactory & GetInstance()
00351     {
00352       std::string className = typeid(PFactory).name();
00353       PWaitAndSignal m(GetFactoriesMutex());
00354       FactoryMap & factories = GetFactories();
00355       FactoryMap::const_iterator entry = factories.find(className);
00356       if (entry != factories.end()) {
00357         PAssert(entry->second != NULL, "Factory map returned NULL for existing key");
00358         PFactoryBase * b = entry->second;
00359         // don't use the following dynamic cast, because gcc does not like it
00360         //PFactory * f = dynamic_cast<PFactory*>(b);
00361         return *(PFactory *)b;
00362       }
00363 
00364       PFactory * factory = new PFactory;
00365       factories[className] = factory;
00366       return *factory;
00367     }
00368 
00369 
00370     void Register_Internal(const _Key_T & key, WorkerBase * worker)
00371     {
00372       PWaitAndSignal m(mutex);
00373       if (keyMap.find(key) == keyMap.end())
00374         keyMap[key] = worker;
00375     }
00376 
00377     void Unregister_Internal(const _Key_T & key)
00378     {
00379       PWaitAndSignal m(mutex);
00380       keyMap.erase(key);
00381     }
00382 
00383     void UnregisterAll_Internal()
00384     {
00385       PWaitAndSignal m(mutex);
00386       keyMap.erase(keyMap.begin(), keyMap.end());
00387     }
00388 
00389     bool IsRegistered_Internal(const _Key_T & key)
00390     {
00391       PWaitAndSignal m(mutex);
00392       return keyMap.find(key) != keyMap.end();
00393     }
00394 
00395     _Abstract_T * CreateInstance_Internal(const _Key_T & key)
00396     {
00397       PWaitAndSignal m(mutex);
00398       typename KeyMap_T::const_iterator entry = keyMap.find(key);
00399       if (entry != keyMap.end())
00400         return entry->second->CreateInstance(key);
00401       return NULL;
00402     }
00403 
00404     bool IsSingleton_Internal(const _Key_T & key)
00405     {
00406       PWaitAndSignal m(mutex);
00407       if (keyMap.find(key) == keyMap.end())
00408         return false;
00409       return keyMap[key]->isSingleton;
00410     }
00411 
00412     KeyList_T GetKeyList_Internal()
00413     { 
00414       PWaitAndSignal m(mutex);
00415       KeyList_T list;
00416       typename KeyMap_T::const_iterator entry;
00417       for (entry = keyMap.begin(); entry != keyMap.end(); ++entry)
00418         list.push_back(entry->first);
00419       return list;
00420     }
00421 
00422     KeyMap_T keyMap;
00423 
00424   private:
00425     PFactory(const PFactory &) {}
00426     void operator=(const PFactory &) {}
00427 };
00428 
00429 //
00430 //  this macro is used to initialise the static member variable used to force factories to instantiate
00431 //
00432 #define PLOAD_FACTORY(AbstractType, KeyType) \
00433   PWLibFactoryLoader::AbstractType##_##KeyType##_loader = 1; \
00434 
00435 #define PLOAD_FACTORY_DECLARE(AbstractType, KeyType) \
00436 namespace PWLibFactoryLoader { \
00437 extern int AbstractType##_##KeyType##_loader; \
00438 static class AbstractType##_##KeyType##_loader_Instantiate { \
00439 public: AbstractType##_##KeyType##_loader_Instantiate() { \
00440 PLOAD_FACTORY(AbstractType, KeyType); \
00441 } \
00442 } AbstractType##_##KeyType##_loader_instance; \
00443 }; \
00444 
00445 
00446 //
00447 //  this macro is used to instantiate a static variable that accesses the static member variable 
00448 //  in a factory forcing it to load
00449 //
00450 #define PINSTANTIATE_FACTORY(AbstractType, KeyType) \
00451 namespace PWLibFactoryLoader { int AbstractType##_##KeyType##_loader; }
00452 
00453 
00454 #endif // _PFACTORY_H

Generated on Fri Feb 29 13:37:10 2008 for PWLib by  doxygen 1.5.5