Fawkes API  Fawkes Development Version
clips-executive-rest-api.cpp
1 
2 /***************************************************************************
3  * clips-executive-rest-api.cpp - CLIPS Executive REST API
4  *
5  * Created: Fri Mar 16 17:17:17 2018
6  * Copyright 2006-2018 Tim Niemueller [www.niemueller.de]
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Library General Public License for more details.
18  *
19  * Read the full text in the LICENSE.GPL file in the doc directory.
20  */
21 
22 #include "clips-executive-rest-api.h"
23 
24 #include <core/threading/mutex_locker.h>
25 #include <webview/rest_api_manager.h>
26 
27 #include <iostream>
28 
29 using namespace fawkes;
30 
31 /** @class ClipsExecutiveRestApi "clips-executive-rest-api.h"
32  * REST API backend for the CLIPS executive.
33  * @author Tim Niemueller
34  */
35 
36 /** Constructor. */
38 : Thread("ClipsWebviewThread", Thread::OPMODE_WAITFORWAKEUP)
39 {
40 }
41 
42 /** Destructor. */
44 {
45 }
46 
47 void
49 {
50  {
51  std::map<std::string, LockPtr<CLIPS::Environment>> envs = clips_env_mgr->environments();
52  if (envs.find("executive") == envs.end()) {
53  throw Exception("No CLIPS environment named 'executive' found");
54  }
55  clips_ = envs["executive"];
56  }
57 
58  rest_api_ = new WebviewRestApi("clips-executive", logger);
60  WebRequest::METHOD_GET, "/goals", std::bind(&ClipsExecutiveRestApi::cb_list_goals, this));
61  rest_api_->add_handler<Goal>(WebRequest::METHOD_GET,
62  "/goals/{id}",
63  std::bind(&ClipsExecutiveRestApi::cb_get_goal,
64  this,
65  std::placeholders::_1));
67  WebRequest::METHOD_GET,
68  "/domain-operators",
69  std::bind(&ClipsExecutiveRestApi::cb_list_domain_operators, this));
71  WebRequest::METHOD_GET,
72  "/domain-objects",
73  std::bind(&ClipsExecutiveRestApi::cb_list_domain_objects, this));
75  WebRequest::METHOD_GET,
76  "/domain-predicates",
77  std::bind(&ClipsExecutiveRestApi::cb_list_domain_predicates, this));
79  WebRequest::METHOD_GET,
80  "/domain-facts",
81  std::bind(&ClipsExecutiveRestApi::cb_list_domain_facts, this));
83  WebRequest::METHOD_GET, "/plans", std::bind(&ClipsExecutiveRestApi::cb_list_plans, this));
84  rest_api_->add_handler<Plan>(WebRequest::METHOD_GET,
85  "/plans/{goal-id}/{id}",
86  std::bind(&ClipsExecutiveRestApi::cb_get_plan,
87  this,
88  std::placeholders::_1));
90  WebRequest::METHOD_GET,
91  "/pddl-groundings",
92  std::bind(&ClipsExecutiveRestApi::cb_list_pddl_groundings, this));
94  WebRequest::METHOD_GET,
95  "/pddl-predicates",
96  std::bind(&ClipsExecutiveRestApi::cb_list_pddl_predicates, this));
98  WebRequest::METHOD_GET,
99  "/pddl-formulas",
100  std::bind(&ClipsExecutiveRestApi::cb_list_pddl_formulas, this));
102  WebRequest::METHOD_GET,
103  "/grounded-pddl-predicates",
104  std::bind(&ClipsExecutiveRestApi::cb_list_grounded_pddl_predicates, this));
106  WebRequest::METHOD_GET,
107  "/grounded-pddl-formulas",
108  std::bind(&ClipsExecutiveRestApi::cb_list_grounded_pddl_formulas, this));
109 
110  rest_api_->add_handler<PDDLGrounding>(WebRequest::METHOD_GET,
111  "/pddl-groundings/{id}",
112  std::bind(&ClipsExecutiveRestApi::cb_get_pddl_groundings,
113  this,
114  std::placeholders::_1));
115  rest_api_->add_handler<PDDLPredicate>(WebRequest::METHOD_GET,
116  "/pddl-predicates/{id}",
117  std::bind(&ClipsExecutiveRestApi::cb_get_pddl_predicates,
118  this,
119  std::placeholders::_1));
120  rest_api_->add_handler<PDDLFormula>(WebRequest::METHOD_GET,
121  "/pddl-formulas/{id}",
122  std::bind(&ClipsExecutiveRestApi::cb_get_pddl_formulas,
123  this,
124  std::placeholders::_1));
126  WebRequest::METHOD_GET,
127  "/grounded-pddl-predicates/{id}",
128  std::bind(&ClipsExecutiveRestApi::cb_get_grounded_pddl_predicates,
129  this,
130  std::placeholders::_1));
131  rest_api_->add_handler<GroundedPDDLFormula>(
132  WebRequest::METHOD_GET,
133  "/grounded-pddl-groundings/{id}",
134  std::bind(&ClipsExecutiveRestApi::cb_get_grounded_pddl_formulas, this, std::placeholders::_1));
135 
137 }
138 
139 void
141 {
143  delete rest_api_;
144 }
145 
146 void
148 {
149 }
150 
151 /** Get a value from a fact.
152  * @param fact pointer to CLIPS fact
153  * @param slot_name name of field to retrieve
154  * @return template-specific return value
155  */
156 template <typename T>
157 T
158 get_value(const CLIPS::Fact::pointer &fact, const std::string &slot_name)
159 {
160  CLIPS::Values v = fact->slot_value(slot_name);
161  if (v.empty()) {
162  throw Exception("No value for slot '%s'", slot_name.c_str());
163  }
164  if (v[0].type() == CLIPS::TYPE_SYMBOL && v[0].as_string() == "nil") {
165  return T();
166  }
167  return v[0];
168 }
169 
170 /** Specialization for bool.
171  * @param fact pointer to CLIPS fact
172  * @param slot_name name of field to retrieve
173  * @return boolean value
174  */
175 template <>
176 bool
177 get_value(const CLIPS::Fact::pointer &fact, const std::string &slot_name)
178 {
179  CLIPS::Values v = fact->slot_value(slot_name);
180  if (v.empty()) {
181  throw Exception("No value for slot '%s'", slot_name.c_str());
182  }
183  if (v[0].type() != CLIPS::TYPE_SYMBOL) {
184  throw Exception("Value for slot '%s' is not a boolean", slot_name.c_str());
185  }
186  return (v[0].as_string() == "TRUE");
187 }
188 
189 /** Get value array.
190  * This is not a template because the overly verbose operator API
191  * of CLIPS::Value can lead to ambiguous overloads, e.g., resolving
192  * std::string to std::string or const char * operators.
193  * @param fact pointer to CLIPS fact
194  * @param slot_name name of field to retrieve
195  * @return vector of strings from multislot
196  */
197 static std::vector<std::string>
198 get_values(const CLIPS::Fact::pointer &fact, const std::string &slot_name)
199 {
200  CLIPS::Values v = fact->slot_value(slot_name);
201  std::vector<std::string> rv(v.size());
202  for (size_t i = 0; i < v.size(); ++i) {
203  switch (v[i].type()) {
204  case CLIPS::TYPE_FLOAT: rv[i] = std::to_string(static_cast<double>(v[i])); break;
205  case CLIPS::TYPE_INTEGER: rv[i] = std::to_string(static_cast<long long int>(v[i])); break;
206  case CLIPS::TYPE_SYMBOL:
207  case CLIPS::TYPE_STRING:
208  case CLIPS::TYPE_INSTANCE_NAME: rv[i] = static_cast<std::string &>(v[i]); break;
209  default: rv[i] = "CANNOT-REPRESENT"; break;
210  }
211  }
212  return rv;
213 }
214 
215 Goal
216 ClipsExecutiveRestApi::generate_goal(CLIPS::Fact::pointer fact)
217 {
218  Goal g;
219  g.set_kind("Goal");
221  g.set_id(get_value<std::string>(fact, "id"));
222  g.set__class(get_value<std::string>(fact, "class"));
223  g.set_type(get_value<std::string>(fact, "type"));
224  g.set_sub_type(get_value<std::string>(fact, "sub-type"));
225  g.set_mode(get_value<std::string>(fact, "mode"));
226  g.set_parent(get_value<std::string>(fact, "parent"));
227  g.set_outcome(get_value<std::string>(fact, "outcome"));
228  g.set_error(get_values(fact, "error"));
229  g.set_message(get_value<std::string>(fact, "message"));
230  g.set_priority(get_value<long int>(fact, "priority"));
231  g.set_parameters(get_values(fact, "params"));
232  g.set_meta(get_values(fact, "meta"));
233  g.set_required_resources(get_values(fact, "required-resources"));
234  g.set_acquired_resources(get_values(fact, "acquired-resources"));
235 
236  CLIPS::Fact::pointer pfact = clips_->get_facts();
237  while (pfact) {
238  CLIPS::Template::pointer tmpl = pfact->get_template();
239  if (tmpl->name() == "plan") {
240  try {
241  if (get_value<std::string>(pfact, "goal-id") == *g.id()) {
242  g.addto_plans(std::move(get_value<std::string>(pfact, "id")));
243  }
244  } catch (Exception &e) {
245  }
246  }
247  pfact = pfact->next();
248  }
249 
250  return g;
251 }
252 
254 ClipsExecutiveRestApi::cb_list_goals()
255 {
256  MutexLocker lock(clips_.objmutex_ptr());
258 
259  CLIPS::Fact::pointer fact = clips_->get_facts();
260  while (fact) {
261  CLIPS::Template::pointer tmpl = fact->get_template();
262  if (tmpl->name() == "goal") {
263  try {
264  rv.push_back(std::move(generate_goal(fact)));
265  } catch (Exception &e) {
266  logger->log_warn(name(), "Failed to add goal: %s", e.what_no_backtrace());
267  }
268  }
269 
270  fact = fact->next();
271  }
272 
273  return rv;
274 }
275 
276 Goal
277 ClipsExecutiveRestApi::cb_get_goal(WebviewRestParams &params)
278 {
279  const std::string id = params.path_arg("id");
280 
281  MutexLocker lock(clips_.objmutex_ptr());
282  CLIPS::Fact::pointer fact = clips_->get_facts();
283  while (fact) {
284  CLIPS::Template::pointer tmpl = fact->get_template();
285  if (tmpl->name() == "goal") {
286  try {
287  if (get_value<std::string>(fact, "id") == id) {
288  return generate_goal(fact);
289  }
290  } catch (Exception &e) {
291  logger->log_warn(name(), "Failed to add goal: %s", e.what_no_backtrace());
292  }
293  }
294 
295  fact = fact->next();
296  }
297 
298  throw WebviewRestException(WebReply::HTTP_BAD_REQUEST, "Goal '%s' is unknown", id.c_str());
299 }
300 
302 ClipsExecutiveRestApi::cb_list_domain_operators()
303 {
304  MutexLocker lock(clips_.objmutex_ptr());
306 
307  std::map<std::string, std::list<std::pair<std::string, std::string>>> op_params;
308 
309  CLIPS::Fact::pointer fact = clips_->get_facts();
310  while (fact) {
311  CLIPS::Template::pointer tmpl = fact->get_template();
312  if (tmpl->name() == "domain-operator-parameter") {
313  std::string operator_name = get_value<std::string>(fact, "operator");
314  if (op_params.find(operator_name) == op_params.end()) {
315  op_params[operator_name] = {};
316  }
317  op_params[operator_name].push_back(
318  std::make_pair(get_value<std::string>(fact, "name"), get_value<std::string>(fact, "type")));
319  }
320  fact = fact->next();
321  }
322 
323  fact = clips_->get_facts();
324  while (fact) {
325  CLIPS::Template::pointer tmpl = fact->get_template();
326  if (tmpl->name() == "domain-operator") {
327  try {
328  DomainOperator o;
329  o.set_kind("DomainOperator");
331  o.set_name(get_value<std::string>(fact, "name"));
332  o.set_wait_sensed(get_value<bool>(fact, "wait-sensed"));
333  if (op_params.find(*o.name()) != op_params.end()) {
334  for (const auto &p : op_params[*o.name()]) {
336  param.set_name(p.first);
337  param.set_type(p.second);
338  o.addto_parameters(std::move(param));
339  }
340  }
341 
342  rv.push_back(std::move(o));
343  } catch (Exception &e) {
344  logger->log_warn(name(), "Failed to add goal: %s", e.what_no_backtrace());
345  }
346  }
347 
348  fact = fact->next();
349  }
350 
351  return rv;
352 }
353 
355 ClipsExecutiveRestApi::cb_list_domain_objects()
356 {
357  MutexLocker lock(clips_.objmutex_ptr());
359 
360  CLIPS::Fact::pointer fact = clips_->get_facts();
361  while (fact) {
362  CLIPS::Template::pointer tmpl = fact->get_template();
363  if (tmpl->name() == "domain-object") {
364  DomainObject o;
365  o.set_kind("DomainObject");
367  o.set_name(get_value<std::string>(fact, "name"));
368  o.set_type(get_value<std::string>(fact, "type"));
369  rv.push_back(std::move(o));
370  }
371  fact = fact->next();
372  }
373 
374  return rv;
375 }
376 
378 ClipsExecutiveRestApi::cb_list_domain_predicates()
379 {
380  MutexLocker lock(clips_.objmutex_ptr());
382 
383  CLIPS::Fact::pointer fact = clips_->get_facts();
384  while (fact) {
385  CLIPS::Template::pointer tmpl = fact->get_template();
386  if (tmpl->name() == "domain-predicate") {
387  DomainPredicate p;
388  p.set_kind("DomainPredicate");
390  p.set_name(get_value<std::string>(fact, "name"));
391  p.set_sensed(get_value<bool>(fact, "sensed"));
392  p.set_param_names(get_values(fact, "param-names"));
393  p.set_param_types(get_values(fact, "param-types"));
394  rv.push_back(std::move(p));
395  }
396  fact = fact->next();
397  }
398 
399  return rv;
400 }
401 
403 ClipsExecutiveRestApi::cb_list_domain_facts()
404 {
405  MutexLocker lock(clips_.objmutex_ptr());
407 
408  CLIPS::Fact::pointer fact = clips_->get_facts();
409  while (fact) {
410  CLIPS::Template::pointer tmpl = fact->get_template();
411  if (tmpl->name() == "domain-fact") {
412  DomainFact f;
413  f.set_kind("DomainFact");
415  f.set_name(get_value<std::string>(fact, "name"));
416  f.set_param_values(get_values(fact, "param-values"));
417  rv.push_back(std::move(f));
418  }
419  fact = fact->next();
420  }
421 
422  return rv;
423 }
424 
425 std::shared_ptr<PDDLGrounding>
426 ClipsExecutiveRestApi::gen_pddl_grounding(const CLIPS::Fact::pointer fact)
427 {
428  auto grounding = std::make_shared<PDDLGrounding>();
429  grounding->set_kind("PDDLGrounding");
430  grounding->set_apiVersion(PDDLGrounding::api_version());
431  grounding->set_id(get_value<std::string>(fact, "id"));
432 
433  for (const auto &pn : get_values(fact, "param-names")) {
434  grounding->addto_param_names(std::move(pn));
435  }
436 
437  for (const auto &pv : get_values(fact, "param-values")) {
438  grounding->addto_param_values(std::move(pv));
439  }
440 
441  return grounding;
442 }
443 
445 ClipsExecutiveRestApi::cb_list_pddl_groundings()
446 {
447  MutexLocker lock(clips_.objmutex_ptr());
449 
450  CLIPS::Fact::pointer fact = clips_->get_facts();
451  while (fact) {
452  CLIPS::Template::pointer tmpl = fact->get_template();
453  if (tmpl->name() == "pddl-grounding") {
454  rv.push_back(*gen_pddl_grounding(fact));
455  }
456  fact = fact->next();
457  }
458 
459  return rv;
460 }
461 
463 ClipsExecutiveRestApi::cb_get_pddl_groundings(WebviewRestParams &params)
464 {
465  std::string id = params.path_arg("id");
466 
467  MutexLocker lock(clips_.objmutex_ptr());
468  PDDLGrounding ret;
469 
470  CLIPS::Fact::pointer fact = clips_->get_facts();
471  while (fact) {
472  CLIPS::Template::pointer tmpl = fact->get_template();
473  if (tmpl->name() == "pddl-grounding" && get_value<std::string>(fact, "id") == id) {
474  ret = *gen_pddl_grounding(fact);
475  }
476  fact = fact->next();
477  }
478 
479  throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
480  "No grounding with ID '%s' found",
481  id.c_str());
482 
483  return ret;
484 }
485 
486 std::shared_ptr<PDDLFormula>
487 ClipsExecutiveRestApi::gen_pddl_formula(const CLIPS::Fact::pointer fact)
488 {
489  auto formula = std::make_shared<PDDLFormula>();
490  formula->set_kind("PDDLFormula");
491  formula->set_apiVersion(PDDLFormula::api_version());
492  formula->set_id(get_value<std::string>(fact, "id"));
493  formula->set_type(get_value<std::string>(fact, "type"));
494  formula->set_part_of(get_value<std::string>(fact, "part-of"));
495 
496  return formula;
497 }
498 
500 ClipsExecutiveRestApi::cb_list_pddl_formulas()
501 {
502  MutexLocker lock(clips_.objmutex_ptr());
504 
505  CLIPS::Fact::pointer fact = clips_->get_facts();
506  while (fact) {
507  CLIPS::Template::pointer tmpl = fact->get_template();
508  if (tmpl->name() == "pddl-formula") {
509  rv.push_back(*gen_pddl_formula(fact));
510  }
511  fact = fact->next();
512  }
513 
514  return rv;
515 }
516 
518 ClipsExecutiveRestApi::cb_get_pddl_formulas(WebviewRestParams &params)
519 {
520  std::string id = params.path_arg("id");
521 
522  MutexLocker lock(clips_.objmutex_ptr());
523  PDDLFormula ret;
524 
525  CLIPS::Fact::pointer fact = clips_->get_facts();
526  while (fact) {
527  CLIPS::Template::pointer tmpl = fact->get_template();
528  if (tmpl->name() == "pddl-formula" && get_value<std::string>(fact, "id") == id) {
529  ret = *gen_pddl_formula(fact);
530  }
531  fact = fact->next();
532  }
533 
534  throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
535  "No formula with ID '%s' found",
536  id.c_str());
537 
538  return ret;
539 }
540 
541 std::shared_ptr<PDDLPredicate>
542 ClipsExecutiveRestApi::gen_pddl_predicate(const CLIPS::Fact::pointer fact)
543 {
544  auto predicate = std::make_shared<PDDLPredicate>();
545  predicate->set_kind("PDDLPredicate");
546  predicate->set_apiVersion(PDDLPredicate::api_version());
547  predicate->set_id(get_value<std::string>(fact, "id"));
548  predicate->set_part_of(get_value<std::string>(fact, "part-of"));
549  predicate->set_predicate(get_value<std::string>(fact, "predicate"));
550 
551  for (const auto &pn : get_values(fact, "param-names")) {
552  predicate->addto_param_names(std::move(pn));
553  }
554 
555  for (const auto &pc : get_values(fact, "param-constants")) {
556  predicate->addto_param_constants(std::move(pc));
557  }
558 
559  return predicate;
560 }
561 
563 ClipsExecutiveRestApi::cb_list_pddl_predicates()
564 {
565  MutexLocker lock(clips_.objmutex_ptr());
567 
568  CLIPS::Fact::pointer fact = clips_->get_facts();
569  while (fact) {
570  CLIPS::Template::pointer tmpl = fact->get_template();
571  if (tmpl->name() == "pddl-predicate") {
572  rv.push_back(*gen_pddl_predicate(fact));
573  }
574  fact = fact->next();
575  }
576 
577  return rv;
578 }
579 
581 ClipsExecutiveRestApi::cb_get_pddl_predicates(WebviewRestParams &params)
582 {
583  std::string id = params.path_arg("id");
584 
585  MutexLocker lock(clips_.objmutex_ptr());
586  PDDLPredicate ret;
587 
588  CLIPS::Fact::pointer fact = clips_->get_facts();
589  while (fact) {
590  CLIPS::Template::pointer tmpl = fact->get_template();
591  if (tmpl->name() == "pddl-predicate" && get_value<std::string>(fact, "id") == id) {
592  ret = *gen_pddl_predicate(fact);
593  }
594  fact = fact->next();
595  }
596 
597  throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
598  "No predicate with ID '%s' found",
599  id.c_str());
600 
601  return ret;
602 }
603 
604 std::shared_ptr<GroundedPDDLFormula>
605 ClipsExecutiveRestApi::gen_grounded_pddl_formula(const CLIPS::Fact::pointer fact)
606 {
607  auto formula = std::make_shared<GroundedPDDLFormula>();
608  formula->set_kind("GroundedPDDLFormula");
609  formula->set_apiVersion(GroundedPDDLFormula::api_version());
610  formula->set_id(get_value<std::string>(fact, "id"));
611  formula->set_formula_id(get_value<std::string>(fact, "formula-id"));
612  formula->set_grounding(get_value<std::string>(fact, "grounding"));
613  formula->set_is_satisfied(get_value<bool>(fact, "is-satisfied"));
614 
615  return formula;
616 }
617 
619 ClipsExecutiveRestApi::cb_list_grounded_pddl_formulas()
620 {
621  MutexLocker lock(clips_.objmutex_ptr());
623 
624  CLIPS::Fact::pointer fact = clips_->get_facts();
625  while (fact) {
626  CLIPS::Template::pointer tmpl = fact->get_template();
627  if (tmpl->name() == "grounded-pddl-formula") {
628  rv.push_back(*gen_grounded_pddl_formula(fact));
629  }
630  fact = fact->next();
631  }
632 
633  return rv;
634 }
635 
637 ClipsExecutiveRestApi::cb_get_grounded_pddl_formulas(WebviewRestParams &params)
638 {
639  std::string id = params.path_arg("id");
640 
641  MutexLocker lock(clips_.objmutex_ptr());
643 
644  CLIPS::Fact::pointer fact = clips_->get_facts();
645  while (fact) {
646  CLIPS::Template::pointer tmpl = fact->get_template();
647  if (tmpl->name() == "grounded-pddl-formula" && get_value<std::string>(fact, "id") == id) {
648  ret = *gen_grounded_pddl_formula(fact);
649  }
650  fact = fact->next();
651  }
652 
653  throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
654  "No grounded formula with ID '%s' found",
655  id.c_str());
656 
657  return ret;
658 }
659 
660 std::shared_ptr<GroundedPDDLPredicate>
661 ClipsExecutiveRestApi::gen_grounded_pddl_predicate(const CLIPS::Fact::pointer fact)
662 {
663  auto predicate = std::make_shared<GroundedPDDLPredicate>();
664  predicate->set_kind("GroundedPDDLPredicate");
665  predicate->set_apiVersion(GroundedPDDLPredicate::api_version());
666  predicate->set_id(get_value<std::string>(fact, "id"));
667  predicate->set_predicate_id(get_value<std::string>(fact, "predicate-id"));
668  predicate->set_grounding(get_value<std::string>(fact, "grounding"));
669  predicate->set_is_satisfied(get_value<bool>(fact, "is-satisfied"));
670 
671  return predicate;
672 }
673 
675 ClipsExecutiveRestApi::cb_list_grounded_pddl_predicates()
676 {
677  MutexLocker lock(clips_.objmutex_ptr());
679 
680  CLIPS::Fact::pointer fact = clips_->get_facts();
681  while (fact) {
682  CLIPS::Template::pointer tmpl = fact->get_template();
683  if (tmpl->name() == "grounded-pddl-predicate") {
684  rv.push_back(*gen_grounded_pddl_predicate(fact));
685  }
686  fact = fact->next();
687  }
688 
689  return rv;
690 }
691 
693 ClipsExecutiveRestApi::cb_get_grounded_pddl_predicates(WebviewRestParams &params)
694 {
695  std::string id = params.path_arg("id");
696 
697  MutexLocker lock(clips_.objmutex_ptr());
699 
700  CLIPS::Fact::pointer fact = clips_->get_facts();
701  while (fact) {
702  CLIPS::Template::pointer tmpl = fact->get_template();
703  if (tmpl->name() == "grounded-pddl-predicate" && get_value<std::string>(fact, "id") == id) {
704  ret = *gen_grounded_pddl_predicate(fact);
705  }
706  fact = fact->next();
707  }
708 
709  throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
710  "No grounded predicate with ID '%s' found",
711  id.c_str());
712 
713  return ret;
714 }
715 
716 void
717 ClipsExecutiveRestApi::gen_plan_precompute(PlanMap & plans,
718  PlanActionMap & plan_actions,
719  PreCompoundMap & prec,
720  PreAtomMap & prea,
721  PDDLGroundingMap & pgm,
722  PDDLFormulaMap & pfm,
723  PDDLPredicateMap & ppm,
724  GroundedPDDLFormulaMap & gpfm,
725  GroundedPDDLPredicateMap &gppm)
726 {
727  CLIPS::Fact::pointer fact = clips_->get_facts();
728  while (fact) {
729  CLIPS::Template::pointer tmpl = fact->get_template();
730  if (tmpl->name() == "plan") {
731  plans[std::make_pair(get_value<std::string>(fact, "goal-id"),
732  get_value<std::string>(fact, "id"))] = fact;
733  } else if (tmpl->name() == "plan-action") {
734  plan_actions[std::make_pair(get_value<std::string>(fact, "goal-id"),
735  get_value<std::string>(fact, "plan-id"))]
736  .push_back(fact);
737  } else if (tmpl->name() == "pddl-grounding") {
738  pgm[get_value<std::string>(fact, "id")] = fact;
739  } else if (tmpl->name() == "pddl-formula") {
740  pfm[get_value<std::string>(fact, "id")] = (fact);
741  } else if (tmpl->name() == "pddl-predicate") {
742  ppm[get_value<std::string>(fact, "id")] = (fact);
743  } else if (tmpl->name() == "grounded-pddl-formula") {
744  gpfm[get_value<std::string>(fact, "grounding")].push_back(fact);
745  } else if (tmpl->name() == "grounded-pddl-predicate") {
746  gppm[get_value<std::string>(fact, "grounding")].push_back(fact);
747  }
748  fact = fact->next();
749  }
750 }
751 
753 ClipsExecutiveRestApi::gen_plan_compute_precons(PDDLFormulaTreeNode node,
754  PDDLFormulaTreeMap tree,
755  PDDLGroundingMap groundings)
756 {
757  CLIPS::Fact::pointer node_fp = std::get<0>(node);
758  CLIPS::Fact::pointer node_g_fp = std::get<1>(node);
759  CLIPS::Template::pointer tmpl = node_fp->get_template();
760  GroundedFormula formula;
761 
763  if (tmpl->name() == "pddl-predicate") {
764  formula.set_kind("GroundedPredicate");
765  formula.set_name(get_value<std::string>(node_fp, "predicate"));
766  formula.set_type("atom");
767  std::vector<std::string> param_names =
768  get_values(groundings[get_value<std::string>(node_g_fp, "grounding")], "param-names");
769  std::vector<std::string> param_values =
770  get_values(groundings[get_value<std::string>(node_g_fp, "grounding")], "param-values");
771  std::vector<std::string> predicate_param_values;
772  for (const auto &param : get_values(node_fp, "param-names")) {
773  auto it = std::find(param_names.begin(), param_names.end(), param);
774  if (it != param_names.end()) {
775  auto index = std::distance(param_names.begin(), it);
776  predicate_param_values.push_back(param_values[index]);
777  }
778  }
779  formula.set_param_names(get_values(node_g_fp, "param-names"));
780  formula.set_param_values(predicate_param_values);
781  formula.set_param_constants(get_values(node_g_fp, "param-constants"));
782  } else if (tmpl->name() == "pddl-formula") {
783  formula.set_kind("GroundedFormula");
784  formula.set_name(get_value<std::string>(node_fp, "id"));
785  formula.set_type(get_value<std::string>(node_fp, "type"));
786  }
787  get_value<std::string>(node_g_fp, "is-satisfied") == "TRUE" ? formula.set_is_satisfied(true)
788  : formula.set_is_satisfied(false);
789 
790  for (const auto &child_node : tree[get_value<std::string>(node_fp, "id")]) {
791  auto child = get_value<std::string>(std::get<0>(child_node), "id");
792  formula.addto_child(gen_plan_compute_precons(child_node, tree, groundings));
793  }
794 
795  return formula;
796 }
797 
798 Plan
799 ClipsExecutiveRestApi::gen_plan(const PlanKey & plan_key,
800  const CLIPS::Fact::pointer fact,
801  PlanActionMap & plan_actions,
802  PreCompoundMap & prec,
803  PreAtomMap & prea,
804  PDDLGroundingMap & pgm,
805  PDDLFormulaMap & pfm,
806  PDDLPredicateMap & ppm,
807  GroundedPDDLFormulaMap & gpfm,
808  GroundedPDDLPredicateMap & gppm)
809 {
810  const std::string &goal_id = get_value<std::string>(fact, "goal-id");
811  const std::string &plan_id = get_value<std::string>(fact, "id");
812 
813  Plan p;
814  p.set_kind("Plan");
816  p.set_goal_id(goal_id);
817  p.set_id(plan_id);
818  p.set_cost(get_value<double>(fact, "cost"));
819  if (plan_actions.find(plan_key) != plan_actions.end()) {
820  std::vector<std::shared_ptr<PlanAction>> actions;
821 
822  for (auto &pai : plan_actions[plan_key]) {
823  auto pa = std::make_shared<PlanAction>();
824 
825  int64_t action_id = get_value<int64_t>(pai, "id");
826  std::string operator_name = get_value<std::string>(pai, "action-name");
827 
828  // general info
829  pa->set_kind("PlanAction");
830  pa->set_apiVersion(PlanAction::api_version());
831  pa->set_id(action_id);
832  pa->set_operator_name(operator_name);
833  for (const auto &pv : get_values(pai, "param-values")) {
834  pa->addto_param_values(std::move(pv));
835  }
836  pa->set_state(get_value<std::string>(pai, "state"));
837  pa->set_executable(get_value<bool>(pai, "executable"));
838  pa->set_duration(get_value<double>(pai, "duration"));
839  pa->set_dispatch_time(get_value<double>(pai, "dispatch-time"));
840  pa->set_precondition(gen_pddl_grounding(pgm[get_value<std::string>(pai, "precondition")]));
841 
842  // preconditions
843  std::string grnd_name = *(pa->precondition()->id());
844  std::string op_name = *(pa->operator_name());
845  PDDLFormulaTreeMap grounded_parent_map;
846 
847  for (const auto &p : gpfm[grnd_name]) {
848  PDDLFormulaTreeNode node = std::make_tuple(pfm[get_value<std::string>(p, "formula-id")], p);
849  grounded_parent_map[get_value<std::string>(pfm[get_value<std::string>(p, "formula-id")],
850  "part-of")]
851  .push_back(node);
852  }
853  for (const auto &p : gppm[grnd_name]) {
854  PDDLFormulaTreeNode node =
855  std::make_tuple(ppm[get_value<std::string>(p, "predicate-id")], p);
856  grounded_parent_map[get_value<std::string>(ppm[get_value<std::string>(p, "predicate-id")],
857  "part-of")]
858  .push_back(node);
859  }
860 
861  //get root node
862  for (const auto &rnode : grounded_parent_map[op_name]) {
863  CLIPS::Fact::pointer root_fp = std::get<0>(rnode);
864  std::string root = get_value<std::string>(root_fp, "id");
865 
866  //recursively compute the tree and set the preconditions
867  pa->set_preconditions(std::make_shared<GroundedFormula>(
868  gen_plan_compute_precons(rnode, grounded_parent_map, pgm)));
869  }
870 
871  actions.push_back(std::move(pa));
872  }
873 
874  std::sort(actions.begin(),
875  actions.end(),
876  [](std::shared_ptr<PlanAction> &a, std::shared_ptr<PlanAction> &b) {
877  return *a->id() < *b->id();
878  });
879  p.set_actions(actions);
880  }
881 
882  return p;
883 }
884 
886 ClipsExecutiveRestApi::cb_list_plans()
887 {
888  MutexLocker lock(clips_.objmutex_ptr());
890 
891  std::map<PlanKey, CLIPS::Fact::pointer> plans;
892  std::map<PlanKey, ClipsFactList> plan_actions;
893  PreCompoundMap prec;
894  PreAtomMap prea;
895  PDDLGroundingMap pgm;
896  PDDLFormulaMap pfm;
897  PDDLPredicateMap ppm;
898  GroundedPDDLFormulaMap gpfm;
899  GroundedPDDLPredicateMap gppm;
900 
901  gen_plan_precompute(plans, plan_actions, prec, prea, pgm, pfm, ppm, gpfm, gppm);
902 
903  for (auto &pi : plans) {
904  rv.push_back(std::move(
905  gen_plan(pi.first, pi.second, plan_actions, prec, prea, pgm, pfm, ppm, gpfm, gppm)));
906  }
907 
908  return rv;
909 }
910 
911 Plan
912 ClipsExecutiveRestApi::cb_get_plan(WebviewRestParams &params)
913 {
914  std::string goal_id = params.path_arg("goal-id");
915  std::string id = params.path_arg("id");
916 
917  MutexLocker lock(clips_.objmutex_ptr());
919 
920  std::map<PlanKey, CLIPS::Fact::pointer> plans;
921  std::map<PlanKey, ClipsFactList> plan_actions;
922  PreCompoundMap prec;
923  PreAtomMap prea;
924  PDDLGroundingMap pgm;
925  PDDLFormulaMap pfm;
926  PDDLPredicateMap ppm;
927  GroundedPDDLFormulaMap gpfm;
928  GroundedPDDLPredicateMap gppm;
929 
930  gen_plan_precompute(plans, plan_actions, prec, prea, pgm, pfm, ppm, gpfm, gppm);
931 
932  const PlanKey plan_key{goal_id, id};
933  if (plans.find(plan_key) == plans.end()) {
934  throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
935  "No plan for goal '%s' with ID '%s' found",
936  goal_id.c_str(),
937  id.c_str());
938  }
939 
940  return gen_plan(plan_key, plans[plan_key], plan_actions, prec, prea, pgm, pfm, ppm, gpfm, gppm);
941 }
virtual void finalize()
Finalize the thread.
virtual void init()
Initialize the thread.
virtual void loop()
Code to execute in the thread.
DomainFact representation for JSON transfer.
Definition: DomainFact.h:28
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: DomainFact.h:118
void set_kind(const std::string &kind)
Set kind value.
Definition: DomainFact.h:101
static std::string api_version()
Get version of implemented API.
Definition: DomainFact.h:48
void set_name(const std::string &name)
Set name value.
Definition: DomainFact.h:135
void set_param_values(const std::vector< std::string > &param_values)
Set param-values value.
Definition: DomainFact.h:152
DomainObject representation for JSON transfer.
Definition: DomainObject.h:28
void set_name(const std::string &name)
Set name value.
Definition: DomainObject.h:135
void set_type(const std::string &type)
Set type value.
Definition: DomainObject.h:152
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: DomainObject.h:118
void set_kind(const std::string &kind)
Set kind value.
Definition: DomainObject.h:101
static std::string api_version()
Get version of implemented API.
Definition: DomainObject.h:48
DomainOperatorParameter representation for JSON transfer.
void set_type(const std::string &type)
Set type value.
void set_name(const std::string &name)
Set name value.
DomainOperator representation for JSON transfer.
void addto_parameters(const std::shared_ptr< DomainOperatorParameter > &&parameters)
Add element to parameters array.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
void set_kind(const std::string &kind)
Set kind value.
static std::string api_version()
Get version of implemented API.
void set_name(const std::string &name)
Set name value.
void set_wait_sensed(const bool &wait_sensed)
Set wait-sensed value.
std::optional< std::string > name() const
Get name value.
DomainPredicate representation for JSON transfer.
static std::string api_version()
Get version of implemented API.
void set_sensed(const bool &sensed)
Set sensed value.
void set_param_types(const std::vector< std::string > &param_types)
Set param-types value.
void set_name(const std::string &name)
Set name value.
void set_param_names(const std::vector< std::string > &param_names)
Set param-names value.
void set_kind(const std::string &kind)
Set kind value.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Goal representation for JSON transfer.
Definition: Goal.h:28
void set_message(const std::string &message)
Set message value.
Definition: Goal.h:272
void set_acquired_resources(const std::vector< std::string > &acquired_resources)
Set acquired-resources value.
Definition: Goal.h:463
std::optional< std::string > id() const
Get id value.
Definition: Goal.h:126
void set_parameters(const std::vector< std::string > &parameters)
Set parameters value.
Definition: Goal.h:323
void set_id(const std::string &id)
Set id value.
Definition: Goal.h:135
void set_mode(const std::string &mode)
Set mode value.
Definition: Goal.h:203
void set_sub_type(const std::string &sub_type)
Set sub-type value.
Definition: Goal.h:169
void set_meta(const std::vector< std::string > &meta)
Set meta value.
Definition: Goal.h:358
void set_parent(const std::string &parent)
Set parent value.
Definition: Goal.h:289
void set_required_resources(const std::vector< std::string > &required_resources)
Set required-resources value.
Definition: Goal.h:428
void set_outcome(const std::string &outcome)
Set outcome value.
Definition: Goal.h:220
void set__class(const std::string &_class)
Set class value.
Definition: Goal.h:186
void set_kind(const std::string &kind)
Set kind value.
Definition: Goal.h:101
static std::string api_version()
Get version of implemented API.
Definition: Goal.h:48
void addto_plans(const std::string &&plans)
Add element to plans array.
Definition: Goal.h:401
void set_priority(const int64_t &priority)
Set priority value.
Definition: Goal.h:306
void set_error(const std::vector< std::string > &error)
Set error value.
Definition: Goal.h:237
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: Goal.h:118
void set_type(const std::string &type)
Set type value.
Definition: Goal.h:152
GroundedFormula representation for JSON transfer.
static std::string api_version()
Get version of implemented API.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
void set_param_names(const std::vector< std::string > &param_names)
Set param-names value.
void addto_child(const std::shared_ptr< GroundedFormula > &&child)
Add element to child array.
void set_type(const std::string &type)
Set type value.
void set_kind(const std::string &kind)
Set kind value.
void set_param_values(const std::vector< std::string > &param_values)
Set param-values value.
void set_param_constants(const std::vector< std::string > &param_constants)
Set param-constants value.
void set_is_satisfied(const bool &is_satisfied)
Set is-satisfied value.
void set_name(const std::string &name)
Set name value.
GroundedPDDLFormula representation for JSON transfer.
static std::string api_version()
Get version of implemented API.
GroundedPDDLPredicate representation for JSON transfer.
static std::string api_version()
Get version of implemented API.
PDDLFormula representation for JSON transfer.
Definition: PDDLFormula.h:28
static std::string api_version()
Get version of implemented API.
Definition: PDDLFormula.h:48
PDDLGrounding representation for JSON transfer.
Definition: PDDLGrounding.h:28
static std::string api_version()
Get version of implemented API.
Definition: PDDLGrounding.h:48
PDDLPredicate representation for JSON transfer.
Definition: PDDLPredicate.h:28
static std::string api_version()
Get version of implemented API.
Definition: PDDLPredicate.h:48
static std::string api_version()
Get version of implemented API.
Definition: PlanAction.h:52
Plan representation for JSON transfer.
Definition: Plan.h:29
void set_id(const std::string &id)
Set id value.
Definition: Plan.h:136
void set_goal_id(const std::string &goal_id)
Set goal-id value.
Definition: Plan.h:153
static std::string api_version()
Get version of implemented API.
Definition: Plan.h:49
void set_kind(const std::string &kind)
Set kind value.
Definition: Plan.h:102
void set_actions(const std::vector< std::shared_ptr< PlanAction >> &actions)
Set actions value.
Definition: Plan.h:187
void set_cost(const float &cost)
Set cost value.
Definition: Plan.h:170
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: Plan.h:119
Container to return array via REST.
Definition: rest_array.h:36
void push_back(M &m)
Add item at the back of the container.
Definition: rest_array.h:123
LockPtr< CLIPSEnvManager > clips_env_mgr
CLIPS environment manager.
Definition: clips_manager.h:44
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual const char * what_no_backtrace() const noexcept
Get primary string (does not implicitly print the back trace).
Definition: exception.cpp:663
Mutex * objmutex_ptr() const
Get object mutex.
Definition: lockptr.h:284
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
Mutex locking helper.
Definition: mutex_locker.h:34
Thread class encapsulation of pthreads.
Definition: thread.h:46
const char * name() const
Get name of thread.
Definition: thread.h:100
WebviewRestApiManager * webview_rest_api_manager
Webview REST API manager.
Definition: webview.h:55
void unregister_api(WebviewRestApi *api)
Remove a request processor.
void register_api(WebviewRestApi *api)
Add a REST API.
Webview REST API component.
Definition: rest_api.h:221
void add_handler(WebRequest::Method method, std::string path, Handler handler)
Add handler function.
Definition: rest_api.cpp:85
REST processing exception.
Definition: rest_api.h:71
REST parameters to pass to handlers.
Definition: rest_api.h:125
std::string path_arg(const std::string &what)
Get a path argument.
Definition: rest_api.h:142
Fawkes library namespace.