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