21#include "yaml-cpp/yaml.h"
30 static Node encode(
const Manifest::ParamMap& rhs)
33 for (
const auto& [name, params] : rhs)
36 params_node[Manifest::PARAM_NAME_CLASS] = params.class_name;
37 params_node[Manifest::PARAM_NAME_PACKAGE] = params.package;
38 params_node[Manifest::PARAM_NAME_LIBRARY] = params.library;
39 params_node[Manifest::PARAM_NAME_PORT] = params.port;
40 params_node[Manifest::PARAM_NAME_WAIT_TIMEOUT] = params.wait_timeout.count();
41 params_node[Manifest::PARAM_NAME_REQUEST_TIMEOUT] = params.request_timeout.count();
42 node[name] = params_node;
46 static bool decode(
const Node& node, Manifest::ParamMap& lhs)
49 throw std::runtime_error(
"Root YAML::Node must be map but is type " + std::to_string(node.Type()) +
50 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
52 for (YAML::const_iterator it = node.begin(); it != node.end(); ++it)
54 const auto& name = it->first.as<std::string>();
55 const auto& params_node = it->second;
56 if (!params_node.IsMap())
57 throw std::runtime_error(
"Params YAML::Node must be map but is type " + std::to_string(params_node.Type()) +
58 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
60 Manifest::Params params;
61 for (YAML::const_iterator p = params_node.begin(); p != params_node.end(); ++p)
63 const auto param_key = p->first.as<std::string>();
64 const auto& val = p->second;
66 throw std::runtime_error(
"Value for key '" + param_key +
"' must be scalar but is type " +
67 std::to_string(val.Type()) +
68 " (0: Undefined - 1: Null - 2: Scalar - 3: Sequence - 4: Map).");
70 if (param_key == Manifest::PARAM_NAME_CLASS)
72 params.class_name = val.as<std::string>();
75 if (param_key == Manifest::PARAM_NAME_PORT)
77 params.port = val.as<std::string>();
80 if (param_key == Manifest::PARAM_NAME_PACKAGE)
82 params.package = val.as<std::string>();
85 if (param_key == Manifest::PARAM_NAME_LIBRARY)
87 params.library = val.as<std::string>();
90 if (param_key == Manifest::PARAM_NAME_WAIT_TIMEOUT)
92 params.wait_timeout = std::chrono::duration<double>(val.as<
double>());
95 if (param_key == Manifest::PARAM_NAME_REQUEST_TIMEOUT)
97 params.request_timeout = std::chrono::duration<double>(val.as<
double>());
101 throw std::runtime_error(
"Unkown parameter '" + param_key +
"'.");
130 if (file_paths.empty())
133 for (
size_t i = 1; i < file_paths.size(); ++i)
142 return YAML::LoadFile(file_path).as<
ParamMap>();
148 std::all_of(manifest_str.begin(), manifest_str.end(), [](
unsigned char c) { return std::isspace(c); });
154 return param_map_.find(node_name) != param_map_.end();
160 return param_map_[node_name];
161 throw std::out_of_range{
"Node '" + node_name +
"' doesn't exist in manifest (Size: " +
162 std::to_string(param_map_.size()) +
"). Use the Add() method to add an entry." };
168 return param_map_.at(node_name);
169 throw std::out_of_range{
"Node '" + node_name +
170 "' doesn't exist in manifest (Size: " + std::to_string(param_map_.size()) +
")." };
177 throw std::logic_error{
"Node '" + node_name +
178 "' already exists in manifest (Size: " + std::to_string(param_map_.size()) +
")." };
180 param_map_[node_name] = p;
188 throw std::logic_error{
"Node '" + node_name +
189 "' doesn't exist in manifest, so the corresponding entry cannot be removed." };
191 param_map_.erase(node_name);
198 add(node_name, params);
204 for (
const auto& [node_name, params] : param_map_)
206 const std::string node_package_name = class_loader.getClassPackage(params.class_name);
207 if (node_package_name.empty())
210 "' required by node '" + node_name +
211 "', because no such resource is registered with this "
212 "plugin loader instance.");
214 const std::string node_lib_path = class_loader.getClassLibraryPath(params.class_name);
215 if (!params.package.empty())
218 if (params.package == node_package_name)
221 "Cannot find class '" + params.class_name +
"' required by node '" + node_name +
"' in package '" +
222 params.package +
"'. Internally, the resource is registered by package '" + node_package_name +
223 "' instead. This can occur if multiple packages register a node plugin with the same class name. "
224 "To resolve this issue, introduce a unique package namespace to the respective class names.");
227 param_map_[node_name].package = node_package_name;
228 param_map_[node_name].library = node_lib_path;
237 std::ofstream out_stream{ file_path };
238 if (out_stream.is_open())
245 throw std::runtime_error(
"Error opening node plugin manifest output file '" + file_path +
"'.");
Data structure for resource lookup data and configuration parameters required for loading and registe...
static const std::string PARAM_NAME_REQUEST_TIMEOUT
static NodeManifest fromFile(const std::string &file_path)
Create a node plugin manifest from a file.
std::string toString() const
const ParamMap & getInternalMap() const
NodeManifest & merge(const NodeManifest &m)
static const std::string PARAM_NAME_CLASS
static const std::string PARAM_NAME_PACKAGE
bool contains(const std::string &node_name) const
static const std::string PARAM_NAME_LIBRARY
std::map< std::string, NodeRegistrationParams > ParamMap
Mapping of a node's name and its registration parameters.
static NodeManifest fromString(const std::string &manifest_str)
static const std::string PARAM_NAME_WAIT_TIMEOUT
static NodeManifest fromFiles(const std::vector< std::string > &file_paths)
Create a node plugin manifest from multiple files. They are loaded in the given order.
void toFile(const std::string &file_path) const
static const std::string PARAM_NAME_PORT
NodeManifest & add(const std::string &node_name, const NodeRegistrationParams &p)
NodeManifest(const ParamMap ¶m_map={})
NodeManifest & autoComplete(NodePluginClassLoader &class_loader)
Automatically fill node plugin resource information in manifest.
NodeManifest & remove(const std::string &node_name)
NodeRegistrationParams & operator[](const std::string &node_name)
Version of pluginlib::ClassLoader specifically for loading installed behavior tree node plugins.
Behavior tree node registration parameters.