PTLib  Version 2.12.9
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
pfactory.h
Go to the documentation of this file.
1 /*
2  * factory.h
3  *
4  * Abstract Factory Classes
5  *
6  * Portable Windows Library
7  *
8  * Copyright (C) 2004 Post Increment
9  *
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/
14  *
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.
19  *
20  * The Original Code is Portable Windows Library.
21  *
22  * The Initial Developer of the Original Code is Post Increment
23  *
24  * Contributor(s): ______________________________________.
25  *
26  * $Revision: 27635 $
27  * $Author: rjongbloed $
28  * $Date: 2012-05-15 16:14:08 +1000 (Tue, 15 May 2012) $
29  */
30 
31 #ifndef PTLIB_FACTORY_H
32 #define PTLIB_FACTORY_H
33 
34 #ifdef P_USE_PRAGMA
35 #pragma interface
36 #endif
37 
38 #include <ptlib.h>
39 
40 #include <typeinfo>
41 #include <string>
42 #include <map>
43 #include <vector>
44 
45 #if defined(_MSC_VER)
46 #pragma warning(disable:4786)
47 #endif
48 
116 {
117  protected:
119  { }
120  public:
121  virtual ~PFactoryBase()
122  { }
123 
124  virtual void DestroySingletons() = 0;
125 
126  class FactoryMap : public std::map<std::string, PFactoryBase *>, public PMutex
127  {
128  public:
129  ~FactoryMap();
130  void DestroySingletons();
131  };
132 
133  static FactoryMap & GetFactories();
134 
135  protected:
136  static PFactoryBase & InternalGetFactory(const std::string & className, PFactoryBase * (*createFactory)());
137 
138  template <class TheFactory> static PFactoryBase * CreateFactory() { return new TheFactory; }
139 
140  template <class TheFactory> static TheFactory & GetFactoryAs()
141  {
142  return dynamic_cast<TheFactory&>(InternalGetFactory(typeid(TheFactory).name(), CreateFactory<TheFactory>));
143  }
144 
145  protected:
147 
148  private:
149  PFactoryBase(const PFactoryBase &) {}
150  void operator=(const PFactoryBase &) {}
151 };
152 
153 
156 template <class AbstractClass, typename ParamType, typename KeyType>
158 {
159  public:
160  class WorkerBase;
161 
162  typedef AbstractClass Abstract_T;
163  typedef ParamType Param_T;
164  typedef KeyType Key_T;
165  typedef std::vector<Key_T> KeyList_T;
166  typedef std::map<Key_T, WorkerBase*> WorkerMap_T;
167  typedef typename WorkerMap_T::iterator WorkerIter_T;
168 
170  {
171  public:
172  enum Types {
176  };
177 
178  WorkerBase(bool singleton = false)
179  : m_type(singleton ? DynamicSingleton : NonSingleton)
180  , m_singletonInstance(NULL)
181  {
182  }
183 
184  WorkerBase(Abstract_T * instance, bool delSingleton = true)
185  : m_type(delSingleton ? DynamicSingleton : StaticSingleton)
186  , m_singletonInstance(instance)
187  {
188  }
189 
190  virtual ~WorkerBase()
191  {
193  }
194 
196  {
197  if (m_type == NonSingleton)
198  return Create(param);
199 
200  if (m_singletonInstance == NULL)
201  m_singletonInstance = Create(param);
202  return m_singletonInstance;
203  }
204 
205  virtual void DestroySingleton()
206  {
207  if (m_type == DynamicSingleton) {
208  delete m_singletonInstance;
209  m_singletonInstance = NULL;
210  }
211  }
212 
213  bool IsSingleton() const { return m_type != NonSingleton; }
214 
215  protected:
216  virtual Abstract_T * Create(Param_T /*param*/) const
217  {
218  PAssert(this->m_type == StaticSingleton, "Incorrect factory worker descendant");
219  return this->m_singletonInstance;
220  }
221 
224  };
225 
226  virtual void DestroySingletons()
227  {
228  for (WorkerIter_T it = m_workers.begin(); it != m_workers.end(); ++it)
229  it->second->DestroySingleton();
230  }
231 
232  protected:
234  { }
235 
237  {
239  }
240 
241  bool InternalRegister(const Key_T & key, WorkerBase * worker)
242  {
243  PWaitAndSignal mutex(m_mutex);
244  if (m_workers.find(key) != m_workers.end())
245  return false;
246 
248  m_workers[key] = PAssertNULL(worker);
249  return true;
250  }
251 
252  bool InternalRegister(const Key_T & key, Abstract_T * instance, bool autoDeleteInstance)
253  {
254  PWaitAndSignal mutex(m_mutex);
255  if (m_workers.find(key) != m_workers.end())
256  return false;
257 
259  m_workers[key] = PNEW WorkerBase(instance, autoDeleteInstance);
260  return true;
261  }
262 
263  PBoolean InternalRegisterAs(const Key_T & newKey, const Key_T & oldKey)
264  {
265  PWaitAndSignal mutex(m_mutex);
266  if (m_workers.find(oldKey) == m_workers.end())
267  return false;
268 
269  m_workers[newKey] = m_workers[oldKey];
270  return true;
271  }
272 
273  void InternalUnregister(const Key_T & key)
274  {
275  m_mutex.Wait();
276  m_workers.erase(key);
277  m_mutex.Signal();
278  }
279 
280  void InternalUnregister(WorkerBase * instance)
281  {
282  m_mutex.Wait();
283  for (WorkerIter_T it = m_workers.begin(); it != m_workers.end(); ++it) {
284  if (it->second == instance) {
285  m_workers.erase(it);
286  break;
287  }
288  }
289  m_mutex.Signal();
290  }
291 
293  {
294  m_mutex.Wait();
295  m_workers.clear();
296  m_mutex.Signal();
297  }
298 
299  bool InternalIsRegistered(const Key_T & key)
300  {
301  PWaitAndSignal mutex(m_mutex);
302  return m_workers.find(key) != m_workers.end();
303  }
304 
306  {
307  PWaitAndSignal mutex(m_mutex);
308  WorkerIter_T entry = m_workers.find(key);
309  return entry == m_workers.end() ? NULL : entry->second->CreateInstance(param);
310  }
311 
312  void InternalDestroy(const Key_T & key, Abstract_T * instance)
313  {
314  PWaitAndSignal mutex(m_mutex);
315  WorkerIter_T entry = m_workers.find(key);
316  if (entry != m_workers.end() && !entry->second->IsSingleton())
317  delete instance;
318  }
319 
320  bool InternalIsSingleton(const Key_T & key)
321  {
322  PWaitAndSignal mutex(m_mutex);
323  WorkerIter_T entry = m_workers.find(key);
324  return entry != m_workers.end() && entry->second->IsSingleton();
325  }
326 
328  {
329  PWaitAndSignal mutex(m_mutex);
330  KeyList_T list;
331  for (WorkerIter_T entry = m_workers.begin(); entry != m_workers.end(); ++entry)
332  list.push_back(entry->first);
333  return list;
334  }
335 
336  protected:
338 
339  private:
341  void operator=(const PFactoryTemplate &) {}
342 
343  friend class PFactoryBase;
344 };
345 
346 
348 typedef std::string PDefaultPFactoryKey;
349 
350 
351 #define PFACTORY_STATICS(cls) \
352  static cls & GetFactory() { return PFactoryBase::GetFactoryAs<cls>(); } \
353  static bool Register(const Key_T & k, WorkerBase_T * w) { return GetFactory().InternalRegister(k, w); } \
354  static bool Register(const Key_T & k, Abstract_T * i, bool a = true) { return GetFactory().InternalRegister(k, i, a); } \
355  static bool RegisterAs(const Key_T & synonym, const Key_T & original){ return GetFactory().InternalRegisterAs(synonym, original); } \
356  static void Unregister(const Key_T & k) { GetFactory().InternalUnregister(k); } \
357  static void Unregister(WorkerBase_T * a) { GetFactory().InternalUnregister(a); } \
358  static void UnregisterAll() { GetFactory().InternalUnregisterAll(); } \
359  static bool IsRegistered(const Key_T & k) { return GetFactory().InternalIsRegistered(k); } \
360  static bool IsSingleton(const Key_T & k) { return GetFactory().InternalIsSingleton(k); } \
361  static typename Base_T::KeyList_T GetKeyList() { return GetFactory().InternalGetKeyList(); } \
362  static PMutex & GetMutex() { return GetFactory().m_mutex; } \
363 
364 
368 template <class AbstractClass, typename KeyType = PDefaultPFactoryKey>
369 class PFactory : public PFactoryTemplate<AbstractClass, const KeyType &, KeyType>
370 {
371  public:
373  typedef typename Base_T::WorkerBase WorkerBase_T;
374  typedef typename Base_T::Abstract_T Abstract_T;
375  typedef typename Base_T::Param_T Param_T;
376  typedef typename Base_T::Key_T Key_T;
377 
379 
380  template <class ConcreteClass>
381  class Worker : protected WorkerBase_T
382  {
383  public:
384  Worker(const Key_T & key, bool singleton = false)
385  : WorkerBase_T(singleton)
386  {
387  Register(key, this);
388  }
389 
390  protected:
391  virtual Abstract_T * Create(Param_T) const
392  {
393  return new ConcreteClass();
394  }
395  };
396 
397  static Abstract_T * CreateInstance(const Key_T & key)
398  {
399  return GetFactory().InternalCreateInstance(key, key);
400  }
401 
402  template <class Derived_T>
403  static Derived_T * CreateInstanceAs(const Key_T & key)
404  {
405  Abstract_T * instance = GetFactory().InternalCreateInstance(key, key);
406  Derived_T * derived = dynamic_cast<Derived_T *>(instance);
407  if (derived != NULL)
408  return derived;
409 
410  GetFactory().InternalDestroy(key, instance);
411  return NULL;
412  }
413 };
414 
415 
419 template <class AbstractClass, typename ParamType, typename KeyType = PDefaultPFactoryKey>
420 class PParamFactory : public PFactoryTemplate<AbstractClass, ParamType, KeyType>
421 {
422  public:
425  typedef typename Base_T::Abstract_T Abstract_T;
426  typedef typename Base_T::Param_T Param_T;
427  typedef typename Base_T::Key_T Key_T;
428 
430 
431  template <class ConcreteClass>
432  class Worker : protected WorkerBase_T
433  {
434  public:
435  Worker(const Key_T & key, bool singleton = false)
436  : WorkerBase_T(singleton)
437  {
438  Register(key, this);
439  }
440 
441  protected:
442  virtual Abstract_T * Create(Param_T param) const
443  {
444  return new ConcreteClass(param);
445  }
446  };
447 
448  static Abstract_T * CreateInstance(const Key_T & key, Param_T param)
449  {
450  return GetFactory().InternalCreateInstance(key, param);
451  }
452 
453  template <class Derived_T>
454  static Derived_T * CreateInstanceAs(const Key_T & key, Param_T param)
455  {
456  Abstract_T * instance = GetFactory().InternalCreateInstance(key, param);
457  Derived_T * derived = dynamic_cast<Derived_T *>(instance);
458  if (derived != NULL)
459  return derived;
460  GetFactory().InternalDestroy(key, instance);
461  return NULL;
462  }
463 };
464 
465 
477 #define PFACTORY_CREATE(factory, ConcreteClass, ...) \
478  namespace PFactoryLoader { \
479  int ConcreteClass##_link() { return 0; } \
480  factory::Worker<ConcreteClass> ConcreteClass##_instance(__VA_ARGS__); \
481  }
482 
483 #define PFACTORY_CREATE_SINGLETON(factory, ConcreteClass) \
484  PFACTORY_CREATE(factory, ConcreteClass, typeid(ConcreteClass).name(), true)
485 
486 #define PFACTORY_GET_SINGLETON(factory, ConcreteClass) \
487  static ConcreteClass & GetInstance() { \
488  return *factory::CreateInstanceAs<ConcreteClass>(typeid(ConcreteClass).name()); \
489  }
490 
491 
492 
493 
494 /* This macro is used to force linking of factories.
495  See PFACTORY_CREATE() for more information
496  */
497 #define PFACTORY_LOAD(ConcreteType) \
498  namespace PFactoryLoader { \
499  extern int ConcreteType##_link(); \
500  int const ConcreteType##_loader = ConcreteType##_link(); \
501  }
502 
503 
504 #endif // PTLIB_FACTORY_H
505 
506 
507 // End Of File ///////////////////////////////////////////////////////////////