factory.hh
Go to the documentation of this file.
1 /* -*- mia-c++ -*-
2  *
3  * This file is part of MIA - a toolbox for medical image analysis
4  * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
5  *
6  * MIA is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with MIA; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #ifndef mia_core_factory_hh
22 #define mia_core_factory_hh
23 
24 #include <iostream>
25 #include <memory>
26 #include <string>
27 #include <mia/core/handler.hh>
28 #include <mia/core/msgstream.hh>
29 #include <mia/core/errormacro.hh>
30 #include <mia/core/product_base.hh>
31 #include <mia/core/optionparser.hh>
32 #include <mia/core/productcache.hh>
33 #include <mia/core/traits.hh>
35 
37 
38 
48 template <typename P>
50  public TPlugin<typename P::plugin_data, typename P::plugin_type> {
51 public:
52 
54  typedef P Product;
55 
57  typedef std::shared_ptr<P > SharedProduct;
58 
59 
61  typedef std::unique_ptr<P > UniqueProduct;
62 
66  TFactory(char const * const name);
67 
77  virtual Product *create(const CParsedOptions& options, char const *params) __attribute__((warn_unused_result));
78 
79 private:
80  virtual Product *do_create() const __attribute__((warn_unused_result)) = 0 ;
81  CMutex m_mutex;
82 };
83 
84 
92 template <typename I>
94 protected:
96 
97 
103 public:
105  typedef typename I::Product Product;
106 
108  typedef typename I::SharedProduct ProductPtr;
109 
111  typedef typename I::UniqueProduct UniqueProduct;
112 
119  ProductPtr produce(const std::string& plugindescr)const;
120 
122  ProductPtr produce(const char *plugindescr) const{
123  return produce(std::string(plugindescr));
124  }
125 
133  UniqueProduct produce_unique(const std::string& plugindescr)const;
134 
136  UniqueProduct produce_unique(const char *plugindescr) const{
137  return produce_unique(std::string(plugindescr));
138  }
139 
145  void set_caching(bool enable) const;
146 
147 
148 private:
149  std::string get_handler_type_string_and_help(std::ostream& os) const;
150 
151  std::string do_get_handler_type_string() const;
152 
153  virtual bool do_validate_parameter_string(const std::string& s) const;
154 
155  typename I::Product *produce_raw(const std::string& plugindescr) const;
156 
157  mutable TProductCache<ProductPtr> m_cache;
158 
159  template <typename Handler, typename Chained, bool chainable>
160  friend struct create_plugin;
161 
162 };
163 
164 /*
165  Implementation of the factory
166 */
167 
168 template <typename I>
169 TFactory<I>::TFactory(char const * const name):
170  TPlugin<typename I::plugin_data, typename I::plugin_type>(name)
171 {
172 }
173 
174 template <typename I>
175 typename TFactory<I>::Product *TFactory<I>::create(const CParsedOptions& options, char const *params)
176 {
177  CScopedLock lock(m_mutex);
178  try {
179  this->set_parameters(options);
180  this->check_parameters();
181  auto product = this->do_create();
182  if (product) {
183  product->set_module(this->get_module());
184  product->set_init_string(params);
185  }
186  return product;
187  }
188  catch (std::length_error& x) {
189  std::stringstream msg;
190  msg << "CParamList::set: Some string was not created properly\n";
191  msg << " options were:\n";
192  for (auto i = options.begin();
193  i != options.end(); ++i) {
194  msg << " " << i->first << "=" << i->second << "\n";
195  }
196  cverr() << msg.str();
197  throw std::logic_error("Probably a race condition");
198 
199  }
200 }
201 
202 template <typename I>
204  m_cache(this->get_descriptor())
205 {
206  set_caching(__cache_policy<I>::apply());
207 }
208 
209 template <typename I>
211 {
212  cvdebug() << this->get_descriptor() << ":Set cache policy to " << enable << "\n";
213  m_cache.enable_write(enable);
214 }
215 
216 template <typename I>
218 TFactoryPluginHandler<I>::produce(const std::string& plugindescr) const
219 {
220  auto result = m_cache.get(plugindescr);
221  if (!result) {
222  result.reset(this->produce_raw(plugindescr));
223  m_cache.add(plugindescr, result);
224  }else
225  cvdebug() << "Use cached '" << plugindescr << "'\n";
226  return result;
227 }
228 
229 template <typename I>
231 TFactoryPluginHandler<I>::produce_unique(const std::string& plugindescr) const
232 {
233  return UniqueProduct(this->produce_raw(plugindescr));
234 }
235 
236 template <typename I>
237 std::string TFactoryPluginHandler<I>::get_handler_type_string_and_help(std::ostream& os) const
238 {
239  os << " The string value will be used to construct a plug-in.";
240  return do_get_handler_type_string();
241 }
242 
243 template <typename I>
245 {
246  return "factory";
247 }
248 
249 template <typename I>
250 bool TFactoryPluginHandler<I>::do_validate_parameter_string(const std::string& s) const
251 {
252  cvdebug() << "Check whether factory '" << this->get_descriptor() << "' can understand '" << s << "'\n";
253  // find the part describing the plug-in name and check whether it
254  // is available
255  auto colon_pos = s.find(':');
256  auto plugin_name = s.substr(0, colon_pos);
257  if (this->plugin(plugin_name.c_str()))
258  return true;
259  return false;
260 }
261 
262 template <typename Handler, typename Chained, bool chainable>
264  typedef typename Handler::Product Product;
265  static Product *apply(const Handler& h, const CComplexOptionParser& param_list, const std::string& params) {
266  if (param_list.size() > 1) {
267  throw create_exception<std::invalid_argument>( "Factory " , h.get_descriptor(),
268  ": No chaining supported but ", param_list.size(),
269  " plugin descriptors were given. "
270  "If the description contains a '+' sign as part "
271  "of a parameter you must protect it by enclosing the "
272  "value in square brackets like this: [1e+6]");
273  }
274 
275  cvdebug() << "TFactoryPluginHandler<P>::produce use '" << param_list.begin()->first << "'\n";
276  const std::string& factory_name = param_list.begin()->first;
277 
278  if (factory_name == plugin_help) {
279  cvdebug() << "print help\n";
280  cvmsg() << "\n";
281  h.print_help(cverb);
282  return nullptr;
283  }
284 
285  cvdebug() << "TFactoryPluginHandler<"<< h.get_descriptor() << ">::produce: "
286  "Create plugin from '" << factory_name << "'\n";
287 
288  auto factory = h.plugin(factory_name.c_str());
289  if (!factory)
290  throw create_exception<std::invalid_argument>("Factory " , h.get_descriptor(),
291  ":Unable to find plugin for '", factory_name, "'");
292  return factory->create(param_list.begin()->second,params.c_str());
293  }
294 };
295 
296 template <typename Handler, typename ProductChained>
297 struct create_plugin<Handler, ProductChained, true> {
298  typedef typename Handler::Product Product;
299 
300  static Product *apply(const Handler& h, const CComplexOptionParser& param_list, const std::string& params) {
301 
302  if (param_list.size() == 1)
303  return create_plugin<Handler, ProductChained, false>::apply(h, param_list, params);
304 
305  ProductChained *result = new ProductChained();
306  try {
307  for (auto ipl = param_list.begin(); ipl != param_list.end(); ++ipl) {
308 
309  const std::string& factory_name = ipl->first;
310  cvdebug() << "TFactoryPluginHandler<P>::produce use '" << factory_name << "\n";
311 
312  if (factory_name == plugin_help) {
313  cvdebug() << "print help\n";
314  cvmsg() << "\n";
315  h.print_help(cverb);
316  delete result;
317  return nullptr;
318  }
319 
320  auto factory = h.plugin(factory_name.c_str());
321  if (!factory) {
322  delete result;
323  throw create_exception<std::invalid_argument>("Factory " , h.get_descriptor(),
324  "Unable to find plugin for '", factory_name, "'");
325  }
326 
327  auto r = factory->create(ipl->second,params.c_str());
328  result->push_back(typename Product::Pointer(r));
329  }
330  result->set_init_string(params.c_str());
331  }
332  catch (std::exception& x) {
333  delete result;
334  throw x;
335  }
336  return result;
337  }
338 };
339 
340 
341 template <typename I>
342 typename I::Product *TFactoryPluginHandler<I>::produce_raw(const std::string& params)const
343 {
344  if (params.empty()) {
345  throw create_exception<std::invalid_argument>("Factory ", this->get_descriptor(), ": Empty description string given. "
346  "Supported plug-ins are '", this->get_plugin_names(), "'. "
347  "Set description to 'help' for more information.");
348  }
349 
350  CComplexOptionParser param_list(params);
351 
352  if (param_list.size() < 1) {
353  throw create_exception<std::invalid_argument>( "Factory " , this->get_descriptor(), ": Description string '"
354  , params , "' can not be interpreted. "
355  "Supported plug-ins are '" , this->get_plugin_names() , "'. "
356  "Set description to 'help' for more information.");
357  }
358 
361  plugin_can_chain<I>::value>::apply(*this, param_list, params);
362 }
363 
368 #define EXPLICIT_INSTANCE_PLUGIN(T) \
369  template class TPlugin<T::plugin_data, T::plugin_type>; \
370  template class TFactory<T>;
371 
376 #define EXPLICIT_INSTANCE_PLUGIN_HANDLER(P) \
377  template class TPluginHandler<P>; \
378  template class TFactoryPluginHandler<P>; \
379  template class THandlerSingleton<TFactoryPluginHandler<P> >;
380 
386 #define EXPLICIT_INSTANCE_HANDLER(T) \
387  template class TPlugin<T::plugin_data, T::plugin_type>; \
388  template class TFactory<T>; \
389  template class TPluginHandler<TFactory<T> >; \
390  template class TFactoryPluginHandler<TFactory<T> >; \
391  template class THandlerSingleton<TFactoryPluginHandler<TFactory<T> > >;
392 
399 #define EXPLICIT_INSTANCE_DERIVED_FACTORY_HANDLER(T, F) \
400  template class TPlugin<T::plugin_data, T::plugin_type>; \
401  template class TFactory<T>; \
402  template class TPluginHandler<F>; \
403  template class TFactoryPluginHandler<F>; \
404  template class THandlerSingleton<TFactoryPluginHandler<F> >;
405 
406 
407 
409 #endif
The type specific product cache.
Definition: productcache.hh:78
vstream & cverr()
send errors to this stream adapter
Definition: msgstream.hh:301
CDebugSink & cvdebug()
Definition: msgstream.hh:216
const_iterator begin() const
TFactoryPluginHandler()
Initializes the plugin handler.
Definition: factory.hh:203
static Product * apply(const Handler &h, const CComplexOptionParser &param_list, const std::string &params)
Definition: factory.hh:265
UniqueProduct produce_unique(const std::string &plugindescr) const
Definition: factory.hh:231
ProductPtr produce(const std::string &plugindescr) const
Definition: factory.hh:218
TFactory(char const *const name)
Definition: factory.hh:169
I::UniqueProduct UniqueProduct
The unique pointer type of the the object this plug in hander produces.
Definition: factory.hh:111
#define cverb
define a shortcut to the raw output stream
Definition: msgstream.hh:331
#define NS_MIA_BEGIN
conveniance define to start the mia namespace
Definition: defines.hh:33
Handler::Product Product
Definition: factory.hh:264
ProductPtr produce(const char *plugindescr) const
Definition: factory.hh:122
TPluginHandler< I >::Interface * plugin(const char *plugin) const
I::SharedProduct ProductPtr
The shared pointer type of the the object this plug in hander produces.
Definition: factory.hh:108
#define EXPORT_HANDLER
Definition: core/cost.hh:32
std::map< std::string, std::string > CParsedOptions
Definition: optionparser.hh:38
vstream & cvmsg()
send messages to this stream adapter
Definition: msgstream.hh:321
This is tha base of all plugins that create "things", like filters, cost functions time step operator...
Definition: factory.hh:49
virtual Product * create(const CParsedOptions &options, char const *params) __attribute__((warn_unused_result))
Definition: factory.hh:175
const std::string & get_descriptor() const
std::unique_ptr< P > UniqueProduct
typedef for the unique version of the product
Definition: factory.hh:61
P Product
typedef to describe the product of the factory
Definition: factory.hh:54
void check_parameters()
I::Product Product
The type of the the object this plug in hander produces.
Definition: factory.hh:105
std::shared_ptr< P > SharedProduct
typedef for the shared version of the product
Definition: factory.hh:57
PPluginModule get_module() const
void set_caching(bool enable) const
Definition: factory.hh:210
const_iterator end() const
EXPORT_CORE const std::string plugin_help
standard string to print out help in the factory plug-in handler
static Product * apply(const Handler &h, const CComplexOptionParser &param_list, const std::string &params)
Definition: factory.hh:300
the Base class for all plugn handlers that deal with factory plugins.
Definition: factory.hh:93
CParts::size_type size() const
UniqueProduct produce_unique(const char *plugindescr) const
Definition: factory.hh:136
const std::string get_plugin_names() const
Parser for complex command line options.
Definition: optionparser.hh:55
void set_parameters(const CParsedOptions &options)
std::mutex CMutex
The generic base for all plug-ins.
Definition: plugin_base.hh:170
The basic template of all plugin handlers.
Definition: handler.hh:56
#define NS_MIA_END
conveniance define to end the mia namespace
Definition: defines.hh:36