SkillProviderComponentPlugin.cpp
Go to the documentation of this file.
2
3#include <chrono>
4#include <exception>
5#include <experimental/memory>
6#include <map>
7#include <memory>
8#include <mutex>
9#include <optional>
10#include <shared_mutex>
11#include <sstream>
12#include <string>
13#include <thread>
14#include <tuple>
15#include <utility>
16
17#include <Ice/Current.h>
18#include <IceUtil/Optional.h>
19
25
26#include <RobotAPI/interface/aron/Aron.h>
27#include <RobotAPI/interface/skills/SkillManagerInterface.h>
28#include <RobotAPI/interface/skills/SkillProviderInterface.h>
41
42namespace armarx::plugins
43{
44 void
48
49 void
55
56 void
58 {
60 const std::string providerName = p.getName();
61
62 // register self to manager
63 skills::ProviderInfo i{.providerId = skills::ProviderID{.providerName = providerName},
64 .providerInterface = myPrx,
65 .providedSkills = getSkillDescriptions()};
66
67 ARMARX_INFO << "Adding provider to manager: " << i.providerId;
68 manager->addProvider(i.toIce()); // add provider info to manager
69 }
70
71 void
73 {
75 std::string providerName = p.getName();
76
77 auto id = skills::manager::dto::ProviderID{providerName};
78 manager->removeProvider(id);
79
80 // Drain all in-flight executions before tearing down the runtimes.
81 // Joining must happen before destroying the SkillRuntime objects
82 // because each runtime owns its own std::thread, which must not be
83 // destroyed while joinable (would call std::terminate).
84 std::vector<std::shared_ptr<skills::detail::SkillRuntime>> drained;
85 {
86 const std::unique_lock l(skillExecutionsMutex);
87 for (auto& [id, runtime] : skillExecutions)
88 {
89 drained.push_back(std::move(runtime));
90 }
91 skillExecutions.clear();
92 }
93 ARMARX_INFO << "Waiting for " << drained.size()
94 << " skill executions to finish before disconnect.";
95 for (auto& runtime : drained)
96 {
97 if (not runtime or not runtime->execution.joinable())
98 {
99 continue;
100 }
101 runtime->stopSkill();
102
103 const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5);
104 bool terminated = false;
105 while (not terminated and std::chrono::steady_clock::now() < deadline)
106 {
107 {
108 std::scoped_lock l(runtime->skillStatusesMutex);
109 terminated = runtime->statusUpdate.hasBeenTerminated();
110 }
111 if (not terminated)
112 {
113 std::this_thread::sleep_for(std::chrono::milliseconds(20));
114 }
115 }
116
117 if (terminated)
118 {
119 runtime->execution.join();
120 }
121 else
122 {
123 ARMARX_WARNING << "Skill execution '" << runtime->statusUpdate.executionId.skillId
124 << "' did not terminate within 5s during disconnect. Detaching.";
125 runtime->execution.detach();
126 }
127 }
128 drained.clear();
129
130 // remove all skills
131 ARMARX_INFO << "Removing all skills";
132 skillFactories.clear();
133 }
134
135 void
137 {
138 std::string prefix = "skill.";
139 properties->component(
140 manager,
141 "SkillMemory",
142 prefix + "SkillManager",
143 "The name of the SkillManager (or SkillMemory) proxy this provider belongs to.");
144 properties->topic<armarx::skills::SkillEventListenerInterface>(
145 "SkillEventListener", prefix + "tpc.sub.SkillEventListener");
146 }
147
148 void
149 SkillProviderComponentPlugin::addSkillFactory(std::unique_ptr<skills::SkillBlueprint>&& fac)
150 {
151 if (!fac)
152 {
153 return;
154 }
155
157 const std::string componentName = p.getName();
158
159 const skills::ProviderID providerId({componentName});
160
161 // lock skills map
162 const std::unique_lock l(skillFactoriesMutex);
163 auto skillId = fac->createSkillDescription(providerId).skillId;
164
165 if (skillFactories.find(skillId) != skillFactories.end())
166 {
167 ARMARX_WARNING << "Try to add a skill factory for skill '" + skillId.toString() +
168 "' which already exists in list. Ignoring this skill.";
169 return;
170 }
171
172 ARMARX_INFO << "Adding skill `" << skillId << "` to component `" << componentName << "` .";
173
174 skillFactories.emplace(skillId, std::move(fac));
175
176
177 // if (connected)
178 // {
179 // // if skill is added after onConnect we have to set the proxies manually.
180 // std::string providerName = parent().getName();
181 // s.first->second.skill->manager = manager;
182 // s.first->second.skill->providerName = providerName;
183 // }
184 }
185
192
194 SkillProviderComponentPlugin::getSkillFactory(const armarx::skills::SkillID& skillId)
195 {
196 // NON BLOCKING: WE ASSERT THAT THE LOCK IS ALREADY TAKEN
198
199 if (skillFactories.count(skillId) == 0)
200 {
201 ARMARX_INFO << "Could not find a skill factory for id: " << skillId;
202 return nullptr;
203 }
204
205 auto* facPtr = skillFactories.at(skillId).get();
206 return static_cast<skills::SkillBlueprint*>(facPtr);
207 }
208
209 std::optional<skills::SkillStatusUpdate>
211 const skills::SkillExecutionID& execId) const
212 {
214
215 const std::shared_lock l(skillExecutionsMutex);
216 auto it = skillExecutions.find(execId);
217 if (it == skillExecutions.end())
218 {
219 ARMARX_WARNING << "Skill execution for skill '" + execId.skillId.toString() +
220 "' not found!";
221 return std::nullopt;
222 }
223
224 std::scoped_lock l2{it->second->skillStatusesMutex};
225 return it->second->statusUpdate;
226 }
227
228 std::map<skills::SkillExecutionID, skills::SkillStatusUpdate>
230 {
231 std::map<skills::SkillExecutionID, skills::SkillStatusUpdate> skillUpdates;
232
233 const std::shared_lock l(skillExecutionsMutex);
234 for (const auto& [key, impl] : skillExecutions)
235 {
236 const std::scoped_lock l2(impl->skillStatusesMutex);
237 skillUpdates.insert({key, impl->statusUpdate});
238 }
239 return skillUpdates;
240 }
241
242 std::optional<skills::SkillDescription>
244 {
246
247 const std::shared_lock l(skillFactoriesMutex);
248 if (skillFactories.find(skillId) == skillFactories.end())
249 {
250 std::stringstream ss;
251 ss << "Skill description for skill '" + skillId.toString() +
252 "' not found! Found instead: {"
253 << "\n";
254 for (const auto& [k, _] : skillFactories)
255 {
256 ss << "\t" << k.toString() << "\n";
257 }
258 ss << "}";
259 ARMARX_WARNING << ss.str();
260
261 return std::nullopt;
262 }
263
264 return skillFactories.at(skillId)->createSkillDescription(*skillId.providerId);
265 }
266
267 std::map<skills::SkillID, skills::SkillDescription>
269 {
270 std::map<skills::SkillID, skills::SkillDescription> skillDesciptions;
271 const std::shared_lock l(skillFactoriesMutex);
272 for (const auto& [key, fac] : skillFactories)
273 {
274 ARMARX_CHECK(key.isFullySpecified());
275 skillDesciptions.insert({key, fac->createSkillDescription(*key.providerId)});
276 }
277 return skillDesciptions;
278 }
279
282 const skills::SkillExecutionRequest& executionRequest)
283 {
284 ARMARX_CHECK(executionRequest.skillId.isFullySpecified());
285
286 skills::SkillExecutionID executionId{.skillId = executionRequest.skillId,
287 .executorName = executionRequest.executorName,
288 .executionStartedTime =
290
292 {executionId, executionRequest.parameters, executionRequest.callbackInterface}};
293
294 std::shared_ptr<skills::detail::SkillRuntime> runtime;
295 std::vector<std::shared_ptr<skills::detail::SkillRuntime>> finishedToJoin;
296 {
297 auto l1 = std::unique_lock{skillFactoriesMutex};
298
299 const auto& fac = getSkillFactory(executionId.skillId);
300 ARMARX_CHECK(fac) << "Could not find a factory for skill " << executionId.skillId;
301
302 {
303 const std::unique_lock l2{skillExecutionsMutex};
304
305 // Drop terminated executions from the map. Joining must be
306 // done outside the lock to avoid blocking other API calls
307 // while we wait for a thread to finish.
308 finishedToJoin = collectFinishedExecutions_locked();
309
310 runtime = std::make_shared<skills::detail::SkillRuntime>(
311 fac,
312 executionId,
313 executionRequest.parameters,
314 executionRequest.callbackInterface);
315 skillExecutions.emplace(executionId, runtime);
316 auto const loggingLevel = parent().getEffectiveLoggingLevel();
317 ARMARX_VERBOSE << "Setting skill runtime's logging level to `"
318 << armarx::LogSender::levelToString(loggingLevel) << "`.";
319 runtime->setLocalMinimumLoggingLevel(loggingLevel);
320
321 // Capture the shared_ptr by VALUE so the runtime is kept
322 // alive for as long as the lambda runs, even if the map
323 // entry is erased concurrently. `ret` is captured by
324 // reference because we join the thread before returning
325 // from this function.
326 runtime->execution = std::thread(
327 [runtime, &ret]()
328 {
329 try
330 {
331 auto x = runtime->executeSkill();
332 ret.result = x.result;
333 ret.status = armarx::skills::toSkillStatus(x.status);
334 }
335 catch (std::exception& e)
336 {
337 ARMARX_WARNING << "Got an uncaught exception when executing a "
338 "skill. Exception was: "
339 << e.what();
340 }
341 });
342 }
343 } // 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
344
345 // Drain previously finished executions outside the lock.
346 for (auto& finished : finishedToJoin)
347 {
348 if (finished && finished->execution.joinable())
349 {
350 finished->execution.join();
351 }
352 }
353 finishedToJoin.clear();
354
355 if (runtime && runtime->execution.joinable())
356 {
357 runtime->execution.join();
358 }
359 return ret;
360 }
361
364 const skills::SkillExecutionRequest& executionRequest)
365 {
366 ARMARX_CHECK(executionRequest.skillId.isFullySpecified());
367
368 skills::SkillExecutionID executionId;
369
370 std::shared_ptr<skills::detail::SkillRuntime> runtime;
371 std::vector<std::shared_ptr<skills::detail::SkillRuntime>> finishedToJoin;
372 {
373 auto l1 = std::unique_lock{skillFactoriesMutex};
374
375 const auto& fac = getSkillFactory(executionRequest.skillId);
376 ARMARX_CHECK(fac) << "Could not find a factory for skill " << executionRequest.skillId;
377
378 {
379 const std::unique_lock l2{skillExecutionsMutex};
380
381 // Drop terminated executions from the map.
382 finishedToJoin = collectFinishedExecutions_locked();
383
384 executionId = skills::SkillExecutionID{executionRequest.skillId,
385 executionRequest.executorName,
387
388 if (skillExecutions.count(executionId) > 0)
389 {
390 ARMARX_ERROR << "SkillsExecutionID already exists! This is undefined behaviour "
391 "and should not occur!";
392 }
393
394 runtime = std::make_shared<skills::detail::SkillRuntime>(
395 fac,
396 executionId,
397 executionRequest.parameters,
398 executionRequest.callbackInterface);
399 skillExecutions.emplace(executionId, runtime);
400 auto const loggingLevel = parent().getEffectiveLoggingLevel();
401 ARMARX_INFO << "Setting skill runtime's logging level to `"
402 << armarx::LogSender::levelToString(loggingLevel) << "`.";
403 runtime->setLocalMinimumLoggingLevel(loggingLevel);
404
405 // Capture the shared_ptr by VALUE. The function returns
406 // before the thread finishes, so a reference capture would
407 // dangle as soon as the local `runtime` variable is
408 // destroyed -> use-after-free.
409 runtime->execution = std::thread(
410 [runtime]()
411 {
412 try
413 {
414 auto x = runtime->executeSkill();
415 (void)x;
416 }
417 catch (std::exception& e)
418 {
419 ARMARX_WARNING << "Got an uncaught exception when executing a "
420 "skill. Exception was: "
421 << e.what();
422 }
423 });
424 }
425 }
426
427 // Drain previously finished executions outside the lock.
428 for (auto& finished : finishedToJoin)
429 {
430 if (finished && finished->execution.joinable())
431 {
432 finished->execution.join();
433 }
434 }
435 finishedToJoin.clear();
436
437 // wait until skill is constructed. This assures, that a status update exists.
438 while (true)
439 {
440 {
441 std::scoped_lock l(runtime->skillStatusesMutex);
442
443 if (runtime->statusUpdate.hasBeenConstructed())
444 {
445 break;
446 }
447 }
448
449 std::this_thread::sleep_for(std::chrono::milliseconds(20));
450 }
451
452 return executionId;
453 }
454
455 bool
457 const armarx::aron::data::DictPtr& input)
458 {
460
461 std::shared_ptr<skills::detail::SkillRuntime> runtime;
462 {
463 std::shared_lock l{skillExecutionsMutex};
464 auto it = skillExecutions.find(executionId);
465 if (it == skillExecutions.end())
466 {
467 ARMARX_INFO << "No acive execution for skill '" + executionId.skillId.toString() +
468 "' found! Ignoring prepareSkill request.";
469 return false;
470 }
471 runtime = it->second;
472 }
473
474 std::scoped_lock l2{runtime->skillStatusesMutex};
475 if (runtime->statusUpdate.status != skills::SkillStatus::Preparing)
476 {
477 ARMARX_INFO << "Could not prepare the skill '" + executionId.skillId.toString() +
478 "' because its not in preparing phase.";
479 return false;
480 }
481
482 runtime->updateSkillParameters(input);
483 return true;
484 }
485
486 bool
488 {
490
491 std::shared_ptr<skills::detail::SkillRuntime> runtime;
492 {
493 std::shared_lock l(skillExecutionsMutex);
494 auto it = skillExecutions.find(executionId);
495 if (it == skillExecutions.end())
496 {
497 ARMARX_INFO << "No acive execution for skill '" + executionId.skillId.toString() +
498 "' found! Ignoring abortSkill request.";
499 return false;
500 }
501 runtime = it->second;
502 }
503
504 runtime->stopSkill();
505
506 while (true)
507 {
508 {
509 std::scoped_lock l2(runtime->skillStatusesMutex);
510 auto status = runtime->statusUpdate;
511
512 if (status.hasBeenTerminated())
513 {
514 break;
515 }
516 }
517 std::this_thread::sleep_for(std::chrono::milliseconds(20));
518 }
519
520 return true;
521 }
522
523 bool
525 {
527
528 std::shared_ptr<skills::detail::SkillRuntime> runtime;
529 {
530 std::shared_lock l(skillExecutionsMutex);
531 auto it = skillExecutions.find(executionId);
532 if (it == skillExecutions.end())
533 {
534 ARMARX_INFO << "No active execution for skill '" + executionId.skillId.toString() +
535 "' found! Ignoring abortSkill request.";
536 return false;
537 }
538 runtime = it->second;
539 }
540
541 runtime->stopSkill();
542 return true;
543 }
544
545 void
547 const skills::SkillStatusUpdate& statusUpdate)
548 {
549 // Snapshot the runtimes under the lock so we can call into them
550 // without holding the lock (sub-skill status updates can be slow).
551 std::vector<std::pair<skills::SkillExecutionID,
552 std::shared_ptr<skills::detail::SkillRuntime>>>
553 snapshot;
554 {
555 std::shared_lock l(skillExecutionsMutex);
556 snapshot.reserve(skillExecutions.size());
557 for (const auto& [id, runtime] : skillExecutions)
558 {
559 snapshot.emplace_back(id, runtime);
560 }
561 }
562 for (auto& [id, runtime] : snapshot)
563 {
564 ARMARX_DEBUG << "updating subskill status for " << id.toString() << " with "
565 << statusUpdate.executionId.toString();
566 runtime->updateSubSkillStatus(statusUpdate);
567 }
568 }
569
570 const skills::manager::dti::SkillManagerInterfacePrx&
572 {
573 return manager;
574 }
575
576 std::vector<std::shared_ptr<skills::detail::SkillRuntime>>
577 SkillProviderComponentPlugin::collectFinishedExecutions_locked()
578 {
579 // Caller MUST hold an exclusive lock on skillExecutionsMutex.
580 // We move terminated entries OUT of the map (under the lock) and
581 // return them, so the caller can join the threads outside the lock.
582 // The caller is responsible for joining; the SkillRuntime will be
583 // destroyed when its shared_ptr ref count drops to zero, which is
584 // safe only AFTER the embedded std::thread has been joined.
585 std::vector<std::shared_ptr<skills::detail::SkillRuntime>> ret;
586 for (auto it = skillExecutions.begin(); it != skillExecutions.end();)
587 {
588 const auto& runtime = it->second;
589 bool terminated = false;
590 {
591 std::scoped_lock statusLock(runtime->skillStatusesMutex);
592 terminated = runtime->statusUpdate.hasBeenTerminated();
593 }
594 if (terminated)
595 {
596 ret.push_back(std::move(it->second));
597 it = skillExecutions.erase(it);
598 }
599 else
600 {
601 ++it;
602 }
603 }
604 return ret;
605 }
606} // namespace armarx::plugins
607
608namespace armarx
609{
614
615 IceUtil::Optional<skills::provider::dto::SkillDescription>
617 const skills::provider::dto::SkillID& skillId,
618 const Ice::Current& /*unused*/)
619 {
620 auto id = skills::SkillID::FromIce(skillId, skills::ProviderID{.providerName = getName()});
621 auto o = plugin->getSkillDescription(id);
622 if (o.has_value())
623 {
624 return o->toProviderIce();
625 }
626 return {};
627 }
628
629 skills::provider::dto::SkillDescriptionMap
631 {
632 skills::provider::dto::SkillDescriptionMap ret;
633 for (const auto& [k, v] : plugin->getSkillDescriptions())
634 {
635 ret.insert({k.toProviderIce(), v.toProviderIce()});
636 }
637 return ret;
638 }
639
640 IceUtil::Optional<skills::provider::dto::SkillStatusUpdate>
642 const skills::provider::dto::SkillExecutionID& executionId,
643 const Ice::Current& /*unused*/)
644 {
646 executionId, skills::ProviderID{.providerName = getName()});
647 auto o = plugin->getSkillExecutionStatus(execId);
648 if (o.has_value())
649 {
650 return o->toProviderIce();
651 }
652 return {};
653 }
654
655 skills::provider::dto::SkillStatusUpdateMap
657 {
658 skills::provider::dto::SkillStatusUpdateMap ret;
659 for (const auto& [k, v] : plugin->getSkillExecutionStatuses())
660 {
661 ret.insert({k.toProviderIce(), v.toProviderIce()});
662 }
663 return ret;
664 }
665
666 // Please not that this method waits until the skill can be scheduled!
667 skills::provider::dto::SkillStatusUpdate
669 const skills::provider::dto::SkillExecutionRequest& info,
670 const Ice::Current& /*unused*/)
671 {
673 info, skills::ProviderID{.providerName = getName()});
674 auto up = this->plugin->executeSkill(exec);
675 return up.toProviderIce();
676 }
677
678 skills::provider::dto::SkillExecutionID
680 const skills::provider::dto::SkillExecutionRequest& info,
681 const Ice::Current& current /*unused*/)
682 {
684 info, skills::ProviderID{.providerName = getName()});
685 auto id = this->plugin->executeSkillAsync(exec);
686 return id.toProviderIce();
687 }
688
689 skills::provider::dto::ParameterUpdateResult
691 const skills::provider::dto::SkillExecutionID& id,
692 const aron::data::dto::DictPtr& input,
693 const Ice::Current& current /*unused*/)
694 {
695 skills::provider::dto::ParameterUpdateResult res;
696
697 auto exec =
700 res.success = this->plugin->updateSkillParameters(exec, prep);
701 return res;
702 }
703
704 skills::provider::dto::AbortSkillResult
705 SkillProviderComponentPluginUser::abortSkill(const skills::provider::dto::SkillExecutionID& id,
706 const Ice::Current& /*unused*/)
707 {
708 skills::provider::dto::AbortSkillResult res;
709 auto exec =
711 res.success = this->plugin->abortSkill(exec);
712 return res;
713 }
714
715 skills::provider::dto::AbortSkillResult
717 const skills::provider::dto::SkillExecutionID& id,
718 const Ice::Current& /*unused*/)
719 {
720 skills::provider::dto::AbortSkillResult res;
721 auto exec =
723 res.success = this->plugin->abortSkillAsync(exec);
724 return res;
725 }
726
727 void
729 const skills::provider::dto::SkillStatusUpdate& statusUpdate,
730 const std::string& providerName,
731 const Ice::Current& /*current*/)
732 {
733 auto status = skills::SkillStatusUpdate::FromIce(statusUpdate);
734 status.executionId.skillId.providerId.emplace().providerName = providerName;
735 plugin->updateSubSkillStatus(status);
736 }
737
740 {
741 return plugin;
742 }
743} // namespace armarx
static std::string levelToString(MessageTypeT type)
MessageTypeT getEffectiveLoggingLevel() const
Definition Logging.cpp:130
const std::string & prefix() const
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
std::string getName() const
Retrieve name of object.
IceUtil::Optional< skills::provider::dto::SkillStatusUpdate > getSkillExecutionStatus(const skills::provider::dto::SkillExecutionID &executionId, const Ice::Current &current=Ice::Current()) override
skills::provider::dto::SkillStatusUpdateMap getSkillExecutionStatuses(const Ice::Current &current=Ice::Current()) override
skills::provider::dto::AbortSkillResult abortSkill(const skills::provider::dto::SkillExecutionID &skill, const Ice::Current &current=Ice::Current()) override
IceUtil::Optional< skills::provider::dto::SkillDescription > getSkillDescription(const skills::provider::dto::SkillID &skill, 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
skills::provider::dto::SkillExecutionID executeSkillAsync(const skills::provider::dto::SkillExecutionRequest &executionInfo, const Ice::Current &current=Ice::Current()) override
skills::provider::dto::AbortSkillResult abortSkillAsync(const skills::provider::dto::SkillExecutionID &skill, const Ice::Current &current=Ice::Current()) override
const std::experimental::observer_ptr< plugins::SkillProviderComponentPlugin > & getSkillProviderPlugin() const
void reportSkillEvent(const skills::provider::dto::SkillStatusUpdate &statusUpdate, const std::string &providerName, const Ice::Current &current) override
skills::provider::dto::ParameterUpdateResult updateSkillParameters(const skills::provider::dto::SkillExecutionID &executionId, const armarx::aron::data::dto::DictPtr &parameters, const Ice::Current &current=Ice::Current()) override
skills::provider::dto::SkillDescriptionMap getSkillDescriptions(const Ice::Current &current=Ice::Current()) override
static PointerType FromAronDictDTO(const data::dto::DictPtr &aron)
Definition Dict.cpp:131
static DateTime Now()
Definition DateTime.cpp:51
skills::SkillExecutionID executeSkillAsync(const skills::SkillExecutionRequest &executionInfo)
bool abortSkill(const skills::SkillExecutionID &execId)
skills::SkillStatusUpdate executeSkill(const skills::SkillExecutionRequest &executionInfo)
std::optional< skills::SkillStatusUpdate > getSkillExecutionStatus(const skills::SkillExecutionID &) const
std::optional< skills::SkillDescription > getSkillDescription(const skills::SkillID &) const
void postCreatePropertyDefinitions(PropertyDefinitionsPtr &properties) override
const skills::manager::dti::SkillManagerInterfacePrx & skillManager() const
std::map< skills::SkillExecutionID, skills::SkillStatusUpdate > getSkillExecutionStatuses() const
void addSkillFactory(std::unique_ptr< skills::SkillBlueprint > &&)
bool updateSkillParameters(const skills::SkillExecutionID &id, const armarx::aron::data::DictPtr &params)
std::map< skills::SkillID, skills::SkillDescription > getSkillDescriptions() const
void updateSubSkillStatus(const skills::SkillStatusUpdate &statusUpdate)
bool abortSkillAsync(const skills::SkillExecutionID &execId)
std::function< TerminatedSkillStatus()> FunctionType
Definition LambdaSkill.h:12
callback::dti::SkillProviderCallbackInterfacePrx callbackInterface
static SkillExecutionRequest FromIce(const manager::dto::SkillExecutionRequest &)
provider::dto::SkillExecutionRequest toProviderIce() const
std::string toString() const
Definition SkillID.cpp:68
std::optional< ProviderID > providerId
Definition SkillID.h:40
bool isFullySpecified() const
Definition SkillID.cpp:78
bool isSkillSpecified() const
Definition SkillID.cpp:84
static SkillID FromIce(const manager::dto::SkillID &)
Definition SkillID.cpp:36
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:179
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:194
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:182
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:191
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:185
::IceInternal::Handle< Dict > DictPtr
std::shared_ptr< Dict > DictPtr
Definition Dict.h:42
This file is part of ArmarX.
SkillStatus toSkillStatus(const ActiveOrTerminatedSkillStatus &d)
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
static SkillExecutionID FromIce(const skills::manager::dto::SkillExecutionID &)
static SkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate &update, const std::optional< skills::ProviderID > &providerId=std::nullopt)