// Copyright (C) 2013-2020 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 { template class StubDispatcher { public: typedef typename StubClass_::RemoteEventHandlerType RemoteEventHandlerType; virtual ~StubDispatcher() {} virtual bool dispatchDBusMessage(const DBusMessage &_message, const std::shared_ptr &_stub, RemoteEventHandlerType* _remoteEventHandler, std::weak_ptr _connection_) = 0; virtual void appendGetAllReply(const DBusMessage &_message, const std::shared_ptr &_stub, DBusOutputStream &_output) { (void)_message; (void)_stub; (void)_output; } }; template struct DBusAttributeDispatcherStruct { StubDispatcher* getter; StubDispatcher* setter; DBusAttributeDispatcherStruct(StubDispatcher* g, StubDispatcher* s) { getter = g; setter = s; } }; template struct identity { typedef T type; }; // interfaceMemberName, interfaceMemberSignature typedef std::pair DBusInterfaceMemberPath; template class DBusStubAdapterHelper { public: DBusStubAdapterHelper(const DBusAddress &_address, const std::shared_ptr &_connection, const bool _isManaging, const std::shared_ptr &_stub) { (void)_address; (void)_connection; (void) _isManaging; (void) _stub; } protected: bool findDispatcherAndHandle(const DBusMessage& dbusMessage, DBusInterfaceMemberPath& dbusInterfaceMemberPath) { (void) dbusMessage; (void) dbusInterfaceMemberPath; return false; } bool findAttributeGetDispatcherAndHandle(std::string interfaceName, std::string attributeName, const DBusMessage &_message) { (void) interfaceName; (void) attributeName; (void) _message; return false; } bool findAttributeSetDispatcherAndHandle(std::string interfaceName, std::string attributeName, const DBusMessage &_message) { (void) interfaceName; (void) attributeName; (void) _message; return false; } bool appendGetAllReply(const DBusMessage& dbusMessage, DBusOutputStream& dbusOutputStream) { (void) dbusMessage; (void) dbusOutputStream; return true; } public: template void addStubDispatcher(DBusInterfaceMemberPath _dbusInterfaceMemberPath, StubDispatcher* _stubDispatcher) { (void) _dbusInterfaceMemberPath; (void) _stubDispatcher; } template void setRemoteEventHandler(RemoteEventHandlerType * _remoteEventHandler) { (void) _remoteEventHandler; } }; template class DBusStubAdapterHelper: public virtual DBusStubAdapter, public DBusStubAdapterHelper { public: typedef typename StubClass_::StubAdapterType StubAdapterType; typedef typename StubClass_::RemoteEventHandlerType RemoteEventHandlerType; typedef std::unordered_map*> StubDispatcherTable; typedef std::unordered_map> StubAttributeTable; DBusStubAdapterHelper(const DBusAddress &_address, const std::shared_ptr &_connection, const bool _isManaging, const std::shared_ptr &_stub) : DBusStubAdapter(_address, _connection, _isManaging), DBusStubAdapterHelper(_address, _connection, _isManaging, _stub), remoteEventHandler_(nullptr) { stub_ = std::dynamic_pointer_cast(_stub); } 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); DBusStubAdapterHelper::setRemoteEventHandler(remoteEventHandler_); } void setRemoteEventHandler(RemoteEventHandlerType* _remoteEventHandler) { remoteEventHandler_ = _remoteEventHandler; DBusStubAdapterHelper::setRemoteEventHandler(remoteEventHandler_); } 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(); if (NULL == interfaceMemberName) { COMMONAPI_ERROR(std::string(__FUNCTION__), " member empty"); } if (NULL == interfaceMemberSignature) { COMMONAPI_ERROR(std::string(__FUNCTION__), " signature empty"); } DBusInterfaceMemberPath dbusInterfaceMemberPath = {interfaceMemberName, interfaceMemberSignature}; return findDispatcherAndHandle(dbusMessage, dbusInterfaceMemberPath); } bool findDispatcherAndHandle(const DBusMessage& dbusMessage, DBusInterfaceMemberPath& dbusInterfaceMemberPath) { auto findIterator = stubDispatcherTable_.find(dbusInterfaceMemberPath); const bool foundInterfaceMemberHandler = (findIterator != stubDispatcherTable_.end()); bool dbusMessageHandled = false; if (foundInterfaceMemberHandler) { StubDispatcher* stubDispatcher = findIterator->second; dbusMessageHandled = stubDispatcher->dispatchDBusMessage(dbusMessage, stub_, getRemoteEventHandler(), getDBusConnection()); return dbusMessageHandled; } return DBusStubAdapterHelper::findDispatcherAndHandle(dbusMessage, dbusInterfaceMemberPath); } 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; } template void addStubDispatcher(DBusInterfaceMemberPath _dbusInterfaceMemberPath, StubDispatcher* _stubDispatcher) { addStubDispatcher(_dbusInterfaceMemberPath, _stubDispatcher, identity()); } template void addAttributeDispatcher(std::string _key, StubDispatcher* _stubDispatcherGetter, StubDispatcher* _stubDispatcherSetter) { addAttributeDispatcher(_key, _stubDispatcherGetter, _stubDispatcherSetter, identity()); } std::shared_ptr stub_; RemoteEventHandlerType* remoteEventHandler_; StubDispatcherTable stubDispatcherTable_; StubAttributeTable stubAttributeTable_; protected: bool handleFreedesktopGet(const DBusMessage &_message, DBusInputStream &_input) { std::string interfaceName; std::string attributeName; _input >> interfaceName; _input >> attributeName; if (_input.hasError()) { return false; } return findAttributeGetDispatcherAndHandle(interfaceName, attributeName, _message); } bool findAttributeGetDispatcherAndHandle(std::string interfaceName, std::string attributeName, const DBusMessage &_message) { auto attributeDispatcherIterator = stubAttributeTable_.find(attributeName); if (attributeDispatcherIterator == stubAttributeTable_.end()) { // not found, try parent return DBusStubAdapterHelper::findAttributeGetDispatcherAndHandle(interfaceName, attributeName, _message); } StubDispatcher* getterDispatcher = attributeDispatcherIterator->second.getter; if (NULL == getterDispatcher) { // all attributes have at least a getter COMMONAPI_ERROR(std::string(__FUNCTION__), "getterDispatcher == NULL"); return false; } else { return getterDispatcher->dispatchDBusMessage(_message, stub_, getRemoteEventHandler(), getDBusConnection()); } } bool handleFreedesktopSet(const DBusMessage& dbusMessage, DBusInputStream& dbusInputStream) { std::string interfaceName; std::string attributeName; dbusInputStream >> interfaceName; dbusInputStream >> attributeName; if(dbusInputStream.hasError()) { return false; } return findAttributeSetDispatcherAndHandle(interfaceName, attributeName, dbusMessage); } bool findAttributeSetDispatcherAndHandle(std::string interfaceName, std::string attributeName, const DBusMessage& dbusMessage) { auto attributeDispatcherIterator = stubAttributeTable_.find(attributeName); if(attributeDispatcherIterator == stubAttributeTable_.end()) { // not found, try parent return DBusStubAdapterHelper::findAttributeSetDispatcherAndHandle(interfaceName, attributeName, dbusMessage); } StubDispatcher *setterDispatcher = attributeDispatcherIterator->second.setter; if (setterDispatcher == NULL) { // readonly attributes do not have a setter return false; } return setterDispatcher->dispatchDBusMessage(dbusMessage, stub_, getRemoteEventHandler(), getDBusConnection()); } bool appendGetAllReply(const DBusMessage& dbusMessage, DBusOutputStream& dbusOutputStream) { for(auto attributeDispatcherIterator = stubAttributeTable_.begin(); attributeDispatcherIterator != stubAttributeTable_.end(); attributeDispatcherIterator++) { //To prevent the destruction of the stub whilst still handling a message if (stub_) { StubDispatcher* getterDispatcher = attributeDispatcherIterator->second.getter; if (NULL == getterDispatcher) { // all attributes have at least a getter COMMONAPI_ERROR(std::string(__FUNCTION__), "getterDispatcher == NULL"); return false; } else { dbusOutputStream.align(8); dbusOutputStream << attributeDispatcherIterator->first; getterDispatcher->appendGetAllReply(dbusMessage, stub_, dbusOutputStream); } } } return DBusStubAdapterHelper::appendGetAllReply(dbusMessage, dbusOutputStream); } private: template void addStubDispatcher(DBusInterfaceMemberPath _dbusInterfaceMemberPath, StubDispatcher* _stubDispatcher, identity) { DBusStubAdapterHelper::addStubDispatcher(_dbusInterfaceMemberPath, _stubDispatcher); } void addStubDispatcher(DBusInterfaceMemberPath _dbusInterfaceMemberPath, StubDispatcher* _stubDispatcher, identity) { stubDispatcherTable_.insert({_dbusInterfaceMemberPath, _stubDispatcher}); } template void addAttributeDispatcher(std::string _key, StubDispatcher* _stubDispatcherGetter, StubDispatcher* _stubDispatcherSetter, identity) { DBusStubAdapterHelper::addAttributeDispatcher(_key, _stubDispatcherGetter, _stubDispatcherSetter); } void addAttributeDispatcher(std::string _key, StubDispatcher* _stubDispatcherGetter, StubDispatcher* _stubDispatcherSetter, identity) { stubAttributeTable_.insert({_key, {_stubDispatcherGetter, _stubDispatcherSetter}}); } 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.beginWriteMap(); appendGetAllReply(dbusMessage, dbusOutputStream); dbusOutputStream.endWriteMap(); dbusOutputStream.flush(); return getDBusConnection()->sendDBusMessage(dbusMessageReply); } }; template< class > struct DBusStubSignalHelper; template class In_, class... InArgs_> struct DBusStubSignalHelper> { 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::serialize(outputStream, inArgs...); if (!success) { COMMONAPI_ERROR("DBusStubSignalHelper (dbus): serialization failed! [", dbusMessage.getObjectPath(), " ", dbusMessage.getInterface(), ".", dbusMessage.getMember(), " ", dbusMessage.getSerial()); 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::serialize(outputStream, inArgs...); if (!success) { COMMONAPI_ERROR("DBusStubSignalHelper 2 (dbus): serialization failed! [", dbusMessage.getObjectPath(), " ", dbusMessage.getInterface(), ".", dbusMessage.getMember(), " ", dbusMessage.getSerial()); return false; } outputStream.flush(); } return _stub.getDBusConnection()->sendDBusMessage(dbusMessage); } }; template< class, class, class > class DBusMethodStubDispatcher; template < typename StubClass_, template class In_, class... InArgs_, template class DeplIn_, class... DeplIn_Args> class DBusMethodStubDispatcher, DeplIn_ >: public StubDispatcher { public: typedef typename StubClass_::RemoteEventHandlerType RemoteEventHandlerType; typedef void (StubClass_::*StubFunctor_)(std::shared_ptr, InArgs_...); DBusMethodStubDispatcher(StubFunctor_ stubFunctor, const bool _isImplemented, std::tuple _in): stubFunctor_(stubFunctor), isImplemented_(_isImplemented) { initialize(typename make_sequence_range::type(), _in); } bool dispatchDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr& stub, RemoteEventHandlerType* _remoteEventHandler, std::weak_ptr _connection) { (void) _remoteEventHandler; (void) _connection; if (!this->isImplemented_) return false; return handleDBusMessage(dbusMessage, stub, typename make_sequence_range::type()); } private: template inline void initialize(index_sequence, std::tuple &_in) { in_ = std::make_tuple(std::get(_in)...); } template inline bool handleDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr& stub, index_sequence) { if (sizeof...(InArgs_) > 0) { DBusInputStream dbusInputStream(dbusMessage); const bool success = DBusSerializableArguments...>::deserialize(dbusInputStream, std::get(in_)...); if (!success) { COMMONAPI_ERROR("DBusMethodStubDispatcher (dbus): deserialization failed! [", dbusMessage.getObjectPath(), " ", dbusMessage.getInterface(), ".", dbusMessage.getMember(), " ", dbusMessage.getSerial()); return false; } } std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); (stub.get()->*stubFunctor_)(clientId, std::move(std::get(in_).getValue())...); return true; } StubFunctor_ stubFunctor_; const bool isImplemented_; std::tuple...> in_; }; template< class, class, class, class, class...> class DBusMethodWithReplyStubDispatcher; template < typename StubClass_, template class In_, class... InArgs_, template class Out_, class... OutArgs_, template class DeplIn_, class... DeplIn_Args, template class DeplOut_, class... DeplOutArgs_> class DBusMethodWithReplyStubDispatcher< StubClass_, In_, Out_, DeplIn_, DeplOut_>: public StubDispatcher { public: typedef typename StubClass_::RemoteEventHandlerType RemoteEventHandlerType; typedef std::function ReplyType_t; typedef void (StubClass_::*StubFunctor_)( std::shared_ptr, InArgs_..., ReplyType_t); DBusMethodWithReplyStubDispatcher(StubFunctor_ _stubFunctor, const char* _dbusReplySignature, const bool _isImplemented, const std::tuple &_inDepArgs, const std::tuple &_outDepArgs) : out_(_outDepArgs), currentCall_(0), isImplemented_(_isImplemented), stubFunctor_(_stubFunctor), dbusReplySignature_(_dbusReplySignature) { initialize(typename make_sequence_range::type(), _inDepArgs); } bool dispatchDBusMessage(const DBusMessage& _dbusMessage, const std::shared_ptr& _stub, RemoteEventHandlerType* _remoteEventHandler, std::weak_ptr _connection) { (void) _remoteEventHandler; if (!this->isImplemented_) return false; connection_ = _connection; return handleDBusMessage( _dbusMessage, _stub, typename make_sequence_range::type(), typename make_sequence_range::type()); } bool sendReply(const CommonAPI::CallId_t _call, const std::tuple...> args = std::make_tuple()) { { std::lock_guard lock(mutex_); auto dbusMessage = pending_.find(_call); if(dbusMessage != pending_.end()) { DBusMessage reply = dbusMessage->second.createMethodReturn(dbusReplySignature_); pending_[_call] = reply; } else { return false; } } return sendReplyInternal(_call, typename make_sequence_range::type(), args); } protected: std::tuple...> in_; std::tuple out_; CommonAPI::CallId_t currentCall_; std::map pending_; std::mutex mutex_; // protects pending_ std::weak_ptr connection_; const bool isImplemented_; private: template inline void initialize(index_sequence, const std::tuple& _in) { in_ = std::make_tuple(std::get(_in)...); } template inline bool handleDBusMessage(const DBusMessage& _dbusMessage, const std::shared_ptr& _stub, index_sequence, index_sequence) { if (sizeof...(DeplIn_Args) > 0) { DBusInputStream dbusInputStream(_dbusMessage); const bool success = DBusSerializableArguments...>::deserialize(dbusInputStream, std::get(in_)...); if (!success) { COMMONAPI_ERROR("DBusMethodWithReplyStubDispatcher (dbus): deserialization failed! [", _dbusMessage.getObjectPath(), " ", _dbusMessage.getInterface(), ".", _dbusMessage.getMember(), " ", _dbusMessage.getSerial()); return false; } } std::shared_ptr clientId = std::make_shared(std::string(_dbusMessage.getSender())); CommonAPI::CallId_t call; { std::lock_guard lock(mutex_); call = currentCall_++; pending_[call] = _dbusMessage; } (_stub.get()->*stubFunctor_)( clientId, std::move(std::get(in_).getValue())..., [call, this](OutArgs_... _args){ this->sendReply(call, std::make_tuple(CommonAPI::Deployable( _args, std::get(out_) )...)); } ); return true; } template bool sendReplyInternal(const CommonAPI::CallId_t _call, index_sequence, const std::tuple...>& _args) { std::lock_guard lock(mutex_); auto reply = pending_.find(_call); if (reply != pending_.end()) { if (sizeof...(DeplOutArgs_) > 0) { DBusOutputStream output(reply->second); if (!DBusSerializableArguments...>::serialize( output, std::get(_args)...)) { (void)_args; pending_.erase(_call); COMMONAPI_ERROR("DBusMethodWithReplyStubDispatcher (dbus): serialization failed! [", reply->second.getObjectPath(), " ", reply->second.getInterface(), ".", reply->second.getMember(), " ", reply->second.getSerial()); return false; } output.flush(); } if (std::shared_ptr connection = connection_.lock()) { bool isSuccessful = connection->sendDBusMessage(reply->second); pending_.erase(_call); return isSuccessful; } else { return false; } } return false; } StubFunctor_ stubFunctor_; const char* dbusReplySignature_; }; template < typename StubClass_, template class In_, class... InArgs_, template class Out_, class... OutArgs_, template class DeplIn_, class... DeplIn_Args, template class DeplOut_, class... DeplOutArgs_, class... ErrorReplies_> class DBusMethodWithReplyStubDispatcher< StubClass_, In_, Out_, DeplIn_, DeplOut_, ErrorReplies_...> : public DBusMethodWithReplyStubDispatcher< StubClass_, In_, Out_, DeplIn_, DeplOut_> { public: typedef typename StubClass_::RemoteEventHandlerType RemoteEventHandlerType; typedef std::function ReplyType_t; typedef void (StubClass_::*StubFunctor_)( std::shared_ptr, CommonAPI::CallId_t, InArgs_..., ReplyType_t, ErrorReplies_...); DBusMethodWithReplyStubDispatcher(StubFunctor_ _stubFunctor, const char* _dbusReplySignature, const bool _isImplemented, const std::tuple &_inDepArgs, const std::tuple &_outDepArgs, const ErrorReplies_... _errorReplies) : DBusMethodWithReplyStubDispatcher, Out_, DeplIn_, DeplOut_>(NULL, _dbusReplySignature, _isImplemented, _inDepArgs, _outDepArgs), stubFunctor_(_stubFunctor), errorReplies_(std::make_tuple(_errorReplies...)) { } bool dispatchDBusMessage(const DBusMessage& _dbusMessage, const std::shared_ptr& _stub, RemoteEventHandlerType* _remoteEventHandler, std::weak_ptr _connection) { (void) _remoteEventHandler; if (!this->isImplemented_) return false; this->connection_ = _connection; return handleDBusMessage( _dbusMessage, _stub, typename make_sequence_range::type(), typename make_sequence_range::type(), typename make_sequence_range::type()); } template bool sendErrorReply(const CommonAPI::CallId_t _call, const std::string &_signature, const std::string &_errorName, const std::tuple...>& _args) { { std::lock_guard lock(this->mutex_); auto dbusMessage = this->pending_.find(_call); if(dbusMessage != this->pending_.end()) { DBusMessage reply = dbusMessage->second.createMethodError(_errorName, _signature); this->pending_[_call] = reply; } else { return false; } } return sendErrorReplyInternal(_call, typename make_sequence_range::type(), _args); } private: template inline bool handleDBusMessage(const DBusMessage& _dbusMessage, const std::shared_ptr& _stub, index_sequence, index_sequence, index_sequence) { if (sizeof...(DeplIn_Args) > 0) { DBusInputStream dbusInputStream(_dbusMessage); const bool success = DBusSerializableArguments...>::deserialize(dbusInputStream, std::get(this->in_)...); if (!success) { COMMONAPI_ERROR("DBusMethodWithReplyStubDispatcher w/ error replies (dbus): deserialization failed! [", _dbusMessage.getObjectPath(), " ", _dbusMessage.getInterface(), ".", _dbusMessage.getMember(), " ", _dbusMessage.getSerial()); return false; } } std::shared_ptr clientId = std::make_shared(std::string(_dbusMessage.getSender())); CommonAPI::CallId_t call; { std::lock_guard lock(this->mutex_); call = this->currentCall_++; this->pending_[call] = _dbusMessage; } (_stub.get()->*stubFunctor_)( clientId, call, std::move(std::get(this->in_).getValue())..., [call, this](OutArgs_... _args){ this->sendReply(call, std::make_tuple(CommonAPI::Deployable( _args, std::get(this->out_) )...)); }, std::get(errorReplies_)... ); return true; } template bool sendErrorReplyInternal(CommonAPI::CallId_t _call, index_sequence, const std::tuple...>& _args) { std::lock_guard lock(this->mutex_); auto reply = this->pending_.find(_call); if (reply != this->pending_.end()) { if (sizeof...(ErrorReplyDeplOutArgs_) > 0) { DBusOutputStream output(reply->second); if (!DBusSerializableArguments...>::serialize( output, std::get(_args)...)) { (void)_args; this->pending_.erase(_call); COMMONAPI_ERROR("DBusMethodWithReplyStubDispatcher w/ error replies 2 (dbus): serialization failed! [", reply->second.getObjectPath(), " ", reply->second.getInterface(), ".", reply->second.getMember(), " ", reply->second.getSerial()); return false; } output.flush(); } if (std::shared_ptr connection = this->connection_.lock()) { bool isSuccessful = connection->sendDBusMessage(reply->second); this->pending_.erase(_call); return isSuccessful; } else { return false; } } return false; } StubFunctor_ stubFunctor_; std::tuple errorReplies_; }; template< class, class, class, class > class DBusMethodWithReplyAdapterDispatcher; template < typename StubClass_, typename StubAdapterClass_, template class In_, class... InArgs_, template class Out_, class... OutArgs_> class DBusMethodWithReplyAdapterDispatcher, Out_ > : public StubDispatcher { public: typedef typename StubClass_::RemoteEventHandlerType RemoteEventHandlerType; typedef void (StubAdapterClass_::*StubFunctor_)(std::shared_ptr, InArgs_..., OutArgs_&...); typedef typename CommonAPI::Stub StubType; DBusMethodWithReplyAdapterDispatcher(StubFunctor_ stubFunctor, const char* dbusReplySignature, const bool _isImplemented) : stubFunctor_(stubFunctor), dbusReplySignature_(dbusReplySignature), isImplemented_(_isImplemented) { } bool dispatchDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr& stub, RemoteEventHandlerType *_remoteEventHandler, std::weak_ptr _connection) { (void)_remoteEventHandler; if (!this->isImplemented_) return false; std::tuple argTuple; return handleDBusMessage( dbusMessage, stub, _connection, typename make_sequence_range::type(), typename make_sequence_range::type(),argTuple); } private: template inline bool handleDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr& stub, std::weak_ptr _connection, index_sequence, index_sequence, std::tuple argTuple) const { (void)argTuple; if (sizeof...(InArgs_) > 0) { DBusInputStream dbusInputStream(dbusMessage); const bool success = DBusSerializableArguments::deserialize(dbusInputStream, std::get(argTuple)...); if (!success) { COMMONAPI_ERROR("DBusMethodWithReplyAdapterDispatcher (dbus): deserialization failed! [", dbusMessage.getObjectPath(), " ", dbusMessage.getInterface(), ".", dbusMessage.getMember(), " ", dbusMessage.getSerial()); return false; } } std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); (stub->StubType::getStubAdapter().get()->*stubFunctor_)(clientId, std::move(std::get(argTuple))..., std::get(argTuple)...); DBusMessage dbusMessageReply = dbusMessage.createMethodReturn(dbusReplySignature_); if (sizeof...(OutArgs_) > 0) { DBusOutputStream dbusOutputStream(dbusMessageReply); const bool success = DBusSerializableArguments::serialize(dbusOutputStream, std::get(argTuple)...); if (!success) { COMMONAPI_ERROR("DBusMethodWithReplyAdapterDispatcher (dbus): serialization failed! [", dbusMessageReply.getObjectPath(), " ", dbusMessageReply.getInterface(), ".", dbusMessageReply.getMember(), " ", dbusMessageReply.getSerial()); return false; } dbusOutputStream.flush(); } if (std::shared_ptr connection = _connection.lock()) { bool isSuccessful = connection->sendDBusMessage(dbusMessageReply); return isSuccessful; } else { return false; } } StubFunctor_ stubFunctor_; const char* dbusReplySignature_; const bool isImplemented_; }; template class DBusGetAttributeStubDispatcher: public virtual StubDispatcher { public: typedef typename StubClass_::RemoteEventHandlerType RemoteEventHandlerType; typedef void (StubClass_::*LockStubFunctor)(bool); typedef const AttributeType_& (StubClass_::*GetStubFunctor)(std::shared_ptr); typedef typename StubClass_::StubAdapterType StubAdapterType; typedef typename CommonAPI::Stub StubType; DBusGetAttributeStubDispatcher(LockStubFunctor _lockStubFunctor, GetStubFunctor _getStubFunctor, const char *_signature, const bool _isImplemented, AttributeDepl_ *_depl = nullptr) : lockStubFunctor_(_lockStubFunctor), getStubFunctor_(_getStubFunctor), signature_(_signature), isImplemented_(_isImplemented), depl_(_depl) { } virtual ~DBusGetAttributeStubDispatcher() {}; bool dispatchDBusMessage(const DBusMessage& dbusMessage, const std::shared_ptr& stub, RemoteEventHandlerType* _remoteEventHandler, std::weak_ptr _connection) { (void) _remoteEventHandler; if (!this->isImplemented_) return false; return sendAttributeValueReply(dbusMessage, stub, _connection); } void appendGetAllReply(const DBusMessage& dbusMessage, const std::shared_ptr& stub, DBusOutputStream &_output) { std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); auto varDepl = CommonAPI::DBus::VariantDeployment(true, depl_); // presuming FreeDesktop variant deployment, as support for "legacy" service only (stub.get()->*lockStubFunctor_)(true); auto deployable = CommonAPI::Deployable, CommonAPI::DBus::VariantDeployment>((stub.get()->*getStubFunctor_)(clientId), &varDepl); (stub.get()->*lockStubFunctor_)(false); _output << deployable; _output.flush(); } protected: virtual bool sendAttributeValueReply(const DBusMessage& dbusMessage, const std::shared_ptr& stub, std::weak_ptr connection_) { DBusMessage dbusMessageReply = dbusMessage.createMethodReturn(signature_); DBusOutputStream dbusOutputStream(dbusMessageReply); std::shared_ptr clientId = std::make_shared(std::string(dbusMessage.getSender())); (stub.get()->*lockStubFunctor_)(true); auto deployable = CommonAPI::Deployable((stub.get()->*getStubFunctor_)(clientId), depl_); (stub.get()->*lockStubFunctor_)(false); dbusOutputStream << deployable; dbusOutputStream.flush(); if (std::shared_ptr connection = connection_.lock()) { bool isSuccessful = connection->sendDBusMessage(dbusMessageReply); return isSuccessful; } else { return false; } } LockStubFunctor lockStubFunctor_; GetStubFunctor getStubFunctor_; const char* signature_; const bool isImplemented_; AttributeDepl_ *depl_; }; template class DBusSetAttributeStubDispatcher: public virtual DBusGetAttributeStubDispatcher { public: typedef typename StubClass_::RemoteEventHandlerType RemoteEventHandlerType; typedef typename DBusGetAttributeStubDispatcher::LockStubFunctor LockStubFunctor; typedef typename DBusGetAttributeStubDispatcher::GetStubFunctor GetStubFunctor; typedef bool (RemoteEventHandlerType::*OnRemoteSetFunctor)(std::shared_ptr, AttributeType_); typedef void (RemoteEventHandlerType::*OnRemoteChangedFunctor)(); DBusSetAttributeStubDispatcher(LockStubFunctor _lockStubFunctor, GetStubFunctor _getStubFunctor, OnRemoteSetFunctor onRemoteSetFunctor, OnRemoteChangedFunctor onRemoteChangedFunctor, const char *_signature, const bool _isImplemented, AttributeDepl_ *_depl = nullptr) : DBusGetAttributeStubDispatcher(_lockStubFunctor, _getStubFunctor, _signature, _isImplemented, _depl), onRemoteSetFunctor_(onRemoteSetFunctor), onRemoteChangedFunctor_(onRemoteChangedFunctor) { } virtual ~DBusSetAttributeStubDispatcher() {}; bool dispatchDBusMessage(const DBusMessage &_message, const std::shared_ptr &_stub, RemoteEventHandlerType *_remoteEventHandler, std::weak_ptr _connection) { bool attributeValueChanged; if (!this->isImplemented_) return false; if (!setAttributeValue(_message, _stub, _remoteEventHandler, _connection, attributeValueChanged)) return false; if (attributeValueChanged) notifyOnRemoteChanged(_remoteEventHandler); return true; } protected: virtual AttributeType_ retrieveAttributeValue(const DBusMessage &_message, bool &_errorOccured) { _errorOccured = false; DBusInputStream itsInput(_message); CommonAPI::Deployable itsValue(this->depl_); itsInput >> itsValue; if (itsInput.hasError()) { _errorOccured = true; } return itsValue.getValue(); } inline bool setAttributeValue(const DBusMessage &_message, const std::shared_ptr &_stub, RemoteEventHandlerType *_remoteEventHandler, std::weak_ptr _connection, bool &_hasChanged) { bool errorOccured; CommonAPI::Deployable itsValue( retrieveAttributeValue(_message, errorOccured), this->depl_); if (errorOccured) { return false; } std::shared_ptr clientId = std::make_shared(std::string(_message.getSender())); _hasChanged = (_remoteEventHandler->*onRemoteSetFunctor_)(clientId, std::move(itsValue.getValue())); return this->sendAttributeValueReply(_message, _stub, _connection); } inline void notifyOnRemoteChanged(RemoteEventHandlerType *_remoteEventHandler) { (_remoteEventHandler->*onRemoteChangedFunctor_)(); } inline AttributeType_ getAttributeValue(std::shared_ptr _client, const std::shared_ptr &_stub) { return (_stub.get()->*(this->getStubFunctor_))(_client); } const OnRemoteSetFunctor onRemoteSetFunctor_; const OnRemoteChangedFunctor onRemoteChangedFunctor_; }; template class DBusSetObservableAttributeStubDispatcher: public virtual DBusSetAttributeStubDispatcher { public: typedef typename StubClass_::RemoteEventHandlerType RemoteEventHandlerType; typedef typename StubClass_::StubAdapterType StubAdapterType; typedef typename DBusGetAttributeStubDispatcher::LockStubFunctor LockStubFunctor; typedef typename DBusSetAttributeStubDispatcher::GetStubFunctor GetStubFunctor; typedef typename DBusSetAttributeStubDispatcher::OnRemoteSetFunctor OnRemoteSetFunctor; typedef typename DBusSetAttributeStubDispatcher::OnRemoteChangedFunctor OnRemoteChangedFunctor; typedef typename CommonAPI::Stub StubType; typedef void (StubAdapterType::*FireChangedFunctor)(const AttributeType_&); DBusSetObservableAttributeStubDispatcher(LockStubFunctor _lockStubFunctor, GetStubFunctor _getStubFunctor, OnRemoteSetFunctor onRemoteSetFunctor, OnRemoteChangedFunctor onRemoteChangedFunctor, FireChangedFunctor fireChangedFunctor, const char* dbusSignature, const bool _isImplemented, AttributeDepl_ *_depl = nullptr) : DBusGetAttributeStubDispatcher( _lockStubFunctor, _getStubFunctor, dbusSignature, _isImplemented, _depl), DBusSetAttributeStubDispatcher( _lockStubFunctor, _getStubFunctor, onRemoteSetFunctor, onRemoteChangedFunctor, dbusSignature, _depl), fireChangedFunctor_(fireChangedFunctor) { } virtual ~DBusSetObservableAttributeStubDispatcher() {}; bool dispatchDBusMessage(const DBusMessage &_message, const std::shared_ptr &_stub, RemoteEventHandlerType *_remoteEventHandler, std::weak_ptr _connection) { if (!this->isImplemented_) return false; bool hasChanged; if (!this->setAttributeValue(_message, _stub, _remoteEventHandler, _connection, hasChanged)) return false; if (hasChanged) { std::shared_ptr itsClient = std::make_shared(std::string(_message.getSender())); fireAttributeValueChanged(itsClient, _remoteEventHandler, _stub); this->notifyOnRemoteChanged(_remoteEventHandler); } return true; } protected: virtual void fireAttributeValueChanged(std::shared_ptr _client, RemoteEventHandlerType *_remoteEventHandler, const std::shared_ptr _stub) { (void)_remoteEventHandler; auto stubAdapter = _stub->StubType::getStubAdapter(); (_stub.get()->*DBusGetAttributeStubDispatcher::lockStubFunctor_)(true); (stubAdapter.get()->*fireChangedFunctor_)(this->getAttributeValue(_client, _stub)); (_stub.get()->*DBusGetAttributeStubDispatcher::lockStubFunctor_)(false); } const FireChangedFunctor fireChangedFunctor_; }; } // namespace DBus } // namespace CommonAPI #endif // COMMONAPI_DBUS_DBUSSTUBADAPTERHELPER_HPP_