Added classes for auto unlocking read only and read write mutex on
[pwlib.git] / include / ptlib / pfactory.h
blob410c8afd7533bb9a252422ac8ec9c22f624194a9
1 /*
2 * factory.h
4 * Abstract Factory Classes
6 * Portable Windows Library
8 * Copyright (C) 2004 Post Increment
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Post Increment
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.18 2004/07/12 09:17:20 csoutheren
28 * Fixed warnings and errors under Linux
30 * Revision 1.17 2004/07/06 10:12:52 csoutheren
31 * Added static integer o factory template to assist in ensuring factories are instantiated
33 * Revision 1.16 2004/07/06 04:26:44 csoutheren
34 * Fixed problem when using factory maps with non-standard keys
36 * Revision 1.15 2004/07/02 03:14:47 csoutheren
37 * Made factories non-singleton, by default
38 * Added more docs
40 * Revision 1.14 2004/07/01 11:41:28 csoutheren
41 * Fixed compile and run problems on Linux
43 * Revision 1.13 2004/07/01 04:33:57 csoutheren
44 * Updated documentation on PFactory classes
46 * Revision 1.12 2004/06/30 12:17:04 rjongbloed
47 * Rewrite of plug in system to use single global variable for all factories to avoid all sorts
48 * of issues with startup orders and Windows DLL multiple instances.
50 * Revision 1.11 2004/06/17 06:35:12 csoutheren
51 * Use attribute (( constructor )) to guarantee that factories are
52 * instantiated when loaded from a shared library
54 * Revision 1.10 2004/06/03 13:30:57 csoutheren
55 * Renamed INSTANTIATE_FACTORY to avoid potential namespace collisions
56 * Added documentaton on new PINSTANTIATE_FACTORY macro
57 * Added generic form of PINSTANTIATE_FACTORY
59 * Revision 1.9 2004/06/03 12:47:58 csoutheren
60 * Decomposed PFactory declarations to hopefully avoid problems with Windows DLLs
62 * Revision 1.8 2004/06/01 05:44:12 csoutheren
63 * Added typedefs to allow access to types
64 * Changed singleton class to use new so as to allow full cleanup
66 * Revision 1.7 2004/05/23 12:33:56 rjongbloed
67 * Made some subtle changes to the way the static variables are instantiated in
68 * the factoris to fix problems with DLL's under windows. May not be final solution.
70 * Revision 1.6 2004/05/19 06:48:39 csoutheren
71 * Added new functions to allow handling of singletons without concrete classes
73 * Revision 1.5 2004/05/18 06:01:06 csoutheren
74 * Deferred plugin loading until after main has executed by using abstract factory classes
76 * Revision 1.4 2004/05/18 02:32:08 csoutheren
77 * Fixed linking problems with PGenericFactory classes
79 * Revision 1.3 2004/05/13 15:10:51 csoutheren
80 * Removed warnings under Windows
82 * Revision 1.2 2004/05/13 14:59:00 csoutheren
83 * Removed warning under gcc
85 * Revision 1.1 2004/05/13 14:53:35 csoutheren
86 * Add "abstract factory" template classes
90 #ifndef _PFACTORY_H
91 #define _PFACTORY_H
93 #ifdef P_USE_PRAGMA
94 #pragma interface
95 #endif
97 #include <ptlib.h>
98 #include <string>
99 #include <map>
100 #include <vector>
102 #ifdef _WIN32
103 #pragma warning(disable:4786)
104 #endif
108 * These templates implement an Abstract Factory that allows
109 * creation of a class "factory" that can be used to create
110 * "concrete" instance that are descended from a abstract base class
112 * Given an abstract class A with a descendant concrete class B, the
113 * concrete class is registered by instantiating the PFactory template
114 * as follows:
116 * PFactory<A>::Worker<B> aFactory("B");
118 * To instantiate an object of type B, use the following:
120 * A * b = PFactory<A>::CreateInstance("B");
122 * A vector containing the names of all of the concrete classes for an
123 * abstract type can be obtained as follows:
125 * PFactory<A>::KeyList_T list = PFactory<A>::GetKeyList()
127 * Note that these example assumes that the "key" type for the factory
128 * registration is of the default type PString. If a different key type
129 * is needed, then it is necessary to specify the key type:
131 * PFactory<C, unsigned>::Worker<D> aFactory(42);
132 * C * d = PFactory<C, unsigned>::CreateInstance(42);
133 * PFactory<C, unsigned>::KeyList_T list = PFactory<C, unsigned>::GetKeyList()
135 * The factory functions also allow the creation of "singleton" factories that return a
136 * single instance for all calls to CreateInstance. This can be done by passing a "true"
137 * as a second paramater to the factory registration as shown below, which will cause a single
138 * instance to be minted upon the first call to CreateInstance, and then returned for all
139 * subsequent calls.
141 * PFactory<A>::Worker<E> eFactory("E", true);
143 * It is also possible to manually set the instance in cases where the object needs to be created non-trivially.
145 * The following types are defined as part of the PFactory template class:
147 * KeyList_T a vector<> of the key type (usually std::string)
148 * Worker an abstract factory for a specified concrete type
149 * KeyMap_T a map<> that converts from the key type to the Worker instance
150 * for each concrete type registered for a specific abstract type
152 * As a side issue, note that the factory lists are all thread safe for addition,
153 * creation, and obtaining the key lists.
157 /** Base class for generic factories.
158 This classes reason for existance and the FactoryMap contained within it
159 is to resolve issues with static global construction order and Windows DLL
160 multiple instances issues. THis mechanism guarantees that the one and one
161 only global variable (inside the GetFactories() function) is initialised
162 before any other factory related instances of classes.
164 class PFactoryBase
166 protected:
167 PFactoryBase()
169 public:
170 virtual ~PFactoryBase()
173 class FactoryMap : public std::map<std::string, PFactoryBase *>
175 public:
176 FactoryMap() { }
177 ~FactoryMap();
180 static FactoryMap & GetFactories();
181 static PMutex & GetFactoriesMutex();
183 PMutex mutex;
185 private:
186 PFactoryBase(const PFactoryBase &) {}
187 void operator=(const PFactoryBase &) {}
191 /** Template class for generic factories of an abstract class.
193 template <class _Abstract_T, typename _Key_T = PString>
194 class PFactory : PFactoryBase
196 public:
197 typedef _Key_T Key_T;
198 typedef _Abstract_T Abstract_T;
200 class WorkerBase
202 protected:
203 WorkerBase(bool singleton = false)
204 : isDynamic(false),
205 isSingleton(singleton),
206 singletonInstance(NULL),
207 deleteSingleton(false)
209 WorkerBase(Abstract_T * instance)
210 : isSingleton(true),
211 singletonInstance(instance),
212 deleteSingleton(true)
215 virtual ~WorkerBase()
217 if (deleteSingleton)
218 delete singletonInstance;
221 Abstract_T * CreateInstance()
223 if (!isSingleton)
224 return Create();
226 if (singletonInstance == NULL)
227 singletonInstance = Create();
228 return singletonInstance;
231 virtual Abstract_T * Create() const { return singletonInstance; }
233 bool isDynamic;
234 bool isSingleton;
235 Abstract_T * singletonInstance;
236 bool deleteSingleton;
238 friend class PFactory<_Abstract_T, _Key_T>;
241 template <class _Concrete_T>
242 class Worker : WorkerBase
244 public:
245 Worker(const Key_T & key, bool singleton = false)
246 : WorkerBase(singleton)
248 PFactory<_Abstract_T, _Key_T>::Register(key, this); // here
251 protected:
252 virtual Abstract_T * Create() const { return new _Concrete_T; }
255 typedef std::map<_Key_T, WorkerBase *> KeyMap_T;
256 typedef std::vector<_Key_T> KeyList_T;
258 static void Register(const _Key_T & key, WorkerBase * worker)
260 GetInstance().Register_Internal(key, worker);
263 static void Register(const _Key_T & key, Abstract_T * instance)
265 GetInstance().Register_Internal(key, new WorkerBase(instance));
268 static void Unregister(const _Key_T & key)
270 GetInstance().Unregister_Internal(key);
273 static void UnregisterAll()
275 GetInstance().UnregisterAll_Internal();
278 static bool IsRegistered(const _Key_T & key)
280 return GetInstance().IsRegistered_Internal(key);
283 static _Abstract_T * CreateInstance(const _Key_T & key)
285 return GetInstance().CreateInstance_Internal(key);
288 static BOOL IsSingleton(const _Key_T & key)
290 return GetInstance().IsSingleton_Internal(key);
293 static KeyList_T GetKeyList()
295 return GetInstance().GetKeyList_Internal();
298 static KeyMap_T & GetKeyMap()
300 return GetInstance().keyMap;
303 static PMutex & GetMutex()
305 return GetInstance().mutex;
308 protected:
309 PFactory()
312 ~PFactory()
314 typename KeyMap_T::const_iterator entry;
315 for (entry = keyMap.begin(); entry != keyMap.end(); ++entry) {
316 if (entry->second->isDynamic)
317 delete entry->second;
321 static PFactory & GetInstance()
323 std::string className = typeid(PFactory).name();
324 PWaitAndSignal m(GetFactoriesMutex());
325 FactoryMap & factories = GetFactories();
326 FactoryMap::const_iterator entry = factories.find(className);
327 if (entry != factories.end()) {
328 PAssert(entry->second != NULL, "Factory map returned NULL for existing key");
329 PFactoryBase * b = entry->second;
330 // don't use the following dynamic cast, because gcc does not like it
331 //PFactory * f = dynamic_cast<PFactory*>(b);
332 return *(PFactory *)b;
335 PFactory * factory = new PFactory;
336 factories[className] = factory;
337 return *factory;
341 void Register_Internal(const _Key_T & key, WorkerBase * worker)
343 PWaitAndSignal m(mutex);
344 if (keyMap.find(key) == keyMap.end())
345 keyMap[key] = worker;
348 void Unregister_Internal(const _Key_T & key)
350 PWaitAndSignal m(mutex);
351 keyMap.erase(key);
354 void UnregisterAll_Internal()
356 PWaitAndSignal m(mutex);
357 keyMap.erase(keyMap.begin(), keyMap.end());
360 bool IsRegistered_Internal(const _Key_T & key)
362 PWaitAndSignal m(mutex);
363 return keyMap.find(key) != keyMap.end();
366 _Abstract_T * CreateInstance_Internal(const _Key_T & key)
368 PWaitAndSignal m(mutex);
369 typename KeyMap_T::const_iterator entry = keyMap.find(key);
370 if (entry != keyMap.end())
371 return entry->second->CreateInstance();
372 return NULL;
375 bool IsSingleton_Internal(const _Key_T & key)
377 PWaitAndSignal m(mutex);
378 if (keyMap.find(key) == keyMap.end())
379 return false;
380 return keyMap[key]->isSingleton;
383 KeyList_T GetKeyList_Internal()
385 PWaitAndSignal m(mutex);
386 KeyList_T list;
387 typename KeyMap_T::const_iterator entry;
388 for (entry = keyMap.begin(); entry != keyMap.end(); ++entry)
389 list.push_back(entry->first);
390 return list;
393 KeyMap_T keyMap;
395 private:
396 PFactory(const PFactory &) {}
397 void operator=(const PFactory &) {}
399 #ifdef _WIN32
400 public:
401 static int factoryLoader;
402 #endif
405 #ifdef _WIN32
407 namespace PWLibFactoryLoader {
409 template <class AbstractType, typename KeyType>
410 class Loader
412 public:
413 Loader()
414 { PFactory<AbstractType, KeyType>::factoryLoader = 1; }
420 // this macro is used to declare the static member variable used to force factories to instantiate
422 #define PLOAD_FACTORY(AbstractType, KeyType) \
423 namespace PWLibFactoryLoader { \
424 static Loader<AbstractType, KeyType> AbstractType##_##KeyType##; \
428 // this macro is used to instantiate a static variable that accesses the static member variable
429 // in a factory forcing it to load
431 #define PINSTANTIATE_FACTORY(AbstractType, KeyType) \
432 int PFactory<AbstractType, KeyType>::factoryLoader;
434 #endif // _WIN32
436 #endif // _PFACTORY_H