CernVM-FS  2.12.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
plugin.h
Go to the documentation of this file.
1 
5 #ifndef CVMFS_UTIL_PLUGIN_H_
6 #define CVMFS_UTIL_PLUGIN_H_
7 
8 #include <pthread.h>
9 
10 #include <cassert>
11 #include <vector>
12 
13 #include "util/atomic.h"
14 #include "util/concurrency.h"
15 
16 #ifdef CVMFS_NAMESPACE_GUARD
17 namespace CVMFS_NAMESPACE_GUARD {
18 #endif
19 
32 template <class AbstractProductT, typename ParameterT, typename InfoT>
34  public:
36  virtual ~AbstractFactory() {}
37 
38  virtual bool WillHandle(const ParameterT &param) const = 0;
39  virtual AbstractProductT* Construct(const ParameterT &param) const = 0;
40  virtual InfoT Introspect() const = 0;
41 };
42 
43 
57 template <class ConcreteProductT,
58  class AbstractProductT,
59  typename ParameterT,
60  typename InfoT>
61 class AbstractFactoryImpl2 : public AbstractFactory<AbstractProductT,
62  ParameterT,
63  InfoT>
64 {
65  public:
66  inline bool WillHandle(const ParameterT &param) const {
67  return ConcreteProductT::WillHandle(param);
68  }
69  inline AbstractProductT* Construct(const ParameterT &param) const {
70  AbstractProductT* product = new ConcreteProductT(param);
71  return product;
72  }
73 };
74 
75 
82 template <class ConcreteProductT,
83  class AbstractProductT,
84  typename ParameterT,
85  typename InfoT>
87  public AbstractFactoryImpl2<ConcreteProductT,
88  AbstractProductT,
89  ParameterT,
90  InfoT>
91 {
92  inline InfoT Introspect() const {
93  return ConcreteProductT::GetInfo();
94  }
95 };
96 
101 template <class ConcreteProductT,
102  class AbstractProductT,
103  typename ParameterT>
104 class AbstractFactoryImpl<ConcreteProductT,
105  AbstractProductT,
106  ParameterT,
107  void> :
108  public AbstractFactoryImpl2<ConcreteProductT,
109  AbstractProductT,
110  ParameterT,
111  void>
112 {
113  inline void Introspect() const {}
114 };
115 
179 template <class AbstractProductT, typename ParameterT, typename InfoT>
181  protected:
183  typedef std::vector<Factory*> RegisteredPlugins;
184 
185  public:
187 
188  static AbstractProductT* Construct(const ParameterT &param) {
189  LazilyRegisterPlugins();
190 
191  // select and initialize the correct plugin at runtime
192  // (polymorphic construction)
193  typename RegisteredPlugins::const_iterator i = registered_plugins_.begin();
194  typename RegisteredPlugins::const_iterator iend = registered_plugins_.end();
195  for (; i != iend; ++i) {
196  if ((*i)->WillHandle(param)) {
197  // create and initialize the class that claimed responsibility
198  AbstractProductT *product = (*i)->Construct(param);
199  if (!product->Initialize()) {
200  delete product;
201  continue;
202  }
203  return product;
204  }
205  }
206 
207  // no plugin found to handle the given parameter...
208  return NULL;
209  }
210 
211  protected:
212  static void LazilyRegisterPlugins() {
213  // Thread Safety Note:
214  // Double Checked Locking with atomics!
215  // Simply double checking registered_plugins_.empty() is _not_ thread safe
216  // since a second thread might find a registered_plugins_ list that is
217  // currently under construction and therefore _not_ empty but also _not_
218  // fully initialized!
219  // See StackOverflow: http://stackoverflow.com/questions/8097439/lazy-initialized-caching-how-do-i-make-it-thread-safe
220  if (atomic_read32(&needs_init_)) {
221  MutexLockGuard m(&init_mutex_);
222  if (atomic_read32(&needs_init_)) {
223  AbstractProductT::RegisterPlugins();
224  atomic_dec32(&needs_init_);
225  }
226  }
227 
228  assert(!registered_plugins_.empty());
229  }
230 
234  friend class PolymorphicConstructionUnittestAdapter;
235 
247  template <class ConcreteProductT>
248  static void RegisterPlugin() {
249  registered_plugins_.push_back(
250  new AbstractFactoryImpl<ConcreteProductT,
251  AbstractProductT,
252  ParameterT,
253  InfoT>());
254  }
255 
256  virtual bool Initialize() { return true; }
257 
258  private:
270  static void UnregisterAllPlugins() {
271  registered_plugins_.clear();
272  needs_init_ = 1;
273  }
274 
275  protected:
276  static RegisteredPlugins registered_plugins_;
277 
278  private:
280  static pthread_mutex_t init_mutex_;
281 };
282 
283 
291 template <class AbstractProductT, typename ParameterT, typename InfoT = void>
293  public PolymorphicConstructionImpl<AbstractProductT, ParameterT, InfoT> {
294  private:
297 
298  public:
299  typedef std::vector<InfoT> IntrospectionData;
300 
302  IntrospectionData introspection_data;
303  introspection_data.reserve(T::registered_plugins_.size());
304  const RegisteredPlugins &plugins = T::registered_plugins_;
305 
306  T::LazilyRegisterPlugins();
307  typename RegisteredPlugins::const_iterator i = plugins.begin();
308  typename RegisteredPlugins::const_iterator iend = plugins.end();
309  for (; i != iend; ++i) {
310  introspection_data.push_back((*i)->Introspect());
311  }
312 
313  return introspection_data;
314  }
315 };
316 
321 template <class AbstractProductT, typename ParameterT>
322 class PolymorphicConstruction<AbstractProductT, ParameterT, void> :
323  public PolymorphicConstructionImpl<AbstractProductT, ParameterT, void> {};
324 
325 
326 
327 template <class AbstractProductT, typename ParameterT, typename InfoT>
330  needs_init_ = 1;
331 
332 template <class AbstractProductT, typename ParameterT, typename InfoT>
333 pthread_mutex_t
335  PTHREAD_MUTEX_INITIALIZER;
336 
337 // init the static member registered_plugins_ inside the
338 // PolymorphicConstructionImpl template... whoa, what ugly code :o)
339 template <class AbstractProductT, typename ParameterT, typename InfoT>
341  RegisteredPlugins
343  registered_plugins_;
344 
345 
346 #ifdef CVMFS_NAMESPACE_GUARD
347 } // namespace CVMFS_NAMESPACE_GUARD
348 #endif
349 
350 #endif // CVMFS_UTIL_PLUGIN_H_
virtual bool Initialize()
Definition: plugin.h:256
static IntrospectionData Introspect()
Definition: plugin.h:301
virtual ~PolymorphicConstructionImpl()
Definition: plugin.h:186
virtual ~AbstractFactory()
Definition: plugin.h:36
AbstractFactory< AbstractProductT, ParameterT, InfoT > Factory
Definition: plugin.h:182
assert((mem||(size==0))&&"Out Of Memory")
InfoT Introspect() const
Definition: plugin.h:92
static RegisteredPlugins registered_plugins_
Definition: plugin.h:276
int32_t atomic_int32
Definition: atomic.h:17
static AbstractProductT * Construct(const ParameterT &param)
Definition: plugin.h:188
std::vector< InfoT > IntrospectionData
Definition: plugin.h:299
static void UnregisterAllPlugins()
Definition: plugin.h:270
PolymorphicConstructionImpl< AbstractProductT, ParameterT, InfoT > T
Definition: plugin.h:295
std::vector< Factory * > RegisteredPlugins
Definition: plugin.h:183
static atomic_int32 needs_init_
Definition: plugin.h:279
bool WillHandle(const ParameterT &param) const
Definition: plugin.h:66
static void LazilyRegisterPlugins()
Definition: plugin.h:212
T::RegisteredPlugins RegisteredPlugins
Definition: plugin.h:296
static void RegisterPlugin()
Definition: plugin.h:248
Definition: mutex.h:42
static pthread_mutex_t init_mutex_
Definition: plugin.h:280
AbstractFactory()
Definition: plugin.h:35
static void size_t size
Definition: smalloc.h:54
AbstractProductT * Construct(const ParameterT &param) const
Definition: plugin.h:69