blob: 47e08847b18b0f41743b60a3cb177d1b40ddd6d4 [file] [log] [blame]
Václav Kubernátbddbb172018-06-13 16:27:39 +02001/*
2 * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
3 * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
4 *
5 * Written by Václav Kubernát <kubervac@fit.cvut.cz>
6 *
7*/
8
Václav Kubernát9456b5c2019-10-02 21:14:52 +02009#include <boost/algorithm/string/predicate.hpp>
Václav Kubernátbddbb172018-06-13 16:27:39 +020010#include "static_schema.hpp"
11#include "utils.hpp"
12
13InvalidNodeException::~InvalidNodeException() = default;
14
15StaticSchema::StaticSchema()
16{
Václav Kubernátefcac932020-01-10 15:26:32 +010017 m_nodes.emplace("/", std::unordered_map<std::string, NodeType>());
Václav Kubernátbddbb172018-06-13 16:27:39 +020018}
19
20const std::unordered_map<std::string, NodeType>& StaticSchema::children(const std::string& name) const
21{
22 return m_nodes.at(name);
23}
24
Václav Kubernát744f57f2018-06-29 22:46:26 +020025bool StaticSchema::nodeExists(const std::string& location, const std::string& node) const
Václav Kubernátbddbb172018-06-13 16:27:39 +020026{
Václav Kubernát744f57f2018-06-29 22:46:26 +020027 if (node.empty())
Václav Kubernátbddbb172018-06-13 16:27:39 +020028 return true;
29 const auto& childrenRef = children(location);
30
Václav Kubernát744f57f2018-06-29 22:46:26 +020031 return childrenRef.find(node) != childrenRef.end();
Václav Kubernátbddbb172018-06-13 16:27:39 +020032}
33
Václav Kubernát75877de2019-11-20 17:43:02 +010034bool StaticSchema::isModule(const std::string& name) const
Václav Kubernátbddbb172018-06-13 16:27:39 +020035{
Václav Kubernát744f57f2018-06-29 22:46:26 +020036 return m_modules.find(name) != m_modules.end();
37}
38
Václav Kubernát2eaceb82018-10-08 19:56:30 +020039bool StaticSchema::isContainer(const schemaPath_& location, const ModuleNodePair& node) const
Václav Kubernát744f57f2018-06-29 22:46:26 +020040{
Václav Kubernátefcac932020-01-10 15:26:32 +010041 std::string locationString = pathToSchemaString(location, Prefixes::Always);
Václav Kubernát744f57f2018-06-29 22:46:26 +020042 auto fullName = fullNodeName(location, node);
43 if (!nodeExists(locationString, fullName))
Václav Kubernátbddbb172018-06-13 16:27:39 +020044 return false;
45
Václav Kubernát744f57f2018-06-29 22:46:26 +020046 return children(locationString).at(fullName).type() == typeid(yang::container);
Václav Kubernátbddbb172018-06-13 16:27:39 +020047}
48
49void StaticSchema::addContainer(const std::string& location, const std::string& name, yang::ContainerTraits isPresence)
50{
51 m_nodes.at(location).emplace(name, yang::container{isPresence});
52
53 //create a new set of children for the new node
54 std::string key = joinPaths(location, name);
55 m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
56}
57
Václav Kubernát2eaceb82018-10-08 19:56:30 +020058bool StaticSchema::listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const
Václav Kubernátbddbb172018-06-13 16:27:39 +020059{
Václav Kubernátefcac932020-01-10 15:26:32 +010060 std::string locationString = pathToSchemaString(location, Prefixes::Always);
Václav Kubernát744f57f2018-06-29 22:46:26 +020061 assert(isList(location, node));
Václav Kubernátbddbb172018-06-13 16:27:39 +020062
Václav Kubernát744f57f2018-06-29 22:46:26 +020063 const auto& child = children(locationString).at(fullNodeName(location, node));
Václav Kubernátbddbb172018-06-13 16:27:39 +020064 const auto& list = boost::get<yang::list>(child);
65 return list.m_keys.find(key) != list.m_keys.end();
66}
67
Václav Kubernát2eaceb82018-10-08 19:56:30 +020068const std::set<std::string> StaticSchema::listKeys(const schemaPath_& location, const ModuleNodePair& node) const
Václav Kubernátbddbb172018-06-13 16:27:39 +020069{
Václav Kubernátefcac932020-01-10 15:26:32 +010070 std::string locationString = pathToSchemaString(location, Prefixes::Always);
Václav Kubernát744f57f2018-06-29 22:46:26 +020071 assert(isList(location, node));
Václav Kubernátbddbb172018-06-13 16:27:39 +020072
Václav Kubernát744f57f2018-06-29 22:46:26 +020073 const auto& child = children(locationString).at(fullNodeName(location, node));
Václav Kubernátbddbb172018-06-13 16:27:39 +020074 const auto& list = boost::get<yang::list>(child);
75 return list.m_keys;
76}
77
Václav Kubernát2eaceb82018-10-08 19:56:30 +020078bool StaticSchema::isList(const schemaPath_& location, const ModuleNodePair& node) const
Václav Kubernátbddbb172018-06-13 16:27:39 +020079{
Václav Kubernátefcac932020-01-10 15:26:32 +010080 std::string locationString = pathToSchemaString(location, Prefixes::Always);
Václav Kubernát744f57f2018-06-29 22:46:26 +020081 auto fullName = fullNodeName(location, node);
82 if (!nodeExists(locationString, fullName))
Václav Kubernátbddbb172018-06-13 16:27:39 +020083 return false;
Václav Kubernát744f57f2018-06-29 22:46:26 +020084 const auto& child = children(locationString).at(fullName);
Václav Kubernátbddbb172018-06-13 16:27:39 +020085 if (child.type() != typeid(yang::list))
86 return false;
87
88 return true;
89}
90
91void StaticSchema::addList(const std::string& location, const std::string& name, const std::set<std::string>& keys)
92{
93 m_nodes.at(location).emplace(name, yang::list{keys});
94
Václav Kubernát1446fe12019-10-02 19:32:51 +020095 std::string key = joinPaths(location, name);
96 m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
Václav Kubernátbddbb172018-06-13 16:27:39 +020097}
98
Václav Kubernát2eaceb82018-10-08 19:56:30 +020099bool StaticSchema::isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const
Václav Kubernátbddbb172018-06-13 16:27:39 +0200100{
Václav Kubernát744f57f2018-06-29 22:46:26 +0200101 if (!isContainer(location, node))
Václav Kubernátbddbb172018-06-13 16:27:39 +0200102 return false;
Václav Kubernátefcac932020-01-10 15:26:32 +0100103 std::string locationString = pathToSchemaString(location, Prefixes::Always);
Václav Kubernát744f57f2018-06-29 22:46:26 +0200104 return boost::get<yang::container>(children(locationString).at(fullNodeName(location, node))).m_presence == yang::ContainerTraits::Presence;
Václav Kubernátbddbb172018-06-13 16:27:39 +0200105}
106
107void StaticSchema::addLeaf(const std::string& location, const std::string& name, const yang::LeafDataTypes& type)
108{
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200109 m_nodes.at(location).emplace(name, yang::leaf{type, {}, {}, {}});
Václav Kubernáte69133a2019-11-01 19:01:34 +0100110 std::string key = joinPaths(location, name);
111 m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
Václav Kubernátbddbb172018-06-13 16:27:39 +0200112}
113
114void StaticSchema::addLeafEnum(const std::string& location, const std::string& name, std::set<std::string> enumValues)
115{
Václav Kubernáteeb38842019-03-20 19:46:05 +0100116 yang::leaf toAdd;
117 toAdd.m_type = yang::LeafDataTypes::Enum;
118 toAdd.m_enumValues = enumValues;
119 m_nodes.at(location).emplace(name, toAdd);
Václav Kubernáte69133a2019-11-01 19:01:34 +0100120 std::string key = joinPaths(location, name);
121 m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
Václav Kubernáteeb38842019-03-20 19:46:05 +0100122}
123
124void StaticSchema::addLeafIdentityRef(const std::string& location, const std::string& name, const ModuleValuePair& base)
125{
126 assert(base.first); // base identity cannot have an empty module
127 yang::leaf toAdd;
128 toAdd.m_type = yang::LeafDataTypes::IdentityRef;
129 toAdd.m_identBase = base;
130 m_nodes.at(location).emplace(name, toAdd);
Václav Kubernáte69133a2019-11-01 19:01:34 +0100131 std::string key = joinPaths(location, name);
132 m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
Václav Kubernátbddbb172018-06-13 16:27:39 +0200133}
134
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200135void StaticSchema::addLeafRef(const std::string& location, const std::string& name, const std::string& source)
136{
137 yang::leaf toAdd;
138 toAdd.m_type = yang::LeafDataTypes::LeafRef;
139 toAdd.m_leafRefSource = source;
140 m_nodes.at(location).emplace(name, toAdd);
Václav Kubernáte69133a2019-11-01 19:01:34 +0100141 std::string key = joinPaths(location, name);
142 m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200143}
144
Václav Kubernát744f57f2018-06-29 22:46:26 +0200145void StaticSchema::addModule(const std::string& name)
Václav Kubernátbddbb172018-06-13 16:27:39 +0200146{
Václav Kubernát744f57f2018-06-29 22:46:26 +0200147 m_modules.emplace(name);
148}
Václav Kubernátbddbb172018-06-13 16:27:39 +0200149
Václav Kubernáteeb38842019-03-20 19:46:05 +0100150void StaticSchema::addIdentity(const std::optional<ModuleValuePair>& base, const ModuleValuePair& name)
151{
152 if (base)
153 m_identities.at(base.value()).emplace(name);
154
155 m_identities.emplace(name, std::set<ModuleValuePair>());
156}
Václav Kubernát744f57f2018-06-29 22:46:26 +0200157
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200158bool StaticSchema::leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const
Václav Kubernát744f57f2018-06-29 22:46:26 +0200159{
Václav Kubernát989b5de2019-02-20 16:28:35 +0100160 auto enums = enumValues(location, node);
161 return enums.find(value) != enums.end();
Václav Kubernátbddbb172018-06-13 16:27:39 +0200162}
163
Václav Kubernáteeb38842019-03-20 19:46:05 +0100164void StaticSchema::getIdentSet(const ModuleValuePair& ident, std::set<ModuleValuePair>& res) const
165{
166 res.insert(ident);
167 auto derivedIdentities = m_identities.at(ident);
168 for (auto it : derivedIdentities) {
169 getIdentSet(it, res);
170 }
171}
172
173const std::set<std::string> StaticSchema::validIdentities(const schemaPath_& location, const ModuleNodePair& node, const Prefixes prefixes) const
174{
Václav Kubernátefcac932020-01-10 15:26:32 +0100175 std::string locationString = pathToSchemaString(location, Prefixes::Always);
Václav Kubernáteeb38842019-03-20 19:46:05 +0100176 assert(isLeaf(location, node));
177
178 const auto& child = children(locationString).at(fullNodeName(location, node));
179 const auto& leaf = boost::get<yang::leaf>(child);
180
181 std::set<ModuleValuePair> identSet;
182 getIdentSet(leaf.m_identBase, identSet);
183
184 std::set<std::string> res;
185 std::transform(identSet.begin(), identSet.end(), std::inserter(res, res.end()), [location, node, prefixes](const auto& it) {
186 auto topLevelModule = location.m_nodes.empty() ? node.first.get() : location.m_nodes.front().m_prefix.get().m_name;
187 std::string stringIdent;
188 if (prefixes == Prefixes::Always || (it.first && it.first.value() != topLevelModule)) {
189 stringIdent += it.first ? it.first.value() : topLevelModule;
190 stringIdent += ":";
191 }
192 stringIdent += it.second;
193 return stringIdent;
194 });
195
196 return res;
197}
198
199bool StaticSchema::leafIdentityIsValid(const schemaPath_& location, const ModuleNodePair& node, const ModuleValuePair& value) const
200{
201 auto identities = validIdentities(location, node, Prefixes::Always);
202
203 auto topLevelModule = location.m_nodes.empty() ? node.first.get() : location.m_nodes.front().m_prefix.get().m_name;
204 auto identModule = value.first ? value.first.value() : topLevelModule;
Václav Kubernát1bf704e2019-04-12 13:30:50 +0200205 return std::any_of(identities.begin(), identities.end(), [toFind = identModule + ":" + value.second](const auto& x) { return x == toFind; });
Václav Kubernáteeb38842019-03-20 19:46:05 +0100206}
207
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200208bool StaticSchema::isLeaf(const schemaPath_& location, const ModuleNodePair& node) const
Václav Kubernátbddbb172018-06-13 16:27:39 +0200209{
Václav Kubernátefcac932020-01-10 15:26:32 +0100210 std::string locationString = pathToSchemaString(location, Prefixes::Always);
Václav Kubernát744f57f2018-06-29 22:46:26 +0200211 auto fullName = fullNodeName(location, node);
212 if (!nodeExists(locationString, fullName))
Václav Kubernátbddbb172018-06-13 16:27:39 +0200213 return false;
214
Václav Kubernát744f57f2018-06-29 22:46:26 +0200215 return children(locationString).at(fullName).type() == typeid(yang::leaf);
Václav Kubernátbddbb172018-06-13 16:27:39 +0200216}
217
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200218std::string lastNodeOfSchemaPath(const std::string& path)
219{
220 std::string res = path;
221 auto pos = res.find_last_of('/');
Václav Kubernátefcac932020-01-10 15:26:32 +0100222 if (pos == 0) { // path had only one path fragment - "/something:something"
223 res.erase(0, 1);
224 return res;
225 }
226 if (pos != res.npos) { // path had more fragments
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200227 res.erase(0, pos);
Václav Kubernátefcac932020-01-10 15:26:32 +0100228 return res;
229 }
230
231 // path was empty
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200232 return res;
233}
234
235yang::LeafDataTypes StaticSchema::leafrefBase(const schemaPath_& location, const ModuleNodePair& node) const
236{
Václav Kubernátefcac932020-01-10 15:26:32 +0100237 std::string locationString = pathToSchemaString(location, Prefixes::Always);
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200238 auto leaf{boost::get<yang::leaf>(children(locationString).at(fullNodeName(location, node)))};
239 auto locationOfSource = stripLastNodeFromPath(leaf.m_leafRefSource);
240 auto nameOfSource = lastNodeOfSchemaPath(leaf.m_leafRefSource);
241 return boost::get<yang::leaf>(children(locationOfSource).at(nameOfSource)).m_type;
242}
243
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200244yang::LeafDataTypes StaticSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
Václav Kubernátbddbb172018-06-13 16:27:39 +0200245{
Václav Kubernátefcac932020-01-10 15:26:32 +0100246 std::string locationString = pathToSchemaString(location, Prefixes::Always);
Václav Kubernát744f57f2018-06-29 22:46:26 +0200247 return boost::get<yang::leaf>(children(locationString).at(fullNodeName(location, node))).m_type;
248}
249
Václav Kubernát989b5de2019-02-20 16:28:35 +0100250const std::set<std::string> StaticSchema::enumValues(const schemaPath_& location, const ModuleNodePair& node) const
251{
Václav Kubernátefcac932020-01-10 15:26:32 +0100252 std::string locationString = pathToSchemaString(location, Prefixes::Always);
Václav Kubernát989b5de2019-02-20 16:28:35 +0100253 assert(isLeaf(location, node));
254
255 const auto& child = children(locationString).at(fullNodeName(location, node));
256 const auto& leaf = boost::get<yang::leaf>(child);
257 return leaf.m_enumValues;
258}
259
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200260// We do not test StaticSchema, so we don't need to implement recursive childNodes
261// for this class.
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200262std::set<std::string> StaticSchema::childNodes(const schemaPath_& path, const Recursion) const
Václav Kubernát744f57f2018-06-29 22:46:26 +0200263{
Václav Kubernátefcac932020-01-10 15:26:32 +0100264 std::string locationString = pathToSchemaString(path, Prefixes::Always);
Václav Kubernát744f57f2018-06-29 22:46:26 +0200265 std::set<std::string> res;
266
267 auto childrenRef = children(locationString);
268
Václav Kubernát90de9502019-11-20 17:19:44 +0100269 std::transform(childrenRef.begin(), childrenRef.end(), std::inserter(res, res.end()), [](auto it) { return it.first; });
Václav Kubernát744f57f2018-06-29 22:46:26 +0200270 return res;
Václav Kubernátbddbb172018-06-13 16:27:39 +0200271}
Václav Kubernát9456b5c2019-10-02 21:14:52 +0200272
273// We do not test StaticSchema, so we don't need to implement recursive moduleNodes
274// for this class.
275std::set<std::string> StaticSchema::moduleNodes(const module_& module, const Recursion) const
276{
277 std::set<std::string> res;
278 auto topLevelNodes = m_nodes.at("");
279 auto modulePlusColon = module.m_name + ":";
280 for (const auto& it : topLevelNodes) {
281 if (boost::algorithm::starts_with(it.first, modulePlusColon)) {
282 res.insert(it.first);
283 }
284 }
285 return res;
286}