Line data Source code
1 : #include <stdlib.h>
2 : #include <iostream>
3 : #include <regex>
4 : #include <sstream>
5 : #include <unordered_map>
6 :
7 : #include <dlfcn.h>
8 :
9 : #include "ers/ers.hpp"
10 : #include "ers/internal/SingletonCreator.hpp"
11 :
12 : #include "conffwk/Change.hpp"
13 : #include "conffwk/DalObject.hpp"
14 : #include "conffwk/DalObjectPrint.hpp"
15 : #include "conffwk/DalFactory.hpp"
16 : #include "conffwk/ConfigObject.hpp"
17 : #include "conffwk/ConfigAction.hpp"
18 : #include "conffwk/Configuration.hpp"
19 : #include "conffwk/ConfigurationImpl.hpp"
20 : #include "conffwk/Schema.hpp"
21 :
22 : namespace dunedaq {
23 :
24 4 : ERS_DEFINE_ISSUE_CXX( conffwk, Exception, , )
25 :
26 0 : ERS_DEFINE_ISSUE_BASE_CXX(
27 : conffwk,
28 : Generic,
29 : conffwk::Exception,
30 : what,
31 : ,
32 : ((const char*)what)
33 : )
34 :
35 4 : ERS_DEFINE_ISSUE_BASE_CXX(
36 : conffwk,
37 : NotFound,
38 : conffwk::Exception,
39 : type << " \"" << data << "\" is not found",
40 : ,
41 : ((const char*)type)
42 : ((const char*)data)
43 : )
44 :
45 0 : ERS_DEFINE_ISSUE_BASE_CXX(
46 : conffwk,
47 : DeletedObject,
48 : conffwk::Exception,
49 : "object \'" << object_id << '@' << class_name << "\' was deleted",
50 : ,
51 : ((const char*)class_name)
52 : ((const char*)object_id)
53 : )
54 :
55 :
56 : namespace conffwk {
57 :
58 : template <typename T> static T* get_new(ConfigObject& co,
59 : const std::string& attrname) {
60 : T* retval = new T;
61 : co.get(attrname, *retval);
62 : return retval;
63 : }
64 :
65 : void
66 0 : Configuration::add_action(ConfigAction * ac)
67 : {
68 0 : std::lock_guard<std::mutex> scoped_lock(m_actn_mutex);
69 0 : m_actions.push_back(ac);
70 0 : }
71 :
72 : void
73 0 : Configuration::remove_action(ConfigAction * ac)
74 : {
75 0 : std::lock_guard<std::mutex> scoped_lock(m_actn_mutex);
76 0 : m_actions.remove(ac);
77 0 : }
78 :
79 : void
80 17 : Configuration::action_on_update(const ConfigObject& obj, const std::string& name)
81 : {
82 17 : std::lock_guard<std::mutex> scoped_lock(m_actn_mutex);
83 17 : for (auto &i : m_actions)
84 0 : i->update(obj, name);
85 17 : }
86 :
87 : ////////////////////////////////////////////////////////////////////////////////
88 :
89 : static bool
90 80 : check_prefetch_needs()
91 : {
92 80 : return (getenv("TDAQ_DB_PREFETCH_ALL_DATA") != nullptr);
93 : }
94 :
95 : ////////////////////////////////////////////////////////////////////////////////
96 :
97 0 : Configuration::Configuration() :
98 0 : p_number_of_cache_hits(0), p_number_of_template_object_created(0), p_number_of_template_object_read(0), m_impl(nullptr), m_shlib_h(nullptr), m_registry(*this){
99 :
100 0 : }
101 :
102 80 : Configuration::Configuration(const std::string& spec) :
103 80 : p_number_of_cache_hits(0), p_number_of_template_object_created(0), p_number_of_template_object_read(0), m_impl(nullptr), m_shlib_h(nullptr), m_registry(*this)
104 : {
105 80 : std::string s;
106 :
107 80 : if (spec.empty())
108 : {
109 0 : if (const char *env = getenv("TDAQ_DB"))
110 0 : m_impl_spec = env;
111 : }
112 : else
113 : {
114 80 : m_impl_spec = spec;
115 : }
116 :
117 80 : if (m_impl_spec.empty())
118 0 : throw dunedaq::conffwk::Generic(ERS_HERE, "no database parameter found (check parameter of the constructor or value of TDAQ_DB environment variable)");
119 :
120 80 : std::string::size_type idx = m_impl_spec.find_first_of(':');
121 :
122 80 : if (idx == std::string::npos)
123 : {
124 4 : m_impl_name = m_impl_spec;
125 : }
126 : else
127 : {
128 76 : m_impl_name = m_impl_spec.substr(0, idx);
129 76 : m_impl_param = m_impl_spec.substr(idx + 1);
130 : }
131 :
132 80 : std::string plugin_name = std::string("lib") + m_impl_name + ".so";
133 80 : std::string impl_creator = std::string("_") + m_impl_name + "_creator_";
134 :
135 : // load plug-in
136 80 : m_shlib_h = dlopen(plugin_name.c_str(), RTLD_LAZY | RTLD_GLOBAL);
137 :
138 80 : if (!m_shlib_h)
139 : {
140 0 : std::ostringstream text;
141 0 : text << "failed to load implementation plug-in \'" << plugin_name << "\': \"" << dlerror() << '\"';
142 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
143 0 : }
144 :
145 : // search in plug-in implementation creator function
146 :
147 80 : ConfigurationImpl *
148 : (*f)(const std::string& spec);
149 :
150 160 : f = (ConfigurationImpl*
151 80 : (*)(const std::string&))dlsym(m_shlib_h, impl_creator.c_str());
152 :
153 80 : char * error = 0;
154 :
155 80 : if ((error = dlerror()) != 0)
156 : {
157 0 : std::ostringstream text;
158 0 : text << "failed to find implementation creator function \'" << impl_creator << "\' in plug-in \'" << plugin_name << "\': \"" << error << '\"';
159 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
160 0 : }
161 :
162 :
163 : // create implementation
164 :
165 80 : m_impl = (*f)(m_impl_param);
166 :
167 80 : if (m_impl)
168 : {
169 : // m_impl->get_superclasses(p_superclasses);
170 : // set_subclasses();
171 80 : update_classes();
172 80 : m_impl->set(this);
173 : }
174 :
175 80 : if (check_prefetch_needs())
176 0 : m_impl->prefetch_all_data();
177 :
178 80 : TLOG_DEBUG(2) << "\n*** DUMP CONFIGURATION ***\n" << *this;
179 80 : }
180 :
181 :
182 : void
183 0 : Configuration::print_profiling_info() noexcept
184 : {
185 0 : std::lock_guard < std::mutex > scoped_lock(m_impl_mutex);
186 :
187 0 : std::cout << "Configuration profiler report:\n"
188 0 : " number of created template objects: " << p_number_of_template_object_created << "\n"
189 0 : " number of read template objects: " << p_number_of_template_object_read << "\n"
190 0 : " number of cache hits: " << p_number_of_cache_hits << std::endl;
191 :
192 : // FIXME: re-implement for the dal registry
193 : // const char * s = ::getenv("TDAQ_DUMP_CONFFWK_PROFILER_INFO");
194 : // if (s && !strcmp(s, "DEBUG"))
195 : // {
196 : // std::cout << " Details of accessed objects:\n";
197 :
198 : // for (auto & i : m_cache_map)
199 : // {
200 : // Cache<DalObject> *c = static_cast<Cache<DalObject>*>(i.second);
201 : // std::cout << " *** " << c->m_cache.size() << " objects is class \'" << *i.first << "\' were accessed ***\n";
202 : // for (auto & j : c->m_cache)
203 : // std::cout << " - object \'" << j.first << '\'' << std::endl;
204 : // }
205 : // }
206 :
207 0 : if (m_impl)
208 : {
209 0 : m_impl->print_cache_info();
210 0 : m_impl->print_profiling_info();
211 : }
212 0 : }
213 :
214 80 : Configuration::~Configuration() noexcept
215 : {
216 80 : if (::getenv("TDAQ_DUMP_CONFFWK_PROFILER_INFO"))
217 0 : print_profiling_info();
218 :
219 80 : try
220 : {
221 80 : unload();
222 :
223 80 : if (m_shlib_h)
224 : {
225 80 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
226 :
227 80 : delete m_impl;
228 80 : m_impl = 0;
229 : //dlclose(m_shlib_h);
230 80 : m_shlib_h = 0;
231 80 : }
232 : }
233 0 : catch (dunedaq::conffwk::Generic& ex)
234 : {
235 0 : ers::error(ex);
236 0 : }
237 80 : }
238 :
239 : void
240 5 : Configuration::get(const std::string& class_name, const std::string& id, ConfigObject& object, unsigned long rlevel, const std::vector<std::string> * rclasses)
241 : {
242 5 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
243 5 : _get(class_name, id, object, rlevel, rclasses);
244 5 : }
245 :
246 : void
247 110 : Configuration::_get(const std::string& class_name, const std::string& name, ConfigObject& object, unsigned long rlevel, const std::vector<std::string> * rclasses)
248 : {
249 110 : try
250 : {
251 110 : m_impl->get(class_name, name, object, rlevel, rclasses);
252 : }
253 0 : catch (dunedaq::conffwk::Generic& ex)
254 : {
255 0 : std::ostringstream text;
256 0 : text << "failed to get object \'" << name << '@' << class_name << '\'';
257 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex );
258 0 : }
259 108 : }
260 :
261 : void
262 45 : Configuration::get(const std::string& class_name, std::vector<ConfigObject>& objects, const std::string& query, unsigned long rlevel, const std::vector<std::string> * rclasses)
263 : {
264 45 : try
265 : {
266 45 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
267 45 : m_impl->get(class_name, objects, query, rlevel, rclasses);
268 45 : }
269 0 : catch (dunedaq::conffwk::Generic& ex)
270 : {
271 0 : std::ostringstream text;
272 0 : text << "failed to get objects of class \'" << class_name << '\'';
273 0 : if (!query.empty())
274 : {
275 0 : text << " with query \'" << query << '\'';
276 : }
277 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex );
278 0 : }
279 45 : }
280 :
281 : void
282 0 : Configuration::get(const ConfigObject& obj_from, const std::string& query, std::vector<ConfigObject>& objects, unsigned long rlevel, const std::vector<std::string> * rclasses)
283 : {
284 0 : try
285 : {
286 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
287 0 : m_impl->get(obj_from, query, objects, rlevel, rclasses);
288 0 : }
289 0 : catch (dunedaq::conffwk::Generic& ex)
290 : {
291 0 : std::ostringstream text;
292 0 : text << "failed to get path \'" << query << "\' from object \'" << obj_from << '\'';
293 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex );
294 0 : }
295 0 : }
296 :
297 : bool
298 0 : Configuration::loaded() const noexcept
299 : {
300 0 : return (m_impl != nullptr) ? m_impl->loaded() : false;
301 : }
302 :
303 : void
304 0 : Configuration::load(const std::string& db_name)
305 : {
306 0 : std::string name;
307 :
308 0 : if (db_name.empty())
309 : {
310 0 : if (!m_impl_spec.empty() && !m_impl_param.empty())
311 : {
312 0 : name = m_impl_param;
313 : }
314 : else
315 : {
316 0 : const char * s = ::getenv("TDAQ_DB_NAME");
317 0 : if (s == 0 || *s == 0)
318 0 : s = ::getenv("TDAQ_DB_DATA");
319 :
320 0 : if (s && *s)
321 : {
322 0 : name = s;
323 : }
324 : else
325 : {
326 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, "no database name was provided" ) );
327 : }
328 : }
329 : }
330 : else
331 : {
332 0 : name = db_name;
333 : }
334 :
335 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
336 :
337 : // call conffwk actions if any
338 0 : {
339 0 : std::lock_guard<std::mutex> scoped_lock(m_actn_mutex);
340 0 : for (auto & i : m_actions)
341 : {
342 0 : i->load();
343 : }
344 0 : }
345 :
346 0 : if (m_impl)
347 : {
348 0 : m_impl->open_db(name);
349 : // m_impl->get_superclasses(p_superclasses);
350 : // set_subclasses();
351 0 : update_classes();
352 0 : m_impl->set(this);
353 :
354 0 : if(check_prefetch_needs())
355 : {
356 0 : m_impl->prefetch_all_data();
357 : }
358 :
359 0 : TLOG_DEBUG(2) << "\n*** DUMP CONFIGURATION ***\n" << *this;
360 : }
361 : else
362 : {
363 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "no implementation loaded" );
364 : }
365 0 : }
366 :
367 : void
368 80 : Configuration::unload()
369 : {
370 80 : if (m_impl == nullptr)
371 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "nothing to unload" );
372 :
373 80 : std::lock_guard<std::mutex> scoped_lock1(m_tmpl_mutex); // always lock template objects mutex first
374 80 : std::lock_guard<std::mutex> scoped_lock2(m_impl_mutex);
375 :
376 : // call conffwk actions if any
377 80 : {
378 80 : std::lock_guard<std::mutex> scoped_lock(m_actn_mutex);
379 80 : for(auto & i : m_actions)
380 : {
381 0 : i->unload();
382 : }
383 80 : }
384 :
385 : // for (auto& i : m_cache_map) {
386 : // delete i.second;
387 : // }
388 :
389 : // m_cache_map.clear();
390 80 : m_registry.clear();
391 :
392 80 : {
393 80 : std::lock_guard<std::mutex> scoped_lock3(m_else_mutex);
394 :
395 83 : for (auto& cb : m_callbacks)
396 3 : delete cb;
397 :
398 80 : for (auto& cb : m_pre_callbacks)
399 0 : delete cb;
400 :
401 80 : m_callbacks.clear();
402 80 : m_pre_callbacks.clear();
403 :
404 80 : m_impl->unsubscribe();
405 :
406 80 : for (auto& l : m_convert_map) {
407 0 : for (auto& a : *l.second)
408 0 : delete a;
409 :
410 0 : delete l.second;
411 : }
412 :
413 80 : m_convert_map.clear();
414 80 : }
415 :
416 80 : p_superclasses.clear();
417 :
418 81 : for(auto& j : p_direct_classes_desc_cache)
419 1 : delete j.second;
420 :
421 5637 : for(auto& j : p_all_classes_desc_cache)
422 5557 : delete j.second;
423 :
424 80 : p_direct_classes_desc_cache.clear();
425 80 : p_all_classes_desc_cache.clear();
426 :
427 80 : m_impl->close_db();
428 80 : }
429 :
430 : void
431 4 : Configuration::create(const std::string& db_name, const std::list<std::string>& includes)
432 : {
433 4 : if (m_impl == nullptr)
434 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "no implementation loaded" );
435 :
436 4 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
437 :
438 4 : try
439 : {
440 4 : m_impl->create(db_name, includes);
441 4 : update_classes();
442 : }
443 0 : catch(dunedaq::conffwk::Generic & ex)
444 : {
445 0 : std::ostringstream text;
446 0 : text << "failed to create database \'" << db_name << '\'';
447 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex ) );
448 0 : }
449 4 : }
450 :
451 :
452 : bool
453 0 : Configuration::is_writable(const std::string& db_name) const
454 : {
455 0 : if (m_impl == nullptr)
456 0 : throw(dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded" ) );
457 :
458 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
459 :
460 0 : try
461 : {
462 0 : return m_impl->is_writable(db_name);
463 : }
464 0 : catch(dunedaq::conffwk::Generic & ex)
465 : {
466 0 : std::ostringstream text;
467 0 : text << "failed to get write access status for database \'" << db_name<< '\'';
468 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex ) );
469 0 : }
470 0 : }
471 :
472 :
473 : void
474 0 : Configuration::add_include(const std::string& db_name, const std::string& include)
475 : {
476 0 : if (m_impl == nullptr)
477 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "no implementation loaded" );
478 :
479 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
480 :
481 0 : try
482 : {
483 0 : m_impl->add_include(db_name, include);
484 : // m_impl->get_superclasses(p_superclasses);
485 : // set_subclasses();
486 0 : update_classes();
487 : }
488 0 : catch(dunedaq::conffwk::Generic & ex)
489 : {
490 0 : std::ostringstream text;
491 0 : text << "failed to add include \'" << include << "\' to database \'" << db_name<< '\'';
492 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex ) );
493 0 : }
494 0 : }
495 :
496 : void
497 0 : Configuration::remove_include(const std::string& db_name, const std::string& include)
498 : {
499 0 : if (m_impl == nullptr)
500 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "no implementation loaded" );
501 :
502 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
503 0 : std::lock_guard<std::mutex> scoped_lock2(m_tmpl_mutex);
504 :
505 0 : try
506 : {
507 0 : m_impl->remove_include(db_name, include);
508 : // m_impl->get_superclasses(p_superclasses);
509 : // set_subclasses();
510 0 : update_classes();
511 : }
512 0 : catch(dunedaq::conffwk::Generic & ex)
513 : {
514 0 : std::ostringstream text;
515 0 : text << "failed to remove include \'" << include << "\' from database \'" << db_name<< '\'';
516 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex ) );
517 0 : }
518 0 : }
519 :
520 : void
521 0 : Configuration::get_includes(const std::string& db_name, std::list<std::string>& includes) const
522 : {
523 0 : if (m_impl == nullptr)
524 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "no implementation loaded" );
525 :
526 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
527 :
528 0 : try
529 : {
530 0 : m_impl->get_includes(db_name, includes);
531 : }
532 0 : catch(dunedaq::conffwk::Generic & ex)
533 : {
534 0 : std::ostringstream text;
535 0 : text << "failed to get includes of database \'" << db_name<< '\'';
536 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex ) );
537 0 : }
538 0 : }
539 :
540 :
541 : void
542 0 : Configuration::get_updated_dbs(std::list<std::string>& dbs) const
543 : {
544 0 : if (m_impl == nullptr)
545 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "no implementation loaded" );
546 :
547 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
548 :
549 0 : try
550 : {
551 0 : m_impl->get_updated_dbs(dbs);
552 : }
553 0 : catch(dunedaq::conffwk::Generic & ex)
554 : {
555 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, "get_updated_dbs failed", ex ) );
556 0 : }
557 0 : }
558 :
559 :
560 : void
561 0 : Configuration::set_commit_credentials(const std::string& user, const std::string& password)
562 : {
563 0 : if (m_impl == nullptr)
564 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "no implementation loaded" );
565 :
566 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
567 :
568 0 : try
569 : {
570 0 : m_impl->set_commit_credentials(user, password);
571 : }
572 0 : catch(dunedaq::conffwk::Generic & ex)
573 : {
574 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, "set_commit_credentials failed", ex ) );
575 0 : }
576 0 : }
577 :
578 :
579 : void
580 0 : Configuration::commit(const std::string& log_message)
581 : {
582 0 : TLOG_DEBUG(1) << "call commit";
583 :
584 0 : if (m_impl == nullptr)
585 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "no implementation loaded");
586 :
587 0 : std::lock_guard<std::mutex> scoped_lock1(m_tmpl_mutex); // always lock template objects mutex first
588 0 : std::lock_guard<std::mutex> scoped_lock2(m_impl_mutex);
589 :
590 0 : try
591 : {
592 0 : m_impl->commit(log_message);
593 : }
594 0 : catch (dunedaq::conffwk::Generic & ex)
595 : {
596 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, "commit failed", ex ) );
597 0 : }
598 0 : }
599 :
600 : void
601 0 : Configuration::abort()
602 : {
603 0 : TLOG_DEBUG(1) << "call abort";
604 :
605 0 : if (m_impl == nullptr)
606 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "no implementation loaded");
607 :
608 0 : std::lock_guard<std::mutex> scoped_lock1(m_tmpl_mutex); // always lock template objects mutex first
609 0 : std::lock_guard<std::mutex> scoped_lock2(m_impl_mutex);
610 :
611 0 : try
612 : {
613 0 : m_impl->abort();
614 0 : _unread_implementation_objects(dunedaq::conffwk::Unknown);
615 0 : _unread_template_objects();
616 : // m_impl->get_superclasses(p_superclasses);
617 : // set_subclasses();
618 0 : update_classes();
619 :
620 : }
621 0 : catch (dunedaq::conffwk::Generic & ex)
622 : {
623 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, "abort failed", ex));
624 0 : }
625 0 : }
626 :
627 : void
628 9 : Configuration::prefetch_all_data()
629 : {
630 9 : std::lock_guard<std::mutex> scoped_lock1(m_tmpl_mutex); // always lock template objects mutex first
631 9 : std::lock_guard<std::mutex> scoped_lock2(m_impl_mutex);
632 :
633 9 : try
634 : {
635 9 : m_impl->prefetch_all_data();
636 : }
637 0 : catch (dunedaq::conffwk::Generic & ex)
638 : {
639 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, "prefetch all data failed", ex));
640 0 : }
641 9 : }
642 :
643 : void
644 0 : Configuration::unread_all_objects(bool unread_implementation_objs) noexcept
645 : {
646 0 : if (unread_implementation_objs)
647 0 : unread_implementation_objects(dunedaq::conffwk::Unknown);
648 :
649 0 : unread_template_objects();
650 0 : }
651 :
652 :
653 : // FIXME: find better name?
654 : void
655 0 : Configuration::_unread_template_objects() noexcept
656 : {
657 0 : m_registry.unread_all();
658 0 : }
659 :
660 : void
661 0 : Configuration::_unread_implementation_objects(dunedaq::conffwk::ObjectState state) noexcept
662 : {
663 0 : for (auto &i : m_impl->m_impl_objects)
664 0 : for (auto &j : *i.second)
665 : {
666 0 : std::lock_guard<std::mutex> scoped_lock(j.second->m_mutex);
667 0 : j.second->clear();
668 0 : j.second->m_state = state;
669 0 : }
670 :
671 0 : for (auto& x : m_impl->m_tangled_objects)
672 : {
673 0 : std::lock_guard<std::mutex> scoped_lock(x->m_mutex);
674 0 : x->clear();
675 0 : x->m_state = state;
676 0 : }
677 0 : }
678 :
679 :
680 : void
681 84 : Configuration::set_subclasses() noexcept
682 : {
683 84 : p_subclasses.clear();
684 :
685 5641 : for (const auto &i : p_superclasses)
686 10979 : for (const auto &j : i.second)
687 5422 : p_subclasses[j].insert(i.first);
688 84 : }
689 :
690 :
691 : void
692 84 : Configuration::update_classes() noexcept
693 : {
694 84 : m_impl->get_superclasses(p_superclasses);
695 84 : this->set_subclasses();
696 84 : this->set_class_domain_map();
697 84 : m_registry.update_class_maps();
698 84 : }
699 :
700 :
701 : std::deque<std::set<std::string>>
702 168 : Configuration::find_class_domains()
703 : {
704 168 : std::deque<std::set<std::string>> domains;
705 :
706 168 : std::deque<dunedaq::conffwk::class_t> seeds;
707 11282 : for (const auto& c : get_class_list()) {
708 11114 : auto ci = this->_get_class_info(c);
709 11114 : if (ci.p_superclasses.empty())
710 5086 : seeds.push_back(ci);
711 11282 : }
712 :
713 5254 : for (const auto& ci : seeds) {
714 : // Make a candidate domain based using the seed subclasses
715 5086 : std::set<std::string> class_domain;
716 5086 : class_domain.insert(ci.p_name);
717 5086 : class_domain.insert(ci.p_subclasses.begin(), ci.p_subclasses.end());
718 :
719 : // Look for overlaps with other domains
720 5086 : std::deque<std::set<std::string>> overlapping;
721 93344 : for (auto& d : domains) {
722 88258 : std::set<std::string> intersection;
723 88258 : std::set_intersection(d.begin(), d.end(), class_domain.begin(), class_domain.end(), std::inserter(intersection, intersection.begin()));
724 : // non-zero intersection, overlap found
725 88258 : if (intersection.size() > 0) {
726 298 : overlapping.push_back(d);
727 : }
728 88258 : }
729 :
730 : // If overlapping are found, add all overlapping to
731 : // the new domain and remove them from the domain list
732 5086 : if ( !overlapping.empty() ) {
733 592 : for( auto& d : overlapping ) {
734 : // merge the existing cluster in class_domain
735 298 : class_domain.insert(d.begin(), d.end());
736 : // Remove the old cluster from the list
737 298 : auto it = std::find(domains.begin(), domains.end(), d);
738 298 : if (it!= domains.end()) {
739 298 : domains.erase(it);
740 : }
741 : }
742 : }
743 :
744 5086 : domains.push_back(class_domain);
745 5086 : }
746 :
747 168 : return domains;
748 168 : }
749 :
750 :
751 : void
752 84 : Configuration::set_class_domain_map() {
753 :
754 84 : p_class_domain_map.clear();
755 :
756 84 : auto domains = this->find_class_domains();
757 2478 : for( size_t i(0); i<domains.size(); ++i ) {
758 2394 : const auto& dom = domains[i];
759 7951 : for( const auto& class_name : dom ) {
760 5557 : p_class_domain_map[&conffwk::DalFactory::instance().get_known_class_name_ref(class_name)] = i;
761 : }
762 : }
763 84 : }
764 :
765 :
766 : //////////////////////////////////////////////////////////////////////////////////////////
767 :
768 : //
769 : // Test, create and destroy object methods
770 : //
771 :
772 : //////////////////////////////////////////////////////////////////////////////////////////
773 :
774 : bool
775 0 : Configuration::test_object(const std::string& class_name, const std::string& id, unsigned long rlevel, const std::vector<std::string> * rclasses)
776 : {
777 0 : try
778 : {
779 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
780 0 : return m_impl->test_object(class_name, id, rlevel, rclasses);
781 0 : }
782 0 : catch (dunedaq::conffwk::Generic& ex)
783 : {
784 0 : std::ostringstream text;
785 0 : text << "failed to test existence of object \'" << id << '@' << class_name << '\'';
786 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex );
787 0 : }
788 : }
789 :
790 : void
791 23 : Configuration::create(const std::string& at, const std::string& class_name, const std::string& id, ConfigObject& object)
792 : {
793 23 : try
794 : {
795 23 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
796 23 : m_impl->create(at, class_name, id, object);
797 23 : }
798 0 : catch (dunedaq::conffwk::Generic& ex)
799 : {
800 0 : std::ostringstream text;
801 0 : text << "failed to create object \'" << id << '@' << class_name << '\'';
802 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex );
803 0 : }
804 23 : }
805 :
806 : void
807 0 : Configuration::create(const ConfigObject& at, const std::string& class_name, const std::string& id, ConfigObject& object)
808 : {
809 0 : try
810 : {
811 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
812 0 : m_impl->create(at, class_name, id, object);
813 0 : }
814 0 : catch (dunedaq::conffwk::Generic& ex)
815 : {
816 0 : std::ostringstream text;
817 0 : text << "failed to create object \'" << id << '@' << class_name << '\'';
818 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex );
819 0 : }
820 0 : }
821 :
822 :
823 : void
824 0 : Configuration::destroy_obj(ConfigObject& object)
825 : {
826 0 : try
827 : {
828 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
829 0 : std::lock_guard<std::mutex> scoped_lock2(m_tmpl_mutex);
830 0 : m_impl->destroy(object);
831 0 : }
832 0 : catch (dunedaq::conffwk::Generic& ex)
833 : {
834 0 : std::ostringstream text;
835 0 : text << "failed to destroy object \'" << object << '\'';
836 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex );
837 0 : }
838 0 : }
839 :
840 :
841 : void
842 0 : Configuration::rename_object(ConfigObject& obj, const std::string& new_id)
843 : {
844 0 : std::lock_guard<std::mutex> scoped_impl_lock(m_tmpl_mutex); // always lock template objects mutex first
845 0 : std::lock_guard<std::mutex> scoped_tmpl_lock(m_impl_mutex);
846 :
847 0 : std::lock_guard<std::mutex> scoped_obj_lock(obj.m_impl->m_mutex);
848 :
849 0 : const std::string old_id(obj.m_impl->m_id);
850 :
851 0 : obj.m_impl->throw_if_deleted();
852 0 : obj.m_impl->rename(new_id);
853 0 : obj.m_impl->m_id = new_id;
854 0 : m_impl->rename_impl_object(obj.m_impl->m_class_name, old_id, new_id);
855 :
856 0 : TLOG_DEBUG(3) << " * call rename \'" << old_id << "\' to \'" << new_id << "\' in class \'" << obj.class_name() << "\')";
857 :
858 0 : m_registry._rename_object(obj.class_name(), old_id, new_id);
859 :
860 : // conffwk::fmap<CacheBase*>::iterator j = m_cache_map.find(&obj.class_name());
861 : // if (j != m_cache_map.end())
862 : // j->second->m_functions.m_rename_object_fn(j->second, old_id, new_id);
863 :
864 : // conffwk::fmap<conffwk::fset>::const_iterator sc = p_superclasses.find(&obj.class_name());
865 :
866 : // if (sc != p_superclasses.end())
867 : // for (conffwk::fset::const_iterator c = sc->second.begin(); c != sc->second.end(); ++c)
868 : // {
869 : // conffwk::fmap<CacheBase*>::iterator j = m_cache_map.find(*c);
870 :
871 : // if (j != m_cache_map.end())
872 : // j->second->m_functions.m_rename_object_fn(j->second, old_id, new_id);
873 : // }
874 0 : }
875 :
876 :
877 :
878 : //////////////////////////////////////////////////////////////////////////////////////////
879 : //
880 : // Meta-information access methods
881 : //
882 : //////////////////////////////////////////////////////////////////////////////////////////
883 :
884 :
885 : const dunedaq::conffwk::class_t&
886 18 : Configuration::get_class_info(const std::string& class_name, bool direct_only)
887 : {
888 18 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
889 :
890 34 : return this->_get_class_info(class_name, direct_only);
891 18 : }
892 :
893 :
894 : const dunedaq::conffwk::class_t&
895 11132 : Configuration::_get_class_info(const std::string& class_name, bool direct_only)
896 : {
897 11132 : conffwk::map<dunedaq::conffwk::class_t *>& d_cache(direct_only ? p_direct_classes_desc_cache : p_all_classes_desc_cache);
898 :
899 11132 : conffwk::map<dunedaq::conffwk::class_t *>::const_iterator i = d_cache.find(class_name);
900 :
901 11132 : if (i != d_cache.end())
902 5572 : return *(i->second);
903 :
904 5560 : try
905 : {
906 5560 : dunedaq::conffwk::class_t * d = m_impl->get(class_name, direct_only);
907 5558 : d_cache[class_name] = d;
908 5558 : return *d;
909 : }
910 : // catch Generic exception only; the NotFound is forwarded from implementation
911 0 : catch (dunedaq::conffwk::Generic& ex)
912 : {
913 0 : std::ostringstream text;
914 0 : text << "failed to get description of class \'" << class_name << '\'';
915 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex );
916 0 : }
917 : }
918 :
919 : //////////////////////////////////////////////////////////////////////////////////////////
920 :
921 : static void
922 0 : init_regex(std::unique_ptr<std::regex>& ptr, const std::string& str, const char * what)
923 : {
924 0 : if (!str.empty())
925 0 : try
926 : {
927 0 : ptr = std::make_unique<std::regex>(str);
928 : }
929 0 : catch (const std::regex_error &ex)
930 : {
931 0 : std::ostringstream text;
932 0 : text << "failed to create " << what << " regex \"" << str << "\": " << ex.what();
933 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str());
934 0 : }
935 0 : }
936 :
937 :
938 : template<class T>
939 : static void
940 0 : add_array_item(boost::property_tree::ptree &pt, const T &val)
941 : {
942 0 : boost::property_tree::ptree child;
943 0 : child.put("", val);
944 0 : pt.push_back(std::make_pair("", child));
945 0 : }
946 :
947 : void
948 0 : Configuration::export_schema(boost::property_tree::ptree& pt, const std::string& classes_str, bool direct_only)
949 : {
950 0 : std::unique_ptr<std::regex> classes_regex;
951 :
952 0 : init_regex(classes_regex, classes_str, "classes");
953 :
954 0 : auto cmp_str_ptr = [](const std::string * s1, const std::string * s2) { return *s1 < *s2; };
955 0 : std::set<const std::string *, decltype(cmp_str_ptr)> sorted_classes(cmp_str_ptr);
956 :
957 0 : for (const auto &c : superclasses())
958 0 : if (classes_str.empty() || std::regex_match(*c.first, *classes_regex.get()))
959 0 : sorted_classes.insert(c.first);
960 :
961 0 : for (const auto &c : sorted_classes)
962 0 : if (classes_str.empty() || std::regex_match(*c, *classes_regex.get()))
963 : {
964 0 : const dunedaq::conffwk::class_t& info(get_class_info(*c, direct_only));
965 :
966 0 : boost::property_tree::ptree class_pt;
967 :
968 0 : class_pt.put("abstract", info.p_abstract);
969 0 : if (!info.p_description.empty())
970 0 : class_pt.put("description", info.p_description);
971 :
972 0 : if (!info.p_superclasses.empty())
973 : {
974 0 : boost::property_tree::ptree superclasses;
975 :
976 0 : for (const auto &x : info.p_superclasses)
977 0 : add_array_item(superclasses, x);
978 :
979 0 : class_pt.add_child("superclasses", superclasses);
980 0 : }
981 :
982 0 : if (!info.p_attributes.empty())
983 : {
984 0 : boost::property_tree::ptree attributes;
985 :
986 0 : for (const auto &x : info.p_attributes)
987 : {
988 0 : boost::property_tree::ptree attribute;
989 :
990 0 : attribute.put("type", dunedaq::conffwk::attribute_t::type(x.p_type));
991 0 : if (!x.p_range.empty())
992 0 : attribute.put("range", x.p_range);
993 0 : if (x.p_int_format != dunedaq::conffwk::na_int_format)
994 0 : attribute.put("format", dunedaq::conffwk::attribute_t::format2str(x.p_int_format));
995 0 : if (x.p_is_not_null)
996 0 : attribute.put("is-not-null", x.p_is_not_null);
997 0 : if (x.p_is_multi_value)
998 0 : attribute.put("is-multi-value", x.p_is_multi_value);
999 0 : if (!x.p_default_value.empty())
1000 0 : attribute.put("default-value", x.p_default_value);
1001 0 : if (!x.p_description.empty())
1002 0 : attribute.put("description", x.p_description);
1003 :
1004 0 : attributes.push_back(boost::property_tree::ptree::value_type(x.p_name, attribute));
1005 0 : }
1006 :
1007 0 : class_pt.add_child("attributes", attributes);
1008 0 : }
1009 :
1010 0 : if (!info.p_relationships.empty())
1011 : {
1012 0 : boost::property_tree::ptree relationships;
1013 :
1014 0 : for (const auto &x : info.p_relationships)
1015 : {
1016 0 : boost::property_tree::ptree relationship;
1017 :
1018 0 : relationship.put("type", x.p_type);
1019 0 : relationship.put("cardinality", dunedaq::conffwk::relationship_t::card2str(x.p_cardinality));
1020 0 : if (!x.p_is_aggregation)
1021 0 : relationship.put("is-aggregation", x.p_is_aggregation);
1022 0 : if (!x.p_description.empty())
1023 0 : relationship.put("description", x.p_description);
1024 :
1025 0 : relationships.push_back(boost::property_tree::ptree::value_type(x.p_name, relationship));
1026 0 : }
1027 :
1028 0 : class_pt.add_child("relationships", relationships);
1029 0 : }
1030 :
1031 0 : pt.put_child(boost::property_tree::ptree::path_type(*c), class_pt);
1032 0 : }
1033 0 : }
1034 :
1035 : template<class T>
1036 : static void
1037 0 : add_data(boost::property_tree::ptree &pt, const ConfigObject &obj, const dunedaq::conffwk::attribute_t &attribute, const std::string &empty_array_item)
1038 : {
1039 0 : auto &o = const_cast<ConfigObject&>(obj);
1040 0 : if (!attribute.p_is_multi_value)
1041 : {
1042 0 : T val;
1043 0 : const_cast<ConfigObject&>(obj).get(attribute.p_name, val);
1044 0 : pt.put(attribute.p_name, val);
1045 0 : }
1046 : else
1047 : {
1048 0 : std::vector<T> values;
1049 0 : o.get(attribute.p_name, values);
1050 :
1051 0 : boost::property_tree::ptree children;
1052 :
1053 0 : if (!values.empty())
1054 0 : for (const auto &v : values)
1055 0 : add_array_item(children, v);
1056 :
1057 0 : else if (!empty_array_item.empty())
1058 0 : add_array_item(children, empty_array_item);
1059 :
1060 0 : pt.add_child(attribute.p_name, children);
1061 0 : }
1062 0 : }
1063 :
1064 : static void
1065 0 : add_data(boost::property_tree::ptree &pt, const ConfigObject &obj, const dunedaq::conffwk::relationship_t &relationship, const std::string &empty_array_item)
1066 : {
1067 0 : if (relationship.p_cardinality == dunedaq::conffwk::zero_or_many || relationship.p_cardinality == dunedaq::conffwk::one_or_many)
1068 : {
1069 0 : std::vector<ConfigObject> values;
1070 0 : const_cast<ConfigObject&>(obj).get(relationship.p_name, values);
1071 :
1072 0 : boost::property_tree::ptree children;
1073 :
1074 0 : if (!values.empty())
1075 0 : for (const auto &v : values)
1076 0 : add_array_item(children, v.full_name());
1077 :
1078 0 : else if (!empty_array_item.empty())
1079 0 : add_array_item(children, empty_array_item);
1080 :
1081 0 : pt.add_child(relationship.p_name, children);
1082 0 : }
1083 : else
1084 : {
1085 0 : ConfigObject val;
1086 0 : const_cast<ConfigObject&>(obj).get(relationship.p_name, val);
1087 0 : pt.put(relationship.p_name, !val.is_null() ? val.full_name() : "");
1088 0 : }
1089 0 : }
1090 :
1091 : void
1092 0 : Configuration::export_data(boost::property_tree::ptree& pt, const std::string& classes_str, const std::string& objects_str, const std::string& files_str, const std::string& empty_array_item)
1093 : {
1094 0 : std::unique_ptr<std::regex> classes_regex, objects_regex, files_regex;
1095 :
1096 0 : init_regex(classes_regex, classes_str, "classes");
1097 0 : init_regex(objects_regex, objects_str, "objects");
1098 0 : init_regex(files_regex, files_str, "files");
1099 :
1100 0 : auto cmp_str_ptr = [](const std::string * s1, const std::string * s2) { return *s1 < *s2; };
1101 0 : std::set<const std::string *, decltype(cmp_str_ptr)> sorted_classes(cmp_str_ptr);
1102 :
1103 0 : for (const auto &c : superclasses())
1104 0 : if (classes_str.empty() || std::regex_match(*c.first, *classes_regex.get()))
1105 0 : sorted_classes.insert(c.first);
1106 :
1107 0 : for (const auto &c : sorted_classes)
1108 0 : if (classes_str.empty() || std::regex_match(*c, *classes_regex.get()))
1109 : {
1110 0 : const dunedaq::conffwk::class_t& info(get_class_info(*c));
1111 :
1112 0 : boost::property_tree::ptree pt_objects;
1113 :
1114 0 : std::vector<ConfigObject> objects;
1115 0 : get(*c, objects);
1116 :
1117 0 : auto comp_obj_ptr = [](const ConfigObject * o1, const ConfigObject * o2) { return o1->UID() < o2->UID(); };
1118 0 : std::set<const ConfigObject *, decltype(comp_obj_ptr)> sorted_objects(comp_obj_ptr);
1119 :
1120 0 : for (const auto& x : objects)
1121 0 : if (objects_str.empty() || std::regex_match(x.UID(), *objects_regex.get()))
1122 0 : if (x.class_name() == *c)
1123 0 : if(files_str.empty() || std::regex_match(x.contained_in(), *files_regex.get()))
1124 0 : sorted_objects.insert(&x);
1125 :
1126 0 : if (!sorted_objects.empty())
1127 : {
1128 0 : boost::property_tree::ptree pt_objects;
1129 :
1130 0 : for (const auto& x : sorted_objects)
1131 : {
1132 0 : boost::property_tree::ptree data;
1133 :
1134 0 : for (const auto &a : info.p_attributes)
1135 0 : switch (a.p_type)
1136 : {
1137 0 : case dunedaq::conffwk::bool_type:
1138 0 : add_data<bool>(data, *x, a, empty_array_item);
1139 : break;
1140 0 : case dunedaq::conffwk::s8_type:
1141 0 : add_data<int8_t>(data, *x, a, empty_array_item);
1142 : break;
1143 0 : case dunedaq::conffwk::u8_type:
1144 0 : add_data<uint8_t>(data, *x, a, empty_array_item);
1145 : break;
1146 0 : case dunedaq::conffwk::s16_type:
1147 0 : add_data<int16_t>(data, *x, a, empty_array_item);
1148 : break;
1149 0 : case dunedaq::conffwk::u16_type:
1150 0 : add_data<uint16_t>(data, *x, a, empty_array_item);
1151 : break;
1152 0 : case dunedaq::conffwk::s32_type:
1153 0 : add_data<int32_t>(data, *x, a, empty_array_item);
1154 : break;
1155 0 : case dunedaq::conffwk::u32_type:
1156 0 : add_data<uint32_t>(data, *x, a, empty_array_item);
1157 : break;
1158 0 : case dunedaq::conffwk::s64_type:
1159 0 : add_data<int64_t>(data, *x, a, empty_array_item);
1160 : break;
1161 0 : case dunedaq::conffwk::u64_type:
1162 0 : add_data<uint64_t>(data, *x, a, empty_array_item);
1163 : break;
1164 0 : case dunedaq::conffwk::float_type:
1165 0 : add_data<float>(data, *x, a, empty_array_item);
1166 : break;
1167 0 : case dunedaq::conffwk::double_type:
1168 0 : add_data<double>(data, *x, a, empty_array_item);
1169 : break;
1170 0 : case dunedaq::conffwk::date_type:
1171 0 : case dunedaq::conffwk::time_type:
1172 0 : case dunedaq::conffwk::enum_type:
1173 0 : case dunedaq::conffwk::class_type:
1174 0 : case dunedaq::conffwk::string_type:
1175 0 : add_data<std::string>(data, *x, a, empty_array_item);
1176 : break;
1177 0 : default:
1178 0 : throw std::runtime_error("Invalid type of attribute " + a.p_name);
1179 :
1180 : }
1181 :
1182 0 : for (const auto &r : info.p_relationships)
1183 0 : add_data(data, *x, r, empty_array_item);
1184 :
1185 0 : pt_objects.push_back(boost::property_tree::ptree::value_type(x->UID(), data));
1186 0 : }
1187 :
1188 0 : pt.put_child(boost::property_tree::ptree::path_type(*c), pt_objects);
1189 0 : }
1190 0 : }
1191 0 : }
1192 :
1193 : //////////////////////////////////////////////////////////////////////////////////////////
1194 :
1195 : //
1196 : // Methods to get versions
1197 : //
1198 :
1199 : //////////////////////////////////////////////////////////////////////////////////////////
1200 :
1201 :
1202 : std::vector<dunedaq::conffwk::Version>
1203 0 : Configuration::get_changes()
1204 : {
1205 0 : try
1206 : {
1207 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
1208 0 : return m_impl->get_changes();
1209 0 : }
1210 0 : catch (dunedaq::conffwk::Generic& ex)
1211 : {
1212 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "failed to get new versions", ex );
1213 0 : }
1214 : }
1215 :
1216 :
1217 : std::vector<dunedaq::conffwk::Version>
1218 0 : Configuration::get_versions(const std::string& since, const std::string& until, dunedaq::conffwk::Version::QueryType type, bool skip_irrelevant)
1219 : {
1220 0 : try
1221 : {
1222 0 : std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
1223 0 : return m_impl->get_versions(since, until, type, skip_irrelevant);
1224 0 : }
1225 0 : catch (dunedaq::conffwk::Generic& ex)
1226 : {
1227 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "failed to get versions", ex );
1228 0 : }
1229 : }
1230 :
1231 : //////////////////////////////////////////////////////////////////////////////////////////
1232 :
1233 : //
1234 : // Subscription and notification methods
1235 : //
1236 :
1237 : //////////////////////////////////////////////////////////////////////////////////////////
1238 :
1239 :
1240 : // The methods checks that given callback exists
1241 :
1242 : Configuration::CallbackSubscription *
1243 0 : Configuration::find_callback(CallbackId cb_handler) const
1244 : {
1245 0 : return ((!cb_handler || (m_callbacks.find(cb_handler) == m_callbacks.end())) ? 0 : cb_handler);
1246 : }
1247 :
1248 :
1249 : Configuration::CallbackId
1250 3 : Configuration::subscribe(const ConfigurationSubscriptionCriteria& criteria, notify user_cb, void * parameter)
1251 : {
1252 : // check if there is no subscription function provided
1253 :
1254 3 : if (!user_cb)
1255 : {
1256 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "callback function is not defined" );
1257 : }
1258 :
1259 : // create callback subscription structure
1260 :
1261 3 : Configuration::CallbackSubscription * cs = new CallbackSubscription();
1262 :
1263 3 : cs->m_criteria = criteria;
1264 3 : cs->m_cb = user_cb;
1265 3 : cs->m_param = parameter;
1266 :
1267 : // FIXME: bug in OksConfiguration subscribe() with enter_loop=true
1268 3 : std::lock_guard<std::mutex> scoped_lock(m_else_mutex);// TEST 2010-02-03
1269 :
1270 3 : m_callbacks.insert(cs);
1271 :
1272 3 : try
1273 : {
1274 3 : reset_subscription();
1275 3 : return cs;
1276 : }
1277 0 : catch (dunedaq::conffwk::Generic& ex)
1278 : {
1279 0 : m_callbacks.erase(cs);
1280 0 : delete cs;
1281 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "subscription failed", ex );
1282 0 : }
1283 3 : }
1284 :
1285 : Configuration::CallbackId
1286 0 : Configuration::subscribe(pre_notify user_cb, void * parameter)
1287 : {
1288 : // check if there is no subscription function provided
1289 :
1290 0 : if (!user_cb)
1291 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, "callback function is not defined" ) );
1292 :
1293 : // create callback subscription structure
1294 :
1295 0 : CallbackPreSubscription * cs = new CallbackPreSubscription();
1296 :
1297 0 : cs->m_cb = user_cb;
1298 0 : cs->m_param = parameter;
1299 :
1300 0 : {
1301 0 : std::lock_guard<std::mutex> scoped_lock(m_else_mutex);
1302 0 : m_pre_callbacks.insert(cs);
1303 0 : }
1304 :
1305 0 : return reinterpret_cast<CallbackSubscription *>(cs);
1306 : }
1307 :
1308 :
1309 : void
1310 0 : Configuration::unsubscribe(CallbackId id)
1311 : {
1312 0 : std::lock_guard < std::mutex > scoped_lock(m_else_mutex);
1313 :
1314 0 : if (id)
1315 : {
1316 0 : CallbackSet::iterator i = m_callbacks.find(id);
1317 0 : PreCallbackSet::iterator j = m_pre_callbacks.find(reinterpret_cast<CallbackPreSubscription *>(id));
1318 :
1319 0 : if (i != m_callbacks.end())
1320 : {
1321 0 : delete id;
1322 0 : m_callbacks.erase(i);
1323 : }
1324 0 : else if (j != m_pre_callbacks.end())
1325 : {
1326 0 : delete reinterpret_cast<CallbackPreSubscription *>(id);
1327 0 : m_pre_callbacks.erase(j);
1328 : }
1329 : else
1330 : {
1331 0 : std::ostringstream text;
1332 0 : text << "unsubscription failed for CallbackId = " << (void *) id << " (no such callback id found)";
1333 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
1334 0 : }
1335 : }
1336 : else
1337 : {
1338 0 : for (auto &i : m_callbacks)
1339 0 : delete i;
1340 :
1341 0 : for (auto &i : m_pre_callbacks)
1342 0 : delete i;
1343 :
1344 0 : m_callbacks.clear();
1345 0 : m_pre_callbacks.clear();
1346 : }
1347 :
1348 0 : try
1349 : {
1350 0 : reset_subscription();
1351 : }
1352 0 : catch (dunedaq::conffwk::Generic& ex)
1353 : {
1354 0 : throw dunedaq::conffwk::Generic( ERS_HERE, "unsubscription failed", ex );
1355 0 : }
1356 0 : }
1357 :
1358 : void
1359 3 : Configuration::reset_subscription()
1360 : {
1361 : // check that there is no at least one subscription
1362 : // if NO, then unsubscribe
1363 :
1364 3 : if (m_callbacks.empty())
1365 : {
1366 0 : m_impl->unsubscribe();
1367 0 : return;
1368 : }
1369 :
1370 : // prepare subscription criteria
1371 :
1372 3 : ConfigurationSubscriptionCriteria::ObjectMap obj_subscriptions;
1373 3 : std::set<std::string> class_subscriptions;
1374 :
1375 : // among existing subscriptions find one who has all subscriptions
1376 :
1377 3 : bool found_subscribe_all = false;
1378 :
1379 3 : for (const auto &i : m_callbacks)
1380 3 : if (i->m_criteria.get_classes_subscription().empty() && i->m_criteria.get_objects_subscription().empty())
1381 : {
1382 : found_subscribe_all = true;
1383 : break;
1384 : }
1385 :
1386 3 : if (found_subscribe_all == false)
1387 : {
1388 : // build list of all classes for which there is a subscription
1389 0 : for (const auto &i : m_callbacks)
1390 0 : for (const auto &j : i->m_criteria.get_classes_subscription())
1391 0 : class_subscriptions.insert(j);
1392 :
1393 : // build list of all objects for which there is a subscription (if there is no such class)
1394 0 : for (const auto &i : m_callbacks)
1395 0 : for (const auto &j : i->m_criteria.get_objects_subscription())
1396 : {
1397 0 : const std::string &obj_class_name = j.first;
1398 0 : if (class_subscriptions.find(obj_class_name) == class_subscriptions.end())
1399 0 : for (const auto &k : j.second)
1400 0 : obj_subscriptions[obj_class_name].insert(k);
1401 : }
1402 : }
1403 :
1404 3 : m_impl->subscribe(class_subscriptions, obj_subscriptions, system_cb, system_pre_cb);
1405 3 : }
1406 :
1407 :
1408 : void
1409 0 : Configuration::update_impl_objects(conffwk::pmap<conffwk::map<ConfigObjectImpl *> * >& cache, ConfigurationChange& change, const std::string * class_name)
1410 : {
1411 0 : if (change.get_removed_objs().empty() == false)
1412 : {
1413 0 : conffwk::pmap<conffwk::map<ConfigObjectImpl *> *>::iterator i = cache.find(class_name);
1414 :
1415 0 : if (i != cache.end())
1416 : {
1417 0 : for (auto & x : change.get_removed_objs())
1418 : {
1419 0 : conffwk::map<ConfigObjectImpl *>::iterator j = i->second->find(x);
1420 0 : if (j != i->second->end())
1421 : {
1422 0 : TLOG_DEBUG( 2 ) << "set implementation object " << x << '@' << *class_name << " [" << (void *)j->second << "] deleted";
1423 :
1424 0 : std::lock_guard<std::mutex> scoped_lock(j->second->m_mutex);
1425 0 : j->second->m_state = dunedaq::conffwk::Deleted;
1426 0 : j->second->clear();
1427 0 : }
1428 : }
1429 : }
1430 : }
1431 :
1432 0 : if (change.get_created_objs().empty() == false)
1433 : {
1434 0 : conffwk::pmap<conffwk::map<ConfigObjectImpl *> *>::iterator i = cache.find(class_name);
1435 :
1436 0 : if (i != cache.end())
1437 : {
1438 0 : for (auto & x : change.get_created_objs())
1439 : {
1440 0 : conffwk::map<ConfigObjectImpl *>::iterator j = i->second->find(x);
1441 0 : if (j != i->second->end())
1442 : {
1443 0 : TLOG_DEBUG( 2 ) << "re-set created implementation object " << x << '@' << *class_name << " [" << (void *)j->second << ']';
1444 :
1445 0 : std::lock_guard<std::mutex> scoped_lock(j->second->m_mutex);
1446 0 : j->second->reset(); // it does not matter what the state was, always reset
1447 0 : }
1448 : }
1449 : }
1450 : }
1451 :
1452 0 : if (change.get_modified_objs().empty() == false)
1453 : {
1454 0 : conffwk::pmap<conffwk::map<ConfigObjectImpl *> *>::iterator i = cache.find(class_name);
1455 :
1456 0 : if (i != cache.end())
1457 : {
1458 0 : for (auto & x : change.get_modified_objs())
1459 : {
1460 0 : conffwk::map<ConfigObjectImpl *>::iterator j = i->second->find(x);
1461 0 : if (j != i->second->end())
1462 : {
1463 0 : TLOG_DEBUG(2) << "clear implementation object " << x << '@' << *class_name << " [" << (void *)j->second << ']';
1464 :
1465 0 : std::lock_guard<std::mutex> scoped_lock(j->second->m_mutex);
1466 :
1467 0 : if(j->second->m_state != dunedaq::conffwk::Valid)
1468 0 : j->second->reset();
1469 : else
1470 0 : j->second->clear();
1471 0 : }
1472 : }
1473 : }
1474 : }
1475 0 : }
1476 :
1477 :
1478 : // note, the std::lock_guard<std::mutex> scoped_lock(conf->m_tmpl_mutex) is already set by caller
1479 :
1480 : void
1481 0 : Configuration::update_cache(std::vector<ConfigurationChange *>& changes) noexcept
1482 : {
1483 0 : TLOG_DEBUG(3) << "*** Enter Configuration::update_cache() with changes:\n" << changes;
1484 :
1485 : // Remove deleted and update modified implementation objects first
1486 0 : for (const auto& i : changes)
1487 : {
1488 0 : const std::string * class_name = &DalFactory::instance().get_known_class_name_ref(i->get_class_name());
1489 :
1490 0 : update_impl_objects(m_impl->m_impl_objects, *i, class_name);
1491 :
1492 : // delete/update implementation objects defined in superclasses
1493 0 : conffwk::fmap<conffwk::fset>::const_iterator sc = p_superclasses.find(class_name);
1494 :
1495 0 : if (sc != p_superclasses.end())
1496 0 : for (const auto &c : sc->second)
1497 0 : update_impl_objects(m_impl->m_impl_objects, *i, c);
1498 :
1499 : // delete/update implementation objects defined in subclasses
1500 0 : sc = p_subclasses.find(class_name);
1501 :
1502 0 : if (sc != p_subclasses.end())
1503 0 : for (const auto &c : sc->second)
1504 0 : update_impl_objects(m_impl->m_impl_objects, *i, c);
1505 : }
1506 :
1507 0 : for (const auto& i : changes)
1508 : {
1509 :
1510 0 : m_registry.update(i->get_class_name(), i->get_modified_objs(), i->get_removed_objs(), i->get_created_objs());
1511 :
1512 : // const std::string * class_name = &DalFactory::instance().get_known_class_name_ref(i->get_class_name()); // FIXME: optimise with above
1513 :
1514 : // // invoke configuration update if there are template objects of given class
1515 :
1516 : // {
1517 : // conffwk::fmap<CacheBase*>::iterator j = m_cache_map.find(class_name);
1518 :
1519 : // if (j != m_cache_map.end())
1520 : // {
1521 : // TLOG_DEBUG(3) << " * call update on \'" << j->first << "\' template objects";
1522 : // j->second->m_functions.m_update_fn(*this, i);
1523 : // }
1524 : // }
1525 :
1526 :
1527 : // // invoke configuration update if there are template objects in super-classes
1528 :
1529 : // {
1530 : // conffwk::fmap<conffwk::fset>::const_iterator sc = p_superclasses.find(class_name);
1531 :
1532 : // if (sc != p_superclasses.end())
1533 : // {
1534 : // for (const auto& c : sc->second)
1535 : // {
1536 : // conffwk::fmap<CacheBase*>::iterator j = m_cache_map.find(c);
1537 :
1538 : // if (j != m_cache_map.end())
1539 : // {
1540 : // TLOG_DEBUG(3) << " * call update on \'" << j->first << "\' template objects (as super-class of \'" << *class_name << "\')";
1541 : // j->second->m_functions.m_update_fn(*this, i);
1542 : // }
1543 : // }
1544 : // }
1545 : // }
1546 :
1547 :
1548 : // // invoke configuration update if there are template objects in sub-classes
1549 :
1550 : // {
1551 : // conffwk::fmap<conffwk::fset>::const_iterator sc = p_subclasses.find(class_name);
1552 :
1553 : // if (sc != p_subclasses.end())
1554 : // {
1555 : // for (const auto& c : sc->second)
1556 : // {
1557 : // conffwk::fmap<CacheBase*>::iterator j = m_cache_map.find(c);
1558 :
1559 : // if (j != m_cache_map.end())
1560 : // {
1561 : // TLOG_DEBUG(3) << " * call update on \'" << j->first << "\' template objects (as sub-class of \'" << *class_name << "\')";
1562 : // j->second->m_functions.m_update_fn(*this, i);
1563 : // }
1564 : // }
1565 : // }
1566 : // }
1567 :
1568 : }
1569 :
1570 0 : }
1571 :
1572 :
1573 : void
1574 0 : Configuration::system_cb(std::vector<ConfigurationChange *>& changes, Configuration * conf) noexcept
1575 : {
1576 :
1577 0 : TLOG_DEBUG(3) <<
1578 : "*** Enter Configuration::system_cb()\n"
1579 0 : "*** Number of user subscriptions: " << conf->m_callbacks.size()
1580 0 : ;
1581 :
1582 : // call conffwk actions if any
1583 0 : {
1584 0 : std::lock_guard<std::mutex> scoped_lock(conf->m_impl_mutex);
1585 0 : std::lock_guard<std::mutex> scoped_lock2(conf->m_actn_mutex);
1586 0 : for (auto & i : conf->m_actions)
1587 0 : i->notify(changes);
1588 0 : }
1589 :
1590 :
1591 : // update template objects in cache
1592 0 : {
1593 0 : std::lock_guard<std::mutex> scoped_lock(conf->m_tmpl_mutex); // always lock template objects mutex first
1594 0 : std::lock_guard<std::mutex> scoped_lock2(conf->m_impl_mutex);
1595 0 : conf->update_cache(changes);
1596 0 : }
1597 :
1598 :
1599 : // user removed all subscriptions
1600 0 : if(conf->m_callbacks.empty()) return;
1601 :
1602 : // note, one cannot lock m_tmpl_mutex or m_impl_mutex here,
1603 : // since user callback may call arbitrary get() methods to access conffwk
1604 : // and template objects locking above two mutexes
1605 0 : std::lock_guard<std::mutex> scoped_lock(conf->m_else_mutex);
1606 :
1607 : // check if there is only one subscription
1608 0 : if (conf->m_callbacks.size() == 1)
1609 : {
1610 0 : auto j = *conf->m_callbacks.begin();
1611 0 : (*(j->m_cb))(changes, j->m_param);
1612 : }
1613 : // may need to calculate the changes for each subscription
1614 : else
1615 : {
1616 0 : for (const auto &j : conf->m_callbacks)
1617 : {
1618 :
1619 0 : if (ers::debug_level() >= 3)
1620 : {
1621 0 : std::ostringstream text;
1622 :
1623 0 : text <<
1624 0 : "*** Process subscription " << (void*) j << "\n"
1625 0 : " class subscription done for " << j->m_criteria.get_classes_subscription().size() << " classes:\n";
1626 :
1627 0 : for (const auto &i1 : j->m_criteria.get_classes_subscription())
1628 0 : text << " * class \"" << i1 << "\"\n";
1629 :
1630 0 : text << " object subscription done in " << j->m_criteria.get_objects_subscription().size() << " classes:\n";
1631 :
1632 0 : for (const auto &i2 : j->m_criteria.get_objects_subscription())
1633 : {
1634 0 : text << " * class \"" << (i2.first) << "\":\n";
1635 0 : for (const auto &i3 : i2.second)
1636 0 : text << " - \"" << i3 << "\"\n";
1637 : }
1638 :
1639 0 : TLOG_DEBUG(3) << text.str();
1640 0 : }
1641 :
1642 0 : if (j->m_criteria.get_classes_subscription().empty() && j->m_criteria.get_objects_subscription().empty())
1643 : {
1644 0 : try
1645 : {
1646 0 : TLOG_DEBUG(3) << "*** Invoke callback " << (void *)j << " with\n" << changes;
1647 0 : (*(j->m_cb))(changes, j->m_param);
1648 : }
1649 0 : catch (const ers::Issue &ex)
1650 : {
1651 0 : ers::error(dunedaq::conffwk::Generic( ERS_HERE, "user callback thrown ers exception", ex));
1652 0 : }
1653 0 : catch (const std::exception &ex)
1654 : {
1655 0 : ers::error(dunedaq::conffwk::Generic( ERS_HERE, "user callback thrown std exception", ex));
1656 0 : }
1657 0 : catch (...)
1658 : {
1659 0 : ers::error(dunedaq::conffwk::Generic( ERS_HERE, "user callback thrown unknown exception"));
1660 0 : }
1661 : }
1662 : else
1663 : {
1664 0 : std::vector<ConfigurationChange*> changes1;
1665 :
1666 0 : for (const auto &i : changes)
1667 : {
1668 0 : const std::string &cname = i->get_class_name();
1669 0 : ConfigurationChange *class_changes = nullptr;
1670 :
1671 0 : ConfigurationSubscriptionCriteria::ObjectMap::const_iterator p = j->m_criteria.get_objects_subscription().find(cname);
1672 0 : const bool found_obj_subscription(p != j->m_criteria.get_objects_subscription().end());
1673 0 : const bool found_class_subscription(j->m_criteria.get_classes_subscription().find(cname) != j->m_criteria.get_classes_subscription().end());
1674 :
1675 0 : if (found_class_subscription || found_obj_subscription)
1676 0 : class_changes = new ConfigurationChange(cname);
1677 :
1678 0 : if (found_class_subscription)
1679 : {
1680 0 : for (const auto &k : i->m_modified)
1681 0 : class_changes->m_modified.push_back(k);
1682 :
1683 0 : for (const auto &k : i->m_created)
1684 0 : class_changes->m_created.push_back(k);
1685 :
1686 0 : for (const auto &k : i->m_removed)
1687 0 : class_changes->m_removed.push_back(k);
1688 : }
1689 :
1690 0 : if (found_obj_subscription)
1691 : {
1692 0 : for (const auto &obj_id : i->m_modified)
1693 0 : if (p->second.find(obj_id) != p->second.end())
1694 0 : class_changes->m_modified.push_back(obj_id);
1695 :
1696 0 : for (const auto &obj_id : i->m_removed)
1697 0 : if (p->second.find(obj_id) != p->second.end())
1698 0 : class_changes->m_removed.push_back(obj_id);
1699 : }
1700 :
1701 : // the changes for given class can be empty if there is subscription on objects of given class, but no such objects were modified
1702 0 : if (class_changes)
1703 : {
1704 0 : if (class_changes->m_modified.empty() && class_changes->m_created.empty() && class_changes->m_removed.empty())
1705 0 : delete class_changes;
1706 : else
1707 0 : changes1.push_back(class_changes);
1708 : }
1709 : }
1710 :
1711 0 : if (!changes1.empty())
1712 : {
1713 0 : TLOG_DEBUG(3) << "*** Invoke callback " << (void *)j << " with\n" << changes1;
1714 :
1715 0 : try
1716 : {
1717 0 : (*(j->m_cb))(changes1, j->m_param);
1718 : }
1719 0 : catch (const ers::Issue &ex)
1720 : {
1721 0 : ers::error(dunedaq::conffwk::Generic( ERS_HERE, "user callback thrown ers exception", ex));
1722 0 : }
1723 0 : catch (const std::exception &ex)
1724 : {
1725 0 : ers::error(dunedaq::conffwk::Generic( ERS_HERE, "user callback thrown std exception", ex));
1726 0 : }
1727 0 : catch (...)
1728 : {
1729 0 : ers::error(dunedaq::conffwk::Generic( ERS_HERE, "user callback thrown unknown exception"));
1730 0 : }
1731 :
1732 0 : for (const auto &i : changes1)
1733 0 : delete i;
1734 : }
1735 0 : }
1736 : }
1737 : }
1738 :
1739 0 : TLOG_DEBUG(3) <<"*** Leave Configuration::system_cb()";
1740 0 : }
1741 :
1742 :
1743 : void
1744 0 : Configuration::system_pre_cb(Configuration * conf) noexcept
1745 : {
1746 0 : TLOG_DEBUG(3) <<"*** Enter Configuration::system_pre_cb()";
1747 :
1748 0 : std::lock_guard<std::mutex> scoped_lock(conf->m_else_mutex);
1749 :
1750 0 : for(auto& j : conf->m_pre_callbacks)
1751 : {
1752 0 : TLOG_DEBUG(3) << "*** Invoke callback " << (void *)(j);
1753 0 : (*(j->m_cb))(j->m_param);
1754 : }
1755 :
1756 0 : TLOG_DEBUG(3) <<"*** Leave Configuration::system_pre_cb()";
1757 0 : }
1758 :
1759 :
1760 : void
1761 0 : ConfigurationChange::add(std::vector<ConfigurationChange*> &changes, const std::string &class_name, const std::string &obj_name, const char action)
1762 : {
1763 0 : ConfigurationChange *class_changes = nullptr;
1764 :
1765 0 : for (const auto &c : changes)
1766 0 : if (class_name == c->get_class_name())
1767 : {
1768 0 : class_changes = c;
1769 0 : break;
1770 : }
1771 :
1772 0 : if (!class_changes)
1773 : {
1774 0 : class_changes = new ConfigurationChange(class_name);
1775 0 : changes.push_back(class_changes);
1776 : }
1777 :
1778 0 : std::vector<std::string>& clist = (
1779 0 : action == '+' ? class_changes->m_created :
1780 0 : action == '-' ? class_changes->m_removed :
1781 0 : class_changes->m_modified
1782 : );
1783 :
1784 0 : clist.push_back(obj_name);
1785 0 : }
1786 :
1787 :
1788 : void
1789 0 : ConfigurationChange::clear(std::vector<ConfigurationChange*> &changes)
1790 : {
1791 0 : for (const auto &i : changes)
1792 0 : delete i;
1793 :
1794 0 : changes.clear();
1795 0 : }
1796 :
1797 :
1798 : static void
1799 0 : print_svect(std::ostream& s, const std::vector<std::string>& v, const char * name)
1800 : {
1801 0 : s << " * " << v.size() << name;
1802 :
1803 0 : for (auto i = v.begin(); i != v.end(); ++i)
1804 : {
1805 0 : s << ((i == v.begin()) ? ": " : ", ");
1806 0 : s << '\"' << *i << '\"';
1807 : }
1808 :
1809 0 : s << std::endl;
1810 0 : }
1811 :
1812 :
1813 : std::ostream&
1814 0 : operator<<(std::ostream &s, const ConfigurationChange &c)
1815 : {
1816 0 : s << " changes for class \'" << c.get_class_name() << "\' include:\n";
1817 :
1818 0 : print_svect(s, c.get_modified_objs(), " modified object(s)");
1819 0 : print_svect(s, c.get_created_objs(), " created object(s)");
1820 0 : print_svect(s, c.get_removed_objs(), " removed object(s)");
1821 :
1822 0 : return s;
1823 : }
1824 :
1825 :
1826 : std::ostream&
1827 0 : operator<<(std::ostream &s, const std::vector<ConfigurationChange*> &v)
1828 : {
1829 0 : s << "There are configuration changes in " << v.size() << " classes:\n";
1830 :
1831 0 : for (const auto &i : v)
1832 0 : s << *i;
1833 :
1834 0 : return s;
1835 : }
1836 :
1837 : void
1838 0 : Configuration::print(std::ostream &s) const noexcept
1839 : {
1840 0 : s << "Configuration object:\n Inheritance Hierarchy (class - all it's superclasses):\n";
1841 :
1842 0 : for (const auto &i : p_superclasses)
1843 : {
1844 0 : s << " * \'" << *i.first << "\' - ";
1845 0 : if (i.second.empty())
1846 0 : s << "(null)";
1847 : else
1848 0 : for (auto j = i.second.begin(); j != i.second.end(); ++j)
1849 : {
1850 0 : if (j != i.second.begin())
1851 0 : s << ", ";
1852 0 : s << '\'' << **j << '\'';
1853 : }
1854 0 : s << std::endl;
1855 : }
1856 0 : }
1857 :
1858 :
1859 : bool
1860 0 : Configuration::try_cast(const std::string& target, const std::string& source) noexcept
1861 : {
1862 0 : return is_superclass_of(target, source);
1863 : }
1864 :
1865 : bool
1866 0 : Configuration::try_cast(const std::string *target, const std::string *source) noexcept
1867 : {
1868 0 : return is_superclass_of(target, source);
1869 : }
1870 :
1871 : bool
1872 1511 : Configuration::is_superclass_of(const std::string& base_class, const std::string& child_class) noexcept
1873 : {
1874 1511 : return is_superclass_of(&DalFactory::instance().get_known_class_name_ref(base_class), &DalFactory::instance().get_known_class_name_ref(child_class));
1875 : }
1876 :
1877 : bool
1878 1511 : Configuration::is_superclass_of(const std::string *base_class, const std::string *child_class) noexcept
1879 : {
1880 1511 : if (base_class == child_class)
1881 : {
1882 835 : TLOG_DEBUG(50) << "cast \'" << *child_class << "\' => \'" << *base_class << "\' is allowed (equal classes)";
1883 835 : return true;
1884 : }
1885 :
1886 676 : conffwk::fmap<conffwk::fset>::iterator i = p_superclasses.find(child_class);
1887 :
1888 676 : if (i == p_superclasses.end())
1889 : {
1890 0 : TLOG_DEBUG(50) << "cast \'" << *child_class << "\' => \'" << *base_class << "\' is not possible (base class is not loaded)";
1891 0 : return false;
1892 : }
1893 :
1894 676 : if (i->second.find(base_class) != i->second.end())
1895 : {
1896 338 : TLOG_DEBUG(50) << "cast \'" << *child_class << "\' => \'" << *base_class << "\' is allowed (use inheritance)";
1897 338 : return true;
1898 : }
1899 :
1900 338 : TLOG_DEBUG(50) << "cast \'" << *child_class << "\' => \'" << *base_class << "\' is not allowed (class \'" << *child_class << "\' has no \'" << *base_class << "\' as a superclass)";
1901 :
1902 338 : return false;
1903 : }
1904 :
1905 :
1906 : std::ostream&
1907 0 : operator<<(std::ostream &s, const Configuration &c)
1908 : {
1909 0 : c.print(s);
1910 0 : return s;
1911 : }
1912 :
1913 : // std::ostream&
1914 : // operator<<(std::ostream& s, const DalObject * obj)
1915 : // {
1916 : // if (obj == nullptr)
1917 : // DalObject::p_null(s);
1918 : // else if (obj->is_deleted())
1919 : // s << "(deleted object " << obj->UID() << '@' << obj->class_name() << ')';
1920 : // else
1921 : // s << '\'' << obj->UID() << '@' << obj->class_name() << '\'';
1922 :
1923 : // return s;
1924 : // }
1925 :
1926 : // std::ostream&
1927 : // operator<<(std::ostream& s, const DalObject * obj)
1928 : // {
1929 : // if (obj == nullptr)
1930 : // DalObject::p_null(s);
1931 : // else if (obj->is_deleted())
1932 : // s << "(deleted object " << obj->UID() << '@' << obj->class_name() << ')';
1933 : // else
1934 : // s << '\'' << obj->UID() << '@' << obj->class_name() << '\'';
1935 :
1936 : // return s;
1937 : // }
1938 :
1939 : std::string
1940 0 : Configuration::mk_ref_ex_text(const char * what, const std::string& cname, const std::string& rname, const ConfigObject& obj) noexcept
1941 : {
1942 0 : std::ostringstream text;
1943 0 : text << "failed to get " << what << " of class \'" << cname << "\' via relationship \'" << rname << "\' of object \'" << obj << '\'';
1944 0 : return text.str();
1945 0 : }
1946 :
1947 :
1948 : std::string
1949 0 : Configuration::mk_ref_by_ex_text(const std::string& cname, const std::string& rname, const ConfigObject& obj) noexcept
1950 : {
1951 0 : std::ostringstream text;
1952 0 : text << "failed to get objects of class \'" << cname << "\' referencing object \'" << obj << "\' via relationship \'" << rname << '\'';
1953 0 : return text.str();
1954 0 : }
1955 :
1956 : // std::vector<const DalObject*>
1957 : // Configuration::make_dal_objects(std::vector<ConfigObject>& objs, bool upcast_unregistered)
1958 : // {
1959 : // std::vector<const DalObject*> result;
1960 :
1961 : // for (auto &i : objs)
1962 : // // if (DalObject *o = DalFactory::instance().get(*this, i, i.UID(), upcast_unregistered)) // FIXME: 2018-11-09: pass right UID()
1963 : // if (DalObject *o = m_registry.get(i,upcast_unregistered)) // FIXME: 2018-11-09: pass right UID()
1964 : // result.push_back(o);
1965 :
1966 : // return result;
1967 : // }
1968 :
1969 : // const DalObject*
1970 : // Configuration::make_dal_object(ConfigObject& obj, const std::string& uid, const std::string& class_name)
1971 : // {
1972 : // return DalFactory::instance().get(*this, obj, uid, class_name);
1973 : // return m_registry.get(*this, obj, uid, class_name);
1974 : // }
1975 :
1976 :
1977 : std::vector<const DalObject*>
1978 0 : Configuration::referenced_by(const DalObject& obj, const std::string& relationship_name,
1979 : bool check_composite_only, bool upcast_unregistered,
1980 : bool /*init*/, unsigned long rlevel,
1981 : const std::vector<std::string> * rclasses)
1982 : {
1983 0 : try
1984 : {
1985 0 : std::vector<ConfigObject> objs;
1986 0 : std::lock_guard<std::mutex> scoped_lock(m_tmpl_mutex);
1987 :
1988 0 : obj.p_obj.referenced_by(objs, relationship_name, check_composite_only, rlevel, rclasses);
1989 : // return make_dal_objects(objs, upcast_unregistered);
1990 0 : return m_registry.get(objs, upcast_unregistered);
1991 0 : }
1992 0 : catch (dunedaq::conffwk::Generic & ex)
1993 : {
1994 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, mk_ref_by_ex_text("DalObject", relationship_name, obj.p_obj).c_str(), ex ) );
1995 0 : }
1996 : }
1997 :
1998 : std::unordered_map<std::string, std::unordered_map<std::string, std::string>>
1999 0 : Configuration::attributes_pybind(const std::string& class_name, bool all) {
2000 :
2001 0 : std::unordered_map<std::string, std::unordered_map<std::string, std::string>> all_attributes_properties;
2002 :
2003 0 : const dunedaq::conffwk::class_t& c = this->get_class_info(class_name, !all);
2004 :
2005 0 : for (const auto& ap : c.p_attributes) {
2006 0 : std::unordered_map<std::string, std::string> attribute_properties;
2007 0 : attribute_properties["type"] = dunedaq::conffwk::attribute_t::type(ap.p_type);
2008 :
2009 0 : attribute_properties["range"] = ap.p_range.empty() ? "None" : ap.p_range;
2010 :
2011 0 : attribute_properties["description"] = ap.p_description;
2012 :
2013 0 : attribute_properties["multivalue"] = ap.p_is_multi_value ? "True" : "False";
2014 :
2015 0 : attribute_properties["not-null"] = ap.p_is_not_null ? "True" : "False";
2016 :
2017 0 : attribute_properties["init-value"] = ap.p_default_value.empty() ? "None" : ap.p_default_value;
2018 :
2019 0 : all_attributes_properties[ap.p_name] = attribute_properties;
2020 0 : }
2021 :
2022 0 : return all_attributes_properties;
2023 0 : }
2024 :
2025 : std::vector<std::string>
2026 168 : Configuration::get_class_list() const {
2027 168 : std::vector<std::string> classes;
2028 11282 : for (const auto& it : this->superclasses()) {
2029 11114 : classes.push_back(*it.first);
2030 : }
2031 :
2032 168 : return classes;
2033 0 : }
2034 :
2035 : ConfigObject*
2036 0 : Configuration::create_and_return_obj_pybind(const std::string& at, const std::string& class_name, const std::string& id) {
2037 0 : auto co = new ConfigObject;
2038 0 : this->create(at, class_name, id, *co);
2039 0 : return co;
2040 : }
2041 :
2042 : ConfigObject*
2043 0 : Configuration::create_and_return_obj_pybind(const ConfigObject& at, const std::string& class_name, const std::string& id) \
2044 : {
2045 0 : auto co = new ConfigObject;
2046 0 : this->create(at, class_name, id, *co);
2047 0 : return co;
2048 : }
2049 :
2050 : ConfigObject*
2051 0 : Configuration::get_obj_pybind(const std::string& class_name, const std::string& id)
2052 : {
2053 0 : auto co = new ConfigObject;
2054 0 : this->get(class_name, id, *co);
2055 0 : if (co->is_null()) {
2056 0 : delete co;
2057 0 : co = nullptr;
2058 : }
2059 0 : return co;
2060 : }
2061 :
2062 : std::vector<ConfigObject>*
2063 0 : Configuration::get_objs_pybind(const std::string& class_name, const std::string& query) {
2064 0 : auto objs = new std::vector<ConfigObject>;
2065 0 : this->get(class_name, *objs, query);
2066 0 : return objs;
2067 : }
2068 :
2069 :
2070 : std::unordered_map<std::string, std::unordered_map<std::string, std::string>>
2071 0 : Configuration::relations_pybind(const std::string& class_name, bool all) {
2072 :
2073 0 : std::unordered_map<std::string, std::unordered_map<std::string, std::string>> all_relationships_properties;
2074 :
2075 0 : const dunedaq::conffwk::class_t& c = this->get_class_info(class_name, !all);
2076 :
2077 0 : for (const auto& rp : c.p_relationships) {
2078 0 : std::unordered_map<std::string, std::string> relationship_properties;
2079 :
2080 0 : relationship_properties["type"] = rp.p_type;
2081 0 : relationship_properties["description"] = rp.p_description;
2082 0 : relationship_properties["multivalue"] = (rp.p_cardinality == dunedaq::conffwk::zero_or_many || rp.p_cardinality == dunedaq::conffwk::one_or_many) ? "True" : "False";
2083 0 : relationship_properties["aggregation"] = rp.p_is_aggregation ? "True" : "False";
2084 0 : relationship_properties["not-null"] = (rp.p_cardinality == dunedaq::conffwk::only_one || rp.p_cardinality == dunedaq::conffwk::one_or_many) ? "True" : "False";
2085 :
2086 0 : all_relationships_properties[rp.p_name] = relationship_properties;
2087 0 : }
2088 :
2089 0 : return all_relationships_properties;
2090 0 : }
2091 :
2092 : std::list<std::string>*
2093 0 : Configuration::return_includes_pybind(const std::string& db_name) {
2094 0 : auto l = new std::list<std::string>;
2095 0 : this->get_includes(db_name, *l);
2096 0 : return l;
2097 : }
2098 :
2099 : std::vector<std::string>
2100 0 : Configuration::subclasses_pybind(const std::string& class_name, bool all) {
2101 :
2102 0 : const dunedaq::conffwk::class_t& c = this->get_class_info(class_name, !all);
2103 0 : return c.p_subclasses;
2104 : }
2105 :
2106 : std::vector<std::string>
2107 0 : Configuration::superclasses_pybind(const std::string& class_name, bool all) {
2108 :
2109 0 : const dunedaq::conffwk::class_t& c = this->get_class_info(class_name, !all);
2110 0 : return c.p_superclasses;
2111 : }
2112 :
2113 : const std::string&
2114 0 : Configuration::get_schema_path_pybind(const std::string& class_name) {
2115 0 : const dunedaq::conffwk::class_t& c = this->get_class_info(class_name, false);
2116 0 : return c.p_schema_path;
2117 : }
2118 : } // namespace conffwk
2119 : } // namespace dunedaq
|