diff --git a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp index a53e04a2a92d5062dcb8785ca94301c44fc7865c..c76da14105facaf03ff55742b22ac968fe1fd196 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp +++ b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp @@ -6,24 +6,26 @@ namespace armarx::plugins { - void SkillProviderComponentPlugin::preOnInitComponent() + void + SkillProviderComponentPlugin::preOnInitComponent() { - } - void SkillProviderComponentPlugin::preOnConnectComponent() + void + SkillProviderComponentPlugin::preOnConnectComponent() { auto& p = parent<SkillProviderComponentPluginUser>(); p.getProxy(myPrx, -1); } - void SkillProviderComponentPlugin::postOnConnectComponent() + void + SkillProviderComponentPlugin::postOnConnectComponent() { auto& p = parent<SkillProviderComponentPluginUser>(); const std::string providerName = p.getName(); // update skill ownership - for (auto& [skillName, impl] : p.skillImplementations) + for (auto& [skillName, impl] : skillImplementations) { impl.skill->manager = manager; impl.skill->providerName = providerName; @@ -38,10 +40,11 @@ namespace armarx::plugins i.providedSkills = p.getSkillDescriptions(); manager->addProvider(i); - p.connected = true; + connected = true; } - void SkillProviderComponentPlugin::preOnDisconnectComponent() + void + SkillProviderComponentPlugin::preOnDisconnectComponent() { auto& p = parent<SkillProviderComponentPluginUser>(); std::string providerName = p.getName(); @@ -49,22 +52,27 @@ namespace armarx::plugins manager->removeProvider(providerName); } - void SkillProviderComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) + void + SkillProviderComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) { std::string prefix = "skill."; - properties->component(manager, "SkillMemory", prefix + "SkillManager", "The name of the SkillManager (or SkillMemory) proxy this provider belongs to."); + properties->component( + manager, + "SkillMemory", + prefix + "SkillManager", + "The name of the SkillManager (or SkillMemory) proxy this provider belongs to."); } -} - -namespace armarx -{ - SkillProviderComponentPluginUser::SkillProviderComponentPluginUser() + void + SkillProviderComponentPlugin::addSkill(const skills::LambdaSkill::FunT& f, + const skills::SkillDescription& desc) { - addPlugin(plugin); + auto lambda = std::make_unique<skills::LambdaSkill>(f, desc); + addSkill(std::move(lambda)); } - void SkillProviderComponentPluginUser::addSkill(std::unique_ptr<skills::Skill>&& skill) + void + SkillProviderComponentPlugin::addSkill(std::unique_ptr<skills::Skill>&& skill) { if (!skill) { @@ -74,70 +82,119 @@ namespace armarx std::string skillName = skill->description.skillName; if (connected) // TODO: fix so that skills can be added anytime!!! { - ARMARX_WARNING << "The SkillProvider already registered to a manager. The skill '" + skillName + "' therefore cannot be added anymore. Please only add skills in the onInit method."; + ARMARX_WARNING << "The SkillProvider already registered to a manager. The skill '" + + skillName + + "' therefore cannot be added anymore. Please only add skills in " + "the onInit method."; return; } // lock skills map - std::unique_lock l(skillsMutex); + const std::unique_lock l(skillsMutex); if (skillImplementations.find(skillName) != skillImplementations.end()) { - ARMARX_WARNING << "Try to add a skill '" + skillName + "' which already exists in list. Ignoring this skill."; + ARMARX_WARNING << "Try to add a skill '" + skillName + + "' which already exists in list. Ignoring this skill."; return; } ARMARX_INFO << "Adding skill and set owning provider name" << skillName; auto s = skillImplementations.emplace(skillName, std::move(skill)); - s.first->second.statusUpdate.skillId = skills::SkillID(getName(), skillName); + s.first->second.statusUpdate.skillId = skills::SkillID(parent().getName(), skillName); } - void SkillProviderComponentPluginUser::addSkill(const skills::LambdaSkill::FunT& f, const skills::SkillDescription& desc) + skills::detail::SkillImplementationWrapper& + SkillProviderComponentPlugin::getSkill(const std::string& name) { - auto lambda = std::make_unique<skills::LambdaSkill>(f, desc); - addSkill(std::move(lambda)); + ARMARX_CHECK_GREATER(skillImplementations.count(name), 0) + << "Skill '" + name + "' not found."; + const std::unique_lock l(skillsMutex); + return skillImplementations.at(name); } - skills::provider::dto::SkillDescription SkillProviderComponentPluginUser::getSkillDescription(const std::string& name, const Ice::Current &) + skills::provider::dto::SkillStatusUpdateMap + SkillProviderComponentPlugin::getSkillExecutionStatuses() const { - std::shared_lock l(skillsMutex); - const auto& skillWrapper = skillImplementations.at(name); - return skillWrapper.skill->description.toIce(); + skills::provider::dto::SkillStatusUpdateMap skillUpdates; + const std::unique_lock l(skillsMutex); + for (const auto& [key, impl] : skillImplementations) + { + const std::shared_lock l2(impl.skillStatusMutex); + skillUpdates.insert({key, impl.statusUpdate.toIce()}); + } + return skillUpdates; } - skills::provider::dto::SkillDescriptionMap SkillProviderComponentPluginUser::getSkillDescriptions(const Ice::Current &) + skills::provider::dto::SkillDescriptionMap + SkillProviderComponentPlugin::getSkillDescriptions() const { - std::shared_lock l(skillsMutex); skills::provider::dto::SkillDescriptionMap skillDesciptions; - for (const auto& [key, skillWrapper] : skillImplementations) + const std::unique_lock l(skillsMutex); + for (const auto& [key, impl] : skillImplementations) { - skillDesciptions.insert({key, skillWrapper.skill->description.toIce()}); + skillDesciptions.insert({key, impl.skill->description.toIce()}); } return skillDesciptions; } - skills::provider::dto::SkillStatusUpdate SkillProviderComponentPluginUser::getSkillExecutionStatus(const std::string& skill, const Ice::Current &) +} // namespace armarx::plugins + +namespace armarx +{ + SkillProviderComponentPluginUser::SkillProviderComponentPluginUser() + { + addPlugin(plugin); + } + + void + SkillProviderComponentPluginUser::addSkill(std::unique_ptr<skills::Skill>&& skill) { - std::shared_lock l(skillsMutex); - auto& skillWrapper = skillImplementations.at(skill); + plugin->addSkill(std::move(skill)); + } + + void + SkillProviderComponentPluginUser::addSkill(const skills::LambdaSkill::FunT& f, + const skills::SkillDescription& desc) + { + plugin->addSkill(f, desc); + } + + skills::provider::dto::SkillDescription + SkillProviderComponentPluginUser::getSkillDescription(const std::string& name, + const Ice::Current& /*unused*/) + { + + const auto& skillWrapper = plugin->getSkill(name); + return skillWrapper.skill->description.toIce(); + } + + skills::provider::dto::SkillDescriptionMap + SkillProviderComponentPluginUser::getSkillDescriptions(const Ice::Current& /*unused*/) + { + return plugin->getSkillDescriptions(); + } - std::shared_lock l2(skillWrapper.skillStatusMutex); + skills::provider::dto::SkillStatusUpdate + SkillProviderComponentPluginUser::getSkillExecutionStatus(const std::string& skill, + const Ice::Current& /*unused*/) + { + auto& skillWrapper = plugin->getSkill(skill); + + const std::shared_lock l(skillWrapper.skillStatusMutex); return skillWrapper.statusUpdate.toIce(); } - skills::provider::dto::SkillStatusUpdateMap SkillProviderComponentPluginUser::getSkillExecutionStatuses(const Ice::Current &) + skills::provider::dto::SkillStatusUpdateMap + SkillProviderComponentPluginUser::getSkillExecutionStatuses(const Ice::Current& /*unused*/) { - std::shared_lock l(skillsMutex); - skills::provider::dto::SkillStatusUpdateMap skillUpdates; - for (const auto& [key, skillWrapper] : skillImplementations) - { - std::shared_lock l2(skillWrapper.skillStatusMutex); - skillUpdates.insert({key, skillWrapper.statusUpdate.toIce()}); - } - return skillUpdates; + return plugin->getSkillExecutionStatuses(); } // Please not that this method waits until the skill can be scheduled! - skills::provider::dto::SkillStatusUpdate SkillProviderComponentPluginUser::executeSkill(const skills::provider::dto::SkillExecutionRequest& info, const Ice::Current &) + skills::provider::dto::SkillStatusUpdate + SkillProviderComponentPluginUser::executeSkill( + const skills::provider::dto::SkillExecutionRequest& info, + const Ice::Current& /*unused*/) { // The skill will be executed in a different thread std::thread execution; @@ -149,19 +206,17 @@ namespace armarx skills::provider::dto::SkillStatusUpdate ret; { - std::shared_lock l(skillsMutex); - std::string skillName = info.skillName; - ARMARX_CHECK_EXPRESSION(skillImplementations.count(skillName) > 0) << "\nThe names are: " << VAROUT(skillName) << ", " << VAROUT(getName()); - - // get reference of the wrapper - auto& wrapper = skillImplementations.at(skillName); + const std::string skillName = info.skillName; + auto& wrapper = plugin->getSkill(skillName); // async start execution. But we wait for the execution to finish at the end of this method - execution = std::thread([&ret, &wrapper, &info, &usedParameterization](){ - // execute waits until the previous execution finishes. - auto x = wrapper.setupAndExecuteSkill(info.executorName, usedParameterization); - ret = x.toIce(); - }); + execution = std::thread( + [&ret, &wrapper, &info, &usedParameterization]() + { + // execute waits until the previous execution finishes. + auto x = wrapper.setupAndExecuteSkill(info.executorName, usedParameterization); + ret = x.toIce(); + }); } // release lock. We don't know how long the skill needs to finish and we have to release the lock for being able to abort the execution if (execution.joinable()) @@ -171,12 +226,16 @@ namespace armarx return ret; } - void SkillProviderComponentPluginUser::abortSkill(const std::string& skillName, const Ice::Current &) + void + SkillProviderComponentPluginUser::abortSkill(const std::string& skillName, const Ice::Current& /*unused*/) { - std::shared_lock l(skillsMutex); - ARMARX_CHECK_EXPRESSION(skillImplementations.count(skillName) > 0); - - auto& wrapper = skillImplementations.at(skillName); + auto& wrapper = plugin->getSkill(skillName); wrapper.skill->notifySkillToStopASAP(); } -} + + const std::experimental::observer_ptr<plugins::SkillProviderComponentPlugin>& + SkillProviderComponentPluginUser::getSkillProviderPlugin() const + { + return plugin; + } +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h index d6d8a49a944aa190c47152aced4065bd15a19885..6b74dd1e2479068ca920dde2b8f2ec102b0d7646 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h +++ b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h @@ -1,29 +1,32 @@ #pragma once -#include <shared_mutex> +#include <functional> #include <queue> +#include <shared_mutex> #include <thread> -#include <functional> #include <type_traits> +#include <experimental/memory> #include <ArmarXCore/core/ComponentPlugin.h> #include <ArmarXCore/core/ManagedIceObject.h> - #include <ArmarXCore/core/services/tasks/RunningTask.h> #include <RobotAPI/interface/skills/SkillManagerInterface.h> #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> // Include all types of skills -#include "Skill.h" -#include "SpecializedSkill.h" #include "LambdaSkill.h" #include "PeriodicSkill.h" #include "PeriodicSpecializedSkill.h" +#include "Skill.h" +#include "SpecializedSkill.h" // Helper wrapper for execution #include "detail/SkillImplementationWrapper.h" - +namespace armarx +{ + class SkillProviderComponentPluginUser; // forward declaration +} namespace armarx::plugins { class SkillProviderComponentPlugin : public ComponentPlugin @@ -40,53 +43,82 @@ namespace armarx::plugins void preOnDisconnectComponent() override; + void addSkill(const skills::LambdaSkill::FunT&, const skills::SkillDescription&); + void addSkill(std::unique_ptr<skills::Skill>&&); + + template <typename T> + T* + addSkill() + { + static_assert(std::is_base_of<skills::Skill, T>::value, + "T must be derived from skills::Skill!"); + static_assert(std::is_default_constructible<T>::value, + "T must be default constructible!"); + + auto skill = std::make_unique<T>(); + auto* skillPtr = skill.get(); + addSkill(std::move(skill)); + return static_cast<T*>(skillPtr); + } + private: + skills::detail::SkillImplementationWrapper& getSkill(const std::string& name); + skills::provider::dto::SkillStatusUpdateMap getSkillExecutionStatuses() const; + skills::provider::dto::SkillDescriptionMap getSkillDescriptions() const; + skills::manager::dti::SkillManagerInterfacePrx manager; skills::provider::dti::SkillProviderInterfacePrx myPrx; + + mutable std::shared_mutex skillsMutex; + + bool connected = false; + std::map<std::string, skills::detail::SkillImplementationWrapper> skillImplementations; + + friend class armarx::SkillProviderComponentPluginUser; }; -} +} // namespace armarx::plugins namespace armarx { class SkillProviderComponentPluginUser : - virtual public ManagedIceObject, - virtual public skills::provider::dti::SkillProviderInterface + virtual public ManagedIceObject, + virtual public skills::provider::dti::SkillProviderInterface { public: SkillProviderComponentPluginUser(); - skills::provider::dto::SkillDescription getSkillDescription(const std::string&, const Ice::Current ¤t = Ice::Current()) override; - skills::provider::dto::SkillDescriptionMap getSkillDescriptions(const Ice::Current ¤t = Ice::Current()) override; - skills::provider::dto::SkillStatusUpdate getSkillExecutionStatus(const std::string& skill, const Ice::Current ¤t = Ice::Current()) override; - skills::provider::dto::SkillStatusUpdateMap getSkillExecutionStatuses(const Ice::Current ¤t = Ice::Current()) override; - - skills::provider::dto::SkillStatusUpdate executeSkill(const skills::provider::dto::SkillExecutionRequest& executionInfo, const Ice::Current ¤t = Ice::Current()) override; - void abortSkill(const std::string& name, const Ice::Current ¤t = Ice::Current()) override; + skills::provider::dto::SkillDescription + getSkillDescription(const std::string&, + const Ice::Current& current = Ice::Current()) override; + skills::provider::dto::SkillDescriptionMap + getSkillDescriptions(const Ice::Current& current = Ice::Current()) override; + skills::provider::dto::SkillStatusUpdate + getSkillExecutionStatus(const std::string& skill, + const Ice::Current& current = Ice::Current()) override; + skills::provider::dto::SkillStatusUpdateMap + getSkillExecutionStatuses(const Ice::Current& current = Ice::Current()) override; + + skills::provider::dto::SkillStatusUpdate + executeSkill(const skills::provider::dto::SkillExecutionRequest& executionInfo, + const Ice::Current& current = Ice::Current()) override; + void abortSkill(const std::string& name, + const Ice::Current& current = Ice::Current()) override; + + const std::experimental::observer_ptr<plugins::SkillProviderComponentPlugin>& + getSkillProviderPlugin() const; protected: void addSkill(const skills::LambdaSkill::FunT&, const skills::SkillDescription&); void addSkill(std::unique_ptr<skills::Skill>&&); - template<typename T> - T* addSkill() + template <typename T> + T* + addSkill() { - static_assert(std::is_base_of<skills::Skill, T>::value, "T must be derived from skills::Skill!"); - static_assert(std::is_default_constructible<T>::value, "T must be default constructible!"); - - auto skill = std::make_unique<T>(); - auto* skillPtr = skill.get(); - addSkill(std::move(skill)); - return static_cast<T*>(skillPtr); + return plugin->addSkill<T>(); } private: - armarx::plugins::SkillProviderComponentPlugin* plugin = nullptr; - - protected: - mutable std::shared_mutex skillsMutex; - - public: - bool connected = false; - std::map<std::string, skills::detail::SkillImplementationWrapper> skillImplementations; + std::experimental::observer_ptr<plugins::SkillProviderComponentPlugin> plugin = nullptr; }; -} +} // namespace armarx