// Copyright (C) 2013-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #if !defined (COMMONAPI_INTERNAL_COMPILATION) #error "Only can be included directly, this file may disappear or change contents." #endif #ifndef COMMONAPI_DBUS_DBUSSTUBADAPTERHELPER_HPP_ #define COMMONAPI_DBUS_DBUSSTUBADAPTERHELPER_HPP_ #include #include #include #include #include #include #include #include #include #include #include #include namespace CommonAPI { namespace DBus { class StubDispatcherBase { public: virtual ~StubDispatcherBase() { } }; struct DBusAttributeDispatcherStruct { StubDispatcherBase* getter; StubDispatcherBase* setter; DBusAttributeDispatcherStruct(StubDispatcherBase* g, StubDispatcherBase* s) { getter = g; setter = s; } }; typedef std::unordered_map StubAttributeTable; template class DBusStubAdapterHelper: public virtual DBusStubAdapter { public: typedef typename _StubClass::StubAdapterType StubAdapterType; typedef typename _StubClass::RemoteEventHandlerType RemoteEventHandlerType; class StubDispatcher: public StubDispatcherBase { public: virtual ~StubDispatcher() {} virtual bool dispatchDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelper<_StubClass>& dbusStubAdapterHelper) = 0; virtual void appendGetAllReply(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelper<_StubClass>& dbusStubAdapterHelper, DBusOutputStream &_output) {} }; // interfaceMemberName, interfaceMemberSignature typedef std::pair DBusInterfaceMemberPath; typedef std::unordered_map StubDispatcherTable; DBusStubAdapterHelper(const DBusAddress &_address, const std::shared_ptr &_connection, const std::shared_ptr<_StubClass> &_stub, const bool _isManaging): DBusStubAdapter(_address, _connection, _isManaging), stub_(_stub), remoteEventHandler_(nullptr) { } virtual ~DBusStubAdapterHelper() { DBusStubAdapter::deinit(); stub_.reset(); } virtual void init(std::shared_ptr instance) { DBusStubAdapter::init(instance); std::shared_ptr stubAdapter = std::dynamic_pointer_cast(instance); remoteEventHandler_ = stub_->initStubAdapter(stubAdapter); } virtual void deinit() { DBusStubAdapter::deinit(); stub_.reset(); } inline RemoteEventHandlerType* getRemoteEventHandler() { return remoteEventHandler_; } protected: virtual bool onInterfaceDBusMessage(const DBusMessage& dbusMessage) { const char* interfaceMemberName = dbusMessage.getMember(); const char* interfaceMemberSignature = dbusMessage.getSignature(); assert(interfaceMemberName); assert(interfaceMemberSignature); DBusInterfaceMemberPath dbusInterfaceMemberPath(interfaceMemberName, interfaceMemberSignature); auto findIterator = getStubDispatcherTable().find(dbusInterfaceMemberPath); const bool foundInterfaceMemberHandler = (findIterator != getStubDispatcherTable().end()); bool dbusMessageHandled = false; if (foundInterfaceMemberHandler) { StubDispatcher* stubDispatcher = static_cast(findIterator->second); dbusMessageHandled = stubDispatcher->dispatchDBusMessage(dbusMessage, stub_, *this); } return dbusMessageHandled; } virtual bool onInterfaceDBusFreedesktopPropertiesMessage(const DBusMessage &_message) { DBusInputStream input(_message); if (_message.hasMemberName("Get")) { return handleFreedesktopGet(_message, input); } else if (_message.hasMemberName("Set")) { return handleFreedesktopSet(_message, input); } else if (_message.hasMemberName("GetAll")) { return handleFreedesktopGetAll(_message, input); } return false; } virtual const StubDispatcherTable& getStubDispatcherTable() = 0; virtual const StubAttributeTable& getStubAttributeTable() = 0; std::shared_ptr<_StubClass> stub_; RemoteEventHandlerType* remoteEventHandler_; private: bool handleFreedesktopGet(const DBusMessage &_message, DBusInputStream &_input) { std::string interfaceName; std::string attributeName; _input >> interfaceName; _input >> attributeName; if (_input.hasError()) { return false; } auto attributeDispatcherIterator = getStubAttributeTable().find(attributeName); if (attributeDispatcherIterator == getStubAttributeTable().end()) { return false; } StubDispatcher* getterDispatcher = static_cast(attributeDispatcherIterator->second.getter); assert(getterDispatcher != NULL); // all attributes have at least a getter return (getterDispatcher->dispatchDBusMessage(_message, stub_, *this)); } bool handleFreedesktopSet(const DBusMessage& dbusMessage, DBusInputStream& dbusInputStream) { std::string interfaceName; std::string attributeName; dbusInputStream >> interfaceName; dbusInputStream >> attributeName; if(dbusInputStream.hasError()) { return false; } auto attributeDispatcherIterator = getStubAttributeTable().find(attributeName); if(attributeDispatcherIterator == getStubAttributeTable().end()) { return false; } StubDispatcher *setterDispatcher = static_cast(attributeDispatcherIterator->second.setter); if (setterDispatcher == NULL) { // readonly attributes do not have a setter return false; } return setterDispatcher->dispatchDBusMessage(dbusMessage, stub_, *this); } bool handleFreedesktopGetAll(const DBusMessage& dbusMessage, DBusInputStream& dbusInputStream) { std::string interfaceName; dbusInputStream >> interfaceName; if(dbusInputStream.hasError()) { return false; } DBusMessage dbusMessageReply = dbusMessage.createMethodReturn("a{sv}"); DBusOutputStream dbusOutputStream(dbusMessageReply); dbusOutputStream.beginWriteVectorOfSerializableStructs(); std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); for(auto attributeDispatcherIterator = getStubAttributeTable().begin(); attributeDispatcherIterator != getStubAttributeTable().end(); attributeDispatcherIterator++) { //To prevent the destruction of the stub whilst still handling a message if (stub_) { StubDispatcher* getterDispatcher = static_cast(attributeDispatcherIterator->second.getter); assert(getterDispatcher != NULL); // all attributes have at least a getter dbusOutputStream << attributeDispatcherIterator->first; getterDispatcher->appendGetAllReply(dbusMessage, stub_, *this, dbusOutputStream); } } dbusOutputStream.endWriteVector(); dbusOutputStream.flush(); return getDBusConnection()->sendDBusMessage(dbusMessageReply); } }; template< class > struct DBusStubSignalHelper; template class _In, class... _InArgs> struct DBusStubSignalHelper<_In> { static inline bool sendSignal(const char* objectPath, const char* interfaceName, const char* signalName, const char* signalSignature, const std::shared_ptr& dbusConnection, const _InArgs&... inArgs) { DBusMessage dbusMessage = DBusMessage::createSignal( objectPath, interfaceName, signalName, signalSignature); if (sizeof...(_InArgs) > 0) { DBusOutputStream outputStream(dbusMessage); const bool success = DBusSerializableArguments<_InArgs...>::serialize(outputStream, inArgs...); if (!success) { return false; } outputStream.flush(); } const bool dbusMessageSent = dbusConnection->sendDBusMessage(dbusMessage); return dbusMessageSent; } template static bool sendSignal(const _DBusStub &_stub, const char *_name, const char *_signature, const _InArgs&... inArgs) { return(sendSignal(_stub.getDBusAddress().getObjectPath().c_str(), _stub.getDBusAddress().getInterface().c_str(), _name, _signature, _stub.getDBusConnection(), inArgs...)); } template static bool sendSignal(const char *_target, const _DBusStub &_stub, const char *_name, const char *_signature, const _InArgs&... inArgs) { DBusMessage dbusMessage = DBusMessage::createSignal( _stub.getDBusAddress().getObjectPath().c_str(), _stub.getDBusAddress().getInterface().c_str(), _name, _signature); dbusMessage.setDestination(_target); if (sizeof...(_InArgs) > 0) { DBusOutputStream outputStream(dbusMessage); const bool success = DBusSerializableArguments<_InArgs...>::serialize(outputStream, inArgs...); if (!success) { return false; } outputStream.flush(); } return _stub.getDBusConnection()->sendDBusMessage(dbusMessage); } }; template< class, class > class DBusMethodStubDispatcher; template < typename _StubClass, template class _In, class... _InArgs> class DBusMethodStubDispatcher<_StubClass, _In<_InArgs...> >: public DBusStubAdapterHelper<_StubClass>::StubDispatcher { public: typedef DBusStubAdapterHelper<_StubClass> DBusStubAdapterHelperType; typedef void (_StubClass::*_StubFunctor)(std::shared_ptr, _InArgs...); DBusMethodStubDispatcher(_StubFunctor stubFunctor): stubFunctor_(stubFunctor) { } bool dispatchDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper) { return handleDBusMessage(dbusMessage, stub, dbusStubAdapterHelper, typename make_sequence::type()); } private: template inline bool handleDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper, index_sequence<_InArgIndices...>) const { std::tuple<_InArgs...> argTuple; if (sizeof...(_InArgs) > 0) { DBusInputStream dbusInputStream(dbusMessage); const bool success = DBusSerializableArguments<_InArgs...>::deserialize(dbusInputStream, std::get<_InArgIndices>(argTuple)...); if (!success) return false; } std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); (stub.get()->*stubFunctor_)(clientId, std::move(std::get<_InArgIndices>(argTuple))...); return true; } _StubFunctor stubFunctor_; }; template< class, class, class> class DBusMethodWithReplyStubDispatcher; template < typename _StubClass, template class _In, class... _InArgs, template class _Out, class... _OutArgs> class DBusMethodWithReplyStubDispatcher<_StubClass, _In<_InArgs...>, _Out<_OutArgs...> >: public DBusStubAdapterHelper<_StubClass>::StubDispatcher { public: typedef DBusStubAdapterHelper<_StubClass> DBusStubAdapterHelperType; typedef std::function ReplyType_t; typedef void (_StubClass::*_StubFunctor)( std::shared_ptr, _InArgs..., ReplyType_t); DBusMethodWithReplyStubDispatcher(_StubFunctor stubFunctor, const char* dbusReplySignature, std::tuple<_InArgs..., _OutArgs...> _args): stubFunctor_(stubFunctor), dbusReplySignature_(dbusReplySignature), args_(_args), currentCall_(0) { } bool dispatchDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper) { connection_ = dbusStubAdapterHelper.getDBusConnection(); return handleDBusMessage( dbusMessage, stub, dbusStubAdapterHelper, typename make_sequence_range::type(), typename make_sequence_range::type(), args_); } bool sendReply(CommonAPI::CallId_t _call, std::tuple<_OutArgs...> args = std::make_tuple()) { return sendReplyInternal(_call, typename make_sequence_range::type(), args); } private: template inline bool handleDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper, index_sequence<_InArgIndices...>, index_sequence<_OutArgIndices...>, std::tuple<_InArgs..., _OutArgs...> argTuple) { if (sizeof...(_InArgs) > 0) { DBusInputStream dbusInputStream(dbusMessage); const bool success = DBusSerializableArguments<_InArgs...>::deserialize(dbusInputStream, std::get<_InArgIndices>(argTuple)...); if (!success) return false; } std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); DBusMessage reply = dbusMessage.createMethodReturn(dbusReplySignature_); CommonAPI::CallId_t call; { std::lock_guard lock(mutex_); call = currentCall_++; pending_[call] = reply; } (stub.get()->*stubFunctor_)( clientId, std::move(std::get<_InArgIndices>(argTuple))..., [call, this](_OutArgs... _args){ this->sendReply(call, std::make_tuple(_args...)); } ); return true; } template bool sendReplyInternal(CommonAPI::CallId_t _call, index_sequence<_OutArgIndices...>, std::tuple<_OutArgs...> args) { std::lock_guard lock(mutex_); auto reply = pending_.find(_call); if (reply != pending_.end()) { if (sizeof...(_OutArgs) > 0) { DBusOutputStream output(reply->second); if (!DBusSerializableArguments<_OutArgs...>::serialize( output, std::get<_OutArgIndices>(args)...)) { pending_.erase(_call); return false; } output.flush(); } bool isSuccessful = connection_->sendDBusMessage(reply->second); pending_.erase(_call); return isSuccessful; } return false; } _StubFunctor stubFunctor_; const char* dbusReplySignature_; std::tuple<_InArgs..., _OutArgs...> args_; CommonAPI::CallId_t currentCall_; std::map pending_; std::mutex mutex_; // protects pending_ std::shared_ptr connection_; }; template< class, class, class, class > class DBusMethodWithReplyAdapterDispatcher; template < typename _StubClass, typename _StubAdapterClass, template class _In, class... _InArgs, template class _Out, class... _OutArgs> class DBusMethodWithReplyAdapterDispatcher<_StubClass, _StubAdapterClass, _In<_InArgs...>, _Out<_OutArgs...> >: public DBusStubAdapterHelper<_StubClass>::StubDispatcher { public: typedef DBusStubAdapterHelper<_StubClass> DBusStubAdapterHelperType; typedef void (_StubAdapterClass::*_StubFunctor)(std::shared_ptr, _InArgs..., _OutArgs&...); typedef typename CommonAPI::Stub StubType; DBusMethodWithReplyAdapterDispatcher(_StubFunctor stubFunctor, const char* dbusReplySignature): stubFunctor_(stubFunctor), dbusReplySignature_(dbusReplySignature) { } bool dispatchDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper) { std::tuple<_InArgs..., _OutArgs...> argTuple; return handleDBusMessage( dbusMessage, stub, dbusStubAdapterHelper, typename make_sequence_range::type(), typename make_sequence_range::type(),argTuple); } private: template inline bool handleDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper, index_sequence<_InArgIndices...>, index_sequence<_OutArgIndices...>, std::tuple<_InArgs..., _OutArgs...> argTuple) const { if (sizeof...(_InArgs) > 0) { DBusInputStream dbusInputStream(dbusMessage); const bool success = DBusSerializableArguments<_InArgs...>::deserialize(dbusInputStream, std::get<_InArgIndices>(argTuple)...); if (!success) return false; } std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); (stub->StubType::getStubAdapter().get()->*stubFunctor_)(clientId, std::move(std::get<_InArgIndices>(argTuple))..., std::get<_OutArgIndices>(argTuple)...); DBusMessage dbusMessageReply = dbusMessage.createMethodReturn(dbusReplySignature_); if (sizeof...(_OutArgs) > 0) { DBusOutputStream dbusOutputStream(dbusMessageReply); const bool success = DBusSerializableArguments<_OutArgs...>::serialize(dbusOutputStream, std::get<_OutArgIndices>(argTuple)...); if (!success) return false; dbusOutputStream.flush(); } return dbusStubAdapterHelper.getDBusConnection()->sendDBusMessage(dbusMessageReply); } _StubFunctor stubFunctor_; const char* dbusReplySignature_; }; template class DBusGetAttributeStubDispatcher: public virtual DBusStubAdapterHelper<_StubClass>::StubDispatcher { public: typedef DBusStubAdapterHelper<_StubClass> DBusStubAdapterHelperType; typedef const _AttributeType& (_StubClass::*GetStubFunctor)(std::shared_ptr); DBusGetAttributeStubDispatcher(GetStubFunctor _getStubFunctor, const char *_signature, _AttributeDepl *_depl = nullptr): getStubFunctor_(_getStubFunctor), signature_(_signature), depl_(_depl) { } virtual ~DBusGetAttributeStubDispatcher() {}; bool dispatchDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper) { return sendAttributeValueReply(dbusMessage, stub, dbusStubAdapterHelper); } void appendGetAllReply(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper, DBusOutputStream &_output) { std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); auto varDepl = CommonAPI::DBus::VariantDeployment<_AttributeDepl>(true, depl_); // presuming FreeDesktop variant deployment, as support for "legacy" service only _output << CommonAPI::Deployable, CommonAPI::DBus::VariantDeployment<_AttributeDepl>>((stub.get()->*getStubFunctor_)(clientId), &varDepl); _output.flush(); } protected: virtual bool sendAttributeValueReply(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper) { DBusMessage dbusMessageReply = dbusMessage.createMethodReturn(signature_); DBusOutputStream dbusOutputStream(dbusMessageReply); std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); dbusOutputStream << CommonAPI::Deployable<_AttributeType, _AttributeDepl>((stub.get()->*getStubFunctor_)(clientId), depl_); dbusOutputStream.flush(); return dbusStubAdapterHelper.getDBusConnection()->sendDBusMessage(dbusMessageReply); } GetStubFunctor getStubFunctor_; const char* signature_; _AttributeDepl *depl_; }; template class DBusSetAttributeStubDispatcher: public virtual DBusGetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl> { public: typedef typename DBusGetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl>::DBusStubAdapterHelperType DBusStubAdapterHelperType; typedef typename DBusStubAdapterHelperType::RemoteEventHandlerType RemoteEventHandlerType; typedef typename DBusGetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl>::GetStubFunctor GetStubFunctor; typedef bool (RemoteEventHandlerType::*OnRemoteSetFunctor)(std::shared_ptr, _AttributeType); typedef void (RemoteEventHandlerType::*OnRemoteChangedFunctor)(); DBusSetAttributeStubDispatcher(GetStubFunctor getStubFunctor, OnRemoteSetFunctor onRemoteSetFunctor, OnRemoteChangedFunctor onRemoteChangedFunctor, const char* dbusSignature, _AttributeDepl *_depl = nullptr) : DBusGetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl>(getStubFunctor, dbusSignature, _depl), onRemoteSetFunctor_(onRemoteSetFunctor), onRemoteChangedFunctor_(onRemoteChangedFunctor) { } virtual ~DBusSetAttributeStubDispatcher() {}; bool dispatchDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper) { bool attributeValueChanged; if (!setAttributeValue(dbusMessage, stub, dbusStubAdapterHelper, attributeValueChanged)) return false; if (attributeValueChanged) notifyOnRemoteChanged(dbusStubAdapterHelper); return true; } protected: virtual _AttributeType retrieveAttributeValue(const DBusMessage& dbusMessage, bool& errorOccured) { errorOccured = false; DBusInputStream dbusInputStream(dbusMessage); CommonAPI::Deployable<_AttributeType, _AttributeDepl> attributeValue(this->depl_); dbusInputStream >> attributeValue; if (dbusInputStream.hasError()) { errorOccured = true; } return attributeValue.getValue(); } inline bool setAttributeValue(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper, bool& attributeValueChanged) { bool errorOccured; CommonAPI::Deployable<_AttributeType, _AttributeDepl> attributeValue( retrieveAttributeValue(dbusMessage, errorOccured), this->depl_); if(errorOccured) { return false; } std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); attributeValueChanged = (dbusStubAdapterHelper.getRemoteEventHandler()->*onRemoteSetFunctor_)(clientId, std::move(attributeValue.getValue())); return this->sendAttributeValueReply(dbusMessage, stub, dbusStubAdapterHelper); } inline void notifyOnRemoteChanged(DBusStubAdapterHelperType& dbusStubAdapterHelper) { (dbusStubAdapterHelper.getRemoteEventHandler()->*onRemoteChangedFunctor_)(); } inline const _AttributeType& getAttributeValue(std::shared_ptr clientId, const std::shared_ptr<_StubClass>& stub) { return (stub.get()->*(this->getStubFunctor_))(clientId); } const OnRemoteSetFunctor onRemoteSetFunctor_; const OnRemoteChangedFunctor onRemoteChangedFunctor_; }; template class DBusSetObservableAttributeStubDispatcher: public virtual DBusSetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl> { public: typedef typename DBusSetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl>::DBusStubAdapterHelperType DBusStubAdapterHelperType; typedef typename DBusStubAdapterHelperType::StubAdapterType StubAdapterType; typedef typename DBusSetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl>::GetStubFunctor GetStubFunctor; typedef typename DBusSetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl>::OnRemoteSetFunctor OnRemoteSetFunctor; typedef typename DBusSetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl>::OnRemoteChangedFunctor OnRemoteChangedFunctor; typedef typename CommonAPI::Stub StubType; typedef void (StubAdapterType::*FireChangedFunctor)(const _AttributeType&); DBusSetObservableAttributeStubDispatcher(GetStubFunctor getStubFunctor, OnRemoteSetFunctor onRemoteSetFunctor, OnRemoteChangedFunctor onRemoteChangedFunctor, FireChangedFunctor fireChangedFunctor, const char* dbusSignature, _AttributeDepl *_depl = nullptr) : DBusGetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl>( getStubFunctor, dbusSignature, _depl), DBusSetAttributeStubDispatcher<_StubClass, _AttributeType, _AttributeDepl>( getStubFunctor, onRemoteSetFunctor, onRemoteChangedFunctor, dbusSignature, _depl), fireChangedFunctor_(fireChangedFunctor) { } virtual ~DBusSetObservableAttributeStubDispatcher() {}; bool dispatchDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr<_StubClass>& stub, DBusStubAdapterHelperType& dbusStubAdapterHelper) { bool attributeValueChanged; if (!this->setAttributeValue(dbusMessage, stub, dbusStubAdapterHelper, attributeValueChanged)) return false; if (attributeValueChanged) { std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); fireAttributeValueChanged(clientId, dbusStubAdapterHelper, stub); this->notifyOnRemoteChanged(dbusStubAdapterHelper); } return true; } protected: virtual void fireAttributeValueChanged(std::shared_ptr clientId, DBusStubAdapterHelperType& dbusStubAdapterHelper, const std::shared_ptr<_StubClass> stub) { (stub->StubType::getStubAdapter().get()->*fireChangedFunctor_)(this->getAttributeValue(clientId, stub)); } const FireChangedFunctor fireChangedFunctor_; }; } // namespace DBus } // namespace CommonAPI #endif // COMMONAPI_DBUS_DBUSSTUBADAPTERHELPER_HPP_