fw4spl
IService.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/IService.hpp"
8 
9 #include "fwServices/registry/ActiveWorkers.hpp"
10 #include "fwServices/registry/ObjectService.hpp"
11 #include "fwServices/registry/Proxy.hpp"
12 
13 #include <fwCom/Slot.hpp>
14 #include <fwCom/Slot.hxx>
15 #include <fwCom/Slots.hpp>
16 #include <fwCom/Slots.hxx>
17 
18 #include <fwRuntime/Convert.hpp>
19 #include <fwRuntime/EConfigurationElement.hpp>
20 
21 #include <fwThread/Worker.hpp>
22 
23 #include <fwTools/fwID.hpp>
24 
25 #include <boost/property_tree/ptree.hpp>
26 #include <boost/regex.hpp>
27 
28 #include <functional>
29 
30 namespace fwServices
31 {
32 
33 //-----------------------------------------------------------------------------
34 
35 const ::fwCom::Slots::SlotKeyType IService::s_STARTED_SIG = "started";
36 const ::fwCom::Slots::SlotKeyType IService::s_UPDATED_SIG = "updated";
37 const ::fwCom::Slots::SlotKeyType IService::s_STOPPED_SIG = "stopped";
38 
39 const ::fwCom::Slots::SlotKeyType IService::s_START_SLOT = "start";
40 const ::fwCom::Slots::SlotKeyType IService::s_STOP_SLOT = "stop";
41 const ::fwCom::Slots::SlotKeyType IService::s_UPDATE_SLOT = "update";
42 const ::fwCom::Slots::SlotKeyType IService::s_SWAP_SLOT = "swap";
43 const ::fwCom::Slots::SlotKeyType IService::s_SWAPKEY_SLOT = "swapKey";
44 
45 const std::string IService::s_DEFAULT_OBJECT = "defaultObject";
46 
47 //-----------------------------------------------------------------------------
48 
50  m_configuration( new ::fwRuntime::EConfigurationElement("EmptyConfigurationElement") ),
51  m_globalState( STOPPED ),
52  m_updatingState( NOTUPDATING ),
53  m_configurationState( UNCONFIGURED )
54 {
55  newSignal<StartedSignalType>( s_STARTED_SIG );
56  newSignal<UpdatedSignalType>( s_UPDATED_SIG );
57  newSignal<StoppedSignalType>( s_STOPPED_SIG );
58 
59  m_slotStart = newSlot( s_START_SLOT, &IService::startSlot, this );
60  m_slotStop = newSlot( s_STOP_SLOT, &IService::stopSlot, this );
61  m_slotUpdate = newSlot( s_UPDATE_SLOT, &IService::updateSlot, this );
62  m_slotSwap = newSlot( s_SWAP_SLOT, &IService::swapSlot, this );
63  m_slotSwapKey = newSlot( s_SWAPKEY_SLOT, &IService::swapKeySlot, this );
64 }
65 
66 //-----------------------------------------------------------------------------
67 
69 {
70 }
71 
72 //-----------------------------------------------------------------------------
73 
74 void IService::info( std::ostream& )
75 {
76 }
77 
78 //-----------------------------------------------------------------------------
79 
80 void IService::setOutput(const IService::KeyType& key, const fwData::Object::sptr& object, size_t index)
81 {
82  std::string outKey = key;
83 
84  if(m_keyGroupSize.find(key) != m_keyGroupSize.end())
85  {
86  outKey = KEY_GROUP_NAME(key, index);
87  }
88  if(::fwServices::OSR::isRegistered(outKey, ::fwServices::IService::AccessType::OUTPUT, this->getSptr()))
89  {
90  ::fwServices::OSR::unregisterServiceOutput(outKey, this->getSptr());
91  }
92 
93  if(object != nullptr)
94  {
95  ::fwServices::OSR::registerServiceOutput(object, outKey, this->getSptr());
96  }
97 }
98 
99 //-----------------------------------------------------------------------------
100 
101 ::fwData::Object::sptr IService::getObject()
102 {
103  FW_DEPRECATED("getObject()", "getInput() or getInOut()", "20.0");
104 
105  // Handle compatibility with new behavior
106  if(m_associatedObject.expired())
107  {
108  // If we have an appXml but with an old service definition, we consider that the old primary object is the
109  // first one in the map
110  if(!m_inputsMap.empty())
111  {
112  return ::fwData::Object::constCast(m_inputsMap.begin()->second.lock());
113  }
114  else if(!m_inOutsMap.empty())
115  {
116  return m_inOutsMap.begin()->second.lock();
117  }
118  else if(!m_outputsMap.empty())
119  {
120  return m_outputsMap.begin()->second;
121  }
122  else
123  {
124  OSLM_ASSERT("Associated Object of " <<this->getID()<<" ["<<this->getClassname()<<"] is expired", false );
125  }
126  }
127  return m_associatedObject.lock();
128 }
129 
130 //------------------------------------------------------------------------------
131 
132 void IService::registerInput(const ::fwData::Object::csptr& obj, const std::string& key, const bool autoConnect,
133  const bool optional)
134 {
135  ::fwServices::OSR::registerServiceInput(obj, key, this->getSptr());
136 
137  ObjectServiceConfig objConfig;
138  objConfig.m_key = key;
139  objConfig.m_access = AccessType::INPUT;
140  objConfig.m_autoConnect = autoConnect;
141  objConfig.m_optional = optional;
142 
143  m_serviceConfig.m_objects.push_back(objConfig);
144 }
145 
146 //------------------------------------------------------------------------------
147 
148 void IService::registerInOut(const ::fwData::Object::sptr& obj, const std::string& key, const bool autoConnect,
149  const bool optional)
150 {
151  ::fwServices::OSR::registerService(obj, key, AccessType::INOUT, this->getSptr());
152 
153  ObjectServiceConfig objConfig;
154  objConfig.m_key = key;
155  objConfig.m_access = AccessType::INOUT;
156  objConfig.m_autoConnect = autoConnect;
157  objConfig.m_optional = optional;
158 
159  m_serviceConfig.m_objects.push_back(objConfig);
160 }
161 
162 //-----------------------------------------------------------------------------
163 
164 bool IService::hasObjectId(const KeyType& _key) const
165 {
166  auto it = m_idsMap.find(_key);
167  return (it != m_idsMap.end());
168 }
169 
170 //-----------------------------------------------------------------------------
171 
172 IService::IdType IService::getObjectId(const IService::KeyType& _key) const
173 {
174  auto it = m_idsMap.find(_key);
175  FW_RAISE_IF("Object key '" + _key + "' not found in service " + this->getID() + ".", it == m_idsMap.end());
176  return it->second;
177 }
178 
179 //-----------------------------------------------------------------------------
180 
181 void IService::setObjectId(const IService::KeyType& _key, const IService::IdType& _id)
182 {
183  m_idsMap[_key] = _id;
184 }
185 
186 //-----------------------------------------------------------------------------
187 
188 void displayPt(::boost::property_tree::ptree& pt, std::string indent = "")
189 {
190  OSLM_ERROR(indent << " data : '" << pt.data() << "'" );
191 
192  for( ::boost::property_tree::ptree::value_type& v : pt)
193  {
194  OSLM_ERROR((indent + " '") << v.first << "':" );
195  displayPt(v.second, indent + " ");
196 
197  }
198 }
199 
200 //-----------------------------------------------------------------------------
201 
202 void IService::setConfiguration(const ::fwRuntime::ConfigurationElement::sptr _cfgElement)
203 {
204  SLM_ASSERT( "Invalid ConfigurationElement", _cfgElement );
205  m_configuration = _cfgElement;
206  m_configurationState = UNCONFIGURED;
207 }
208 
209 //-----------------------------------------------------------------------------
210 
211 void IService::setConfiguration(const Config& _configuration)
212 {
213  SLM_ASSERT( "Invalid ConfigurationElement", _configuration.m_config );
214 
215  // TODO: Remove this ugly const_cast
216  m_configuration = ::fwRuntime::ConfigurationElement::constCast(_configuration.m_config);
217  m_configurationState = UNCONFIGURED;
218 
219  m_serviceConfig = _configuration;
220 }
221 
222 //-----------------------------------------------------------------------------
223 
224 void IService::setConfiguration( const ConfigType& ptree )
225 {
226  ::fwRuntime::ConfigurationElement::sptr ce;
227 
228  ConfigType serviceConfig;
229  serviceConfig.add_child("service", ptree);
230 
231  ce = ::fwRuntime::Convert::fromPropertyTree(serviceConfig);
232 
233  SLM_ASSERT( "Invalid ConfigurationElement", ce );
234 
235  this->setConfiguration(ce);
236 }
237 
238 //-----------------------------------------------------------------------------
239 
240 ::fwRuntime::ConfigurationElement::sptr IService::getConfiguration() const
241 {
242  return m_configuration;
243 }
244 
245 //-----------------------------------------------------------------------------
246 
247 IService::ConfigType IService::getConfigTree() const
248 {
249  const auto configTree = ::fwRuntime::Convert::toPropertyTree(this->getConfiguration());
250 
251  // This is in case we get the configuration from a ::fwServices::registry::ServiceConfig
252  auto srvConfig = configTree.get_child_optional("config");
253 
254  if(srvConfig.is_initialized())
255  {
256  return srvConfig.value();
257  }
258  else
259  {
260  srvConfig = configTree.get_child_optional("service");
261  if(srvConfig.is_initialized())
262  {
263  return srvConfig.value();
264  }
265  return IService::ConfigType();
266  }
267 }
268 
269 //-----------------------------------------------------------------------------
270 
272 {
273  if( m_configurationState == UNCONFIGURED )
274  {
275  m_configurationState = CONFIGURING;
276  if( m_globalState == STOPPED )
277  {
278  try
279  {
280  this->configuring();
281  }
282  catch (std::exception& e)
283  {
284  SLM_ERROR("Error while configuring service '" + this->getID() + "' : " + e.what());
285  }
286  }
287  else if( m_globalState == STARTED )
288  {
289  this->reconfiguring();
290  }
291  m_configurationState = CONFIGURED;
292  }
293 }
294 
295 //-----------------------------------------------------------------------------
296 
298 {
299  OSLM_FATAL(
300  "If this method (reconfiguring) is called, it must be overriden in the implementation ("<<this->getClassname()<<", "<< this->getID() <<
301  ")" );
302 }
303 
304 //-----------------------------------------------------------------------------
305 
307 {
309  {
310  return this->internalStart(false);
311  }
312  else
313  {
314  return m_slotStart->asyncRun();
315  }
316 }
317 
318 //-----------------------------------------------------------------------------
319 
321 {
323  {
324  return this->internalStop(false);
325  }
326  else
327  {
328  return m_slotStop->asyncRun();
329  }
330 }
331 
332 //-----------------------------------------------------------------------------
333 
335 {
337  {
338  return this->internalUpdate(false);
339  }
340  else
341  {
342  return m_slotUpdate->asyncRun();
343  }
344 }
345 
346 //-----------------------------------------------------------------------------
347 
348 IService::SharedFutureType IService::swap( ::fwData::Object::sptr _obj )
349 {
351  {
352  return this->internalSwap(_obj, false);
353  }
354  else
355  {
356  return m_slotSwap->asyncRun( _obj );
357  }
358 }
359 
360 //-----------------------------------------------------------------------------
361 
362 IService::SharedFutureType IService::swapKey(const IService::KeyType& _key, fwData::Object::sptr _obj)
363 {
365  {
366  return this->internalSwapKey(_key, _obj, false);
367  }
368  else
369  {
370  return m_slotSwapKey->asyncRun( _key, _obj );
371  }
372 }
373 
374 //-----------------------------------------------------------------------------
375 
377 {
378  return m_globalState;
379 }
380 
381 //-----------------------------------------------------------------------------
382 
383 bool IService::isStarted() const noexcept
384 {
385  return (m_globalState == STARTED);
386 }
387 
388 //-----------------------------------------------------------------------------
389 
390 bool IService::isStopped() const noexcept
391 {
392  return (m_globalState == STOPPED);
393 }
394 
395 //-----------------------------------------------------------------------------
396 
398 {
399  return m_configurationState;
400 }
401 
402 //-----------------------------------------------------------------------------
403 
405 {
406  return m_updatingState;
407 }
408 
409 //-----------------------------------------------------------------------------
410 
411 void IService::setWorker( ::fwThread::Worker::sptr worker )
412 {
413  m_associatedWorker = worker;
414  ::fwCom::HasSlots::m_slots.setWorker( m_associatedWorker );
415 }
416 
417 //-----------------------------------------------------------------------------
418 
419 ::fwThread::Worker::sptr IService::getWorker() const
420 {
421  return m_associatedWorker;
422 }
423 
424 //-----------------------------------------------------------------------------
425 
427 {
428  KeyConnectionsMap connections;
429  return connections;
430 }
431 
432 //-----------------------------------------------------------------------------
433 
434 IService::SharedFutureType IService::startSlot()
435 {
436  return this->internalStart(true);
437 }
438 
439 //-----------------------------------------------------------------------------
440 
441 IService::SharedFutureType IService::internalStart(bool _async)
442 {
443  OSLM_FATAL_IF("Service "<<this->getID()<<" already started", m_globalState != STOPPED);
444 
445  this->connectToConfig();
446 
447  m_globalState = STARTING;
448 
449  PackagedTaskType task( std::bind(&IService::starting, this) );
450  SharedFutureType future = task.get_future();
451  task();
452 
453  try
454  {
455  // This allows to trigger the exception if there was one
456  future.get();
457  }
458  catch (const std::exception& e)
459  {
460  SLM_ERROR("Error while STARTING service '" + this->getID() + "' : " + e.what());
461  SLM_ERROR("Service '" + this->getID() + "' is still STOPPED.");
462  m_globalState = STOPPED;
463  this->disconnectFromConfig();
464 
465  if(!_async)
466  {
467  // The future is shared, thus the caller can still catch the exception if needed with ufuture.get()
468  return future;
469  }
470  else
471  {
472  // Rethrow the same exception
473  throw;
474  }
475 
476  }
477  m_globalState = STARTED;
478 
479  this->autoConnect();
480 
481  auto sig = this->signal<StartedSignalType>(s_STARTED_SIG);
482  sig->asyncEmit();
483 
484  return future;
485 }
486 
487 //-----------------------------------------------------------------------------
488 
489 IService::SharedFutureType IService::stopSlot()
490 {
491  return this->internalStop(true);
492 }
493 
494 //-----------------------------------------------------------------------------
495 
496 IService::SharedFutureType IService::internalStop(bool _async)
497 {
498  OSLM_FATAL_IF("Service "<<this->getID()<<" already stopped", m_globalState != STARTED);
499 
500  this->autoDisconnect();
501 
502  PackagedTaskType task( std::bind(&IService::stopping, this) );
503  SharedFutureType future = task.get_future();
504 
505  m_globalState = STOPPING;
506  task();
507 
508  try
509  {
510  // This allows to trigger the exception if there was one
511  future.get();
512  }
513  catch (std::exception& e)
514  {
515  SLM_ERROR("Error while STOPPING service '" + this->getID() + "' : " + e.what());
516  SLM_ERROR("Service '" + this->getID() + "' is still STARTED.");
517  m_globalState = STARTED;
518  this->autoConnect();
519 
520  if(!_async)
521  {
522  // The future is shared, thus the caller can still catch the exception if needed with ufuture.get()
523  return future;
524  }
525  else
526  {
527  // Rethrow the same exception
528  throw;
529  }
530  }
531  m_globalState = STOPPED;
532 
533  auto sig = this->signal<StoppedSignalType>(s_STOPPED_SIG);
534  sig->asyncEmit();
535 
536  this->disconnectFromConfig();
537 
538  return future;
539 
540 }
541 
542 //-----------------------------------------------------------------------------
543 
544 IService::SharedFutureType IService::swapSlot(::fwData::Object::sptr _obj)
545 {
546  return this->internalSwap(_obj, true);
547 }
548 
549 //-----------------------------------------------------------------------------
550 
551 IService::SharedFutureType IService::internalSwap(::fwData::Object::sptr _obj, bool _async)
552 {
553  OSLM_ASSERT("Swapping on "<< this->getID() << " with same Object " << _obj->getID(),
554  m_associatedObject.lock() != _obj );
555  OSLM_FATAL_IF("Service "<< this->getID() << " is not STARTED, no swapping with Object " << _obj->getID(),
556  m_globalState != STARTED);
557 
558  PackagedTaskType task( std::bind(static_cast<void (IService::*)()>(&IService::swapping), this) );
559  SharedFutureType future = task.get_future();
560 
561  m_globalState = SWAPPING;
562  ::fwServices::OSR::swapService( _obj, this->getSptr() );
563  task();
564  m_globalState = STARTED;
565 
566  try
567  {
568  // This allows to trigger the exception if there was one
569  future.get();
570  }
571  catch (std::exception& e)
572  {
573  SLM_ERROR("Error while SWAPPING service '" + this->getID() + "' : " + e.what());
574 
575  if(!_async)
576  {
577  // The future is shared, thus the caller can still catch the exception if needed with ufuture.get()
578  return future;
579  }
580  else
581  {
582  // Rethrow the same exception
583  throw;
584  }
585  }
586 
587  return future;
588 }
589 
590 //-----------------------------------------------------------------------------
591 
592 IService::SharedFutureType IService::swapKeySlot(const KeyType& _key, ::fwData::Object::sptr _obj)
593 {
594  return this->internalSwapKey(_key, _obj, true);
595 }
596 
597 //-----------------------------------------------------------------------------
598 
599 IService::SharedFutureType IService::internalSwapKey(const KeyType& _key, ::fwData::Object::sptr _obj, bool _async)
600 {
601  OSLM_FATAL_IF("Service "<< this->getID() << " is not STARTED, no swapping with Object " <<
602  (_obj ? _obj->getID() : "nullptr"),
603  m_globalState != STARTED);
604 
605  auto fn = std::bind(static_cast<void (IService::*)(const KeyType&)>(&IService::swapping), this, _key);
606  PackagedTaskType task( fn );
607  SharedFutureType future = task.get_future();
608 
609  this->autoDisconnect();
610 
611  m_globalState = SWAPPING;
612  task();
613  m_globalState = STARTED;
614 
615  try
616  {
617  // This allows to trigger the exception if there was one
618  future.get();
619  }
620  catch (std::exception& e)
621  {
622  SLM_ERROR("Error while SWAPPING service '" + this->getID() + "' : " + e.what());
623 
624  if(!_async)
625  {
626  // The future is shared, thus the caller can still catch the exception if needed with ufuture.get()
627  return future;
628  }
629  else
630  {
631  // Rethrow the same exception
632  throw;
633  }
634  }
635 
636  this->autoConnect();
637 
638  return future;
639 
640 }
641 
642 //-----------------------------------------------------------------------------
643 
644 IService::SharedFutureType IService::updateSlot()
645 {
646  return this->internalUpdate(true);
647 }
648 
649 //-----------------------------------------------------------------------------
650 
651 IService::SharedFutureType IService::internalUpdate(bool _async)
652 {
653  if(m_globalState != STARTED)
654  {
655  OSLM_WARN("INVOKING update WHILE STOPPED ("<<m_globalState<<") on service '" << this->getID() <<
656  "' of type '" << this->getClassname() << "': update is discarded." );
657  return SharedFutureType();
658  }
659  OSLM_ASSERT("INVOKING update WHILE NOT IDLE ("<<m_updatingState<<") on service '" << this->getID() <<
660  "' of type '" << this->getClassname() << "'", m_updatingState == NOTUPDATING );
661 
662  PackagedTaskType task( std::bind(&IService::updating, this) );
663  SharedFutureType future = task.get_future();
664  m_updatingState = UPDATING;
665  task();
666 
667  try
668  {
669  // This allows to trigger the exception if there was one
670  future.get();
671  }
672  catch (std::exception& e)
673  {
674  SLM_ERROR("Error while UPDATING service '" + this->getID() + "' : " + e.what());
675 
676  m_updatingState = NOTUPDATING;
677  if(!_async)
678  {
679  // The future is shared, thus the caller can still catch the exception if needed with ufuture.get()
680  return future;
681  }
682  else
683  {
684  // Rethrow the same exception
685  throw;
686  }
687  }
688  m_updatingState = NOTUPDATING;
689 
690  auto sig = this->signal<StartedSignalType>(s_UPDATED_SIG);
691  sig->asyncEmit();
692 
693  return future;
694 }
695 
696 //-----------------------------------------------------------------------------
697 
698 void IService::connectToConfig()
699 {
700  ::fwServices::registry::Proxy::sptr proxy = ::fwServices::registry::Proxy::getDefault();
701 
702  for(const auto& proxyCfg : m_proxies)
703  {
704  for(const auto& signalCfg : proxyCfg.second.m_signals)
705  {
706  SLM_ASSERT("Invalid signal source", signalCfg.first == this->getID());
707 
708  ::fwCom::SignalBase::sptr sig = this->signal(signalCfg.second);
709  SLM_ASSERT("Signal '" + signalCfg.second + "' not found in source '" + signalCfg.first + "'.", sig);
710  try
711  {
712  proxy->connect(proxyCfg.second.m_channel, sig);
713 
714  }
715  catch (const std::exception& e)
716  {
717  SLM_ERROR("Signal '" + signalCfg.second + "' from '" + signalCfg.first + "' can not be connected to the"
718  " channel '" + proxyCfg.second.m_channel + "': " + std::string(e.what()));
719  }
720  }
721 
722  for(const auto& slotCfg : proxyCfg.second.m_slots)
723  {
724  SLM_ASSERT("Invalid slot destination", slotCfg.first == this->getID());
725 
726  ::fwCom::SlotBase::sptr slot = this->slot(slotCfg.second);
727  SLM_ASSERT("Slot '" + slotCfg.second + "' not found in source '" + slotCfg.first + "'.", slot);
728 
729  try
730  {
731  proxy->connect(proxyCfg.second.m_channel, slot);
732  }
733  catch (const std::exception& e)
734  {
735  SLM_ERROR("Slot '" + slotCfg.second + "' from '" + slotCfg.first + "' can not be connected to the "
736  "channel '" + proxyCfg.second.m_channel + "': " + std::string(e.what()));
737  }
738  }
739  }
740 }
741 
742 //-----------------------------------------------------------------------------
743 
744 void IService::autoConnect()
745 {
747 
748  SLM_ERROR_IF("The service '" + this->getID() + "'(" + this->getClassname() +
749  ") is set to 'autoConnect=\"yes\"' but is has no object to connect",
750  m_serviceConfig.m_globalAutoConnect && m_serviceConfig.m_objects.empty());
751 
752  // For compatibility with V1, we allow services to connect explicitly with the default object
753  // For these services we will ignore all auto connections with any other data
754  // This is intended notably for managers-like services
755  const bool hasDefaultObjectConnectionV1 =
756  (connectionMap.find(::fwServices::IService::s_DEFAULT_OBJECT) != connectionMap.end());
757 
758  for(const auto& objectCfg : m_serviceConfig.m_objects)
759  {
760  if ((m_serviceConfig.m_globalAutoConnect || objectCfg.m_autoConnect) && !hasDefaultObjectConnectionV1)
761  {
763  if(!connectionMap.empty())
764  {
765  auto it = connectionMap.find(objectCfg.m_key);
766  if( it != connectionMap.end())
767  {
768  connections = it->second;
769  }
770  else
771  {
772  // Special case if we have a key from a group we check with the name of the group
773  boost::smatch match;
774  static const ::boost::regex reg("(.*)#[0-9]+");
775  if( ::boost::regex_match(objectCfg.m_key, match, reg ) && match.size() == 2)
776  {
777  const std::string group = match[1].str();
778  auto it = connectionMap.find(group);
779  if( it != connectionMap.end())
780  {
781  connections = it->second;
782  }
783  }
784  }
785  SLM_ERROR_IF("Object '" + objectCfg.m_key + "' of '" + this->getID() + "'(" + this->getClassname() +
786  ") is set to 'autoConnect=\"yes\"' but there is no connection available.",
787  connections.empty() && objectCfg.m_autoConnect);
788  }
789  else
790  {
791  // V1 compatibility, we didn't implemented the new function, so we stick to the old behavior
792  // This also allows to get the default connection with the s_UPDATE_SLOT. When we remove this
793  // function, we will have to implement this behavior with getAutoConnections()
794  connections = this->getObjSrvConnections();
795  FW_DEPRECATED_IF("getObjSrvConnections()", "getAutoConnections()", "20.0", !connections.empty());
796  }
797 
798  ::fwData::Object::csptr obj;
799 
800  switch(objectCfg.m_access)
801  {
802  case AccessType::INPUT:
803  {
804  auto itObj = m_inputsMap.find(objectCfg.m_key);
805  if(itObj != m_inputsMap.end())
806  {
807  obj = itObj->second.lock();
808  }
809  break;
810  }
811  case AccessType::INOUT:
812  {
813  auto itObj = m_inOutsMap.find(objectCfg.m_key);
814  if(itObj != m_inOutsMap.end())
815  {
816  obj = itObj->second.lock();
817  }
818  break;
819  }
820  case AccessType::OUTPUT:
821  {
822  SLM_WARN("Can't autoConnect to an output for now");
823  auto itObj = m_outputsMap.find(objectCfg.m_key);
824  if(itObj != m_outputsMap.end())
825  {
826  obj = itObj->second;
827  }
828  break;
829  }
830  }
831 
832  SLM_ASSERT("Object '" + objectCfg.m_uid +
833  "' has not been found when autoConnecting service '" + m_serviceConfig.m_uid + "'.",
834  (!objectCfg.m_optional && obj) || objectCfg.m_optional);
835 
836  if(obj)
837  {
838  m_autoConnections.connect( obj, this->getSptr(), connections );
839  }
840  }
841  }
842 
843  // Autoconnect with the default object - to be cleaned when V1 compatibility is over
844  auto defaultObj = this->getInOut< ::fwData::Object >(s_DEFAULT_OBJECT);
845 
846  if(m_serviceConfig.m_globalAutoConnect && defaultObj)
847  {
849  auto it = connectionMap.find(::fwServices::IService::s_DEFAULT_OBJECT);
850  if( it != connectionMap.end())
851  {
852  connections = it->second;
853  }
854  else if(m_serviceConfig.m_objects.size() == 0)
855  {
856  // Only use the old callback automatically in case we put a composite as the only data
857  connections = this->getObjSrvConnections();
858  }
859 
860  m_autoConnections.connect( defaultObj, this->getSptr(), connections );
861  }
862 }
863 
864 //-----------------------------------------------------------------------------
865 
866 void IService::disconnectFromConfig()
867 {
868  ::fwServices::registry::Proxy::sptr proxy = ::fwServices::registry::Proxy::getDefault();
869 
870  for(const auto& proxyCfg : m_proxies)
871  {
872  for(const auto& signalCfg : proxyCfg.second.m_signals)
873  {
874  SLM_ASSERT("Invalid signal source", signalCfg.first == this->getID());
875 
876  ::fwCom::SignalBase::sptr sig = this->signal(signalCfg.second);
877 
878  try
879  {
880  proxy->disconnect(proxyCfg.second.m_channel, sig);
881  }
882  catch (const std::exception& e)
883  {
884  SLM_ERROR("Signal '" + signalCfg.second + "' from '" + signalCfg.first + "' can not be disconnected "
885  "from the channel '" + proxyCfg.second.m_channel + "': " + std::string(e.what()));
886  }
887  }
888  for(const auto& slotCfg : proxyCfg.second.m_slots)
889  {
890  SLM_ASSERT("Invalid slot destination", slotCfg.first == this->getID());
891 
892  ::fwCom::SlotBase::sptr slot = this->slot(slotCfg.second);
893  try
894  {
895  proxy->disconnect(proxyCfg.second.m_channel, slot);
896  }
897  catch (const std::exception& e)
898  {
899  SLM_ERROR("Slot '" + slotCfg.second + "' from '" + slotCfg.first + "' can not be disconnected from the "
900  "channel '" + proxyCfg.second.m_channel + "': " + std::string(e.what()));
901  }
902  }
903  }
904 }
905 
906 //-----------------------------------------------------------------------------
907 
908 void IService::autoDisconnect()
909 {
910  m_autoConnections.disconnect();
911 }
912 
913 //-----------------------------------------------------------------------------
914 
915 void IService::addProxyConnection(const helper::ProxyConnections& proxy)
916 {
917  m_proxies[proxy.m_channel] = proxy;
918 }
919 
920 //-----------------------------------------------------------------------------
921 
923 {
924  KeyConnectionsType connections;
925  connections.push_back( std::make_pair( ::fwData::Object::s_MODIFIED_SIG, s_UPDATE_SLOT ) );
926  return connections;
927 }
928 
929 //-----------------------------------------------------------------------------
930 
936 std::ostream& operator<<(std::ostream& _ostream, IService& _service)
937 {
938  _service.info( _ostream );
939  return _ostream;
940 }
941 
942 //-----------------------------------------------------------------------------
943 
944 }
Base class for all services.
Definition: IService.hpp:61
This class is a helper to define the connections of a service and its data.
Definition: IService.hpp:454
virtual FWSERVICES_API void starting()=0
Initialize the service activity.
GlobalStatus
Defines all possible global status for a service, including transitions.
Definition: IService.hpp:122
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_SWAPKEY_SLOT
Slot to call start method.
Definition: IService.hpp:183
FWSERVICES_API SharedFutureType stop()
Invoke stopping() if m_globalState == STARTED. Does nothing otherwise. Stops all observations.
Definition: IService.cpp:320
FWCOM_API void disconnect()
Disconnect all registered connections and clear m_connections.
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_STOP_SLOT
Slot to call start method.
Definition: IService.hpp:174
FWSERVICES_API bool isStopped() const noexcept
Test if the service is stopped or not.
Definition: IService.cpp:390
static FWSERVICES_API const std::string s_DEFAULT_OBJECT
Definition: IService.hpp:113
virtual FWSERVICES_API void stopping()=0
Uninitialize the service activity. The stop() method is always invoked before destroying a service...
FWSERVICES_API SharedFutureType swapKey(const KeyType &_key,::fwData::Object::sptr _obj)
Associate the service to another object.
Definition: IService.cpp:362
#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
virtual FWSERVICES_API ~IService()
IService desctructor.
Definition: IService.cpp:68
static FWSERVICES_API Proxy::sptr getDefault()
Returns an instance of Proxy.
Definition: Proxy.cpp:33
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_START_SLOT
Slot to call start method.
Definition: IService.hpp:171
FWSERVICES_API IdType getObjectId(const KeyType &_key) const
Return the id of the object, throw if it is not found.
Definition: IService.cpp:172
FWSERVICES_API SharedFutureType start()
Invoke starting() if m_globalState == STOPPED. Does nothing otherwise.
Definition: IService.cpp:306
std::shared_future< void > SharedFutureType
Slot to call start method.
Definition: IService.hpp:167
FWSERVICES_API SharedFutureType swap(::fwData::Object::sptr _obj)
Associate the service to another object.
Definition: IService.cpp:348
FWSERVICES_API SharedFutureType update()
Invoke updating() if m_globalState == STARTED. Does nothing otherwise.
Definition: IService.cpp:334
FWSERVICES_API void configure()
Invoke configuring() if m_globalState == STOPPED. Invoke reconfiguring() if m_globalState == STARTED...
Definition: IService.cpp:271
virtual FWSERVICES_API void updating()=0
Perform some computations according to object (this service is attached to) attribute values and its ...
SwapKeySlotType::sptr m_slotSwapKey
Slot to call swap method.
Definition: IService.hpp:696
Namespace fwServices is dedicated to (mimic) the dynamic affectation of methods to (pure data) object...
FWSERVICES_API void registerInput(const ::fwData::Object::csptr &obj, const std::string &key, const bool autoConnect=false, const bool optional=false)
Register an input object for this service.
Definition: IService.cpp:132
virtual FWSERVICES_API void reconfiguring()
Reconfigure the service activity when is started.
Definition: IService.cpp:297
FWTHREAD_API ThreadIdType getCurrentThreadId()
Returns the current thread id.
Definition: Worker.cpp:14
virtual void swapping()
Swap the service from associated object to another object.
Definition: IService.hpp:613
FWSERVICES_API friend std::ostream & operator<<(std::ostream &_sstream, IService &_service)
Streaming a service.
Definition: IService.cpp:936
SwapSlotType::sptr m_slotSwap
Slot to call swap method.
Definition: IService.hpp:693
#define SLM_WARN(message)
Definition: spyLog.hpp:261
FWSERVICES_API void registerInOut(const ::fwData::Object::sptr &obj, const std::string &key, const bool autoConnect=false, const bool optional=false)
Register an in/out object for this service.
Definition: IService.cpp:148
#define FW_DEPRECATED_IF(oldFnName, newFnName, version, condition)
Use this macro when deprecating a function to warn the developer.
Definition: spyLog.hpp:352
Used to store object configuration in a service.
Definition: IService.hpp:90
The namespace fwRuntime contains classes to manage bundle, configuration element, extension point in ...
UpdateSlotType::sptr m_slotUpdate
Slot to call update method.
Definition: IService.hpp:690
#define SLM_ERROR(message)
Definition: spyLog.hpp:272
std::packaged_task< void()> PackagedTaskType
Slot to call start method.
Definition: IService.hpp:168
FWSERVICES_API void setOutput(const ::fwServices::IService::KeyType &key, const ::fwData::Object::sptr &object, size_t index=0)
Register an output object at a given key in the OSR, replacing it if it already exists.
Definition: IService.cpp:80
FWTOOLS_API IDType getID(Policy policy=GENERATE) const
Returns the id of the object. If it is not set and the policy value is.
Definition: fwID.cpp:78
#define OSLM_ERROR(message)
Definition: spyLog.hpp:274
#define SLM_ERROR_IF(message, cond)
Definition: spyLog.hpp:276
#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
Helper class to register proxy connections.
FWSERVICES_API void setObjectId(const KeyType &_key, const IdType &_id)
Set the id of an object key.
Definition: IService.cpp:181
FWSERVICES_API::fwRuntime::ConfigurationElement::sptr getConfiguration() const
Return the configuration, in an xml format read using runtime library.
Definition: IService.cpp:240
::fwRuntime::ConfigurationElement::sptr m_configuration
Configuration element used to configure service internal state using a generic XML like structure TOD...
Definition: IService.hpp:670
::fwCom::helper::SigSlotConnection::KeyConnectionsType KeyConnectionsType
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
Definition: IService.hpp:449
FWSERVICES_API UpdatingStatus getUpdatingStatus() const noexcept
Return the update process status.
Definition: IService.cpp:404
FWSERVICES_API void setWorker(std::shared_ptr< ::fwThread::Worker > worker)
Initializes m_associatedWorker and associates this worker to all service slots.
Definition: IService.cpp:411
::fwData::Object::wptr m_associatedObject
associated object of service
Definition: IService.hpp:676
UpdatingStatus
Defines all possible status for an update process.
Definition: IService.hpp:132
#define OSLM_FATAL(message)
Definition: spyLog.hpp:285
FWSERVICES_API::fwData::Object::sptr getObject()
Return the object associated to service.
Definition: IService.cpp:101
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
ConfigurationStatus
Defines all possible status for a configuration process.
Definition: IService.hpp:139
virtual FWSERVICES_API KeyConnectionsMap getAutoConnections() const
Returns proposals to connect service slots to associated objects signals, this method is used for obj...
Definition: IService.cpp:426
FWSERVICES_API GlobalStatus getStatus() const noexcept
Return the global process status.
Definition: IService.cpp:376
FWSERVICES_API bool hasObjectId(const KeyType &_key) const
Return true if the object with the given key has an identifier.
Definition: IService.cpp:164
std::shared_ptr< ::fwThread::Worker > m_associatedWorker
Associated worker.
Definition: IService.hpp:699
StopSlotType::sptr m_slotStop
Slot to call stop method.
Definition: IService.hpp:687
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_SWAP_SLOT
Slot to call start method.
Definition: IService.hpp:180
FWCOM_API void connect(const ::fwCom::HasSignals::csptr &hasSignals,::fwCom::Signals::SignalKeyType signalKey, const ::fwCom::HasSlots::csptr &hasSlots,::fwCom::Slots::SlotKeyType slotKey)
Connect signal to slot, and register this new connection in m_connections.
FWSERVICES_API bool isRegistered(const ::fwServices::IService::KeyType &objKey,::fwServices::IService::AccessType access,::fwServices::IService::sptr service)
Return true if a key is registered for a given service.
StartSlotType::sptr m_slotStart
Slot to call start method.
Definition: IService.hpp:684
#define OSLM_FATAL_IF(message, cond)
Definition: spyLog.hpp:289
FWSERVICES_API void setConfiguration(const ::fwRuntime::ConfigurationElement::sptr _cfgElement)
Affect the configuration, using a generic XML like structure.
Definition: IService.cpp:202
virtual FWSERVICES_API void configuring()=0
Configure the service before starting. Apply the configuration to service.
FWSERVICES_API ConfigurationStatus getConfigurationStatus() const noexcept
Return the configuration process status.
Definition: IService.cpp:397
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_UPDATE_SLOT
Slot to call start method.
Definition: IService.hpp:177
Used to store a service configuration.
Definition: IService.hpp:100
virtual FWSERVICES_API KeyConnectionsType getObjSrvConnections() const
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
Definition: IService.cpp:922
FWSERVICES_API IService()
IService constructor.
Definition: IService.cpp:49
virtual FWSERVICES_API void info(std::ostream &_sstream)
Write information in a stream.
Definition: IService.cpp:74
FWSERVICES_API bool isStarted() const noexcept
Test if the service is started or not.
Definition: IService.cpp:383
FWSERVICES_API std::shared_ptr< ::fwThread::Worker > getWorker() const
Returns associate worker.
Definition: IService.cpp:419
#define FW_DEPRECATED(oldFnName, newFnName, version)
Use this macro when deprecating a function to warn the developer.
Definition: spyLog.hpp:344
virtual const std::string & getClassname() const override
return full object&#39;s classname with its namespace, i.e. fwCore::BaseObject
Definition: IService.hpp:71
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.
Definition: IService.cpp:247