AutoAPMS
Streamlining behaviors in ROS 2
Loading...
Searching...
No Matches
tree_resource.cpp
1// Copyright 2024 Robin Müller
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "auto_apms_behavior_tree_core/tree/tree_resource.hpp"
16
17#include <tinyxml2.h>
18
19#include <filesystem>
20
21#include "ament_index_cpp/get_resource.hpp"
22#include "auto_apms_behavior_tree_core/definitions.hpp"
23#include "auto_apms_behavior_tree_core/exceptions.hpp"
24#include "auto_apms_behavior_tree_core/tree/tree_document.hpp"
25#include "auto_apms_util/resource.hpp"
26#include "auto_apms_util/string.hpp"
27
29{
30
31TreeResourceIdentity::TreeResourceIdentity(const std::string & identity)
32: BehaviorResourceIdentity(identity, _AUTO_APMS_BEHAVIOR_TREE_CORE__DEFAULT_BEHAVIOR_CATEGORY__TREE)
33{
34 std::vector<std::string> tokens =
35 auto_apms_util::splitString(behavior_alias, _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP, true);
36
37 // If only a single token is given, assume it's file_stem
38 if (tokens.size() > 1) {
39 file_stem = tokens[0];
40 tree_name = tokens[1];
41 } else if (tokens.size() > 0) {
42 file_stem = tokens[0];
43 tree_name = "";
44 }
45
46 if (file_stem.empty() && tree_name.empty()) {
47 throw auto_apms_util::exceptions::ResourceIdentityFormatError(
48 "Behavior tree resource identity string '" + identity +
49 "' is invalid. It's not allowed to omit both <tree_file_stem> and <tree_name>.");
50 }
51}
52
53TreeResourceIdentity::TreeResourceIdentity(const char * identity) : TreeResourceIdentity(std::string(identity)) {}
54
56{
57 // Fill the tree specific fields for the unique identity
58 const std::vector<std::string> & tokens = auto_apms_util::splitString(
59 unique_identity_.behavior_alias, _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP, false);
60
61 if (tokens.size() != 2) {
62 throw auto_apms_util::exceptions::ResourceIdentityFormatError(
63 "Unique tree resource identity string '" + unique_identity_.str() +
64 "' is invalid. Behavior alias must be <tree_file_stem>" +
65 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP + "<tree_name>.");
66 }
67
68 unique_identity_.file_stem = tokens[0];
69 unique_identity_.tree_name = tokens[1];
70
71 // Verify that the file is ok
72 TreeDocument doc;
73 try {
74 doc.mergeFile(build_request_file_path_, true);
75 } catch (const std::exception & e) {
76 throw auto_apms_util::exceptions::ResourceError(
77 "Failed to create TreeResource with identity '" + unique_identity_.str() + "' because tree file " +
78 build_request_file_path_ + " cannot be parsed: " + e.what());
79 }
80
81 // Verify that the tree <tree_name> specified by the identity string is actually present
82 if (!unique_identity_.tree_name.empty()) {
83 if (!auto_apms_util::contains(doc.getAllTreeNames(), unique_identity_.tree_name)) {
84 throw auto_apms_util::exceptions::ResourceError(
85 "Cannot create TreeResource with identity '" + unique_identity_.str() + "' because '" +
86 unique_identity_.tree_name + "' does not exist in tree file " + build_request_file_path_ + ".");
87 }
88 }
89
90 // Save the root tree name if available
91 if (doc.hasRootTreeName()) {
92 doc_root_tree_name_ = doc.getRootTreeName();
93 }
94}
95
96TreeResource::TreeResource(const std::string & search_identity) : TreeResource(TreeResourceIdentity(search_identity)) {}
97
98TreeResource::TreeResource(const char * search_identity) : TreeResource(std::string(search_identity)) {}
99
100TreeResource TreeResource::findByTreeName(const std::string & tree_name, const std::string & package_name)
101{
102 return TreeResource(
103 package_name + _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP +
104 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP + tree_name);
105}
106
107TreeResource TreeResource::findByFileStem(const std::string & file_name, const std::string & package_name)
108{
109 return TreeResource(
110 package_name + _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP + file_name +
111 _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP);
112}
113
115{
116 return !unique_identity_.tree_name.empty() || !doc_root_tree_name_.empty();
117}
118
120{
121 if (!unique_identity_.tree_name.empty()) return unique_identity_.tree_name;
122
123 // If <tree_name> wasn't provided, look for root tree attribute in XML file
124 if (!doc_root_tree_name_.empty()) return doc_root_tree_name_;
125
126 // Root tree cannot be determined
127 throw auto_apms_util::exceptions::ResourceError(
128 "Cannot get root tree name of tree resource '" + unique_identity_.str() +
129 "'. Since there is no XML attribute named '" + TreeDocument::ROOT_TREE_ATTRIBUTE_NAME +
130 "' and the resource identity doesn't specify <tree_name>, the root tree is unkown.");
131}
132
134{
136 i.package_name = unique_identity_.package_name;
137 i.file_stem = unique_identity_.file_stem;
138 i.tree_name = tree_name;
139 return i;
140}
141
142} // namespace auto_apms_behavior_tree::core
std::string getRootTreeName() const
Get the name of this document's root tree.
TreeDocument & mergeFile(const std::string &path, bool adopt_root_tree=false)
Create a tree document from a file and merge it with this one.
std::vector< std::string > getAllTreeNames() const
Get the names of all behavior trees inside this document.
bool hasRootTreeName() const
Determine if this document specifies which of its trees is the root tree.
TreeResourceIdentity createIdentityForTree(const std::string &tree_name="") const
Create a valid identity string for a specific behavior tree of this resource.
std::string getRootTreeName() const
Get the name of the root tree of this behavior tree resource.
static TreeResource findByTreeName(const std::string &tree_name, const std::string &package_name="")
Find an installed behavior tree resource using a specific behavior tree name.
static TreeResource findByFileStem(const std::string &file_stem, const std::string &package_name="")
Find an installed behavior tree resource using a specific behavior tree XML file stem.
TreeResource(const TreeResourceIdentity &search_identity)
Assemble a behavior tree resource using a TreeResourceIdentity.
bool hasRootTreeName() const
Determine if this behavior tree resource specifies a root tree.
bool contains(const ContainerT< ValueT, AllocatorT > &c, const ValueT &val)
Check whether a particular container structure contains a value.
Definition container.hpp:36
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...
Definition string.cpp:24
Core API for AutoAPMS's behavior tree implementation.
Definition behavior.hpp:32
BehaviorResourceIdentity(const std::string &identity)
Constructor of a behavior resource identity object.
Definition behavior.cpp:28
std::string behavior_alias
Alias for a single registered behavior.
Definition behavior.hpp:97
std::string package_name
Name of the package that registers the behavior resource.
Definition behavior.hpp:95
Struct that encapsulates the identity string for a registered behavior tree.
std::string tree_name
Name of a specific tree inside the resource's tree document.
std::string file_stem
Name of the file (without extension) that contains the resource's tree document.
TreeResourceIdentity()=default
Constructor of an empty behavior tree resource identity object.
TreeResourceIdentity(const std::string &identity)
Constructor of a tree resource identity object.