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: 2025-12-21 13:07:08 Functions: 19.6 % 143 28

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

Generated by: LCOV version 2.0-1