LCOV - code coverage report
Current view: top level - conffwk/src - Configuration.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 20.6 % 1051 216
Test Date: 2026-10-11 15:05:20 Functions: 19.6 % 143 28

            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
        

Generated by: LCOV version 2.0-1