/* The software in this package is distributed under the GNU General Public License version 2 (with a special exception described below). A copy of GNU General Public License (GPL) is included in this distribution, in the file COPYING.GPL. As a special exception, if other files instantiate templates or use macros or inline functions from this file, or you compile this file and link it with other works to produce a work based on this file, this file does not by itself cause the resulting work to be covered by the GNU General Public License. However the source code for this file must still be made available in accordance with section (3) of the GNU General Public License. This exception does not invalidate any other reasons why a work based on this file might be covered by the GNU General Public License. */ /** @file * * @author Reinhard Pfau * * @copyright © Copyright 2008 by Intra2net AG */ #include "i2n_global_config.hpp" #include #include #include #include #include #include #include #include //#define NOISEDEBUG #undef NOISEDEBUG #ifdef NOISEDEBUG #include #include #define DOUT(msg) std::cout << msg << std::endl #else #define DOUT(msg) do {} while (0) #endif namespace I2n { namespace Config { namespace Detail { } // eo namespace Detail namespace { Logger::PartLogger& module_logger() { static Logger::PartLogger _logger(HERE); return _logger; } // eo module_logger() std::string config_file_name; ConfigData config_data; /* ** */ struct HideOut : public Detail::Thing { HideOut( const std::string& section, const std::string& key, const Detail::FeedFunction& feed, const Detail::FeedFunction2& feed2); virtual ~HideOut(); Detail::FeedFunction m_feed; Detail::FeedFunction2 m_feed2; std::string m_section; std::string m_key; }; // eo struct HideOut typedef boost::shared_ptr< HideOut > HideOutPtr; class HideOutMap : public GroupedKeyValueData< std::string, std::string, HideOut* > { public: HideOutMap(); virtual ~HideOutMap(); public: static int Instances; }; // eo class HideOutMap int HideOutMap::Instances= 0; HideOutMap::HideOutMap() { DOUT("HideOutMap::HideOutMap()"); ++Instances; } // eo HideOutMap::HideOutMap() HideOutMap::~HideOutMap() { DOUT("HideOutMap::~HideOutMap()"); --Instances; } // eo HideOutMap::~HideOutMap() HideOutMap& hideout_map() { static HideOutMap the_hideout_map; DOUT("hideout_map()"); return the_hideout_map; } // eo hideout_map() // implementation of HideOut: HideOut::HideOut( const std::string& section, const std::string& key, const Detail::FeedFunction& feed, const Detail::FeedFunction2& feed2) : m_feed(feed) , m_feed2(feed2) , m_section(section) , m_key(key) { hideout_map()[section][key]+= this; } // eo HideOut::HideOut(const FeedFunction&) HideOut::~HideOut() { if (HideOutMap::Instances) { hideout_map()[m_section].removeValue(m_key,this); } } // eo HideOut::~HideOut() /* ** */ /** * @brief distributes (new) values to the active config variables. * @param old_config_data reference to the old config data (for determining the deltas). * @return @a true if new values could be converted without an error. */ bool feedEm( ConfigData& old_config_data ) { SCOPETRACKER(); bool result= true; HideOutMap::KeyListType section_list; hideout_map().getKeys(section_list); for(HideOutMap::KeyListType::const_iterator section_it = section_list.begin(); section_it != section_list.end(); ++section_it) { std::string section( *section_it ); DOUT("process section \"" << section << "\""); HideOutMap::GroupDataType::KeyListType key_list; hideout_map()[section].getKeys(key_list); for(HideOutMap::GroupDataType::KeyListType::const_iterator key_it= key_list.begin(); key_it != key_list.end(); ++key_it) { std::string key( *key_it ); DOUT("process key \"" << key << "\""); bool has_new_data= config_data.hasKey(section, key); bool has_old_data= old_config_data.hasKey(section, key); if (not has_new_data and not has_old_data) { // we don't have data and we didn't had data... well, nothing to do: DOUT("no data"); continue; } if (has_new_data) { DOUT("has (new) data"); StringList values; config_data[section].getValues(key, values); std::string value( config_data[section][key] ); if (has_old_data) { StringList old_values; old_config_data[section].getValues(key, old_values); if (values == old_values) { // value didn't change, so we can skip this case. DOUT("data is same as before"); continue; } } // at this point we need to publish (new or changed) value: HideOutMap::GroupDataType::ValueListType func_list; hideout_map()[section].getValues(key, func_list); for(HideOutMap::GroupDataType::ValueListType::iterator func_it= func_list.begin(); func_it != func_list.end(); ++func_it) { DOUT(" feed iteration"); if (not (*func_it)) //paranoia { continue; } if ( (*func_it)->m_feed) { if ( not (*func_it)->m_feed( value ) ) { module_logger().error() << "unable to publish [" <
m_feed2) { if ( not (*func_it)->m_feed2( values ) ) { module_logger().error() << "unable to publish [" <
m_feed) { //TODO reset the data (to initial value) somehow? // for now; we just keep the last value... continue; } if ( (*func_it)->m_feed2) { if ( not (*func_it)->m_feed2( values ) ) { module_logger().error() << "unable to publish [" <
" ; result= false; } continue; } module_logger().error() << "no feeder"; } continue; } } } return result; } // eo feedEm(ConfigData&,ConfigData&) /* ** */ } // eo namespace /************************************************************************\ \************************************************************************/ namespace Detail { FlowerShop seymour( const std::string& section, const std::string& key, const FeedFunction& feed) { DOUT("seymor(\"" << section << "\", \"" << key << "\",FeedFunction)"); FlowerShop result( new HideOut( section, key, feed, 0 ) ); if (not config_data.empty()) { if (config_data.hasKey(section, key)) { feed( config_data[section][key] ); } } return result; } // eo seymour(const std::string&,const std::string&,const FeedFunction&) FlowerShop seymour( const std::string& section, const std::string& key, const FeedFunction2& feed) { DOUT("seymor(\"" << section << "\", \"" << key << "\",FeedFunction2)"); FlowerShop result( new HideOut( section, key, 0, feed ) ); if (not config_data.empty()) { if (config_data.hasKey(section, key)) { StringList values; config_data[section].getValues(key, values); feed( values ); } } return result; } // eo seymour(const std::string&,const std::string&,const FeedFunction2&) FlowerShop seymour(FlowerShop shop, const FeedFunction& feed) { if (!shop) { // no shop; no coordinates; no useful stuff to do... return shop; } HideOutPtr ptr = boost::dynamic_pointer_cast< HideOut >(shop); if (!ptr) { // again, no coordinates... return ptr; } FlowerShop result( new HideOut( ptr->m_section, ptr->m_key, feed, 0 ) ); if (not config_data.empty()) { if (config_data.hasKey(ptr->m_section, ptr->m_key)) { feed( config_data[ptr->m_section][ptr->m_key] ); } } return result; } // eo seymour(FlowerShop,const FeedFunction&) FlowerShop seymour(FlowerShop shop, const FeedFunction2& feed) { if (!shop) { // no shop; no coordinates; no useful stuff to do... return shop; } HideOutPtr ptr = boost::dynamic_pointer_cast< HideOut >(shop); if (!ptr) { // again, no coordinates... return ptr; } FlowerShop result( new HideOut( ptr->m_section, ptr->m_key, 0, feed ) ); if (not config_data.empty()) { if (config_data.hasKey(ptr->m_section, ptr->m_key)) { StringList values; config_data[ptr->m_section].getValues(ptr->m_key, values); feed( values ); } } return result; } // eo seymour(FlowerShop,const FeedFunction&) } // eo namespace Detail /** * @brief reloads the configuration from the last (known) config file. * @return @a true if config was succesfully reloaded. */ bool reload() { ConfigData old_config_data; ConfigData new_config_data; if (config_file_name.empty()) { return false; } bool loaded= load_ini_config_file(config_file_name, new_config_data); bool publish_successful= true; if (loaded) { module_logger().debug() << "new_config_data.empty(): " << new_config_data.empty(); // save old data old_config_data.swap( config_data ); // and install the new data new_config_data.swap( config_data ); // react on the config: publish the values: publish_successful = feedEm( old_config_data ); } return loaded and publish_successful; } // reload() /** * @brief sets the path of the config file and loads it. * @param path the path to the config file. * @return @a true iff the config could be loaded and all values pushed into their config vars. */ bool set_config_file(const std::string& path) { if (not config_file_name.empty()) { // WTF?!... // a new config file.. well... why not? } Stat stat(path); if (not stat or not stat.is_regular_file()) { return false; } config_file_name= path; return reload(); } // eo set_config_file(const std::string&) /** * @brief returns the current config file path. * @return the current path. */ std::string get_config_file() { return config_file_name; } // eo get_config_file() } // eo namespace config } // eo namespace I2n