15#include "auto_apms_behavior_tree_core/node/node_manifest.hpp"
19#include "auto_apms_behavior_tree_core/exceptions.hpp"
20#include "auto_apms_behavior_tree_core/tree/tree_document.hpp"
21#include "auto_apms_util/resource.hpp"
22#include "auto_apms_util/string.hpp"
29 if (identity.empty()) {
30 throw auto_apms_util::exceptions::ResourceIdentityFormatError(
31 "Cannot create node manifest resource identity from empty string. Must be <package_name>" +
32 std::string(_AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP) +
"<metadata_id>.");
34 if (std::size_t pos = identity.find(_AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP);
35 pos == std::string::npos) {
41 metadata_id = identity.substr(pos + std::string(_AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP).size());
44 throw auto_apms_util::exceptions::ResourceIdentityFormatError(
45 "Node manifest resource identity string '" + identity +
"' is invalid. Metadata ID must not be empty.");
56 return str() == other.
str();
59bool NodeManifestResourceIdentity::operator<(
const NodeManifestResourceIdentity & other)
const
61 return str() < other.str();
73 std::set<NodeManifestResourceIdentity> identities;
75 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_TYPE_NAME__NODE_MANIFEST, exclude_packages)) {
77 std::string base_path;
78 if (ament_index_cpp::get_resource(
79 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_TYPE_NAME__NODE_MANIFEST, p, content, &base_path)) {
80 for (
const auto & line :
83 line, _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_MARKER_FILE_FIELD_PER_LINE_SEP,
false);
84 if (parts.size() > 0) {
103 for (
const auto & path : paths) {
105 manifest.
merge(fromFile(path));
106 }
catch (
const std::exception & e) {
107 throw exceptions::NodeManifestError(
"Error creating node manifest from multiple files: " + std::string(e.what()));
120 std::ofstream out_stream(file_path);
121 if (out_stream.is_open()) {
122 out_stream << this->encode();
125 throw exceptions::NodeManifestError(
"Error opening node manifest output file '" + file_path +
"'.");
133 if (
contains(node_name))
return map_[node_name];
134 throw std::out_of_range{
135 "Node '" + node_name +
"' doesn't exist in node manifest (Size: " + std::to_string(map_.size()) +
136 "). Use the add() method to add an entry."};
141 if (
contains(node_name))
return map_.at(node_name);
142 throw std::out_of_range{
143 "Node '" + node_name +
"' doesn't exist in node manifest (Size: " + std::to_string(map_.size()) +
")."};
149 throw exceptions::NodeManifestError{
150 "Node '" + node_name +
"' already exists in node manifest (Size: " + std::to_string(map_.size()) +
")."};
153 throw exceptions::NodeManifestError(
154 "Cannot add node '" + node_name +
"' to manifest. Parameter class_name must not be empty.");
156 map_[node_name] = opt;
163 throw std::out_of_range{
164 "Node '" + node_name +
"' doesn't exist in node manifest, so the corresponding entry cannot be removed."};
166 map_.erase(node_name);
172 for (
const auto & [node_name, params] : other.
map()) {
175 map_.erase(node_name);
177 throw exceptions::NodeManifestError(
178 "Cannot merge node manifests, because node '" + node_name +
179 "' already exists and argument replace is false (Won't replace existing entries).");
182 add(node_name, params);
188 const NodeManifest & other,
const std::string & with_namespace,
const std::string & sep)
190 for (
const auto & [node_name, params] : other.
map()) {
192 const std::string final_name = with_namespace + sep + node_name;
194 throw exceptions::NodeManifestError(
195 "Cannot merge node manifests, because node '" + final_name +
"' already exists.");
197 add(final_name, params);
206 for (
const auto & [node_name, params] : old_map) {
207 const std::string final_name = ns + sep + node_name;
208 map_[final_name] = params;
215 std::vector<std::string> names;
216 names.reserve(map_.size());
217 for (
const auto & [name, _] : map_) names.push_back(name);
229 std::set<std::string> search_packages;
237 size_t matching_count = 0;
238 for (
const auto & p : search_packages) {
240 std::string base_path;
241 if (ament_index_cpp::get_resource(
242 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_TYPE_NAME__NODE_MANIFEST, p, content, &base_path)) {
243 std::vector<std::string> lines =
245 for (
const std::string & line : lines) {
247 line, _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_MARKER_FILE_FIELD_PER_LINE_SEP,
false);
248 if (parts.size() != 3) {
249 throw auto_apms_util::exceptions::ResourceError(
250 "Invalid node manifest resource file (Package: '" + p +
"'). Invalid line: " + line +
".");
254 std::string found_metadata_id = parts[0];
255 if (found_metadata_id != search_identity.
metadata_id)
continue;
263 unique_identity_.package_name = p;
264 unique_identity_.metadata_id = found_metadata_id;
265 node_manifest_file_path_ = base_path +
"/" + parts[1];
266 node_model_file_path_ = base_path +
"/" + parts[2];
267 node_manifest_ = NodeManifest::fromFile(node_manifest_file_path_);
269 tinyxml2::XMLDocument model_doc;
270 if (model_doc.LoadFile(node_model_file_path_.c_str()) != tinyxml2::XMLError::XML_SUCCESS) {
271 throw exceptions::TreeDocumentError(
272 "Error parsing the node model associated with node manifest " + unique_identity_.str());
279 if (matching_count == 0) {
280 throw auto_apms_util::exceptions::ResourceError(
281 "No node manifest resource was found using identity '" + search_identity.
str() +
"'.");
283 if (matching_count > 1) {
284 throw auto_apms_util::exceptions::ResourceError(
285 "There are multiple node manifest resources with metadata ID '" + search_identity.
str() +
"'.");
Class containing behavior tree node manifest resource data.
NodeManifestResource(const Identity &search_identity)
Constructor of a node manifest resource object.
const NodeModelMap & getNodeModel() const
Get the node model object associated with this resource.
const Identity & getIdentity() const
Get the unique identity for this resource.
const NodeManifest & getNodeManifest() const
Get the node manifest object associated with this resource.
Data structure for information about which behavior tree node plugin to load and how to configure the...
NodeManifest & applyNodeNamespace(const std::string &ns, const std::string &sep=_AUTO_APMS_BEHAVIOR_TREE_CORE__NODE_NAMESPACE_DEFAULT_SEP)
Apply a namespace prefix to all node names in this manifest.
std::map< std::string, NodeRegistrationOptions > Map
Mapping of a node's name and its registration parameters.
static NodeManifest fromFiles(const std::vector< std::string > &paths)
Create a node plugin manifest from multiple files. They are loaded in the given order.
size_t size() const
Get the number of behavior tree nodes this manifest holds registration options for.
NodeManifest & add(const std::string &node_name, const RegistrationOptions &opt)
Add registration options for a behavior tree node to the manifest.
bool contains(const std::string &node_name) const
Determine if a behavior tree node has been added to the manifest.
NodeManifest & mergeWithNamespace(const NodeManifest &other, const std::string &with_namespace, const std::string &sep=_AUTO_APMS_BEHAVIOR_TREE_CORE__NODE_NAMESPACE_DEFAULT_SEP)
Merges another NodeManifest with this one using a namespace for the registration names.
bool empty() const
Determine whether any node registration options have been added to the manifest.
NodeManifest & merge(const NodeManifest &other, bool replace=false)
Merges another NodeManifest with this one.
const Map & map() const
Get a view of the internal map.
std::vector< std::string > getNodeNames()
Get all names of the behavior tree nodes specified by the manifest.
RegistrationOptions & operator[](const std::string &node_name)
Access the node manifest and retrieve registration options for a specific behavior tree node.
void toFile(const std::string &file_path) const
Write the node manifest to a file.
NodeManifest(const Map &map={})
Constructor of a NodeManifest data structure.
static NodeManifest fromResource(const NodeManifestResourceIdentity &search_identity)
Create a node manifest from an installed resource.
NodeManifest & remove(const std::string &node_name)
Remove registration options for a behavior tree node.
Document Object Model (DOM) for the behavior tree XML schema. This class offers a programmatic approa...
static NodeModelMap getNodeModel(tinyxml2::XMLDocument &doc, const NodeManifest &manifest)
Convert a behavior tree node model document to the corresponding data structure.
std::set< NodeManifestResourceIdentity > getNodeManifestResourceIdentities(const std::set< std::string > &exclude_packages={})
Get all registered behavior tree node manifest resource identities.
std::vector< std::string > splitString(const std::string &str, const std::string &delimiter, bool remove_empty=true)
Split a string into multiple tokens using a specific delimiter string (Delimiter may consist of multi...
std::set< std::string > getPackagesWithResourceType(const std::string &resource_type, const std::set< std::string > &exclude_packages={})
Get a list of all package names that register a certain type of ament_index resources.
Core API for AutoAPMS's behavior tree implementation.
NodeModelMap getNativeNodeModel()
Get a model of the native BehaviorTree.CPP nodes.
std::map< std::string, NodeModel > NodeModelMap
Mapping of node registration names and their implementation details.
Struct that encapsulates the identity string for a registered behavior tree node manifest.
bool empty() const
Determine whether this node manifest resource identity object is considered empty.
NodeManifestResourceIdentity(const std::string &identity)
Constructor of a node manifest resource identity object.
NodeManifestResourceIdentity()=default
Constructor of an empty node manifest resource identity object.
std::string package_name
Name of the package that registers the behavior resource.
std::string metadata_id
Metadata ID determined when regitering the corresponding node manifest resource.
std::string str() const
Create the corresponding identity string.
bool valid() const
Verify that the options are valid (e.g. all required values are set).