Merge branch 'daemon-ext'
[libi2ncommon] / configlib / i2n_global_config.cpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
23d53eb1
RP
20/** @file
21 *
0e23f538 22 * @author Reinhard Pfau
23d53eb1
RP
23 *
24 * @copyright © Copyright 2008 by Intra2net AG
23d53eb1
RP
25 */
26
27#include "i2n_global_config.hpp"
28
29
30#include <set>
31#include <map>
32
33#include <filefunc.hxx>
34#include <stringfunc.hxx>
35#include <i2n_configdata.hpp>
36#include <i2n_configfile.hpp>
37#include <logfunc.hpp>
38#include <tracefunc.hpp>
39
40//#define NOISEDEBUG
41#undef NOISEDEBUG
42
43#ifdef NOISEDEBUG
44#include <iostream>
45#include <iomanip>
46#define DOUT(msg) std::cout << msg << std::endl
47#else
48#define DOUT(msg) do {} while (0)
49#endif
50
51
52namespace I2n
53{
54
55namespace Config
56{
57
58
59namespace Detail
60{
61
62
63} // eo namespace Detail
64
65
66
67namespace
68{
69
70
71Logger::PartLogger& module_logger()
72{
73 static Logger::PartLogger _logger(HERE);
74 return _logger;
75} // eo module_logger()
76
77
78
79std::string config_file_name;
80
81ConfigData config_data;
82
83
84/*
85**
86*/
87
88
89struct HideOut
90: public Detail::Thing
91{
92 HideOut(
93 const std::string& section,
94 const std::string& key,
95 const Detail::FeedFunction& feed,
96 const Detail::FeedFunction2& feed2);
97
98 virtual ~HideOut();
99
100 Detail::FeedFunction m_feed;
101 Detail::FeedFunction2 m_feed2;
102 std::string m_section;
103 std::string m_key;
104}; // eo struct HideOut
105
106typedef boost::shared_ptr< HideOut > HideOutPtr;
107
108
109class HideOutMap
110: public GroupedKeyValueData<
111 std::string,
112 std::string,
113 HideOut*
114>
115{
116 public:
117 HideOutMap();
118 virtual ~HideOutMap();
119
120 public:
121
122 static int Instances;
123}; // eo class HideOutMap
124
125int HideOutMap::Instances= 0;
126
127HideOutMap::HideOutMap()
128{
129 DOUT("HideOutMap::HideOutMap()");
130 ++Instances;
131} // eo HideOutMap::HideOutMap()
132
133
134HideOutMap::~HideOutMap()
135{
136 DOUT("HideOutMap::~HideOutMap()");
137 --Instances;
138} // eo HideOutMap::~HideOutMap()
139
140
141HideOutMap& hideout_map()
142{
143 static HideOutMap the_hideout_map;
144 DOUT("hideout_map()");
145 return the_hideout_map;
146} // eo hideout_map()
147
148
149// implementation of HideOut:
150
151
152HideOut::HideOut(
153 const std::string& section,
154 const std::string& key,
155 const Detail::FeedFunction& feed,
156 const Detail::FeedFunction2& feed2)
094a85fe 157: m_feed(feed)
23d53eb1 158, m_feed2(feed2)
094a85fe
TJ
159, m_section(section)
160, m_key(key)
23d53eb1
RP
161{
162 hideout_map()[section][key]+= this;
163} // eo HideOut::HideOut(const FeedFunction&)
164
165
166
167HideOut::~HideOut()
168{
169 if (HideOutMap::Instances)
170 {
171 hideout_map()[m_section].removeValue(m_key,this);
172 }
173} // eo HideOut::~HideOut()
174
175
176
177/*
178**
179*/
180
181
182/**
183 * @brief distributes (new) values to the active config variables.
184 * @param old_config_data reference to the old config data (for determining the deltas).
185 * @return @a true if new values could be converted without an error.
186 */
187bool feedEm( ConfigData& old_config_data )
188{
189 SCOPETRACKER();
190 bool result= true;
191 HideOutMap::KeyListType section_list;
192 hideout_map().getKeys(section_list);
193 for(HideOutMap::KeyListType::const_iterator section_it = section_list.begin();
194 section_it != section_list.end();
195 ++section_it)
196 {
197 std::string section( *section_it );
198 DOUT("process section \"" << section << "\"");
199 HideOutMap::GroupDataType::KeyListType key_list;
200 hideout_map()[section].getKeys(key_list);
201 for(HideOutMap::GroupDataType::KeyListType::const_iterator key_it= key_list.begin();
202 key_it != key_list.end();
203 ++key_it)
204 {
205 std::string key( *key_it );
206 DOUT("process key \"" << key << "\"");
207 bool has_new_data= config_data.hasKey(section, key);
208 bool has_old_data= old_config_data.hasKey(section, key);
209 if (not has_new_data and not has_old_data)
210 {
211 // we don't have data and we didn't had data... well, nothing to do:
212 DOUT("no data");
213 continue;
214 }
215 if (has_new_data)
216 {
217 DOUT("has (new) data");
218 StringList values;
219 config_data[section].getValues(key, values);
220 std::string value( config_data[section][key] );
221 if (has_old_data)
222 {
223 StringList old_values;
224 old_config_data[section].getValues(key, old_values);
225 if (values == old_values)
226 {
227 // value didn't change, so we can skip this case.
228 DOUT("data is same as before");
229 continue;
230 }
231 }
232 // at this point we need to publish (new or changed) value:
233 HideOutMap::GroupDataType::ValueListType func_list;
234 hideout_map()[section].getValues(key, func_list);
235 for(HideOutMap::GroupDataType::ValueListType::iterator func_it= func_list.begin();
236 func_it != func_list.end();
237 ++func_it)
238 {
239 DOUT(" feed iteration");
240 if (not (*func_it)) //paranoia
241 {
242 continue;
243 }
244 if ( (*func_it)->m_feed)
245 {
246 if ( not (*func_it)->m_feed( value ) )
247 {
248 module_logger().error() << "unable to publish [" <<section << "]"
249 << " \"" << key << "\" : \"" << value << "\""
250 ;
251 result= false;
252 }
253 continue;
254 }
255 if ( (*func_it)->m_feed2)
256 {
257 if ( not (*func_it)->m_feed2( values ) )
258 {
259 module_logger().error() << "unable to publish [" <<section << "]"
260 << " \"" << key << "\" : ...\"" << value << "\""
261 ;
262 result= false;
263 }
264 continue;
265 }
266 module_logger().error() << "no feeder";
267 }
268 continue;
269 }
270 // at this point we don't have (new) data, but we had old data...
ee911942
RP
271 {
272 DOUT("had old data");
273 StringList values;
274
275 // at this point we need to publish (vanished) value:
276 HideOutMap::GroupDataType::ValueListType func_list;
277 hideout_map()[section].getValues(key, func_list);
278 for(HideOutMap::GroupDataType::ValueListType::iterator func_it= func_list.begin();
279 func_it != func_list.end();
280 ++func_it)
281 {
282 DOUT(" feed iteration");
283 if (not (*func_it)) //paranoia
284 {
285 continue;
286 }
287 if ( (*func_it)->m_feed)
288 {
289 //TODO reset the data (to initial value) somehow?
290 // for now; we just keep the last value...
291 continue;
292 }
293 if ( (*func_it)->m_feed2)
294 {
295 if ( not (*func_it)->m_feed2( values ) )
296 {
297 module_logger().error() << "unable to publish [" <<section << "]"
298 << " \"" << key << "\" : <empty> "
299 ;
300 result= false;
301 }
302 continue;
303 }
304 module_logger().error() << "no feeder";
305 }
306 continue;
307 }
23d53eb1
RP
308 }
309 }
310 return result;
311} // eo feedEm(ConfigData&,ConfigData&)
312
313
314/*
315**
316*/
317
318
319} // eo namespace <anonymous>
320
321
322/************************************************************************\
323\************************************************************************/
324
325
326namespace Detail
327{
328
329
330FlowerShop seymour(
331 const std::string& section,
332 const std::string& key,
333 const FeedFunction& feed)
334{
335 DOUT("seymor(\"" << section << "\", \"" << key << "\",FeedFunction)");
336 FlowerShop result( new HideOut( section, key, feed, 0 ) );
337 if (not config_data.empty())
338 {
339 if (config_data.hasKey(section, key))
340 {
341 feed( config_data[section][key] );
342 }
343 }
344 return result;
345} // eo seymour(const std::string&,const std::string&,const FeedFunction&)
346
347
348FlowerShop seymour(
349 const std::string& section,
350 const std::string& key,
351 const FeedFunction2& feed)
352{
353 DOUT("seymor(\"" << section << "\", \"" << key << "\",FeedFunction2)");
354 FlowerShop result( new HideOut( section, key, 0, feed ) );
355 if (not config_data.empty())
356 {
357 if (config_data.hasKey(section, key))
358 {
359 StringList values;
360 config_data[section].getValues(key, values);
361 feed( values );
362 }
363 }
364 return result;
365} // eo seymour(const std::string&,const std::string&,const FeedFunction2&)
366
367
368FlowerShop seymour(FlowerShop shop, const FeedFunction& feed)
369{
370 if (!shop)
371 {
372 // no shop; no coordinates; no useful stuff to do...
373 return shop;
374 }
0a4178cf 375 HideOutPtr ptr = boost::dynamic_pointer_cast< HideOut >(shop);
23d53eb1
RP
376 if (!ptr)
377 {
378 // again, no coordinates...
379 return ptr;
380 }
381 FlowerShop result( new HideOut( ptr->m_section, ptr->m_key, feed, 0 ) );
382 if (not config_data.empty())
383 {
384 if (config_data.hasKey(ptr->m_section, ptr->m_key))
385 {
386 feed( config_data[ptr->m_section][ptr->m_key] );
387 }
388 }
389 return result;
390} // eo seymour(FlowerShop,const FeedFunction&)
391
392
393FlowerShop seymour(FlowerShop shop, const FeedFunction2& feed)
394{
395 if (!shop)
396 {
397 // no shop; no coordinates; no useful stuff to do...
398 return shop;
399 }
0a4178cf 400 HideOutPtr ptr = boost::dynamic_pointer_cast< HideOut >(shop);
23d53eb1
RP
401 if (!ptr)
402 {
403 // again, no coordinates...
404 return ptr;
405 }
406 FlowerShop result( new HideOut( ptr->m_section, ptr->m_key, 0, feed ) );
407 if (not config_data.empty())
408 {
409 if (config_data.hasKey(ptr->m_section, ptr->m_key))
410 {
411 StringList values;
412 config_data[ptr->m_section].getValues(ptr->m_key, values);
413 feed( values );
414 }
415 }
416 return result;
417} // eo seymour(FlowerShop,const FeedFunction&)
418
419
420} // eo namespace Detail
421
422
423
424/**
425 * @brief reloads the configuration from the last (known) config file.
426 * @return @a true if config was succesfully reloaded.
427 */
428bool reload()
429{
430 ConfigData old_config_data;
431 ConfigData new_config_data;
432 if (config_file_name.empty())
433 {
434 return false;
435 }
436 bool loaded= load_ini_config_file(config_file_name, new_config_data);
437 bool publish_successful= true;
438 if (loaded)
439 {
440 module_logger().debug() << "new_config_data.empty(): " << new_config_data.empty();
441 // save old data
442 old_config_data.swap( config_data );
443 // and install the new data
444 new_config_data.swap( config_data );
445
446 // react on the config: publish the values:
447 publish_successful = feedEm( old_config_data );
448 }
449 return loaded and publish_successful;
450} // reload()
451
452
453
454
455/**
456 * @brief sets the path of the config file and loads it.
457 * @param path the path to the config file.
458 * @return @a true iff the config could be loaded and all values pushed into their config vars.
459 */
460bool set_config_file(const std::string& path)
461{
462 if (not config_file_name.empty())
463 {
464 // WTF?!...
465 // a new config file.. well... why not?
466 }
467 Stat stat(path);
468 if (not stat or not stat.is_regular_file())
469 {
470 return false;
471 }
472 config_file_name= path;
473 return reload();
474} // eo set_config_file(const std::string&)
475
476
477/**
478 * @brief returns the current config file path.
479 * @return the current path.
480 */
481std::string get_config_file()
482{
483 return config_file_name;
484} // eo get_config_file()
485
486
487} // eo namespace config
488
489} // eo namespace I2n