Skip to content

Commit d0b252f

Browse files
Add schema registry singleton class
1 parent 30883a3 commit d0b252f

File tree

5 files changed

+232
-70
lines changed

5 files changed

+232
-70
lines changed

tesseract_common/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@ add_library(
9696
src/profile.cpp
9797
src/property_tree.cpp
9898
src/resource_locator.cpp
99-
src/types.cpp
99+
src/schema_registry.cpp
100100
src/stopwatch.cpp
101+
src/types.cpp
101102
src/timer.cpp
102103
src/yaml_utils.cpp)
103104
target_link_libraries(

tesseract_common/include/tesseract_common/property_tree.h

Lines changed: 68 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
#define TESSERACT_COMMON_PROPERTY_TREE_H
33

44
#include <string>
5+
#include <string_view>
56
#include <map>
6-
#include <optional>
77
#include <vector>
8+
#include <optional>
9+
#include <functional>
810
#include <yaml-cpp/yaml.h>
911

1012
namespace tesseract_common
@@ -14,7 +16,7 @@ namespace property_type
1416
constexpr std::string_view BOOL{ "bool" };
1517
constexpr std::string_view STRING{ "string" };
1618
constexpr std::string_view INT{ "int" };
17-
constexpr std::string_view FLAOT{ "float" };
19+
constexpr std::string_view FLOAT{ "float" };
1820
} // namespace property_type
1921

2022
namespace property_attribute
@@ -27,79 +29,90 @@ constexpr std::string_view MAXIMUM{ "maximum" };
2729
} // namespace property_attribute
2830

2931
/**
30-
* @brief A hierarchical property tree that stores values, metadata attributes,
31-
* and supports schema merging, default handling, and custom validation.
32+
* @file property_tree.h
33+
* @brief Defines PropertyTree, a hierarchical structure for YAML-based
34+
* configuration with metadata and validation support.
35+
*/
36+
37+
/**
38+
* @class PropertyTree
39+
* @brief Represents a node in a hierarchical property tree.
3240
*
33-
* Each node may contain:
41+
* Each PropertyTree node may contain:
3442
* - A YAML::Node value (scalar, sequence, or map)
35-
* - Metadata attributes (as a map of YAML::Node)
36-
* - Child PropertyTree nodes for nested structures
37-
* - Custom validator functions to enforce constraints
43+
* - A map of metadata attributes (YAML::Node) keyed by string
44+
* - Nested child PropertyTree nodes
45+
* - A list of custom validator functions
3846
*/
3947
class PropertyTree
4048
{
4149
public:
4250
/**
43-
* @brief Signature for custom validator functions.
51+
* @brief Signature for custom validator callbacks.
4452
* @param node The PropertyTree node being validated.
53+
* @throws std::runtime_error on validation failure.
4554
*/
4655
using ValidatorFn = std::function<void(const PropertyTree&)>;
4756

4857
/**
49-
* @brief Default constructor.
58+
* @brief Default constructor. Creates an empty tree node.
5059
*/
5160
PropertyTree() = default;
5261

5362
/**
54-
* @brief Merge a schema tree into this node.
55-
* * Copies schema attributes, applies non-required defaults,
56-
* merges child structure, and registers schema validators.
57-
* @param schema The schema node to merge from.
63+
* @brief Merge schema metadata into this node.
64+
*
65+
* Copies attributes from the schema, applies defaults for non-required
66+
* properties, registers schema validators, and recursively merges children.
67+
* @param schema PropertyTree containing schema definitions.
5868
*/
5969
void mergeSchema(const PropertyTree& schema);
6070

6171
/**
62-
* @brief Validate this tree using registered validators.
63-
* * Traverses the tree, invoking each node's validators.
72+
* @brief Validate the tree using registered validators.
73+
*
74+
* Recursively invokes all validators on this node and its children.
75+
* Throws on the first error encountered.
6476
*/
6577
void validate() const;
6678

6779
/**
6880
* @brief Register a custom validator for this node.
69-
* @param fn Validator function to invoke during validate().
81+
* @param fn Callback to invoke during validation.
7082
*/
7183
void addValidator(ValidatorFn fn);
7284

7385
/**
7486
* @brief Access or create a child node by key.
75-
* @param key Child node identifier.
76-
* @return Reference to the child node.
87+
* @param key Child identifier (string key).
88+
* @return Reference to the child PropertyTree.
7789
*/
7890
PropertyTree& get(std::string_view key);
7991

8092
/**
8193
* @brief Access a child node by key (const).
82-
* @param key Child node identifier.
83-
* @return Const reference to the child node.
94+
* @param key Child identifier.
95+
* @return Const reference to the child.
96+
* @throws std::out_of_range if key not found.
8497
*/
8598
const PropertyTree& get(std::string_view key) const;
8699

87100
/**
88101
* @brief Find a child node without creating it.
89-
* @param key Child node identifier.
90-
* @return Pointer to the child or nullptr if missing.
102+
* @param key Child identifier.
103+
* @return Pointer to child or nullptr if not present.
91104
*/
92105
const PropertyTree* find(std::string_view key) const;
93106

94107
/**
95-
* @brief Set the YAML value for this node.
96-
* @param v YAML::Node representing the value.
108+
* @brief Set the YAML value of this node.
109+
* @param v YAML::Node representing the new value.
97110
*/
98111
void setValue(const YAML::Node& v);
99112

100113
/**
101-
* @brief Get the YAML value stored in this node.
102-
* @return Const reference to YAML::Node.
114+
* @brief Retrieve the YAML value stored at this node.
115+
* @return Const reference to a YAML::Node.
103116
*/
104117
const YAML::Node& getValue() const;
105118

@@ -110,98 +123,84 @@ class PropertyTree
110123
std::vector<std::string> keys() const;
111124

112125
/**
113-
* @brief Set a metadata attribute (YAML::Node form).
126+
* @brief Set a metadata attribute (YAML node form).
114127
* @param name Attribute name.
115128
* @param attr YAML::Node value.
116129
*/
117130
void setAttribute(std::string_view name, const YAML::Node& attr);
118131

119-
/**
120-
* @brief Set a string attribute.
121-
* @param name Attribute name.
122-
* @param attr String value.
123-
*/
132+
/** @brief Convenience overload to set a string attribute. */
124133
void setAttribute(std::string_view name, std::string_view attr);
125-
126-
/**
127-
* @brief Set a C-string attribute.
128-
*/
129134
void setAttribute(std::string_view name, const char* attr);
130-
131-
/**
132-
* @brief Set a boolean attribute.
133-
*/
135+
/** @brief Set a boolean attribute. */
134136
void setAttribute(std::string_view name, bool attr);
135-
136-
/**
137-
* @brief Set an integer attribute.
138-
*/
137+
/** @brief Set an integer attribute. */
139138
void setAttribute(std::string_view name, int attr);
140-
141-
/**
142-
* @brief Set a double attribute.
143-
*/
139+
/** @brief Set a double attribute. */
144140
void setAttribute(std::string_view name, double attr);
145141

146142
/**
147-
* @brief Check if an attribute exists and is non-null.
148-
* @param name Attribute name.
149-
* @return True if present and non-null.
143+
* @brief Check if an attribute exists and is not null.
144+
* @param name Attribute name.
145+
* @return True if present and non-null, false otherwise.
150146
*/
151147
bool hasAttribute(std::string_view name) const;
152148

153149
/**
154-
* @brief Retrieve an attribute value.
155-
* @param name Attribute name.
156-
* @return Optional<YAML::Node> if attribute exists.
150+
* @brief Retrieve an attribute value by name.
151+
* @param name Attribute name.
152+
* @return Optional containing YAML::Node if found.
157153
*/
158154
std::optional<YAML::Node> getAttribute(std::string_view name) const;
159155

160156
/**
161157
* @brief List all metadata attribute keys.
162-
* @return Vector of attribute key strings.
158+
* @return Vector of attribute names.
163159
*/
164160
std::vector<std::string> getAttributeKeys() const;
165161

166162
/**
167-
* @brief Build a PropertyTree from a YAML::Node.
168-
* @param node Root YAML::Node.
163+
* @brief Create a PropertyTree from a YAML::Node.
164+
* @param node Root YAML::Node to convert.
169165
* @return Populated PropertyTree hierarchy.
170166
*/
171167
static PropertyTree fromYAML(const YAML::Node& node);
172168

173169
/**
174-
* @brief Serialize this tree to a YAML::Node.
175-
* @param exclude_attributes If true, omit the attributes map.
170+
* @brief Serialize this tree back into a YAML::Node.
171+
* @param exclude_attributes If true, omit the attributes map.
176172
* @return YAML::Node representation of the tree.
177173
*/
178174
YAML::Node toYAML(bool exclude_attributes = true) const;
179175

180176
private:
181-
YAML::Node value_; /**< Stored YAML value */
177+
YAML::Node value_; /**< Value stored at this node */
182178
std::map<std::string, YAML::Node> attributes_; /**< Metadata attributes */
183179
std::map<std::string, PropertyTree> children_; /**< Nested child nodes */
184-
std::vector<ValidatorFn> validators_; /**< Registered validators */
180+
std::vector<ValidatorFn> validators_; /**< Validators to invoke */
185181
};
186182

187183
/**
188-
* @brief Ensure a required attribute exists and is non-null.
189-
* @param node PropertyTree node to validate.
184+
* @brief Validator: ensure 'required' attribute is present and non-null.
185+
* @param node Node to validate.
186+
* @throws runtime_error if missing.
190187
*/
191188
void validateRequired(const PropertyTree& node);
192189

193190
/**
194-
* @brief Enforce numeric range if 'minimum'/'maximum' attributes are set.
195-
* @param node PropertyTree node to validate.
191+
* @brief Validator: enforce 'minimum'/'maximum' range constraints.
192+
* @param node Node to validate.
193+
* @throws runtime_error if out of range.
196194
*/
197195
void validateRange(const PropertyTree& node);
198196

199197
/**
200-
* @brief Enforce that the node's value is one of the 'enum' attribute list.
201-
* @param node PropertyTree node to validate.
198+
* @brief Validator: enforce that node's value is in 'enum' list.
199+
* @param node Node to validate.
200+
* @throws runtime_error if not found.
202201
*/
203202
void validateEnum(const PropertyTree& node);
204203

205204
} // namespace tesseract_common
206205

207-
#endif // PROPERTY_TREE_H
206+
#endif // TESSERACT_COMMON_PROPERTY_TREE_H
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#ifndef TESSERACT_COMMON_SCHEMA_REGISTRY_H
2+
#define TESSERACT_COMMON_SCHEMA_REGISTRY_H
3+
4+
#include <string>
5+
#include <map>
6+
#include <mutex>
7+
#include <memory>
8+
9+
namespace tesseract_common
10+
{
11+
class PropertyTree;
12+
13+
/**
14+
* @brief A global registry of named schemas for PropertyTree.
15+
*
16+
* Use SchemaRegistry::instance() to access the singleton.
17+
*/
18+
class SchemaRegistry
19+
{
20+
public:
21+
~SchemaRegistry() = default;
22+
SchemaRegistry(const SchemaRegistry&) = delete;
23+
SchemaRegistry& operator=(const SchemaRegistry&) = delete;
24+
SchemaRegistry(const SchemaRegistry&&) = delete;
25+
SchemaRegistry& operator=(const SchemaRegistry&&) = delete;
26+
27+
/** @brief Access the singleton instance. */
28+
static std::shared_ptr<SchemaRegistry> instance();
29+
30+
/**
31+
* @brief Register an already-parsed schema under a logical key.
32+
* @param key Unique identifier for this schema.
33+
* @param schema Parsed PropertyTree schema.
34+
*/
35+
void registerSchema(const std::string& key, const PropertyTree& schema);
36+
37+
/**
38+
* @brief Register a schema from a YAML file path.
39+
* @param key Unique identifier for this schema.
40+
* @param path Path to a .yaml schema file.
41+
*/
42+
void registerSchemaFromFile(const std::string& key, const std::string& path);
43+
44+
/**
45+
* @brief Check whether a schema is registered under this key.
46+
* @param key Logical identifier.
47+
* @return True if present.
48+
*/
49+
bool contains(const std::string& key) const;
50+
51+
/**
52+
* @brief Retrieve a registered schema by key.
53+
* @param key Logical identifier.
54+
* @return Const reference to the schema PropertyTree.
55+
* @throws std::out_of_range if the key is not found.
56+
*/
57+
const PropertyTree& get(const std::string& key) const;
58+
59+
/**
60+
* @brief Load and parse an arbitrary YAML file into a PropertyTree.
61+
* @param path Path to a .yaml file.
62+
* @return Parsed PropertyTree.
63+
* @throws YAML::Exception on parse errors.
64+
*/
65+
static PropertyTree loadFile(const std::string& path);
66+
67+
private:
68+
SchemaRegistry() = default;
69+
70+
mutable std::mutex mutex_;
71+
mutable std::map<std::string, PropertyTree> schemas_;
72+
mutable std::map<std::string, std::string> paths_;
73+
};
74+
75+
} // namespace tesseract_common
76+
77+
#endif // TESSERACT_COMMON_SCHEMA_REGISTRY_H

tesseract_common/src/property_tree.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#include <tesseract_common/property_tree.h>
2+
#include <tesseract_common/schema_registry.h>
23

34
const static std::string ATTRIBUTES_KEY{ "attributes" };
45
const static std::string VALUE_KEY{ "value" };
6+
const static std::string FOLLOW_KEY{ "follow" };
57

68
namespace tesseract_common
79
{
@@ -132,6 +134,17 @@ std::vector<std::string> PropertyTree::getAttributeKeys() const
132134

133135
PropertyTree PropertyTree::fromYAML(const YAML::Node& node)
134136
{
137+
// Handle 'follow' directive: load external YAML or schema file
138+
if (node.IsMap() && node[FOLLOW_KEY] && node[FOLLOW_KEY].IsScalar())
139+
{
140+
if (node.size() > 1)
141+
throw std::runtime_error("'follow' cannot be mixed with other entries");
142+
143+
auto key = node[FOLLOW_KEY].as<std::string>();
144+
auto registry = SchemaRegistry::instance();
145+
return registry->contains(key) ? registry->get(key) : SchemaRegistry::loadFile(key);
146+
}
147+
135148
PropertyTree tree;
136149
tree.value_ = node;
137150
if (node.IsMap())

0 commit comments

Comments
 (0)