fw4spl
ServiceFactory.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "fwServices/registry/ServiceFactory.hpp"
8 
9 #include "fwServices/IService.hpp"
10 #include "fwServices/registry/ActiveWorkers.hpp"
11 
12 #include <fwCore/util/LazyInstantiator.hpp>
13 
14 #include <fwData/Exception.hpp>
15 
16 #include <fwRuntime/ConfigurationElement.hpp>
17 #include <fwRuntime/helper.hpp>
18 #include <fwRuntime/profile/Profile.hpp>
19 #include <fwRuntime/Runtime.hpp>
20 
21 #include <functional>
22 #include <vector>
23 
24 namespace fwServices
25 {
26 namespace registry
27 {
28 
29 //-----------------------------------------------------------------------------
30 
31 ServiceFactory::sptr ServiceFactory::getDefault()
32 {
33  return ::fwCore::util::LazyInstantiator< ServiceFactory >::getInstance();
34 }
35 //-----------------------------------------------------------------------------
36 
38 {
39  SrvRegContainer bundleInfoMap;
40 
41  typedef ::fwRuntime::ConfigurationElement::sptr ConfigurationType;
42  typedef std::shared_ptr< ::fwRuntime::Extension > ExtensionType;
43 
44  std::vector< ExtensionType > extElements;
45  extElements = ::fwRuntime::getAllExtensionsForPoint("::fwServices::registry::ServiceFactory");
46  for(ExtensionType extElt : extElements)
47  {
48  std::vector< ConfigurationType > cfgEltVec = extElt->getElements();
49  std::string type;
50  std::string service;
51  std::vector<std::string> objects;
52  std::string desc;
53  std::string tags;
54 
55  for(ConfigurationType cfgElt : cfgEltVec)
56  {
57  std::string elt = cfgElt->getName();
58  if(elt == "type")
59  {
60  type = cfgElt->getValue();
61  }
62  else if(elt == "service")
63  {
64  service = cfgElt->getValue();
65  }
66  else if(elt == "object")
67  {
68  objects.push_back(cfgElt->getValue());
69  }
70  else if(elt == "desc")
71  {
72  desc = cfgElt->getValue();
73  }
74  else if(elt == "tags")
75  {
76  tags = cfgElt->getValue();
77  }
78  else
79  {
80  SLM_FATAL("Unknown element !");
81  }
82  }
83  SLM_ASSERT("Missing type element.", !type.empty());
84  SLM_ASSERT("Missing service element.", !service.empty());
85 
86  ServiceInfo info;
87  info.serviceType = type;
88  info.objectsSetFromBundle = !objects.empty();
89  info.objectImpl = std::move(objects);
90  info.desc = desc;
91  info.tags = tags;
92  info.bundle = cfgEltVec[0]->getBundle();
93  SLM_ASSERT("Bundle not find.", info.bundle );
94 
95  bundleInfoMap.emplace(std::make_pair(service, info));
96  }
97 
98  this->printInfoMap( bundleInfoMap );
99 
100  ::fwCore::mt::ReadToWriteLock lock(m_srvImplTosrvInfoMutex);
101  // Merge data info
102  for(SrvRegContainer::value_type bundle : bundleInfoMap)
103  {
104  SrvRegContainer::iterator iter = m_srvImplTosrvInfo.find( bundle.first );
105 
106  if ( iter != m_srvImplTosrvInfo.end() )
107  {
108  OSLM_DEBUG(
109  "We already have informations about this service (from register macro) ( "<< bundle.first <<
110  " )." );
111 
112  ServiceInfo& info = iter->second;
113  ServiceInfo& infoBundle = bundle.second;
114 
115  SLM_ASSERT("Try to add bundle, but bundle exists.", !info.bundle );
116  SLM_ASSERT("Try to add bundle, but this srv is already registered and doesn't have the same srv type.",
117  infoBundle.serviceType == info.serviceType );
118  SLM_ASSERT("Try to add bundle, but the service '"
119  << bundle.first << "' is already registered and does not have the same objects.",
120  infoBundle.objectImpl.empty() || infoBundle.objectImpl == info.objectImpl );
121 
122  info.bundle = infoBundle.bundle;
123  info.desc = infoBundle.desc;
124  info.objectsSetFromBundle = infoBundle.objectsSetFromBundle;
125  }
126  else
127  {
128  ::fwCore::mt::UpgradeToWriteLock upgrade(lock);
129  m_srvImplTosrvInfo.emplace(std::make_pair(bundle.first, bundle.second));
130  }
131 
132  }
133 
134  this->printInfoMap( m_srvImplTosrvInfo );
135  this->checkServicesNotDeclaredInPluginXml();
136 }
137 
138 //-----------------------------------------------------------------------------
139 
140 IService::sptr ServiceFactory::create( const std::string& _srvImpl ) const
141 {
142  IService::sptr service;
143 
144  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
145  SrvRegContainer::const_iterator iter = m_srvImplTosrvInfo.find( _srvImpl );
146 
147  OSLM_ASSERT("The service called '" << _srvImpl << "' does not exist in the ServiceFactory ",
148  iter != m_srvImplTosrvInfo.end() );
149 
150  const ServiceInfo& info = iter->second;
151 
152  OSLM_DEBUG("SR creates a new service ( classname = " << _srvImpl << " )");
153 
154  if ( info.factory )
155  {
156  service = info.factory();
157  }
158  else
159  {
160  OSLM_ASSERT( "A bundle must declare the factory named"
161  << _srvImpl
162  <<", the service declaration might be missing (or misspelled) in a bundle plugin.",
163  info.bundle );
164  OSLM_ASSERT( "The bundle '" + info.bundle->getIdentifier() + "' is already loaded and the factory '"
165  + _srvImpl + "' is still missing. The service declaration might be missing (or misspelled)"
166  "in a .cpp file.", !info.bundle->isStarted() );
167 
168  lock.unlock(); // bundle->start() may trigger calls to addFactory
169  info.bundle->start();
170  lock.lock();
171 
172  ::fwRuntime::profile::getCurrentProfile()->setup();
173 
174  FW_RAISE_EXCEPTION_IF(
175  ::fwData::Exception( "After loading the bundle " + info.bundle->getIdentifier() + " , factory " + _srvImpl
176  + " is still missing. The service declaration might be missing (or misspelled) "
177  "in a cpp file."),
178  !info.factory );
179 
180  service = info.factory();
181  }
182 
183  // Setup worker here, this is a better place than the constructor
184  // because here, the service slots are also set up
185  // This allows to setup
187 
188  return service;
189 }
190 
191 //-----------------------------------------------------------------------------
192 
193 IService::sptr ServiceFactory::create( const std::string& _srvType, const std::string& _srvImpl ) const
194 {
195 
196 #ifdef _DEBUG
197  {
198  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
199 
200  OSLM_ASSERT("The service called " << _srvImpl << " does not exist in the ServiceFactory.",
201  m_srvImplTosrvInfo.find( _srvImpl ) != m_srvImplTosrvInfo.end() );
202 
203  OSLM_ASSERT(
204  "Conflicting types were defined for this service, "
205  << _srvType << " != " << m_srvImplTosrvInfo.find( _srvImpl )->second.serviceType,
206  _srvType == m_srvImplTosrvInfo.find( _srvImpl )->second.serviceType);
207  }
208 #endif //_DEBUG
209 
210  IService::sptr service = this->create(_srvImpl);
211  return service;
212 }
213 
214 //------------------------------------------------------------------------------
215 
216 void ServiceFactory::addServiceFactory( FactoryType _factory,
217  const std::string& simpl,
218  const std::string& stype)
219 {
220  SLM_DEBUG("New service registering : simpl =" + simpl + " stype=" + stype);
221 
222  ::fwCore::mt::ReadToWriteLock lock(m_srvImplTosrvInfoMutex);
223  SrvRegContainer::iterator iter = m_srvImplTosrvInfo.find( simpl );
224 
225  if ( iter != m_srvImplTosrvInfo.end() )
226  {
227  SLM_DEBUG("We already have informations about this service ( " + simpl + " )." );
228  ServiceInfo& info = iter->second;
229  OSLM_ASSERT("Try to add factory, but this srv ( " << simpl << " ) already has a registered factory.",
230  !info.factory );
231  OSLM_ASSERT("Try to add factory, but this srv ( "
232  << simpl << " ) is already registered and doesn't have the same srv type. ( "
233  << stype << " != " << info.serviceType <<" )",
234  stype == info.serviceType );
235 
236  ::fwCore::mt::UpgradeToWriteLock upgrade(lock);
237  info.factory = _factory;
238  }
239  else
240  {
241  SLM_DEBUG("Add new service factory in registry ( " + simpl + " )." );
242  ::fwCore::mt::UpgradeToWriteLock upgrade(lock);
243  ServiceInfo info;
244  info.serviceType = stype;
245  info.factory = _factory;
246  m_srvImplTosrvInfo.emplace(std::make_pair(simpl, info));
247  }
248 }
249 
250 //-----------------------------------------------------------------------------
251 
252 void ServiceFactory::addObjectFactory(const std::string& simpl, const std::string& oimpl)
253 {
254  SLM_DEBUG("New object oimpl=" + oimpl + "registering to service: simpl =" + simpl);
255  SLM_ASSERT("Empty oimpl", !oimpl.empty());
256 
257  ::fwCore::mt::ReadToWriteLock lock(m_srvImplTosrvInfoMutex);
258  SrvRegContainer::iterator iter = m_srvImplTosrvInfo.find( simpl );
259 
260  OSLM_ASSERT("Try to associate an object to a service factory, but this srv is not yet registered.",
261  iter != m_srvImplTosrvInfo.end());
262 
263  if ( iter != m_srvImplTosrvInfo.end() )
264  {
265  ServiceInfo& info = iter->second;
266 
267  // Either the bundle does not contain objects informations or this service does not belong to a bundle
268  if(info.objectsSetFromBundle)
269  {
270  const auto itFind = std::find(info.objectImpl.begin(), info.objectImpl.end(), oimpl);
271  SLM_ASSERT("Try to add factory, but the service '" + simpl + "' is already registered and does not have the "
272  "same objects.",
273  info.objectImpl.empty() || itFind != info.objectImpl.end());
274  }
275  else
276  {
277  ::fwCore::mt::UpgradeToWriteLock upgrade(lock);
278  info.objectImpl.push_back(oimpl);
279  }
280  }
281 }
282 
283 //-----------------------------------------------------------------------------
284 
285 void ServiceFactory::printInfoMap( const SrvRegContainer& src ) const
286 {
287  // not thread-safe
288 
289  //Print information
290  for(SrvRegContainer::value_type srvReg : src)
291  {
292  OSLM_DEBUG(" Service name = " << srvReg.first );
293  OSLM_DEBUG(" - type = " << srvReg.second.serviceType );
294 
295 #if SPYLOG_LEVEL >= 5
296  size_t objNum = 0;
297  for(const auto& objImpl : srvReg.second.objectImpl)
298  {
299  OSLM_DEBUG(" - object " << objNum++ << " = " << objImpl)
300  }
301 #endif
302 
303  OSLM_DEBUG_IF(" - bundle = " << srvReg.second.bundle->getIdentifier(), srvReg.second.bundle );
304  OSLM_DEBUG_IF(" - bundle = ( no bundle registered )", !srvReg.second.bundle );
305 
306  OSLM_DEBUG_IF(" - name after creation = "
307  << srvReg.second.factory()->getClassname(), srvReg.second.factory );
308  OSLM_DEBUG_IF(" - name after creation = ( no factory registered )", !srvReg.second.factory );
309  }
310 }
311 
312 //-----------------------------------------------------------------------------
313 
314 void ServiceFactory::checkServicesNotDeclaredInPluginXml() const
315 {
316  // not thread-safe
317  //Print information
318  for(SrvRegContainer::value_type srvReg : m_srvImplTosrvInfo)
319  {
320  if ( !srvReg.second.bundle )
321  {
322  OSLM_WARN("Service " << srvReg.first << " is not declared/found in a plugin.xml." );
323  }
324  }
325 }
326 
327 //-----------------------------------------------------------------------------
328 
329 void ServiceFactory::clearFactory()
330 {
331  ::fwCore::mt::WriteLock lock(m_srvImplTosrvInfoMutex);
332  m_srvImplTosrvInfo.clear();
333 }
334 
335 //-----------------------------------------------------------------------------
336 
337 std::vector< std::string > ServiceFactory::getImplementationIdFromObjectAndType( const std::string& object,
338  const std::string& type ) const
339 {
340  std::vector< std::string > serviceImpl;
341 
342  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
343  for(SrvRegContainer::value_type srv : m_srvImplTosrvInfo)
344  {
345  const ServiceInfo& srvInfo = srv.second;
346  for(const auto& oimpl : srvInfo.objectImpl)
347  {
348  if( srvInfo.serviceType == type &&
349  (oimpl == object || oimpl == "::fwData::Object") )
350  {
351  serviceImpl.push_back(srv.first);
352  break;
353  }
354  }
355  }
356  return serviceImpl;
357 }
358 
359 //-----------------------------------------------------------------------------
360 
361 std::string ServiceFactory::getDefaultImplementationIdFromObjectAndType( const std::string& object,
362  const std::string& type ) const
363 {
364  SLM_ASSERT("This case is not managed ", object != "::fwData::Object" );
365 
366  std::string serviceImpl = "";
367  bool genericImplIsFound = false;
368  bool specificImplIsFound = false;
369 
370  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
371  for( SrvRegContainer::value_type srv : m_srvImplTosrvInfo )
372  {
373  const ServiceInfo& srvInfo = srv.second;
374  if ( srvInfo.serviceType == type )
375  {
376  for(const auto& oimpl : srvInfo.objectImpl)
377  {
378  if ( oimpl == object )
379  {
380  OSLM_ASSERT("Method has already found a specific ("
381  << serviceImpl <<" != " << srv.first
382  << ") service for the object " << oimpl << ".",
383  !specificImplIsFound );
384 
385  specificImplIsFound = true;
386  serviceImpl = srv.first;
387  break;
388  }
389  else if ( oimpl == "::fwData::Object" )
390  {
391  OSLM_ASSERT("Method has already found a generic service for the object ("
392  << oimpl << ").",
393  !genericImplIsFound );
394 
395  genericImplIsFound = true;
396  if ( !specificImplIsFound )
397  {
398  serviceImpl = srv.first;
399  break;
400  }
401  }
402  }
403  }
404  }
405 
406  OSLM_ASSERT("A default implementation is not found for this type of service "<<type, !serviceImpl.empty() );
407 
408  return serviceImpl;
409 }
410 
411 //-----------------------------------------------------------------------------
412 
413 const std::vector<std::string>& ServiceFactory::getServiceObjects(const std::string& srvImpl) const
414 {
415  std::string objImpl;
416  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
417  SrvRegContainer::const_iterator iter = m_srvImplTosrvInfo.find( srvImpl );
418  SLM_ASSERT("The service " << srvImpl << " is not found.", iter != m_srvImplTosrvInfo.end());
419  return iter->second.objectImpl;
420 }
421 
422 //-----------------------------------------------------------------------------
423 
424 std::string ServiceFactory::getServiceDescription(const std::string& srvImpl) const
425 {
426  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
427  SrvRegContainer::const_iterator iter = m_srvImplTosrvInfo.find( srvImpl );
428  SLM_ASSERT("The service " << srvImpl << " is not found.", iter != m_srvImplTosrvInfo.end());
429  return iter->second.desc;
430 }
431 
432 //-----------------------------------------------------------------------------
433 
434 std::string ServiceFactory::getServiceTags(const std::string& srvImpl) const
435 {
436  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
437  SrvRegContainer::const_iterator iter = m_srvImplTosrvInfo.find( srvImpl );
438  SLM_ASSERT("The service " << srvImpl << " is not found.", iter != m_srvImplTosrvInfo.end());
439  return iter->second.tags;
440 }
441 
442 //-----------------------------------------------------------------------------
443 
444 bool ServiceFactory::checkServiceValidity(const std::string& objectClassName, const std::string& srvImpl) const
445 {
446  bool isValid = true;
447  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
448  SrvRegContainer::const_iterator iter = m_srvImplTosrvInfo.find( srvImpl );
449  isValid &= ( iter != m_srvImplTosrvInfo.end() );
450  if (isValid)
451  {
452  const ServiceInfo& srvInfo = iter->second;
453 
454  isValid = false;
455  for(const auto& oimpl : srvInfo.objectImpl)
456  {
457  if(oimpl == "::fwData::Object" || oimpl == objectClassName)
458  {
459  isValid = true;
460  break;
461  }
462  }
463  }
464  return isValid;
465 }
466 
467 //-----------------------------------------------------------------------------
468 
469 bool ServiceFactory::support(const std::string& object, const std::string& srvType, const std::string& srvImpl) const
470 {
471  bool isSupported = true;
472  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
473  SrvRegContainer::const_iterator iter = m_srvImplTosrvInfo.find( srvImpl );
474  isSupported &= ( iter != m_srvImplTosrvInfo.end());
475  if (isSupported)
476  {
477  const ServiceInfo& srvInfo = iter->second;
478 
479  isSupported = false;
480  if(srvInfo.serviceType == srvType)
481  {
482  for(const auto& oimpl : srvInfo.objectImpl)
483  {
484  if(oimpl == "::fwData::Object" || oimpl == object)
485  {
486  isSupported = true;
487  break;
488  }
489  }
490  }
491  }
492  return isSupported;
493 }
494 
495 //-----------------------------------------------------------------------------
496 
497 bool ServiceFactory::support(const std::string& object, const std::string& srvType)
498 {
499  bool isSupported = false;
500  SupportMapType::key_type key(object, srvType);
501  ::fwCore::mt::ReadToWriteLock supportMapLock(m_supportMapMutex);
502  SupportMapType::const_iterator iter = m_supportMap.find( key );
503  if (iter != m_supportMap.end())
504  {
505  isSupported = iter->second;
506  }
507  else
508  {
509  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
510  for(SrvRegContainer::value_type srv : m_srvImplTosrvInfo)
511  {
512  const ServiceInfo& srvInfo = srv.second;
513 
514  if(srvInfo.serviceType == srvType)
515  {
516  for(const auto& oimpl : srvInfo.objectImpl)
517  {
518  if(oimpl == "::fwData::Object" || oimpl == object)
519  {
520  isSupported = true;
521  break;
522  }
523  }
524  }
525  }
526  ::fwCore::mt::UpgradeToWriteLock upgrade(supportMapLock);
527  m_supportMap.insert( SupportMapType::value_type(key, isSupported) );
528  }
529  return isSupported;
530 }
531 
532 //-----------------------------------------------------------------------------
533 
534 ServiceFactory::KeyVectorType ServiceFactory::getFactoryKeys() const
535 {
536  ::fwCore::mt::ReadLock lock(m_srvImplTosrvInfoMutex);
537  KeyVectorType vectKeys;
538  std::transform( m_srvImplTosrvInfo.begin(), m_srvImplTosrvInfo.end(),
539  std::back_inserter(vectKeys),
540  std::bind(&SrvRegContainer::value_type::first, std::placeholders::_1) );
541  return vectKeys;
542 }
543 
544 //-----------------------------------------------------------------------------
545 
546 } // namespace registry
547 } // namespace fwServices
FWSERVICES_API void parseBundleInformation()
Parse bundle information to retrieve service declaration.
Contains fwAtomsFilter::registry details.
FWSERVICES_API bool support(const std::string &object, const std::string &srvType)
Check whether an object (object) supports service of type srvType.
::boost::upgrade_lock< ReadWriteMutex > ReadToWriteLock
Defines an upgradable lock type for read/write mutex.
::boost::upgrade_to_unique_lock< ReadWriteMutex > UpgradeToWriteLock
Defines a write lock upgraded from ReadToWriteLock.
#define OSLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:310
#define OSLM_DEBUG_IF(message, cond)
Definition: spyLog.hpp:245
FWSERVICES_API std::string getDefaultImplementationIdFromObjectAndType(const std::string &object, const std::string &type) const
return the default service implementation for an object
Implements data exception class.
Namespace fwServices is dedicated to (mimic) the dynamic affectation of methods to (pure data) object...
::boost::unique_lock< ReadWriteMutex > WriteLock
Defines a lock of write type for read/write mutex.
#define SLM_DEBUG(message)
Definition: spyLog.hpp:239
FWSERVICES_API std::string getServiceDescription(const std::string &srvImpl) const
return the service description.
#define SLM_FATAL(message)
Definition: spyLog.hpp:283
FWSERVICES_API std::string getServiceTags(const std::string &srvImpl) const
return the service capabilities.
#define OSLM_WARN(message)
Definition: spyLog.hpp:263
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
::boost::shared_lock< ReadWriteMutex > ReadLock
Defines a lock of read type for read/write mutex.
virtual FWSERVICES_API KeyVectorType getFactoryKeys() const
returns the registered factory keys.
FWSERVICES_API const std::vector< std::string > & getServiceObjects(const std::string &srvImpl) const
return the objects registered for a given service.
FWSERVICES_API std::vector< std::string > getImplementationIdFromObjectAndType(const std::string &object, const std::string &type) const
return a vector of service implementation
static FWSERVICES_API::fwThread::Worker::sptr getDefaultWorker()
Get the default registered worker.
static FWSERVICES_API ServiceFactory::sptr getDefault()
Return the unique Instance, create it if required at first access.
FWSERVICES_API bool checkServiceValidity(const std::string &object, const std::string &srvImpl) const
Check if the service with given object and implementation is valid.
FWSERVICES_API std::shared_ptr< IService > create(const std::string &_srvImpl) const
Create a service from a factory type.
#define OSLM_DEBUG(message)
Definition: spyLog.hpp:241