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

Generated on Fri Sep 21 14:40:11 2007 for PWLib by  doxygen 1.5.3