7 #include "fwServices/IService.hpp" 9 #include "fwServices/registry/ActiveWorkers.hpp" 10 #include "fwServices/registry/ObjectService.hpp" 11 #include "fwServices/registry/Proxy.hpp" 13 #include <fwCom/Slot.hpp> 14 #include <fwCom/Slot.hxx> 15 #include <fwCom/Slots.hpp> 16 #include <fwCom/Slots.hxx> 18 #include <fwRuntime/Convert.hpp> 19 #include <fwRuntime/EConfigurationElement.hpp> 21 #include <fwThread/Worker.hpp> 23 #include <fwTools/fwID.hpp> 25 #include <boost/property_tree/ptree.hpp> 26 #include <boost/regex.hpp> 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";
50 m_configuration( new ::
fwRuntime::EConfigurationElement(
"EmptyConfigurationElement") ),
51 m_globalState( STOPPED ),
52 m_updatingState( NOTUPDATING ),
53 m_configurationState( UNCONFIGURED )
55 newSignal<StartedSignalType>( s_STARTED_SIG );
56 newSignal<UpdatedSignalType>( s_UPDATED_SIG );
57 newSignal<StoppedSignalType>( s_STOPPED_SIG );
80 void IService::setOutput(
const IService::KeyType& key,
const fwData::Object::sptr&
object,
size_t index)
82 std::string outKey = key;
84 if(m_keyGroupSize.find(key) != m_keyGroupSize.end())
86 outKey = KEY_GROUP_NAME(key, index);
90 ::fwServices::OSR::unregisterServiceOutput(outKey, this->getSptr());
95 ::fwServices::OSR::registerServiceOutput(
object, outKey, this->getSptr());
103 FW_DEPRECATED(
"getObject()",
"getInput() or getInOut()",
"20.0");
110 if(!m_inputsMap.empty())
112 return ::fwData::Object::constCast(m_inputsMap.begin()->second.lock());
114 else if(!m_inOutsMap.empty())
116 return m_inOutsMap.begin()->second.lock();
118 else if(!m_outputsMap.empty())
120 return m_outputsMap.begin()->second;
135 ::fwServices::OSR::registerServiceInput(obj, key, this->getSptr());
138 objConfig.m_key = key;
139 objConfig.m_access = AccessType::INPUT;
140 objConfig.m_autoConnect = autoConnect;
141 objConfig.m_optional = optional;
143 m_serviceConfig.m_objects.push_back(objConfig);
151 ::fwServices::OSR::registerService(obj, key, AccessType::INOUT, this->getSptr());
154 objConfig.m_key = key;
155 objConfig.m_access = AccessType::INOUT;
156 objConfig.m_autoConnect = autoConnect;
157 objConfig.m_optional = optional;
159 m_serviceConfig.m_objects.push_back(objConfig);
166 auto it = m_idsMap.find(_key);
167 return (it != m_idsMap.end());
174 auto it = m_idsMap.find(_key);
175 FW_RAISE_IF(
"Object key '" + _key +
"' not found in service " + this->
getID() +
".", it == m_idsMap.end());
183 m_idsMap[_key] = _id;
188 void displayPt(::boost::property_tree::ptree& pt, std::string indent =
"")
190 OSLM_ERROR(indent <<
" data : '" << pt.data() <<
"'" );
192 for( ::boost::property_tree::ptree::value_type& v : pt)
194 OSLM_ERROR((indent +
" '") << v.first <<
"':" );
195 displayPt(v.second, indent +
" ");
204 SLM_ASSERT(
"Invalid ConfigurationElement", _cfgElement );
213 SLM_ASSERT(
"Invalid ConfigurationElement", _configuration.m_config );
216 m_configuration = ::fwRuntime::ConfigurationElement::constCast(_configuration.m_config);
219 m_serviceConfig = _configuration;
226 ::fwRuntime::ConfigurationElement::sptr ce;
228 ConfigType serviceConfig;
229 serviceConfig.add_child(
"service", ptree);
231 ce = ::fwRuntime::Convert::fromPropertyTree(serviceConfig);
233 SLM_ASSERT(
"Invalid ConfigurationElement", ce );
249 const auto configTree = ::fwRuntime::Convert::toPropertyTree(this->
getConfiguration());
252 auto srvConfig = configTree.get_child_optional(
"config");
254 if(srvConfig.is_initialized())
256 return srvConfig.value();
260 srvConfig = configTree.get_child_optional(
"service");
261 if(srvConfig.is_initialized())
263 return srvConfig.value();
265 return IService::ConfigType();
282 catch (std::exception& e)
284 SLM_ERROR(
"Error while configuring service '" + this->
getID() +
"' : " + e.what());
287 else if( m_globalState ==
STARTED )
300 "If this method (reconfiguring) is called, it must be overriden in the implementation ("<<this->
getClassname()<<
", "<< this->
getID() <<
310 return this->internalStart(
false);
324 return this->internalStop(
false);
338 return this->internalUpdate(
false);
352 return this->internalSwap(_obj,
false);
366 return this->internalSwapKey(_key, _obj,
false);
378 return m_globalState;
385 return (m_globalState ==
STARTED);
392 return (m_globalState ==
STOPPED);
399 return m_configurationState;
406 return m_updatingState;
436 return this->internalStart(
true);
445 this->connectToConfig();
458 catch (
const std::exception& e)
460 SLM_ERROR(
"Error while STARTING service '" + this->
getID() +
"' : " + e.what());
463 this->disconnectFromConfig();
481 auto sig = this->signal<StartedSignalType>(s_STARTED_SIG);
491 return this->internalStop(
true);
500 this->autoDisconnect();
513 catch (std::exception& e)
515 SLM_ERROR(
"Error while STOPPING service '" + this->
getID() +
"' : " + e.what());
533 auto sig = this->signal<StoppedSignalType>(s_STOPPED_SIG);
536 this->disconnectFromConfig();
546 return this->internalSwap(_obj,
true);
553 OSLM_ASSERT(
"Swapping on "<< this->
getID() <<
" with same Object " << _obj->getID(),
555 OSLM_FATAL_IF(
"Service "<< this->
getID() <<
" is not STARTED, no swapping with Object " << _obj->getID(),
562 ::fwServices::OSR::swapService( _obj, this->getSptr() );
571 catch (std::exception& e)
573 SLM_ERROR(
"Error while SWAPPING service '" + this->
getID() +
"' : " + e.what());
594 return this->internalSwapKey(_key, _obj,
true);
601 OSLM_FATAL_IF(
"Service "<< this->
getID() <<
" is not STARTED, no swapping with Object " <<
602 (_obj ? _obj->getID() :
"nullptr"),
609 this->autoDisconnect();
620 catch (std::exception& e)
622 SLM_ERROR(
"Error while SWAPPING service '" + this->
getID() +
"' : " + e.what());
646 return this->internalUpdate(
true);
655 OSLM_WARN(
"INVOKING update WHILE STOPPED ("<<m_globalState<<
") on service '" << this->
getID() <<
656 "' of type '" << this->
getClassname() <<
"': update is discarded." );
659 OSLM_ASSERT(
"INVOKING update WHILE NOT IDLE ("<<m_updatingState<<
") on service '" << this->
getID() <<
672 catch (std::exception& e)
674 SLM_ERROR(
"Error while UPDATING service '" + this->
getID() +
"' : " + e.what());
690 auto sig = this->signal<StartedSignalType>(s_UPDATED_SIG);
698 void IService::connectToConfig()
702 for(
const auto& proxyCfg : m_proxies)
704 for(
const auto& signalCfg : proxyCfg.second.m_signals)
706 SLM_ASSERT(
"Invalid signal source", signalCfg.first == this->getID());
708 ::fwCom::SignalBase::sptr sig = this->signal(signalCfg.second);
709 SLM_ASSERT(
"Signal '" + signalCfg.second +
"' not found in source '" + signalCfg.first +
"'.", sig);
712 proxy->connect(proxyCfg.second.m_channel, sig);
715 catch (
const std::exception& e)
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()));
722 for(
const auto& slotCfg : proxyCfg.second.m_slots)
724 SLM_ASSERT(
"Invalid slot destination", slotCfg.first == this->getID());
726 ::fwCom::SlotBase::sptr slot = this->slot(slotCfg.second);
727 SLM_ASSERT(
"Slot '" + slotCfg.second +
"' not found in source '" + slotCfg.first +
"'.", slot);
731 proxy->connect(proxyCfg.second.m_channel, slot);
733 catch (
const std::exception& e)
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()));
744 void IService::autoConnect()
749 ") is set to 'autoConnect=\"yes\"' but is has no object to connect",
750 m_serviceConfig.m_globalAutoConnect && m_serviceConfig.m_objects.empty());
755 const bool hasDefaultObjectConnectionV1 =
758 for(
const auto& objectCfg : m_serviceConfig.m_objects)
760 if ((m_serviceConfig.m_globalAutoConnect || objectCfg.m_autoConnect) && !hasDefaultObjectConnectionV1)
763 if(!connectionMap.empty())
765 auto it = connectionMap.find(objectCfg.m_key);
766 if( it != connectionMap.end())
768 connections = it->second;
774 static const ::boost::regex reg(
"(.*)#[0-9]+");
775 if( ::boost::regex_match(objectCfg.m_key, match, reg ) && match.size() == 2)
777 const std::string group = match[1].str();
778 auto it = connectionMap.find(group);
779 if( it != connectionMap.end())
781 connections = it->second;
786 ") is set to 'autoConnect=\"yes\"' but there is no connection available.",
787 connections.empty() && objectCfg.m_autoConnect);
795 FW_DEPRECATED_IF(
"getObjSrvConnections()",
"getAutoConnections()",
"20.0", !connections.empty());
798 ::fwData::Object::csptr obj;
800 switch(objectCfg.m_access)
802 case AccessType::INPUT:
804 auto itObj = m_inputsMap.find(objectCfg.m_key);
805 if(itObj != m_inputsMap.end())
807 obj = itObj->second.lock();
811 case AccessType::INOUT:
813 auto itObj = m_inOutsMap.find(objectCfg.m_key);
814 if(itObj != m_inOutsMap.end())
816 obj = itObj->second.lock();
820 case AccessType::OUTPUT:
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())
833 "' has not been found when autoConnecting service '" + m_serviceConfig.m_uid +
"'.",
834 (!objectCfg.m_optional && obj) || objectCfg.m_optional);
838 m_autoConnections.
connect( obj, this->getSptr(), connections );
846 if(m_serviceConfig.m_globalAutoConnect && defaultObj)
850 if( it != connectionMap.end())
852 connections = it->second;
854 else if(m_serviceConfig.m_objects.size() == 0)
860 m_autoConnections.
connect( defaultObj, this->getSptr(), connections );
866 void IService::disconnectFromConfig()
870 for(
const auto& proxyCfg : m_proxies)
872 for(
const auto& signalCfg : proxyCfg.second.m_signals)
874 SLM_ASSERT(
"Invalid signal source", signalCfg.first == this->getID());
876 ::fwCom::SignalBase::sptr sig = this->signal(signalCfg.second);
880 proxy->disconnect(proxyCfg.second.m_channel, sig);
882 catch (
const std::exception& e)
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()));
888 for(
const auto& slotCfg : proxyCfg.second.m_slots)
890 SLM_ASSERT(
"Invalid slot destination", slotCfg.first == this->getID());
892 ::fwCom::SlotBase::sptr slot = this->slot(slotCfg.second);
895 proxy->disconnect(proxyCfg.second.m_channel, slot);
897 catch (
const std::exception& e)
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()));
908 void IService::autoDisconnect()
917 m_proxies[proxy.m_channel] = proxy;
938 _service.
info( _ostream );
Base class for all services.
This class is a helper to define the connections of a service and its data.
virtual FWSERVICES_API void starting()=0
Initialize the service activity.
GlobalStatus
Defines all possible global status for a service, including transitions.
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_SWAPKEY_SLOT
Slot to call start method.
FWSERVICES_API SharedFutureType stop()
Invoke stopping() if m_globalState == STARTED. Does nothing otherwise. Stops all observations.
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.
FWSERVICES_API bool isStopped() const noexcept
Test if the service is stopped or not.
static FWSERVICES_API const std::string s_DEFAULT_OBJECT
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.
#define OSLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
virtual FWSERVICES_API ~IService()
IService desctructor.
static FWSERVICES_API Proxy::sptr getDefault()
Returns an instance of Proxy.
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_START_SLOT
Slot to call start method.
FWSERVICES_API IdType getObjectId(const KeyType &_key) const
Return the id of the object, throw if it is not found.
FWSERVICES_API SharedFutureType start()
Invoke starting() if m_globalState == STOPPED. Does nothing otherwise.
std::shared_future< void > SharedFutureType
Slot to call start method.
FWSERVICES_API SharedFutureType swap(::fwData::Object::sptr _obj)
Associate the service to another object.
FWSERVICES_API SharedFutureType update()
Invoke updating() if m_globalState == STARTED. Does nothing otherwise.
FWSERVICES_API void configure()
Invoke configuring() if m_globalState == STOPPED. Invoke reconfiguring() if m_globalState == STARTED...
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.
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.
virtual FWSERVICES_API void reconfiguring()
Reconfigure the service activity when is started.
FWTHREAD_API ThreadIdType getCurrentThreadId()
Returns the current thread id.
virtual void swapping()
Swap the service from associated object to another object.
FWSERVICES_API friend std::ostream & operator<<(std::ostream &_sstream, IService &_service)
Streaming a service.
SwapSlotType::sptr m_slotSwap
Slot to call swap method.
#define SLM_WARN(message)
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.
#define FW_DEPRECATED_IF(oldFnName, newFnName, version, condition)
Use this macro when deprecating a function to warn the developer.
Used to store object configuration in a service.
The namespace fwRuntime contains classes to manage bundle, configuration element, extension point in ...
UpdateSlotType::sptr m_slotUpdate
Slot to call update method.
#define SLM_ERROR(message)
std::packaged_task< void()> PackagedTaskType
Slot to call start method.
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.
#define OSLM_ERROR(message)
#define SLM_ERROR_IF(message, cond)
#define OSLM_WARN(message)
#define SLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
Helper class to register proxy connections.
FWSERVICES_API void setObjectId(const KeyType &_key, const IdType &_id)
Set the id of an object key.
FWSERVICES_API::fwRuntime::ConfigurationElement::sptr getConfiguration() const
Return the configuration, in an xml format read using runtime library.
::fwRuntime::ConfigurationElement::sptr m_configuration
Configuration element used to configure service internal state using a generic XML like structure TOD...
::fwCom::helper::SigSlotConnection::KeyConnectionsType KeyConnectionsType
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
FWSERVICES_API UpdatingStatus getUpdatingStatus() const noexcept
Return the update process status.
FWSERVICES_API void setWorker(std::shared_ptr< ::fwThread::Worker > worker)
Initializes m_associatedWorker and associates this worker to all service slots.
::fwData::Object::wptr m_associatedObject
associated object of service
UpdatingStatus
Defines all possible status for an update process.
#define OSLM_FATAL(message)
FWSERVICES_API::fwData::Object::sptr getObject()
Return the object associated to service.
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.
virtual FWSERVICES_API KeyConnectionsMap getAutoConnections() const
Returns proposals to connect service slots to associated objects signals, this method is used for obj...
FWSERVICES_API GlobalStatus getStatus() const noexcept
Return the global process status.
FWSERVICES_API bool hasObjectId(const KeyType &_key) const
Return true if the object with the given key has an identifier.
std::shared_ptr< ::fwThread::Worker > m_associatedWorker
Associated worker.
StopSlotType::sptr m_slotStop
Slot to call stop method.
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_SWAP_SLOT
Slot to call start method.
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.
#define OSLM_FATAL_IF(message, cond)
FWSERVICES_API void setConfiguration(const ::fwRuntime::ConfigurationElement::sptr _cfgElement)
Affect the configuration, using a generic XML like structure.
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.
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_UPDATE_SLOT
Slot to call start method.
Used to store a service configuration.
virtual FWSERVICES_API KeyConnectionsType getObjSrvConnections() const
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
FWSERVICES_API IService()
IService constructor.
virtual FWSERVICES_API void info(std::ostream &_sstream)
Write information in a stream.
FWSERVICES_API bool isStarted() const noexcept
Test if the service is started or not.
FWSERVICES_API std::shared_ptr< ::fwThread::Worker > getWorker() const
Returns associate worker.
#define FW_DEPRECATED(oldFnName, newFnName, version)
Use this macro when deprecating a function to warn the developer.
virtual const std::string & getClassname() const override
return full object's classname with its namespace, i.e. fwCore::BaseObject
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.