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