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

