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

Generated by: LCOV version 2.0-1