Kea  1.5.0
adaptor.cc
Go to the documentation of this file.
1 // Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <yang/adaptor.h>
8 #include <boost/foreach.hpp>
9 
10 #include <iostream>
11 
12 using namespace std;
13 using namespace isc::data;
14 
15 namespace isc {
16 namespace yang {
17 
18 Adaptor::Adaptor() {
19 }
20 
21 Adaptor::~Adaptor() {
22 }
23 
25 Adaptor::getContext(ConstElementPtr parent)
26 {
27  ConstElementPtr context = parent->get("user-context");
28  ConstElementPtr comment = parent->get("comment");
29  if (!comment) {
30  return (context);
31  }
32  ElementPtr result;
33  if (context) {
34  result = copy(context);
35  } else {
36  result = Element::createMap();
37  }
38  result->set("comment", comment);
39  return (result);
40 }
41 
42 void
43 Adaptor::fromParent(const string& name, ConstElementPtr parent,
44  ConstElementPtr list) {
45  ConstElementPtr param = parent->get(name);
46  if (!param) {
47  return;
48  }
49  BOOST_FOREACH(ElementPtr item, list->listValue()) {
50  // don't override. Skip this entry if it already has the parameter.
51  if (item->contains(name)) {
52  continue;
53  }
54  item->set(name, param);
55  }
56 }
57 
58 void
59 Adaptor::toParent(const string& name, ElementPtr parent,
60  ConstElementPtr list) {
61  ConstElementPtr param;
62  bool first = true;
63  BOOST_FOREACH(ElementPtr item, list->listValue()) {
64  if (first) {
65  first = false;
66  param = item->get(name);
67  } else if ((!param && item->contains(name)) ||
68  (param && !item->contains(name)) ||
69  (param && item->contains(name) &&
70  !param->equals(*item->get(name)))) {
72  "inconsistent value of " << name
73  << " in " << list->str());
74  }
75  }
76  if (!first && param) {
77  BOOST_FOREACH(ElementPtr item, list->listValue()) {
78  if (param) {
79  item->remove(name);
80  }
81  }
82  parent->set(name, param);
83  }
84 }
85 
86 namespace {
87 
99 void applyInsert(ConstElementPtr key, ConstElementPtr value,
100  ElementPtr scope) {
101  if (scope->getType() == Element::map) {
102  if (!key || !value || (key->getType() != Element::string)) {
103  return;
104  }
105  string name = key->stringValue();
106  if (!name.empty() && !scope->contains(name)) {
107  scope->set(name, copy(value));
108  }
109  } else if (scope->getType() == Element::list) {
110  if (value) {
111  scope->add(copy(value));
112  }
113  }
114 }
115 
124 void applyReplace(ConstElementPtr key, ConstElementPtr value,
125  ElementPtr scope) {
126  if ((scope->getType() != Element::map) ||
127  !key || !value || (key->getType() != Element::string)) {
128  return;
129  }
130  string name = key->stringValue();
131  if (!name.empty()) {
132  scope->set(name, copy(value));
133  }
134 }
135 
148 void applyDelete(ConstElementPtr key, ElementPtr scope) {
149  if (scope->getType() == Element::map) {
150  if (!key || (key->getType() != Element::string)) {
151  return;
152  }
153  string name = key->stringValue();
154  if (!name.empty()) {
155  scope->remove(name);
156  }
157  } else if (scope->getType() == Element::list) {
158  if (!key) {
159  return;
160  } else if (key->getType() == Element::integer) {
161  int index = key->intValue();
162  if ((index >= 0) && (index < scope->size())) {
163  scope->remove(index);
164  }
165  } else if (key->getType() == Element::map) {
166  ConstElementPtr entry = key->get("key");
167  ConstElementPtr value = key->get("value");
168  if (!entry || !value || (entry->getType() != Element::string)) {
169  return;
170  }
171  string name = entry->stringValue();
172  if (name.empty()) {
173  return;
174  }
175  for (int i = 0; i < scope->size(); ++i) {
176  ConstElementPtr item = scope->get(i);
177  if (!item || (item->getType() != Element::map)) {
178  continue;
179  }
180  ConstElementPtr compare = item->get(name);
181  if (compare && value->equals(*compare)) {
182  scope->remove(i);
183  return;
184  }
185  }
186  }
187  }
188 }
189 
198 void applyAction(ConstElementPtr actions, ElementPtr scope, size_t next) {
199  if (next == actions->size()) {
200  return;
201  }
202  ConstElementPtr action = actions->get(next);
203  ++next;
204  if (!action || (action->getType() != Element::map) ||
205  !action->contains("action")) {
206  applyAction(actions, scope, next);
207  return;
208  }
209  string name = action->get("action")->stringValue();
210  if (name == "insert") {
211  applyInsert(action->get("key"), action->get("value"), scope);
212  } else if (name == "replace") {
213  applyReplace(action->get("key"), action->get("value"), scope);
214  } else if (name == "delete") {
215  applyDelete(action->get("key"), scope);
216  }
217  applyAction(actions, scope, next);
218 }
219 
234 void applyDown(ConstElementPtr path, ConstElementPtr actions, ElementPtr scope,
235  size_t next) {
236  if (!scope) {
237  return;
238  }
239  if (next == path->size()) {
240  applyAction(actions, scope, 0);
241  return;
242  }
243  ConstElementPtr step = path->get(next);
244  ++next;
245  if (scope->getType() == Element::map) {
246  if (!step || (step->getType() != Element::string)) {
247  return;
248  }
249  string name = step->stringValue();
250  if (name.empty() || !scope->contains(name)) {
251  return;
252  }
253  ElementPtr down = boost::const_pointer_cast<Element>(scope->get(name));
254  if (down) {
255  applyDown(path, actions, down, next);
256  }
257  } else if (scope->getType() == Element::list) {
258  if (!step) {
259  return;
260  }
261  auto downs = scope->listValue();
262  if (step->getType() == Element::map) {
263  ConstElementPtr key = step->get("key");
264  ConstElementPtr value = step->get("value");
265  if (!key || !value || (key->getType() != Element::string)) {
266  return;
267  }
268  string name = key->stringValue();
269  if (name.empty()) {
270  return;
271  }
272  for (ElementPtr down : downs) {
273  if (!down || (down->getType() != Element::map)) {
274  continue;
275  }
276  ConstElementPtr compare = down->get(name);
277  if (compare && value->equals(*compare)) {
278  applyDown(path, actions, down, next);
279  return;
280  }
281  }
282  } else if (step->getType() != Element::integer) {
283  return;
284  }
285  int index = step->intValue();
286  if (index == -1) {
287  for (ElementPtr down : downs) {
288  applyDown(path, actions, down, next);
289  }
290  } else if ((index >= 0) && (index < scope->size())) {
291  applyDown(path, actions, scope->getNonConst(index), next);
292  }
293  }
294 }
295 
296 } // end of anonymous namespace
297 
299 void
300 Adaptor::modify(ConstElementPtr path, ConstElementPtr actions,
301  ElementPtr config) {
302  applyDown(path, actions, config, 0);
303 }
304 
305 }; // end of namespace isc::yang
306 }; // end of namespace isc
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1114
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
Defines the logger used by the top-level component of kea-dhcp-ddns.