Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Class Members | File Members

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

Generated on Tue Mar 15 10:44:52 2005 for PWLib by  doxygen 1.4.0