Kea  1.5.0
user_context_utils.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-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 <config.h>
8 
10 
11 using namespace isc::data;
12 
13 namespace {
14 
17 template<typename EP>
18 class Value {
19 public:
21  static Value mkCopy(EP value) { return (Value(value, false)); }
22 
24  static Value mkShare(EP value) { return (Value(value, true)); }
25 
28  EP get() const { return (value_); }
29 
32  bool isShared() const { return (shared_); }
33 
34 private:
38  Value(EP value, bool shared) : value_(value), shared_(shared) { }
39 
41  EP value_;
42 
44  bool shared_;
45 };
46 
53 template<typename EP>
54 Value<EP> moveComments1(EP element) {
55  bool modified = false;
56 
57  // On lists recurse on items
58  if (element->getType() == Element::list) {
59  ElementPtr result = ElementPtr(new ListElement());
60  typedef std::vector<ElementPtr> ListType;
61  const ListType& list = element->listValue();
62  for (ListType::const_iterator it = list.cbegin();
63  it != list.cend(); ++it) {
64  Value<ElementPtr> item = moveComments1(*it);
65  result->add(item.get());
66  if (!item.isShared()) {
67  modified = true;
68  }
69  }
70  if (!modified) {
71  return (Value<EP>::mkShare(element));
72  } else {
73  return (Value<EP>::mkCopy(result));
74  }
75  } else if (element->getType() != Element::map) {
76  return (Value<EP>::mkShare(element));
77  }
78 
79  // Process maps: recurse on items
80  ElementPtr result = ElementPtr(new MapElement());
81  bool has_comment = false;
82  typedef std::map<std::string, ConstElementPtr> map_type;
83  const map_type& map = element->mapValue();
84  for (map_type::const_iterator it = map.cbegin(); it != map.cend(); ++it) {
85  if (it->first == "comment") {
86  // Note there is a comment entry to move
87  has_comment = true;
88  } else if (it->first == "user-context") {
89  // Do not traverse user-context entries
90  result->set("user-context", it->second);
91  } else {
92  // Not comment or user-context
93  Value<ConstElementPtr> item = moveComments1(it->second);
94  result->set(it->first, item.get());
95  if (!item.isShared()) {
96  modified = true;
97  }
98  }
99  }
100  // Check if the value should be not modified
101  if (!has_comment && !modified) {
102  return (Value<EP>::mkShare(element));
103  }
104 
105  if (has_comment) {
106  // Move the comment entry
107  ConstElementPtr comment = element->get("comment");
108  ElementPtr moved = Element::createMap();
109  moved->set("comment", comment);
110  ConstElementPtr previous = element->get("user-context");
111  // If there is already a user context merge it
112  if (previous) {
113  merge(moved, previous);
114  }
115  result->set("user-context", moved);
116  }
117 
118  return (Value<EP>::mkCopy(result));
119 }
120 
121 } // anonymous namespace
122 
123 namespace isc {
124 namespace test {
125 
127  Value<ElementPtr> result = moveComments1(element);
128  return (result.get());
129 }
130 
132  Value<ConstElementPtr> result = moveComments1(element);
133  return (result.get());
134 }
135 
136 }; // end of isc::test namespace
137 }; // end of isc namespace
138 
139 namespace {
140 
150 template<typename EP>
151 Value<EP> extractComments1(EP element) {
152  bool modified = false;
153 
154  // On lists recurse on items
155  if (element->getType() == Element::list) {
156  ElementPtr result = ElementPtr(new ListElement());
157  typedef std::vector<ElementPtr> ListType;
158  const ListType& list = element->listValue();
159  for (ListType::const_iterator it = list.cbegin();
160  it != list.cend(); ++it) {
161  Value<ElementPtr> item = extractComments1(*it);
162  result->add(item.get());
163  if (!item.isShared()) {
164  modified = true;
165  }
166  }
167  if (!modified) {
168  return (Value<EP>::mkShare(element));
169  } else {
170  return (Value<EP>::mkCopy(result));
171  }
172  } else if (element->getType() != Element::map) {
173  return (Value<EP>::mkShare(element));
174  }
175 
176  // Process maps: recurse on items
177  ElementPtr result = ElementPtr(new MapElement());
178  bool has_comment = false;
179  typedef std::map<std::string, ConstElementPtr> map_type;
180  const map_type& map = element->mapValue();
181  for (map_type::const_iterator it = map.cbegin(); it != map.cend(); ++it) {
182  if (it->first == "comment") {
183  // Do not traverse comment entries
184  result->set("comment", it->second);
185  } else if (it->first == "user-context") {
186  if (it->second->contains("comment")) {
187  // Note there is a entry to move
188  has_comment = true;
189  } else {
190  // Do not traverse user-context entries
191  result->set("user-context", it->second);
192  }
193  } else {
194  // Not comment or user-context
195  Value<ConstElementPtr> item = extractComments1(it->second);
196  result->set(it->first, item.get());
197  if (!item.isShared()) {
198  modified = true;
199  }
200  }
201  }
202  // Check if the value should be not modified
203  if (!has_comment && !modified) {
204  return (Value<EP>::mkShare(element));
205  }
206 
207  if (has_comment) {
208  // Move the comment entry
209  const map_type& uc_map = element->get("user-context")->mapValue();
210  ElementPtr user_context = Element::createMap();
211  ConstElementPtr comment;
212  for (map_type::const_iterator it = uc_map.cbegin();
213  it != uc_map.cend(); ++it) {
214  if (it->first == "comment") {
215  comment = it->second;
216  } else {
217  user_context->set(it->first, it->second);
218  }
219  }
220  if (user_context->size() > 0) {
221  result->set("user-context", user_context);
222  }
223  result->set("comment", comment);
224  }
225 
226  return (Value<EP>::mkCopy(result));
227 }
228 
229 } // anonymous namespace
230 
231 namespace isc {
232 namespace test {
233 
235  Value<ElementPtr> result = extractComments1(element);
236  return (result.get());
237 }
238 
240  Value<ConstElementPtr> result = extractComments1(element);
241  return (result.get());
242 }
243 
244 }; // end of isc::test namespace
245 }; // end of isc namespace
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:268
ConstElementPtr extractComments(ConstElementPtr element)
Extract comment entries from user-context (const variant)
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
Defines the logger used by the top-level component of kea-dhcp-ddns.
void merge(ElementPtr element, ConstElementPtr other)
Merges the data from other into element.
Definition: data.cc:1096
ConstElementPtr moveComments(ConstElementPtr element)
Move comment entries to user-context (const variant)