Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * config.cpp - Fawkes configuration interface 00004 * 00005 * Created: Mon Dec 18 14:54:23 2006 00006 * Copyright 2006-2008 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <config/config.h> 00025 #include <config/change_handler.h> 00026 #include <cstring> 00027 00028 namespace fawkes { 00029 00030 /** @class Configuration <config/config.h> 00031 * Interface for configuration handling. 00032 * We know that half of robotics is about parameter tuning. The Configuration 00033 * interface defines a unified way of storing parameters and other 00034 * configuration options no matter of how the database is implemented. 00035 * This is mainly done to allow for testing different solutions for ticket #10. 00036 * 00037 * @fn Configuration::~Configuration() 00038 * Virtual empty destructor. 00039 * 00040 * @fn void Configuration::load(const char *name, const char *defaults_name, const char *tag) 00041 * Load configuration. 00042 * Loads configuration data, or opens a file, depending on the implementation. After 00043 * this call access to all other methods shall be possible. 00044 * @param name name of the host-based configuration. If this does not exist it shall 00045 * be created from the default configuration. The name depends on the implementation and 00046 * could be a filename. 00047 * @param defaults_name name of the default database. As for the name this depends on 00048 * the actual implementation. 00049 * @param tag this optional parameter can denote a specific config version to load. This 00050 * will cause the host-specific database to be flushed and filled with the values for 00051 * the given tag. All values that did not exist for the tag are copied over from the 00052 * default database. 00053 * 00054 * @fn void Configuration::tag(const char *tag) 00055 * Tag this configuration version. 00056 * This creates a new tagged version of the current config. The tagged config can be 00057 * accessed via load(). 00058 * @param tag tag for this version 00059 * 00060 * @fn void Configuration::copy(Configuration *copyconf) 00061 * Copy all values from the given configuration. 00062 * All values from the given configuration are copied. Old values are not erased 00063 * so that the copied values will overwrite existing values, new values are 00064 * created, but values existent in current config but not in the copie config 00065 * will remain unchanged. 00066 * @param copyconf configuration to copy 00067 * 00068 * @fn std::list<std::string> Configuration::tags() 00069 * List of tags. 00070 * @return list of tags 00071 * 00072 * @fn bool Configuration::exists(const char *path) 00073 * Check if a given value exists. 00074 * @param path path to value 00075 * @return true if the value exists, false otherwise 00076 * 00077 * @fn bool Configuration::is_float(const char *path) 00078 * Check if a value is of type float 00079 * @param path path to value 00080 * @return true if the value exists and is of type float 00081 * 00082 * @fn bool Configuration::is_uint(const char *path) 00083 * Check if a value is of type unsigned int 00084 * @param path path to value 00085 * @return true if the value exists and is of type unsigned int 00086 * 00087 * @fn bool Configuration::is_int(const char *path) 00088 * Check if a value is of type int 00089 * @param path path to value 00090 * @return true if the value exists and is of type int 00091 * 00092 * @fn bool Configuration::is_bool(const char *path) 00093 * Check if a value is of type bool 00094 * @param path path to value 00095 * @return true if the value exists and is of type bool 00096 * 00097 * @fn bool Configuration::is_string(const char *path) 00098 * Check if a value is of type string 00099 * @param path path to value 00100 * @return true if the value exists and is of type string 00101 * 00102 * @fn bool Configuration::is_default(const char *path) 00103 * Check if a value was read from the default config. 00104 * @param path path to value 00105 * @return true if the value exists and is only stored in the default config 00106 * 00107 * @fn float Configuration::get_float(const char *path) 00108 * Get value from configuration which is of type float 00109 * @param path path to value 00110 * @return value 00111 * 00112 * @fn unsigned int Configuration::get_uint(const char *path) 00113 * Get value from configuration which is of type unsigned int 00114 * @param path path to value 00115 * @return value 00116 * 00117 * @fn int Configuration::get_int(const char *path) 00118 * Get value from configuration which is of type int 00119 * @param path path to value 00120 * @return value 00121 * 00122 * @fn bool Configuration::get_bool(const char *path) 00123 * Get value from configuration which is of type bool 00124 * @param path path to value 00125 * @return value 00126 * 00127 * @fn std::string Configuration::get_string(const char *path) 00128 * Get value from configuration which is of type string 00129 * @param path path to value 00130 * @return value 00131 * 00132 * @fn Configuration::ValueIterator * Configuration::get_value(const char *path) 00133 * Get value from configuration. 00134 * @param path path to value 00135 * @return value iterator for just this one value, maybe invalid if value does not 00136 * exists. 00137 * 00138 * @fn std::string Configuration::get_type(const char *path) 00139 * Get type of value at given path. 00140 * @param path path to value 00141 * @return string representation of type, one of float, unsigned int, int, bool, 00142 * or string 00143 * @exception ConfigurationException shall be thrown if value does not exist or 00144 * on any other error. 00145 * 00146 * @fn std::string Configuration::get_comment(const char *path) 00147 * Get comment of value at given path. 00148 * The value at the given path must exist in the host-specific configuration. 00149 * @param path path to value 00150 * @return comment 00151 * @exception ConfigEntryNotFoundException shall be thrown if value does not exist 00152 * @exception ConfigurationException shall be thrown on any other error 00153 * 00154 * @fn std::string Configuration::get_default_comment(const char *path) 00155 * Get comment of value at given path. 00156 * The value at the given path must exist in the default configuration. 00157 * @param path path to value 00158 * @return comment 00159 * @exception ConfigEntryNotFoundException shall be thrown if value does not exist 00160 * @exception ConfigurationException shall be thrown on any other error 00161 * 00162 * 00163 * @fn void Configuration::set_float(const char *path, float f) 00164 * Set new value in configuration of type float 00165 * @param path path to value 00166 * @param f new float value 00167 * 00168 * @fn void Configuration::set_uint(const char *path, unsigned int uint) 00169 * Set new value in configuration of type unsigned int 00170 * @param path path to value 00171 * @param uint new unsigned int value 00172 * 00173 * @fn void Configuration::set_int(const char *path, int i) 00174 * Set new value in configuration of type int 00175 * @param path path to value 00176 * @param i new int value 00177 * 00178 * @fn void Configuration::set_bool(const char *path, bool b) 00179 * Set new value in configuration of type bool 00180 * @param path path to value 00181 * @param b new bool value 00182 * 00183 * @fn void Configuration::set_string(const char *path, std::string &s) 00184 * Set new value in configuration of type string 00185 * @param path path to value 00186 * @param s new string value 00187 * 00188 * @fn void Configuration::set_string(const char *path, const char *s) 00189 * Set new value in configuration of type string. Works like the aforementioned method. 00190 * Just takes an good ol' char array instead of a std::string. 00191 * @param path path to value 00192 * @param s new string value 00193 * 00194 * @fn void Configuration::set_comment(const char *path, std::string &comment) 00195 * Set new comment for existing value. 00196 * @param path path to value 00197 * @param comment new comment string 00198 * 00199 * @fn void Configuration::set_comment(const char *path, const char *comment) 00200 * Set new comment for existing value. Works like the aforementioned method. 00201 * Just takes an good ol' char array instead of a std::string. 00202 * @param path path to value 00203 * @param comment new comment string 00204 * 00205 * @fn void Configuration::erase(const char *path) 00206 * Erase the given value from the configuration. It is not an error if the value does 00207 * not exists before deletion. 00208 * @param path path to value 00209 * 00210 * @fn void Configuration::set_default_float(const char *path, float f) 00211 * Set new default value in configuration of type float 00212 * @param path path to value 00213 * @param f new float value 00214 * 00215 * @fn void Configuration::set_default_uint(const char *path, unsigned int uint) 00216 * Set new default value in configuration of type unsigned int 00217 * @param path path to value 00218 * @param uint new unsigned int value 00219 * 00220 * @fn void Configuration::set_default_int(const char *path, int i) 00221 * Set new default value in configuration of type int 00222 * @param path path to value 00223 * @param i new int value 00224 * 00225 * @fn void Configuration::set_default_bool(const char *path, bool b) 00226 * Set new default value in configuration of type bool 00227 * @param path path to value 00228 * @param b new bool value 00229 * 00230 * @fn void Configuration::set_default_string(const char *path, std::string &s) 00231 * Set new default value in configuration of type string 00232 * @param path path to value 00233 * @param s new string value 00234 * 00235 * @fn void Configuration::set_default_string(const char *path, const char *s) 00236 * Set new default value in configuration of type string. Works like the aforementioned method. 00237 * Just takes an good ol' char array instead of a std::string. 00238 * @param path path to value 00239 * @param s new string value 00240 * 00241 * @fn void Configuration::set_default_comment(const char *path, std::string &comment) 00242 * Set new default comment for existing default configuration value. 00243 * @param path path to value 00244 * @param comment new comment string 00245 * 00246 * @fn void Configuration::set_default_comment(const char *path, const char *comment) 00247 * Set new default comment for existing default configuration value. 00248 * Works like the aforementioned method. Just takes an good ol' char array 00249 * instead of a std::string. 00250 * @param path path to value 00251 * @param comment new comment string 00252 * 00253 * @fn void Configuration::erase_default(const char *path) 00254 * Erase the given default value from the configuration. It is not an error if the value does 00255 * not exists before deletion. 00256 * @param path path to value 00257 * 00258 * @fn Configuration::ValueIterator * Configuration::iterator() 00259 * Iterator for all values. 00260 * Returns an iterator that can be used to iterate over all values in the current 00261 * configuration, it will value the overlay. If a default and a host-specific value 00262 * exists you will only see the host-specific value. 00263 * @return iterator over all values 00264 * 00265 * @fn Configuration::ValueIterator * Configuration::iterator_default() 00266 * Iterator for all default values. 00267 * Returns an iterator that can be used to iterate over all default values in 00268 * the current default configuration. Note that this might return less paths than 00269 * available, because the values for which no default entry exists are not 00270 * returned. 00271 * @return iterator over all default values 00272 * 00273 * @fn Configuration::ValueIterator * Configuration::iterator_hostspecific() 00274 * Iterator for all host-specific values. 00275 * Returns an iterator that can be used to iterate over all host-specific values 00276 * in the current configuration. Note that this might return less paths than 00277 * available, because the default values for which no host-specific entry exists 00278 * are not returned. 00279 * @return iterator over all host-specific values 00280 * 00281 * @fn Configuration::ValueIterator * Configuration::search(const char *path) 00282 * Iterator with search results. 00283 * Returns an iterator that can be used to iterate over the search results. All values 00284 * whose path start with the given strings are returned. 00285 * A call like 00286 * @code 00287 * config->search(""); 00288 * @endcode 00289 * is effectively the same as a call to iterator(). 00290 * @param path start of path 00291 * @return iterator to search results 00292 * 00293 * @fn void Configuration::lock() 00294 * Lock the config. 00295 * No further changes or queries can be executed on the configuration and will block until 00296 * the config is unlocked. 00297 * 00298 * @fn bool Configuration::try_lock() 00299 * Try to lock the config. 00300 * @see Configuration::lock() 00301 * @return true, if the lock has been aquired, false otherwise 00302 * 00303 * @fn void Configuration::unlock() 00304 * Unlock the config. 00305 * Modifications and queries are possible again. 00306 * 00307 */ 00308 00309 /** @class ConfigurationException config/config.h 00310 * Generic configuration exception. 00311 * Thrown if there is no other matching exception. 00312 */ 00313 00314 00315 /** Constructor. 00316 * @param msg message 00317 */ 00318 ConfigurationException::ConfigurationException(const char *msg) 00319 : Exception(msg) 00320 { 00321 } 00322 00323 00324 /** Constructor. 00325 * @param prefix Put as "prefix: " before the message, can be used to have a prefix 00326 * and put an error message from another API into msg. 00327 * @param msg message 00328 */ 00329 ConfigurationException::ConfigurationException(const char *prefix, const char *msg) 00330 : Exception() 00331 { 00332 append("%s: %s", prefix, msg); 00333 } 00334 00335 00336 /** @class ConfigEntryNotFoundException config/config.h 00337 * Thrown if a config entry could not be found. 00338 */ 00339 00340 00341 /** Constructor. 00342 * @param path path of value 00343 */ 00344 ConfigEntryNotFoundException::ConfigEntryNotFoundException( const char *path) 00345 : Exception("Config value for '%s' not found", path) 00346 { 00347 } 00348 00349 00350 /** @class ConfigTypeMismatchException config/config.h 00351 * Thrown if there a type problem was detected for example if you tried 00352 * to query a float with get_int(). 00353 */ 00354 00355 /** Constructor. 00356 * @param path path of value 00357 * @param actual actual type 00358 * @param requested requested type 00359 */ 00360 ConfigTypeMismatchException::ConfigTypeMismatchException(const char *path, 00361 const char *actual, 00362 const char *requested) 00363 : Exception() 00364 { 00365 append("Config value for '%s' is not of type '%s', but of type '%s'", 00366 path, requested, actual); 00367 } 00368 00369 /** @class CouldNotOpenConfigException <config/config.h> 00370 * Thrown if config could not be opened. 00371 * This is most likely to happen during the constructor or load(). 00372 */ 00373 00374 /** Constructor. 00375 * @param format format of message to describe cause or symptom of failure 00376 */ 00377 CouldNotOpenConfigException::CouldNotOpenConfigException(const char *format, ...) 00378 : Exception() 00379 { 00380 va_list va; 00381 va_start(va, format); 00382 append_va(format, va); 00383 va_end(va); 00384 } 00385 00386 00387 /** @class Configuration::ValueIterator <config/config.h> 00388 * Iterator interface to iterate over config values. This does not implement a 00389 * classic iterator interface with begin and end nodes but rather mimics a more 00390 * Java-like interface where you iterate over the entries in a while loop until 00391 * you covered all entries (much like a queue). 00392 * If you implement this for your own configuration system you should not make 00393 * the constructor publically accessible. 00394 * 00395 * @fn Configuration::ValueIterator::~ValueIterator() 00396 * Virtual emptry destructor. 00397 * 00398 * @fn bool Configuration::ValueIterator::next() 00399 * Check if there is another element and advance to this if possible. 00400 * This advances to the next element, if there is one. 00401 * @return true, if another element has been reached, false otherwise 00402 * 00403 * @fn bool Configuration::ValueIterator::valid() const 00404 * Check if the current element is valid. 00405 * This is much like the classic end element for iterators. If the iterator is 00406 * invalid there all subsequent calls to next() shall fail. 00407 * @return true, if the iterator is still valid, false otherwise 00408 * 00409 * @fn const char * Configuration::ValueIterator::path() const 00410 * Path of value. 00411 * @return path of value 00412 * 00413 * @fn const char * Configuration::ValueIterator::type() const 00414 * Type of value. 00415 * @return string representation of value type. 00416 * 00417 * @fn bool Configuration::ValueIterator::is_float() const 00418 * Check if current value is a float. 00419 * @return true, if value is a float, false otherwise 00420 * 00421 * @fn bool Configuration::ValueIterator::is_uint() const 00422 * Check if current value is a unsigned int. 00423 * @return true, if value is a unsigned int, false otherwise 00424 * 00425 * @fn bool Configuration::ValueIterator::is_int() const 00426 * Check if current value is a int. 00427 * @return true, if value is a int, false otherwise 00428 * 00429 * @fn bool Configuration::ValueIterator::is_bool() const 00430 * Check if current value is a bool. 00431 * @return true, if value is a bool, false otherwise 00432 * 00433 * @fn bool Configuration::ValueIterator::is_string() const 00434 * Check if current value is a string. 00435 * @return true, if value is a string, false otherwise 00436 * 00437 * @fn bool Configuration::ValueIterator::is_default() const 00438 * Check if current value was read from the default config. 00439 * @return true, if value was read from the default config, false otherwise 00440 * 00441 * @fn float Configuration::ValueIterator::get_float() const 00442 * Get float value. 00443 * @return value 00444 * 00445 * @fn unsigned int Configuration::ValueIterator::get_uint() const 00446 * Get unsigned int value. 00447 * @return value 00448 * 00449 * @fn int Configuration::ValueIterator::get_int() const 00450 * Get int value. 00451 * @return value 00452 * 00453 * @fn bool Configuration::ValueIterator::get_bool() const 00454 * Get bool value. 00455 * @return value 00456 * 00457 * @fn std::string Configuration::ValueIterator::get_string() const 00458 * Get string value. 00459 * @return value 00460 * 00461 * @fn std::string Configuration::ValueIterator::get_comment() const 00462 * Get comment of value. 00463 * @return comment 00464 * 00465 * @fn std::string Configuration::ValueIterator::get_as_string() const 00466 * Get value as string. 00467 * @return value as string 00468 * 00469 */ 00470 00471 00472 00473 /** Add a configuration change handler. 00474 * The added handler is called whenever a value changes and the handler 00475 * desires to get notified for the given component. 00476 * @param h configuration change handler 00477 */ 00478 void 00479 Configuration::add_change_handler(ConfigurationChangeHandler *h) 00480 { 00481 const char *c = h->config_monitor_prefix(); 00482 if ( c == NULL ) { 00483 c = ""; 00484 } 00485 00486 _change_handlers.insert(ChangeHandlerMultimap::value_type(c, h)); 00487 } 00488 00489 00490 /** Remove a configuration change handler. 00491 * The handler is removed from the change handler list and no longer called on 00492 * config changes. 00493 * @param h configuration change handler 00494 */ 00495 void 00496 Configuration::rem_change_handler(ConfigurationChangeHandler *h) 00497 { 00498 const char *c = h->config_monitor_prefix(); 00499 if ( c == NULL ) { 00500 c = ""; 00501 } 00502 bool changed = true; 00503 while (changed) { 00504 changed = false; 00505 for (ChangeHandlerMultimap::const_iterator j = _change_handlers.begin(); !changed && (j != _change_handlers.end()); ++j) { 00506 _ch_range = _change_handlers.equal_range((*j).first); 00507 for (ChangeHandlerMultimap::iterator i = _ch_range.first; !changed && (i != _ch_range.second); ++i) { 00508 if ( (*i).second == h ) { 00509 _change_handlers.erase(i); 00510 changed = true; 00511 break; 00512 } 00513 } 00514 if ( changed) break; 00515 } 00516 } 00517 } 00518 00519 00520 /** Find handlers for given path. 00521 * @param path path to get handlers for 00522 * @return list with config change handlers. 00523 */ 00524 Configuration::ChangeHandlerList * 00525 Configuration::find_handlers(const char *path) 00526 { 00527 ChangeHandlerList *rv = new ChangeHandlerList(); 00528 for (ChangeHandlerMultimap::const_iterator j = _change_handlers.begin(); j != _change_handlers.end(); ++j) { 00529 if ( strstr(path, (*j).first) == path ) { 00530 _ch_range = _change_handlers.equal_range((*j).first); 00531 for (ChangeHandlerMultimap::const_iterator i = _ch_range.first; i != _ch_range.second; ++i) { 00532 rv->push_back((*i).second); 00533 } 00534 } 00535 } 00536 00537 return rv; 00538 } 00539 00540 00541 /** Notify handlers for given path. 00542 * @param path path to notify handlers for 00543 * @param comment_changed true if the change is about a comment change, 00544 * false otherwise 00545 */ 00546 void 00547 Configuration::notify_handlers(const char *path, bool comment_changed) 00548 { 00549 ChangeHandlerList *h = find_handlers(path); 00550 Configuration::ValueIterator *value = get_value(path); 00551 if (value->next()) { 00552 for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) { 00553 if (comment_changed) { 00554 (*i)->config_comment_changed(value); 00555 } else { 00556 (*i)->config_value_changed(value); 00557 } 00558 } 00559 } else { 00560 for (ChangeHandlerList::const_iterator i = h->begin(); i != h->end(); ++i) { 00561 (*i)->config_value_erased(path); 00562 } 00563 } 00564 delete value; 00565 delete h; 00566 } 00567 00568 } // end namespace fawkes