1 | // |
2 | // AbstractConfiguration.cpp |
3 | // |
4 | // Library: Util |
5 | // Package: Configuration |
6 | // Module: AbstractConfiguration |
7 | // |
8 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Util/AbstractConfiguration.h" |
16 | #include "Poco/Util/ConfigurationView.h" |
17 | #include "Poco/Exception.h" |
18 | #include "Poco/NumberParser.h" |
19 | #include "Poco/NumberFormatter.h" |
20 | #include "Poco/String.h" |
21 | |
22 | |
23 | using Poco::Mutex; |
24 | using Poco::NotFoundException; |
25 | using Poco::SyntaxException; |
26 | using Poco::CircularReferenceException; |
27 | using Poco::NumberParser; |
28 | using Poco::NumberFormatter; |
29 | using Poco::icompare; |
30 | |
31 | |
32 | namespace Poco { |
33 | namespace Util { |
34 | |
35 | |
36 | AbstractConfiguration::AbstractConfiguration(): |
37 | _depth(0), |
38 | _eventsEnabled(true) |
39 | { |
40 | } |
41 | |
42 | |
43 | AbstractConfiguration::~AbstractConfiguration() |
44 | { |
45 | } |
46 | |
47 | |
48 | bool AbstractConfiguration::hasProperty(const std::string& key) const |
49 | { |
50 | Mutex::ScopedLock lock(_mutex); |
51 | |
52 | std::string value; |
53 | return getRaw(key, value); |
54 | } |
55 | |
56 | |
57 | bool AbstractConfiguration::hasOption(const std::string& key) const |
58 | { |
59 | return hasProperty(key); |
60 | } |
61 | |
62 | |
63 | bool AbstractConfiguration::has(const std::string& key) const |
64 | { |
65 | return hasProperty(key); |
66 | } |
67 | |
68 | |
69 | std::string AbstractConfiguration::getString(const std::string& key) const |
70 | { |
71 | Mutex::ScopedLock lock(_mutex); |
72 | |
73 | std::string value; |
74 | if (getRaw(key, value)) |
75 | return internalExpand(value); |
76 | else |
77 | throw NotFoundException(key); |
78 | } |
79 | |
80 | |
81 | std::string AbstractConfiguration::getString(const std::string& key, const std::string& defaultValue) const |
82 | { |
83 | Mutex::ScopedLock lock(_mutex); |
84 | |
85 | std::string value; |
86 | if (getRaw(key, value)) |
87 | return internalExpand(value); |
88 | else |
89 | return defaultValue; |
90 | } |
91 | |
92 | |
93 | std::string AbstractConfiguration::getRawString(const std::string& key) const |
94 | { |
95 | Mutex::ScopedLock lock(_mutex); |
96 | |
97 | std::string value; |
98 | if (getRaw(key, value)) |
99 | return value; |
100 | else |
101 | throw NotFoundException(key); |
102 | } |
103 | |
104 | |
105 | std::string AbstractConfiguration::getRawString(const std::string& key, const std::string& defaultValue) const |
106 | { |
107 | |
108 | Mutex::ScopedLock lock(_mutex); |
109 | |
110 | std::string value; |
111 | if (getRaw(key, value)) |
112 | return value; |
113 | else |
114 | return defaultValue; |
115 | } |
116 | |
117 | |
118 | int AbstractConfiguration::getInt(const std::string& key) const |
119 | { |
120 | Mutex::ScopedLock lock(_mutex); |
121 | |
122 | std::string value; |
123 | if (getRaw(key, value)) |
124 | return parseInt(internalExpand(value)); |
125 | else |
126 | throw NotFoundException(key); |
127 | } |
128 | |
129 | |
130 | int AbstractConfiguration::getInt(const std::string& key, int defaultValue) const |
131 | { |
132 | Mutex::ScopedLock lock(_mutex); |
133 | |
134 | std::string value; |
135 | if (getRaw(key, value)) |
136 | return parseInt(internalExpand(value)); |
137 | else |
138 | return defaultValue; |
139 | } |
140 | |
141 | |
142 | unsigned AbstractConfiguration::getUInt(const std::string& key) const |
143 | { |
144 | Mutex::ScopedLock lock(_mutex); |
145 | |
146 | std::string value; |
147 | if (getRaw(key, value)) |
148 | return parseUInt(internalExpand(value)); |
149 | else |
150 | throw NotFoundException(key); |
151 | } |
152 | |
153 | |
154 | unsigned AbstractConfiguration::getUInt(const std::string& key, unsigned defaultValue) const |
155 | { |
156 | Mutex::ScopedLock lock(_mutex); |
157 | |
158 | std::string value; |
159 | if (getRaw(key, value)) |
160 | return parseUInt(internalExpand(value)); |
161 | else |
162 | return defaultValue; |
163 | } |
164 | |
165 | |
166 | #if defined(POCO_HAVE_INT64) |
167 | |
168 | |
169 | Int64 AbstractConfiguration::getInt64(const std::string& key) const |
170 | { |
171 | Mutex::ScopedLock lock(_mutex); |
172 | |
173 | std::string value; |
174 | if (getRaw(key, value)) |
175 | return parseInt64(internalExpand(value)); |
176 | else |
177 | throw NotFoundException(key); |
178 | } |
179 | |
180 | |
181 | Int64 AbstractConfiguration::getInt64(const std::string& key, Int64 defaultValue) const |
182 | { |
183 | Mutex::ScopedLock lock(_mutex); |
184 | |
185 | std::string value; |
186 | if (getRaw(key, value)) |
187 | return parseInt64(internalExpand(value)); |
188 | else |
189 | return defaultValue; |
190 | } |
191 | |
192 | |
193 | UInt64 AbstractConfiguration::getUInt64(const std::string& key) const |
194 | { |
195 | Mutex::ScopedLock lock(_mutex); |
196 | |
197 | std::string value; |
198 | if (getRaw(key, value)) |
199 | return parseUInt64(internalExpand(value)); |
200 | else |
201 | throw NotFoundException(key); |
202 | } |
203 | |
204 | |
205 | UInt64 AbstractConfiguration::getUInt64(const std::string& key, UInt64 defaultValue) const |
206 | { |
207 | Mutex::ScopedLock lock(_mutex); |
208 | |
209 | std::string value; |
210 | if (getRaw(key, value)) |
211 | return parseUInt64(internalExpand(value)); |
212 | else |
213 | return defaultValue; |
214 | } |
215 | |
216 | |
217 | #endif // defined(POCO_HAVE_INT64) |
218 | |
219 | |
220 | double AbstractConfiguration::getDouble(const std::string& key) const |
221 | { |
222 | Mutex::ScopedLock lock(_mutex); |
223 | |
224 | std::string value; |
225 | if (getRaw(key, value)) |
226 | return NumberParser::parseFloat(internalExpand(value)); |
227 | else |
228 | throw NotFoundException(key); |
229 | } |
230 | |
231 | |
232 | double AbstractConfiguration::getDouble(const std::string& key, double defaultValue) const |
233 | { |
234 | Mutex::ScopedLock lock(_mutex); |
235 | |
236 | std::string value; |
237 | if (getRaw(key, value)) |
238 | return NumberParser::parseFloat(internalExpand(value)); |
239 | else |
240 | return defaultValue; |
241 | } |
242 | |
243 | |
244 | bool AbstractConfiguration::getBool(const std::string& key) const |
245 | { |
246 | Mutex::ScopedLock lock(_mutex); |
247 | |
248 | std::string value; |
249 | if (getRaw(key, value)) |
250 | return parseBool(internalExpand(value)); |
251 | else |
252 | throw NotFoundException(key); |
253 | } |
254 | |
255 | |
256 | bool AbstractConfiguration::getBool(const std::string& key, bool defaultValue) const |
257 | { |
258 | Mutex::ScopedLock lock(_mutex); |
259 | |
260 | std::string value; |
261 | if (getRaw(key, value)) |
262 | return parseBool(internalExpand(value)); |
263 | else |
264 | return defaultValue; |
265 | } |
266 | |
267 | |
268 | void AbstractConfiguration::setString(const std::string& key, const std::string& value) |
269 | { |
270 | setRawWithEvent(key, value); |
271 | } |
272 | |
273 | |
274 | void AbstractConfiguration::setInt(const std::string& key, int value) |
275 | { |
276 | setRawWithEvent(key, NumberFormatter::format(value)); |
277 | } |
278 | |
279 | |
280 | void AbstractConfiguration::setUInt(const std::string& key, unsigned int value) |
281 | { |
282 | setRawWithEvent(key, NumberFormatter::format(value)); |
283 | } |
284 | |
285 | |
286 | #if defined(POCO_HAVE_INT64) |
287 | |
288 | |
289 | void AbstractConfiguration::setInt64(const std::string& key, Int64 value) |
290 | { |
291 | Mutex::ScopedLock lock(_mutex); |
292 | |
293 | setRawWithEvent(key, NumberFormatter::format(value)); |
294 | } |
295 | |
296 | |
297 | void AbstractConfiguration::setUInt64(const std::string& key, UInt64 value) |
298 | { |
299 | Mutex::ScopedLock lock(_mutex); |
300 | |
301 | setRawWithEvent(key, NumberFormatter::format(value)); |
302 | } |
303 | |
304 | |
305 | #endif // defined(POCO_HAVE_INT64) |
306 | |
307 | |
308 | void AbstractConfiguration::setDouble(const std::string& key, double value) |
309 | { |
310 | setRawWithEvent(key, NumberFormatter::format(value)); |
311 | } |
312 | |
313 | |
314 | void AbstractConfiguration::setBool(const std::string& key, bool value) |
315 | { |
316 | setRawWithEvent(key, value ? "true" : "false" ); |
317 | } |
318 | |
319 | |
320 | void AbstractConfiguration::keys(Keys& range) const |
321 | { |
322 | Mutex::ScopedLock lock(_mutex); |
323 | |
324 | std::string key; |
325 | range.clear(); |
326 | enumerate(key, range); |
327 | } |
328 | |
329 | |
330 | void AbstractConfiguration::keys(const std::string& key, Keys& range) const |
331 | { |
332 | Mutex::ScopedLock lock(_mutex); |
333 | |
334 | range.clear(); |
335 | enumerate(key, range); |
336 | } |
337 | |
338 | |
339 | const AbstractConfiguration::Ptr AbstractConfiguration::createView(const std::string& prefix) const |
340 | { |
341 | return new ConfigurationView(prefix, AbstractConfiguration::Ptr(const_cast<AbstractConfiguration*>(this), true)); |
342 | } |
343 | |
344 | |
345 | AbstractConfiguration::Ptr AbstractConfiguration::createView(const std::string& prefix) |
346 | { |
347 | return new ConfigurationView(prefix, AbstractConfiguration::Ptr(this, true)); |
348 | } |
349 | |
350 | |
351 | namespace |
352 | { |
353 | class AutoCounter |
354 | { |
355 | public: |
356 | AutoCounter(int& count): _count(count) |
357 | { |
358 | ++_count; |
359 | } |
360 | |
361 | ~AutoCounter() |
362 | { |
363 | --_count; |
364 | } |
365 | |
366 | private: |
367 | int& _count; |
368 | }; |
369 | } |
370 | |
371 | |
372 | std::string AbstractConfiguration::expand(const std::string& value) const |
373 | { |
374 | Mutex::ScopedLock lock(_mutex); |
375 | |
376 | return internalExpand(value); |
377 | } |
378 | |
379 | |
380 | void AbstractConfiguration::remove(const std::string& key) |
381 | { |
382 | if (_eventsEnabled) |
383 | { |
384 | propertyRemoving(this, key); |
385 | } |
386 | { |
387 | |
388 | Mutex::ScopedLock lock(_mutex); |
389 | removeRaw(key); |
390 | } |
391 | if (_eventsEnabled) |
392 | { |
393 | propertyRemoved(this, key); |
394 | } |
395 | } |
396 | |
397 | |
398 | void AbstractConfiguration::enableEvents(bool enable) |
399 | { |
400 | _eventsEnabled = enable; |
401 | } |
402 | |
403 | |
404 | bool AbstractConfiguration::eventsEnabled() const |
405 | { |
406 | return _eventsEnabled; |
407 | } |
408 | |
409 | |
410 | void AbstractConfiguration::removeRaw(const std::string& /*key*/) |
411 | { |
412 | throw Poco::NotImplementedException("removeRaw()" ); |
413 | } |
414 | |
415 | |
416 | std::string AbstractConfiguration::internalExpand(const std::string& value) const |
417 | { |
418 | AutoCounter counter(_depth); |
419 | if (_depth > 10) throw CircularReferenceException("Too many property references encountered" ); |
420 | return uncheckedExpand(value); |
421 | } |
422 | |
423 | |
424 | std::string AbstractConfiguration::uncheckedExpand(const std::string& value) const |
425 | { |
426 | std::string result; |
427 | std::string::const_iterator it = value.begin(); |
428 | std::string::const_iterator end = value.end(); |
429 | while (it != end) |
430 | { |
431 | if (*it == '$') |
432 | { |
433 | ++it; |
434 | if (it != end && *it == '{') |
435 | { |
436 | ++it; |
437 | std::string prop; |
438 | while (it != end && *it != '}') prop += *it++; |
439 | if (it != end) ++it; |
440 | std::string rawValue; |
441 | if (getRaw(prop, rawValue)) |
442 | { |
443 | result.append(internalExpand(rawValue)); |
444 | } |
445 | else |
446 | { |
447 | result.append("${" ); |
448 | result.append(prop); |
449 | result.append("}" ); |
450 | } |
451 | } |
452 | else result += '$'; |
453 | } |
454 | else result += *it++; |
455 | } |
456 | return result; |
457 | } |
458 | |
459 | |
460 | int AbstractConfiguration::parseInt(const std::string& value) |
461 | { |
462 | if ((value.compare(0, 2, "0x" ) == 0) || (value.compare(0, 2, "0X" ) == 0)) |
463 | return static_cast<int>(NumberParser::parseHex(value)); |
464 | else |
465 | return NumberParser::parse(value); |
466 | } |
467 | |
468 | |
469 | unsigned AbstractConfiguration::parseUInt(const std::string& value) |
470 | { |
471 | if ((value.compare(0, 2, "0x" ) == 0) || (value.compare(0, 2, "0X" ) == 0)) |
472 | return NumberParser::parseHex(value); |
473 | else |
474 | return NumberParser::parseUnsigned(value); |
475 | } |
476 | |
477 | |
478 | Int64 AbstractConfiguration::parseInt64(const std::string& value) |
479 | { |
480 | if ((value.compare(0, 2, "0x" ) == 0) || (value.compare(0, 2, "0X" ) == 0)) |
481 | return static_cast<Int64>(NumberParser::parseHex64(value)); |
482 | else |
483 | return NumberParser::parse64(value); |
484 | } |
485 | |
486 | |
487 | UInt64 AbstractConfiguration::parseUInt64(const std::string& value) |
488 | { |
489 | if ((value.compare(0, 2, "0x" ) == 0) || (value.compare(0, 2, "0X" ) == 0)) |
490 | return NumberParser::parseHex64(value); |
491 | else |
492 | return NumberParser::parseUnsigned64(value); |
493 | } |
494 | |
495 | |
496 | bool AbstractConfiguration::parseBool(const std::string& value) |
497 | { |
498 | int n; |
499 | if (NumberParser::tryParse(value, n)) |
500 | return n != 0; |
501 | else if (icompare(value, "true" ) == 0) |
502 | return true; |
503 | else if (icompare(value, "yes" ) == 0) |
504 | return true; |
505 | else if (icompare(value, "on" ) == 0) |
506 | return true; |
507 | else if (icompare(value, "false" ) == 0) |
508 | return false; |
509 | else if (icompare(value, "no" ) == 0) |
510 | return false; |
511 | else if (icompare(value, "off" ) == 0) |
512 | return false; |
513 | else |
514 | throw SyntaxException("Cannot convert to boolean" , value); |
515 | } |
516 | |
517 | |
518 | void AbstractConfiguration::setRawWithEvent(const std::string& key, std::string value) |
519 | { |
520 | KeyValue kv(key, value); |
521 | if (_eventsEnabled) |
522 | { |
523 | propertyChanging(this, kv); |
524 | } |
525 | { |
526 | Mutex::ScopedLock lock(_mutex); |
527 | setRaw(key, value); |
528 | } |
529 | if (_eventsEnabled) |
530 | { |
531 | propertyChanged(this, kv); |
532 | } |
533 | } |
534 | |
535 | |
536 | } } // namespace Poco::Util |
537 | |