CernVM-FS  2.13.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, class AbstractProductT, typename ParameterT,
58  typename InfoT>
60  : public AbstractFactory<AbstractProductT, ParameterT, InfoT> {
61  public:
62  inline bool WillHandle(const ParameterT &param) const {
63  return ConcreteProductT::WillHandle(param);
64  }
65  inline AbstractProductT *Construct(const ParameterT &param) const {
66  AbstractProductT *product = new ConcreteProductT(param);
67  return product;
68  }
69 };
70 
71 
78 template<class ConcreteProductT, class AbstractProductT, typename ParameterT,
79  typename InfoT>
81  : public AbstractFactoryImpl2<ConcreteProductT, AbstractProductT,
82  ParameterT, InfoT> {
83  inline InfoT Introspect() const { return ConcreteProductT::GetInfo(); }
84 };
85 
90 template<class ConcreteProductT, class AbstractProductT, typename ParameterT>
91 class AbstractFactoryImpl<ConcreteProductT, AbstractProductT, ParameterT, void>
92  : public AbstractFactoryImpl2<ConcreteProductT, AbstractProductT,
93  ParameterT, void> {
94  inline void Introspect() const { }
95 };
96 
161 template<class AbstractProductT, typename ParameterT, typename InfoT>
163  protected:
165  typedef std::vector<Factory *> RegisteredPlugins;
166 
167  public:
169 
170  static AbstractProductT *Construct(const ParameterT &param) {
171  LazilyRegisterPlugins();
172 
173  // select and initialize the correct plugin at runtime
174  // (polymorphic construction)
175  typename RegisteredPlugins::const_iterator i = registered_plugins_.begin();
176  typename RegisteredPlugins::const_iterator iend = registered_plugins_.end();
177  for (; i != iend; ++i) {
178  if ((*i)->WillHandle(param)) {
179  // create and initialize the class that claimed responsibility
180  AbstractProductT *product = (*i)->Construct(param);
181  if (!product->Initialize()) {
182  delete product;
183  continue;
184  }
185  return product;
186  }
187  }
188 
189  // no plugin found to handle the given parameter...
190  return NULL;
191  }
192 
193  protected:
194  static void LazilyRegisterPlugins() {
195  // Thread Safety Note:
196  // Double Checked Locking with atomics!
197  // Simply double checking registered_plugins_.empty() is _not_ thread safe
198  // since a second thread might find a registered_plugins_ list that is
199  // currently under construction and therefore _not_ empty but also _not_
200  // fully initialized!
201  // See StackOverflow:
202  // http://stackoverflow.com/questions/8097439/lazy-initialized-caching-how-do-i-make-it-thread-safe
203  if (atomic_read32(&needs_init_)) {
204  MutexLockGuard m(&init_mutex_);
205  if (atomic_read32(&needs_init_)) {
206  AbstractProductT::RegisterPlugins();
207  atomic_dec32(&needs_init_);
208  }
209  }
210 
211  assert(!registered_plugins_.empty());
212  }
213 
217  friend class PolymorphicConstructionUnittestAdapter;
218 
230  template<class ConcreteProductT>
231  static void RegisterPlugin() {
232  registered_plugins_.push_back(
233  new AbstractFactoryImpl<ConcreteProductT, AbstractProductT, ParameterT,
234  InfoT>());
235  }
236 
237  virtual bool Initialize() { return true; }
238 
239  private:
251  static void UnregisterAllPlugins() {
252  registered_plugins_.clear();
253  needs_init_ = 1;
254  }
255 
256  protected:
257  static RegisteredPlugins registered_plugins_;
258 
259  private:
261  static pthread_mutex_t init_mutex_;
262 };
263 
264 
272 template<class AbstractProductT, typename ParameterT, typename InfoT = void>
274  : public PolymorphicConstructionImpl<AbstractProductT, ParameterT, InfoT> {
275  private:
278 
279  public:
280  typedef std::vector<InfoT> IntrospectionData;
281 
283  IntrospectionData introspection_data;
284  introspection_data.reserve(T::registered_plugins_.size());
285  const RegisteredPlugins &plugins = T::registered_plugins_;
286 
287  T::LazilyRegisterPlugins();
288  typename RegisteredPlugins::const_iterator i = plugins.begin();
289  typename RegisteredPlugins::const_iterator iend = plugins.end();
290  for (; i != iend; ++i) {
291  introspection_data.push_back((*i)->Introspect());
292  }
293 
294  return introspection_data;
295  }
296 };
297 
302 template<class AbstractProductT, typename ParameterT>
303 class PolymorphicConstruction<AbstractProductT, ParameterT, void>
304  : public PolymorphicConstructionImpl<AbstractProductT, ParameterT, void> {
305 };
306 
307 
308 template<class AbstractProductT, typename ParameterT, typename InfoT>
309 atomic_int32 PolymorphicConstructionImpl<AbstractProductT, ParameterT,
310  InfoT>::needs_init_ = 1;
311 
312 template<class AbstractProductT, typename ParameterT, typename InfoT>
313 pthread_mutex_t
314  PolymorphicConstructionImpl<AbstractProductT, ParameterT,
315  InfoT>::init_mutex_ = PTHREAD_MUTEX_INITIALIZER;
316 
317 // init the static member registered_plugins_ inside the
318 // PolymorphicConstructionImpl template... whoa, what ugly code :o)
319 template<class AbstractProductT, typename ParameterT, typename InfoT>
320 typename PolymorphicConstructionImpl<AbstractProductT, ParameterT,
321  InfoT>::RegisteredPlugins
322  PolymorphicConstructionImpl<AbstractProductT, ParameterT,
323  InfoT>::registered_plugins_;
324 
325 
326 #ifdef CVMFS_NAMESPACE_GUARD
327 } // namespace CVMFS_NAMESPACE_GUARD
328 #endif
329 
330 #endif // CVMFS_UTIL_PLUGIN_H_
virtual bool Initialize()
Definition: plugin.h:237
static IntrospectionData Introspect()
Definition: plugin.h:282
virtual ~PolymorphicConstructionImpl()
Definition: plugin.h:168
virtual ~AbstractFactory()
Definition: plugin.h:36
AbstractFactory< AbstractProductT, ParameterT, InfoT > Factory
Definition: plugin.h:164
assert((mem||(size==0))&&"Out Of Memory")
static RegisteredPlugins registered_plugins_
Definition: plugin.h:257
InfoT Introspect() const
Definition: plugin.h:83
int32_t atomic_int32
Definition: atomic.h:17
static AbstractProductT * Construct(const ParameterT &param)
Definition: plugin.h:170
std::vector< InfoT > IntrospectionData
Definition: plugin.h:280
static void UnregisterAllPlugins()
Definition: plugin.h:251
PolymorphicConstructionImpl< AbstractProductT, ParameterT, InfoT > T
Definition: plugin.h:276
static atomic_int32 needs_init_
Definition: plugin.h:260
bool WillHandle(const ParameterT &param) const
Definition: plugin.h:62
static void LazilyRegisterPlugins()
Definition: plugin.h:194
T::RegisteredPlugins RegisteredPlugins
Definition: plugin.h:277
static void RegisterPlugin()
Definition: plugin.h:231
Definition: mutex.h:42
static pthread_mutex_t init_mutex_
Definition: plugin.h:261
std::vector< Factory * > RegisteredPlugins
Definition: plugin.h:165
AbstractFactory()
Definition: plugin.h:35
static void size_t size
Definition: smalloc.h:54
AbstractProductT * Construct(const ParameterT &param) const
Definition: plugin.h:65