Commit | Line | Data |
---|---|---|
0e23f538 TJ |
1 | /* |
2 | The software in this package is distributed under the GNU General | |
3 | Public License version 2 (with a special exception described below). | |
4 | ||
5 | A copy of GNU General Public License (GPL) is included in this distribution, | |
6 | in the file COPYING.GPL. | |
7 | ||
8 | As a special exception, if other files instantiate templates or use macros | |
9 | or inline functions from this file, or you compile this file and link it | |
10 | with other works to produce a work based on this file, this file | |
11 | does not by itself cause the resulting work to be covered | |
12 | by the GNU General Public License. | |
13 | ||
14 | However the source code for this file must still be made available | |
15 | in accordance with section (3) of the GNU General Public License. | |
16 | ||
17 | This exception does not invalidate any other reasons why a work based | |
18 | on 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 | ||
52 | namespace I2n | |
53 | { | |
54 | ||
55 | namespace Config | |
56 | { | |
57 | ||
58 | ||
59 | namespace Detail | |
60 | { | |
61 | ||
62 | ||
63 | } // eo namespace Detail | |
64 | ||
65 | ||
66 | ||
67 | namespace | |
68 | { | |
69 | ||
70 | ||
71 | Logger::PartLogger& module_logger() | |
72 | { | |
73 | static Logger::PartLogger _logger(HERE); | |
74 | return _logger; | |
75 | } // eo module_logger() | |
76 | ||
77 | ||
78 | ||
79 | std::string config_file_name; | |
80 | ||
81 | ConfigData config_data; | |
82 | ||
83 | ||
84 | /* | |
85 | ** | |
86 | */ | |
87 | ||
88 | ||
89 | struct 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 | ||
106 | typedef boost::shared_ptr< HideOut > HideOutPtr; | |
107 | ||
108 | ||
109 | class 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 | ||
125 | int HideOutMap::Instances= 0; | |
126 | ||
127 | HideOutMap::HideOutMap() | |
128 | { | |
129 | DOUT("HideOutMap::HideOutMap()"); | |
130 | ++Instances; | |
131 | } // eo HideOutMap::HideOutMap() | |
132 | ||
133 | ||
134 | HideOutMap::~HideOutMap() | |
135 | { | |
136 | DOUT("HideOutMap::~HideOutMap()"); | |
137 | --Instances; | |
138 | } // eo HideOutMap::~HideOutMap() | |
139 | ||
140 | ||
141 | HideOutMap& 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 | ||
152 | HideOut::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 | ||
167 | HideOut::~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 | */ | |
187 | bool 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 | ||
326 | namespace Detail | |
327 | { | |
328 | ||
329 | ||
330 | FlowerShop 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 | ||
348 | FlowerShop 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 | ||
368 | FlowerShop 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 | ||
393 | FlowerShop 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 | */ | |
428 | bool 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 | */ | |
460 | bool 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 | */ | |
481 | std::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 |