Fawkes API Fawkes Development Version

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  * @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
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends