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