1//
2// JSONConfiguration.cpp
3//
4// Library: Util
5// Package: JSON
6// Module: JSONConfiguration
7//
8// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15
16#include "Poco/Util/JSONConfiguration.h"
17
18
19#ifndef POCO_UTIL_NO_JSONCONFIGURATION
20
21
22#include "Poco/FileStream.h"
23#include "Poco/StringTokenizer.h"
24#include "Poco/JSON/Parser.h"
25#include "Poco/JSON/Query.h"
26#include "Poco/RegularExpression.h"
27#include "Poco/NumberParser.h"
28
29
30namespace Poco {
31namespace Util {
32
33
34JSONConfiguration::JSONConfiguration() : _object(new JSON::Object())
35{
36}
37
38
39JSONConfiguration::JSONConfiguration(const std::string& path)
40{
41 load(path);
42}
43
44
45JSONConfiguration::JSONConfiguration(std::istream& istr)
46{
47 load(istr);
48}
49
50
51JSONConfiguration::JSONConfiguration(const JSON::Object::Ptr& object) : _object(object)
52{
53}
54
55
56JSONConfiguration::~JSONConfiguration()
57{
58}
59
60
61void JSONConfiguration::load(const std::string& path)
62{
63 Poco::FileInputStream fis(path);
64 load(fis);
65}
66
67
68void JSONConfiguration::load(std::istream& istr)
69{
70 JSON::Parser parser;
71 parser.parse(istr);
72 DynamicAny result = parser.result();
73 if ( result.type() == typeid(JSON::Object::Ptr) )
74 {
75 _object = result.extract<JSON::Object::Ptr>();
76 }
77}
78
79
80void JSONConfiguration::loadEmpty(const std::string& root)
81{
82 _object = new JSON::Object();
83 JSON::Object::Ptr rootObject = new JSON::Object();
84 _object->set(root, rootObject);
85}
86
87
88bool JSONConfiguration::getRaw(const std::string & key, std::string & value) const
89{
90 JSON::Query query(_object);
91 Poco::DynamicAny result = query.find(key);
92 if ( ! result.isEmpty() )
93 {
94 value = result.convert<std::string>();
95 return true;
96 }
97 return false;
98}
99
100
101void JSONConfiguration::getIndexes(std::string& name, std::vector<int>& indexes)
102{
103 indexes.clear();
104
105 RegularExpression::MatchVec matches;
106 int firstOffset = -1;
107 int offset = 0;
108 RegularExpression regex("\\[([0-9]+)\\]");
109 while(regex.match(name, offset, matches) > 0 )
110 {
111 if ( firstOffset == -1 )
112 {
113 firstOffset = static_cast<int>(matches[0].offset);
114 }
115 std::string num = name.substr(matches[1].offset, matches[1].length);
116 indexes.push_back(NumberParser::parse(num));
117 offset = static_cast<int>(matches[0].offset + matches[0].length);
118 }
119
120 if ( firstOffset != -1 )
121 {
122 name = name.substr(0, firstOffset);
123 }
124}
125
126
127JSON::Object::Ptr JSONConfiguration::findStart(const std::string& key, std::string& lastPart)
128{
129 JSON::Object::Ptr currentObject = _object;
130
131 StringTokenizer tokenizer(key, ".");
132 lastPart = tokenizer[tokenizer.count() - 1];
133
134 for(int i = 0; i < tokenizer.count() - 1; ++i)
135 {
136 std::vector<int> indexes;
137 std::string name = tokenizer[i];
138 getIndexes(name, indexes);
139
140 DynamicAny result = currentObject->get(name);
141
142 if ( result.isEmpty() ) // Not found
143 {
144 if ( indexes.empty() ) // We want an object, create it
145 {
146 JSON::Object::Ptr newObject = new JSON::Object();
147 currentObject->set(name, newObject);
148 currentObject = newObject;
149 }
150 else // We need an array
151 {
152 JSON::Array::Ptr newArray;
153 JSON::Array::Ptr parentArray;
154 JSON::Array::Ptr topArray;
155 for(std::vector<int>::iterator it = indexes.begin(); it != indexes.end(); ++it)
156 {
157 newArray = new JSON::Array();
158 if ( topArray.isNull() )
159 {
160 topArray = newArray;
161 }
162
163 if ( ! parentArray.isNull() )
164 {
165 parentArray->add(newArray);
166 }
167
168 for(int j = 0; j <= *it - 1; ++j)
169 {
170 Poco::DynamicAny nullValue;
171 newArray->add(nullValue);
172 }
173
174 parentArray = newArray;
175 }
176
177 currentObject->set(name, topArray);
178 currentObject = new JSON::Object();
179 newArray->add(currentObject);
180 }
181 }
182 else // We have a value
183 {
184 if ( indexes.empty() ) // We want an object
185 {
186 if ( result.type() == typeid(JSON::Object::Ptr) )
187 {
188 currentObject = result.extract<JSON::Object::Ptr>();
189 }
190 else
191 {
192 throw SyntaxException("Expected a JSON object");
193 }
194 }
195 else
196 {
197 if ( result.type() == typeid(JSON::Array::Ptr) )
198 {
199 JSON::Array::Ptr arr = result.extract<JSON::Array::Ptr>();
200
201 for(std::vector<int>::iterator it = indexes.begin(); it != indexes.end() - 1; ++it)
202 {
203 JSON::Array::Ptr currentArray = arr;
204 arr = arr->getArray(*it);
205 if ( arr.isNull() )
206 {
207 arr = new JSON::Array();
208 currentArray->add(arr);
209 }
210 }
211
212 result = arr->get(*indexes.rbegin());
213 if ( result.isEmpty() ) // Index doesn't exist
214 {
215 JSON::Object::Ptr newObject = new JSON::Object();
216 arr->add(newObject);
217 currentObject = newObject;
218 }
219 else // Index is available
220 {
221 if ( result.type() == typeid(JSON::Object::Ptr) )
222 {
223 currentObject = result.extract<JSON::Object::Ptr>();
224 }
225 else
226 {
227 throw SyntaxException("Expected a JSON object");
228 }
229 }
230 }
231 else
232 {
233 throw SyntaxException("Expected a JSON array");
234 }
235 }
236 }
237 }
238 return currentObject;
239}
240
241
242void JSONConfiguration::setValue(const std::string& key, const Poco::DynamicAny& value)
243{
244
245 std::string sValue;
246
247 value.convert<std::string>(sValue);
248 KeyValue kv(key, sValue);
249
250 if (eventsEnabled())
251 {
252 propertyChanging(this, kv);
253 }
254
255 std::string lastPart;
256 JSON::Object::Ptr parentObject = findStart(key, lastPart);
257
258 std::vector<int> indexes;
259 getIndexes(lastPart, indexes);
260
261 if ( indexes.empty() ) // No Array
262 {
263 parentObject->set(lastPart, value);
264 }
265 else
266 {
267 DynamicAny result = parentObject->get(lastPart);
268 if ( result.isEmpty() )
269 {
270 result = JSON::Array::Ptr(new JSON::Array());
271 parentObject->set(lastPart, result);
272 }
273 else if ( result.type() != typeid(JSON::Array::Ptr) )
274 {
275 throw SyntaxException("Expected a JSON array");
276 }
277
278 JSON::Array::Ptr arr = result.extract<JSON::Array::Ptr>();
279 for(std::vector<int>::iterator it = indexes.begin(); it != indexes.end() - 1; ++it)
280 {
281 JSON::Array::Ptr nextArray = arr->getArray(*it);
282 if ( nextArray.isNull() )
283 {
284 for(int i = static_cast<int>(arr->size()); i <= *it; ++i)
285 {
286 Poco::DynamicAny nullValue;
287 arr->add(nullValue);
288 }
289 nextArray = new JSON::Array();
290 arr->add(nextArray);
291 }
292 arr = nextArray;
293 }
294 arr->set(indexes.back(), value);
295 }
296
297 if (eventsEnabled())
298 {
299 propertyChanged(this, kv);
300 }
301}
302
303
304void JSONConfiguration::setString(const std::string& key, const std::string& value)
305{
306 setValue(key, value);
307}
308
309
310void JSONConfiguration::setRaw(const std::string& key, const std::string& value)
311{
312 setValue(key, value);
313}
314
315
316void JSONConfiguration::setInt(const std::string& key, int value)
317{
318 setValue(key, value);
319}
320
321
322void JSONConfiguration::setBool(const std::string& key, bool value)
323{
324 setValue(key, value);
325}
326
327
328void JSONConfiguration::setDouble(const std::string& key, double value)
329{
330 setValue(key, value);
331}
332
333
334void JSONConfiguration::enumerate(const std::string& key, Keys& range) const
335{
336 JSON::Query query(_object);
337 Poco::DynamicAny result = query.find(key);
338 if ( result.type() == typeid(JSON::Object::Ptr) )
339 {
340 JSON::Object::Ptr object = result.extract<JSON::Object::Ptr>();
341 object->getNames(range);
342 }
343}
344
345
346void JSONConfiguration::save(std::ostream& ostr, unsigned int indent) const
347{
348 _object->stringify(ostr, indent);
349}
350
351
352void JSONConfiguration::removeRaw(const std::string& key)
353
354{
355
356 std::string lastPart;
357 JSON::Object::Ptr parentObject = findStart(key, lastPart);
358 std::vector<int> indexes;
359 getIndexes(lastPart, indexes);
360
361 if ( indexes.empty() ) // No Array
362 {
363 parentObject->remove(lastPart);
364 }
365 else
366 {
367 DynamicAny result = parentObject->get(lastPart);
368 if (!result.isEmpty() && result.type() == typeid(JSON::Array::Ptr))
369 {
370
371 JSON::Array::Ptr arr = result.extract<JSON::Array::Ptr>();
372 for(std::vector<int>::iterator it = indexes.begin(); it != indexes.end() - 1; ++it)
373 {
374 arr = arr->getArray(*it);
375 }
376 arr->remove(indexes.back());
377 }
378 }
379
380}
381
382
383} } // namespace Poco::Util
384
385
386#endif // POCO_UTIL_NO_JSONCONFIGURATION
387