LCOV - code coverage report
Current view: top level - oksconflibs/src - OksConfiguration.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 27.2 % 712 194
Test Date: 2025-12-21 13:07:08 Functions: 38.9 % 72 28

            Line data    Source code
       1              : #include <stdlib.h>
       2              : #include <unistd.h>
       3              : #include <sys/stat.h>
       4              : #include <errno.h>
       5              : 
       6              : #include <algorithm>
       7              : #include <memory>
       8              : 
       9              : #include "ers/ers.hpp"
      10              : 
      11              : #include "oks/file.hpp"
      12              : #include "oks/kernel.hpp"
      13              : #include "oks/object.hpp"
      14              : #include "oks/query.hpp"
      15              : #include "oks/relationship.hpp"
      16              : #include "oksutils/oks/access.hpp"
      17              : 
      18              : #include "conffwk/Configuration.hpp"
      19              : #include "conffwk/ConfigObject.hpp"
      20              : #include "conffwk/Change.hpp"
      21              : #include "conffwk/Schema.hpp"
      22              : 
      23              : #include "oksconflibs/OksConfiguration.hpp"
      24              : #include "oksconflibs/OksConfigObject.hpp"
      25              : 
      26              : namespace dunedaq{
      27           16 :   ERS_DECLARE_ISSUE( oksconflibs, Exception, , )
      28              : }
      29              : using namespace dunedaq;
      30              : using namespace dunedaq::oks;
      31              : using namespace dunedaq::oksconflibs;
      32              :   // to be used as plug-in
      33              : 
      34           80 : extern "C" conffwk::ConfigurationImpl * _oksconflibs_creator_ (const std::string& spec) {
      35           80 :   try {
      36           80 :     std::unique_ptr<OksConfiguration> impl(new OksConfiguration());
      37           80 :     if(!spec.empty()) { impl->open_db(spec); }
      38          160 :     return impl.release();
      39           80 :   }
      40            0 :   catch(dunedaq::conffwk::Exception & ex) {
      41            0 :     throw dunedaq::conffwk::Generic(ERS_HERE, "oksconflibs initialization error", ex);
      42            0 :   }
      43            0 :   catch(...) {
      44            0 :     throw dunedaq::conffwk::Generic(ERS_HERE, "oksconflibs initialization error:\n***** caught unknown exception *****");
      45            0 :   }
      46              : }
      47              : 
      48              : 
      49              : struct dunedaq::oksconflibs::OksConfigurationCheckDB {
      50              : 
      51              :   OksConfiguration * m_db;
      52              :   bool m_run;
      53              : 
      54            3 :   OksConfigurationCheckDB(OksConfiguration * db) : m_db(db), m_run(true) { ; }
      55              : 
      56            3 :   ~OksConfigurationCheckDB() {
      57            3 :     TLOG_DEBUG( 3 ) <<  "Call destructor of OksConfigurationCheckDB object"  ;
      58            3 :     m_db = nullptr;
      59            3 :   }
      60              : 
      61              :   void
      62            3 :   operator()()
      63              :   {
      64            3 :     TLOG_DEBUG(2) <<  "Call user notification" ;
      65              : 
      66            6 :     while (m_run)
      67              :       {
      68            3 :         sleep(1);
      69            3 :         try
      70              :           {
      71            3 :             m_db->check_db();
      72              :           }
      73            0 :         catch (dunedaq::conffwk::Generic& ex)
      74              :           {
      75            0 :             m_db->m_check_db_thread = nullptr;
      76            0 :             m_db->m_check_db_obj = nullptr;
      77              : 
      78            0 :             if (getenv("OKSCONFLIBS_NO_RELOAD_ABORT") != nullptr)
      79              :               {
      80            0 :                 ers::fatal(dunedaq::conffwk::Generic( ERS_HERE, "database reload has failed, unsubscribing...", ex ) );
      81            0 :                 return;
      82              :               }
      83              :             else
      84              :               {
      85            0 :                 ers::fatal ( dunedaq::conffwk::Generic( ERS_HERE, "database reload has failed, aborting...", ex ) );
      86            0 :                 abort();
      87              :               }
      88            0 :           }
      89              :       }
      90              : 
      91            3 :     TLOG_DEBUG( 4 ) <<  "Destroy OksConfigurationCheckDB object = " << (void *)this  ;
      92              : 
      93            3 :     delete this;
      94              : 
      95            3 :     TLOG_DEBUG( 2 ) <<  "Exit user notification"  ;
      96              :   }
      97              : 
      98              : };
      99              : 
     100              : 
     101              : bool
     102           80 : is_repo_name(const std::string& name)
     103              : {
     104           80 :   if (!OksKernel::get_repository_root().empty())
     105              :     {
     106            0 :       std::string s(name);
     107              : 
     108            0 :       Oks::substitute_variables(s);
     109              : 
     110            0 :       bool is_absolute_path = (s[0] == '/');
     111              : 
     112            0 :       if (!is_absolute_path)
     113            0 :         s = std::string(OksKernel::get_cwd()) + '/' + s;
     114              : 
     115              :       // if file system path exists
     116            0 :       if (Oks::real_path(s, true))
     117              :         {
     118            0 :           if (!OksKernel::get_repository_mapping_dir().empty() && s.find(OksKernel::get_repository_mapping_dir()) == 0)
     119              :             return true;
     120              : 
     121            0 :           static std::string user_repo_dir;
     122            0 :           static std::once_flag flag;
     123              : 
     124            0 :           std::call_once(flag, []()
     125              :             {
     126            0 :               if (const char * s = getenv("TDAQ_DB_USER_REPOSITORY"))
     127              :                 {
     128            0 :                   user_repo_dir = s;
     129              : 
     130            0 :                   try
     131              :                     {
     132            0 :                       Oks::real_path(user_repo_dir, false);
     133              :                     }
     134            0 :                   catch(oks::exception& ex)
     135              :                     {
     136            0 :                       TLOG_DEBUG( 0) <<  "Failed to read TDAQ_DB_USER_REPOSITORY = \'" << s << "\':\n\tcaused by: " << ex.what()  ;
     137            0 :                     }
     138              :                 }
     139            0 :             }
     140              :           );
     141              : 
     142            0 :           if (!user_repo_dir.empty() && s.find(user_repo_dir) == 0)
     143              :             return true;
     144              : 
     145              :           return false;
     146              :         }
     147              :       else
     148              :         return true;
     149            0 :     }
     150              : 
     151              :   return false;
     152              : }
     153              : 
     154              : void
     155           76 : OksConfiguration::open_db(const std::string& spec_params)
     156              : {
     157              :     // separate parameters first
     158              : 
     159           76 :   std::string::size_type idx = spec_params.find_first_of('&');
     160              : 
     161           76 :   std::string data, params;
     162              : 
     163           76 :   if (idx == std::string::npos)
     164              :     {
     165           76 :       data = spec_params;
     166              :     }
     167              :   else
     168              :     {
     169            0 :       data = spec_params.substr(0, idx);
     170            0 :       params = spec_params.substr(idx + 1);
     171              :     }
     172              : 
     173           76 :   std::string token;
     174              : 
     175              :   // guess about oks kernel mode based on the file names
     176              : 
     177           76 :     {
     178           76 :       Oks::Tokenizer t(data, ":");
     179              : 
     180          152 :       while (!(token = t.next()).empty())
     181              :         {
     182           76 :           if (is_repo_name(token) == false)
     183           76 :             m_oks_kernel_no_repo = true;
     184              :         }
     185           76 :     }
     186              : 
     187              :     // create OKS kernel if it was not created
     188              : 
     189           76 :   if (m_kernel == nullptr)
     190              :     {
     191           76 :       if (!params.empty())
     192              :         {
     193            0 :           Oks::Tokenizer t(params, ";");
     194              : 
     195            0 :           while (!(token = t.next()).empty())
     196              :             {
     197            0 :               if(token == "norepo")
     198            0 :                 m_oks_kernel_no_repo = true;
     199              :             }
     200            0 :         }
     201              : 
     202           76 :       m_kernel = new OksKernel(m_oks_kernel_silence, false, false, !m_oks_kernel_no_repo);
     203              :     }
     204              : 
     205           76 :   Oks::Tokenizer t(data, ":");
     206              : 
     207          152 :   while(!(token = t.next()).empty()) {
     208           76 :     try {
     209           76 :       m_kernel->load_file(token);
     210              :     }
     211            0 :     catch (oks::exception & e) {
     212            0 :       std::ostringstream text;
     213            0 :       text << "cannot load file \'" << token << "\':\n" << e.what();
     214            0 :       close_db();
     215            0 :       throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     216            0 :     }
     217            0 :     catch (...) {
     218            0 :       std::ostringstream text;
     219            0 :       text << "cannot load file \'" << token << '\'';
     220            0 :       close_db();
     221            0 :       throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     222            0 :     }
     223              :   }
     224           76 : }
     225              : 
     226              : void
     227          160 : OksConfiguration::close_database(bool call_unsubscribe)
     228              : {
     229          160 :   clean(); // clean implementation cache
     230              : 
     231          160 :   if(m_kernel) try {
     232           80 :     if(m_check_db_obj) {
     233            0 :       if(call_unsubscribe)
     234            0 :         unsubscribe();
     235              :       else
     236            0 :         m_check_db_obj->m_run = false;
     237              :     }
     238              : 
     239           80 :     m_kernel->subscribe_create_object(0, 0);
     240           80 :     m_kernel->subscribe_change_object(0, 0);
     241           80 :     m_kernel->subscribe_delete_object(0, 0);
     242              : 
     243           80 :     m_kernel->close_all_data();
     244           80 :     m_kernel->close_all_schema();
     245              : 
     246           80 :     delete m_kernel;
     247           80 :     m_kernel = 0;
     248              :   }
     249            0 :   catch(oksconflibs::Exception& ex) {
     250            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, "failed to close database", ex ) );
     251            0 :   }
     252            0 :   catch(std::exception& ex) {
     253            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, "failed to close database", ex ) );
     254            0 :   }
     255          160 : }
     256              : 
     257              : 
     258              : void
     259            4 : OksConfiguration::create(const std::string& db_name, const std::list<std::string>& includes)
     260              : {
     261              :     // create OKS kernel if it was not created
     262              : 
     263            4 :   if (m_kernel == nullptr)
     264              :     {
     265            4 :       if (is_repo_name(db_name) == false)
     266            4 :         m_oks_kernel_no_repo = true;
     267              : 
     268            4 :       m_kernel = new OksKernel(m_oks_kernel_silence, false, false, !m_oks_kernel_no_repo);
     269              :     }
     270              : 
     271              : 
     272              :     // create new data file
     273              : 
     274            4 :   try {
     275            4 :     OksFile * h = m_kernel->new_data(db_name);
     276            4 :     m_created_files.insert(h);
     277              : 
     278              :       // add includes
     279              : 
     280           12 :     for(std::list<std::string>::const_iterator i = includes.begin(); i != includes.end(); ++i) {
     281            8 :       try {
     282            8 :         h->add_include_file(*i);
     283              :       }
     284            0 :       catch (oks::exception & e) {
     285            0 :         std::ostringstream text;
     286            0 :         text << "cannot add and load include file \'" << *i << "\' to \'" << db_name << "\':\n" << e.what();
     287            0 :         close_db();
     288            0 :         throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     289            0 :       }
     290            0 :       catch (...) {
     291            0 :         std::ostringstream text;
     292            0 :         text << "cannot add and load include file \'" << *i << "\' to \'" << db_name << '\'';
     293            0 :         close_db();
     294            0 :         throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     295            0 :       }
     296              :     }
     297              : 
     298            4 :     m_kernel->bind_objects();
     299              :   }
     300            0 :   catch (oks::exception & ex) {
     301            0 :     close_db();
     302            0 :     std::ostringstream text;
     303            0 :     text << "cannot create new data file \'" << db_name << "\': " << ex.what();
     304            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     305            0 :   }
     306            0 :   catch (dunedaq::conffwk::Generic & ex) {
     307            0 :     close_db();
     308            0 :     std::ostringstream text;
     309            0 :     text << "cannot create new data file \'" << db_name << "\'";
     310            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex ) );
     311            0 :   }
     312            0 :   catch (...) {
     313            0 :     close_db();
     314            0 :     std::ostringstream text;
     315            0 :     text << "cannot create new data file \'" << db_name << '\'';
     316            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     317            0 :   }
     318            4 : }
     319              : 
     320              : static std::string
     321            0 : mk_no_file_error_text(const std::string &db)
     322              : {
     323            0 :   std::ostringstream text;
     324            0 :   text << "cannot find file \'" << db << '\'';
     325            0 :   return text.str();
     326            0 : }
     327              : 
     328              : static std::string
     329            0 : mk_add_include_error_text(const std::string &db, const std::string &include, const char *error = nullptr)
     330              : {
     331            0 :   std::ostringstream text;
     332            0 :   text << "cannot add and load include file \'" << include << "\' to \'" << db << '\'';
     333            0 :   if (error)
     334            0 :       text << ":\n" << error;
     335            0 :   return text.str();
     336            0 : }
     337              : 
     338              : 
     339              : void
     340            0 : OksConfiguration::get_updated_dbs(std::list<std::string>& dbs) const
     341              : {
     342            0 :   for (const auto& i : m_kernel->data_files())
     343              :     {
     344            0 :       if (i.second->is_updated())
     345            0 :         dbs.push_back(i.second->get_full_file_name());
     346              :     }
     347            0 : }
     348              : 
     349              : 
     350              : void
     351            0 : OksConfiguration::set_commit_credentials(const std::string& user, const std::string& password)
     352              : {
     353            0 :   m_user = user;
     354            0 :   m_password = password;
     355            0 : }
     356              : 
     357            0 : static void throw_update_exception(const OksFile * file_h, const char * action, const char * reason)
     358              : {
     359            0 :   std::ostringstream text;
     360            0 :   text << "cannot " << action << " file \'" << file_h->get_full_file_name() << "\' since " << reason;
     361            0 :   throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() );
     362            0 : }
     363              : 
     364              : void
     365            0 : OksConfiguration::commit(const std::string& log_message)
     366              : {
     367            0 :   try
     368              :     {
     369            0 :       m_kernel->set_active_data(nullptr);
     370              :     }
     371            0 :   catch (oks::exception &ex)
     372              :     {
     373            0 :       throw(dunedaq::conffwk::Generic( ERS_HERE, ex.what()));
     374            0 :     }
     375              : 
     376            0 :   const bool commit2repo(!m_kernel->get_user_repository_root().empty() && m_kernel->is_user_repository_created());
     377            0 :   unsigned int count(0);
     378              : 
     379            0 :   for (const auto &i : m_kernel->data_files())
     380              :     {
     381            0 :       OksFile *file_h = i.second;
     382              : 
     383            0 :       if (file_h->is_updated())
     384              :         {
     385            0 :           const OksFile::FileStatus file_status = file_h->get_status_of_file();
     386              : 
     387            0 :           if (file_status == OksFile::FileModified)
     388            0 :             throw_update_exception(file_h, "save", "it was externally modified");
     389            0 :           else if (file_status == OksFile::FileRemoved)
     390            0 :             throw_update_exception(file_h, "save", "it was externally removed");
     391              : 
     392            0 :           try
     393              :             {
     394            0 :               if (!commit2repo && !log_message.empty())
     395            0 :                 file_h->add_comment(log_message, m_kernel->get_user_name());
     396              : 
     397            0 :               m_kernel->save_data(file_h);
     398              : 
     399            0 :               count++;
     400              :             }
     401            0 :           catch (oks::exception &ex)
     402              :             {
     403            0 :               std::ostringstream text;
     404            0 :               text << "cannot save updated data file \'" << *(i.first) << "\':\n" << ex.what();
     405            0 :               throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str()));
     406            0 :             }
     407              :         }
     408              :     }
     409              : 
     410            0 :   if (commit2repo && count)
     411              :     {
     412            0 :       try
     413              :         {
     414            0 :           m_kernel->commit_repository(log_message);
     415              :         }
     416            0 :       catch (oks::exception &ex)
     417              :         {
     418            0 :           throw(dunedaq::conffwk::Generic( ERS_HERE, ex.what()));
     419            0 :         }
     420              :     }
     421              : 
     422            0 :   m_created_files.clear();
     423            0 : }
     424              : 
     425              : namespace dunedaq{
     426              :   namespace oksconflibs{
     427              : class ResubscribeGuard {
     428              : 
     429              :   public:
     430              : 
     431            0 :     ResubscribeGuard(OksConfiguration & db) : m_db(db) {
     432            0 :       if(m_db.m_check_db_obj) {
     433            0 :         m_db.unsubscribe();
     434            0 :         m_restart = true;
     435              :       }
     436              :       else {
     437            0 :         m_restart = false;
     438              :       }
     439              : 
     440            0 :       m_db.m_created.clear();
     441            0 :       m_db.m_modified.clear();
     442            0 :       m_db.m_removed.clear();
     443            0 :     }
     444              : 
     445            0 :     ~ResubscribeGuard() {
     446            0 :       if(m_restart) {
     447            0 :         m_db.subscribe();
     448              :       }
     449            0 :     }
     450              : 
     451              :   private:
     452              : 
     453              :    OksConfiguration& m_db;
     454              :    bool m_restart;
     455              : 
     456              : };
     457              : 
     458              : void
     459            0 : OksConfiguration::abort()
     460              : {
     461              :     // unsubscribe changes; if there are any, re-subscribe on return from this method
     462              : 
     463            0 :   ResubscribeGuard __rg__(*this);
     464              : 
     465              : 
     466              :     // destroy any newly created files
     467            0 :   for (const auto& i : m_created_files)
     468              :     {
     469            0 :       const std::string file_name(i->get_full_file_name());
     470              : 
     471            0 :       TLOG_DEBUG(1) <<  "destroy created file \'" << file_name << "\')" ;
     472            0 :       m_kernel->close_data(i);
     473              : 
     474            0 :       if (int result = unlink(file_name.c_str()))
     475              :         {
     476            0 :           std::ostringstream text;
     477            0 :           text << "abort changes failed since cannot erase created file \'" << file_name << "\'; unlink failed with code " << result << ": " << dunedaq::oks::strerror(errno);
     478            0 :           throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     479            0 :         }
     480            0 :     }
     481              : 
     482            0 :   m_created_files.clear();
     483              : 
     484              : 
     485              : 
     486              :   // add to "updated" any modified file
     487            0 :   std::set<OksFile *> updated;
     488              : 
     489            0 :   for (const auto& i : m_kernel->data_files())
     490              :     {
     491            0 :       if (i.second->is_updated())
     492              :         {
     493            0 :           updated.insert(i.second);
     494            0 :           TLOG_DEBUG(2) <<  "file \'" << i.second->get_full_file_name() << "\' was updated, to be reloaded..." ;
     495              :         }
     496              :     }
     497              : 
     498            0 :   if (!m_kernel->get_user_repository_root().empty())
     499              :     {
     500            0 :       std::set<OksFile *> mfs, rfs;
     501            0 :       try
     502              :         {
     503            0 :           m_kernel->get_modified_files(mfs, rfs, "origin/master");
     504              :         }
     505            0 :       catch (const oks::exception& ex)
     506              :         {
     507            0 :           std::ostringstream text;
     508            0 :           text << "failed to get differences between revisions " << m_kernel->get_repository_version() << " and origin/master: " << ex.what() << '\n';
     509            0 :           throw(dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex));
     510            0 :         }
     511            0 :     }
     512              : 
     513            0 :   if (!updated.empty())
     514              :     {
     515            0 :       try
     516              :         {
     517            0 :           if (!m_kernel->get_user_repository_root().empty())
     518            0 :             m_kernel->update_repository("origin/master", OksKernel::RepositoryUpdateType::DiscardChanges);
     519              : 
     520            0 :           m_kernel->reload_data(updated);
     521              :         }
     522            0 :       catch (oks::exception & ex)
     523              :         {
     524            0 :           throw(dunedaq::conffwk::Generic(ERS_HERE, "cannot reload updated data files", ex));
     525            0 :         }
     526            0 :       catch (...)
     527              :         {
     528            0 :           throw(dunedaq::conffwk::Generic(ERS_HERE, "cannot reload updated data files"));
     529            0 :         }
     530              :     }
     531            0 : }
     532              : 
     533              : 
     534              : static std::vector<dunedaq::conffwk::Version>
     535            0 : oks2config(const std::vector<OksRepositoryVersion>& in)
     536              : {
     537            0 :   std::vector<dunedaq::conffwk::Version> out;
     538            0 :   out.reserve(in.size());
     539              : 
     540            0 :   for (auto& x : in)
     541            0 :     out.emplace_back(x.m_commit_hash, x.m_user, x.m_date, x.m_comment, x.m_files);
     542              : 
     543            0 :   return out;
     544            0 : }
     545              : 
     546              : std::vector<dunedaq::conffwk::Version>
     547            0 : OksConfiguration::get_changes()
     548              : {
     549            0 :   if (!m_kernel->get_repository_root().empty())
     550              :     {
     551            0 :       try
     552              :         {
     553            0 :           return oks2config(m_kernel->get_repository_versions_by_hash(true, m_kernel->get_repository_version()));
     554              :         }
     555            0 :       catch (const oks::exception& ex)
     556              :         {
     557            0 :           throw(dunedaq::conffwk::Generic(ERS_HERE, "cannot get new versions", ex));
     558            0 :         }
     559              :     }
     560              :   else
     561              :     {
     562            0 :       std::vector<dunedaq::conffwk::Version> out;
     563              : 
     564            0 :       std::set<OksFile *> oks_files;
     565            0 :       m_kernel->get_modified_files(oks_files, oks_files, "");
     566              : 
     567            0 :       if (!oks_files.empty())
     568              :         {
     569            0 :           std::vector<std::string> files;
     570              : 
     571            0 :           for(const auto& x : oks_files)
     572            0 :           files.push_back(x->get_well_formed_name());
     573              : 
     574            0 :           out.emplace_back("", "", 0, "", files);
     575            0 :         }
     576              : 
     577            0 :       return out;
     578            0 :     }
     579              : }
     580              : 
     581              : 
     582              : std::vector<dunedaq::conffwk::Version>
     583            0 : OksConfiguration::get_versions(const std::string& since, const std::string& until, dunedaq::conffwk::Version::QueryType type, bool skip_irrelevant)
     584              : {
     585            0 :   if (!m_kernel->get_repository_root().empty())
     586              :     {
     587            0 :       try
     588              :         {
     589            0 :           return oks2config(type == dunedaq::conffwk::Version::query_by_date ? m_kernel->get_repository_versions_by_date(skip_irrelevant, since, until) : m_kernel->get_repository_versions_by_hash(skip_irrelevant, since, until));
     590              :         }
     591            0 :       catch (const oks::exception& ex)
     592              :         {
     593            0 :           throw(dunedaq::conffwk::Generic(ERS_HERE, "cannot get repository versions", ex));
     594            0 :         }
     595              :     }
     596              :   else
     597              :     {
     598            0 :       throw(dunedaq::conffwk::Generic(ERS_HERE, "cannot get versions, repository is not set"));
     599              :     }
     600              : }
     601              : 
     602              : }}
     603              : 
     604              : dunedaq::oksconflibs::OksConfigObject *
     605         1286 : dunedaq::oksconflibs::OksConfiguration::new_object(oks::OksObject * obj) noexcept
     606              : {
     607         1286 :   return insert_object<dunedaq::oksconflibs::OksConfigObject>(obj, obj->GetId(), obj->GetClass()->get_name());
     608              : }
     609              : 
     610              : bool
     611            0 : OksConfiguration::test_object(const std::string& class_name, const std::string& name, unsigned long /*rlevel*/, const std::vector<std::string> * /*rclasses*/)
     612              : {
     613              :   // Looking for the class. If it does not exist, we return false.
     614            0 :   OksClass * cl = m_kernel->find_class(class_name);
     615            0 :   if (!cl)
     616              :     return false;
     617              : 
     618              :   // The object exist for this class?
     619            0 :   if (cl->get_object(name))
     620              :     return true;
     621              : 
     622              :   // Trying all subclasses
     623            0 :   if (const OksClass::FList * subclasses = cl->all_sub_classes())
     624              :     {
     625            0 :       for (OksClass::FList::const_iterator it = subclasses->begin(); it != subclasses->end(); ++it)
     626              :         {
     627            0 :           if ((*it)->get_object(name))
     628            0 :             return true;
     629              :         }
     630              :     }
     631              :   // If we get here, we found the class, but not the object.
     632              :   return false;
     633              : }
     634              : 
     635              : void
     636          110 : dunedaq::oksconflibs::OksConfiguration::get(const std::string &class_name, const std::string &name,
     637              :                                           dunedaq::conffwk::ConfigObject &object, unsigned long /*rlevel*/, const std::vector<std::string>* /* rclasses */)
     638              : {
     639          110 :   if (OksClass * cl = m_kernel->find_class(class_name))
     640              :     {
     641          110 :       OksObject * obj = cl->get_object(name);
     642          110 :       if (obj == nullptr)
     643              :         {
     644              :           // try all subclasses
     645            2 :           if (const OksClass::FList *subclasses = cl->all_sub_classes())
     646              :             {
     647            2 :               for (const auto& it : *subclasses)
     648              :                 {
     649            0 :                   obj = it->get_object(name);
     650            0 :                   if (obj != nullptr)
     651              :                     break;
     652              :                 }
     653              :             }
     654            2 :           if (obj == nullptr)
     655              :             {
     656            2 :               const std::string id(name + '@' + class_name);
     657            2 :               throw dunedaq::conffwk::NotFound(ERS_HERE, "object", id.c_str());
     658            2 :             }
     659              :         }
     660              : 
     661          108 :       object = new_object(obj);
     662              :     }
     663              :   else
     664              :     {
     665            0 :       throw dunedaq::conffwk::NotFound(ERS_HERE, "class", class_name.c_str());
     666              :     }
     667          108 : }
     668              : 
     669              : void
     670           45 : OksConfiguration::get(const std::string& class_name, std::vector<conffwk::ConfigObject>& objects, const std::string& query, unsigned long /*rlevel*/, const std::vector<std::string> * /* rclasses */)
     671              : {
     672           45 :   if(OksClass * cl = m_kernel->find_class(class_name)) {
     673           45 :     objects.clear();
     674              : 
     675           45 :     OksObject::List * objs = 0;
     676              : 
     677           45 :     if(query.empty()) {
     678           45 :       objs = cl->create_list_of_all_objects();
     679              :     }
     680              :     else {
     681            0 :       try {
     682            0 :         std::unique_ptr<OksQuery> qe(new OksQuery(cl, query.c_str()));
     683            0 :         if(qe->good() == false) {
     684            0 :           std::ostringstream text;
     685            0 :           text << "bad query syntax \"" << query << "\" in scope of class \"" << class_name << '\"';
     686            0 :           throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str());
     687            0 :         }
     688            0 :         objs = cl->execute_query(qe.get());  // FIXME: check .get()
     689            0 :       }
     690            0 :       catch(oks::exception& ex) {
     691            0 :         std::ostringstream text;
     692            0 :         text << "failed to execute query:\n" << ex.what();
     693            0 :         throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str());
     694            0 :       }
     695              :     }
     696              : 
     697           45 :     if(objs) {
     698          217 :       for(OksObject::List::iterator i = objs->begin(); i != objs->end(); ++i) {
     699          172 :         objects.push_back(new_object(*i));
     700              :       }
     701           45 :       delete objs;
     702              :     }
     703              :   }
     704              :   else {
     705            0 :     throw dunedaq::conffwk::NotFound(ERS_HERE, "class", class_name.c_str());
     706              :   }
     707           45 : }
     708              : 
     709              : void
     710            0 : OksConfiguration::get(const conffwk::ConfigObject& obj_from, const std::string& query, std::vector<conffwk::ConfigObject>& objects, unsigned long /*rlevel*/, const std::vector<std::string> * /* rclasses */)
     711              : {
     712            0 :   if(obj_from.is_null()) {
     713            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, "parameter \'obj_from\' is (null)" ) );
     714              :   }
     715              : 
     716            0 :   OksObject * o = (static_cast<const OksConfigObject *>(obj_from.implementation()))->m_obj;
     717              : 
     718            0 :   try {
     719            0 :     oks::QueryPath q(query, *m_kernel);
     720            0 :     if(OksObject::List * objs = o->find_path(q)) {
     721            0 :       for(OksObject::List::iterator i = objs->begin(); i != objs->end(); ++i) {
     722            0 :         objects.push_back(new_object(*i));
     723              :       }
     724            0 :       delete objs;
     725              :     }
     726            0 :   }
     727            0 :   catch ( oks::bad_query_syntax& e ) {
     728            0 :     std::ostringstream text;
     729            0 :     text << "bad path-query \"" << query << "\" to object " << o;
     730            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     731            0 :   }
     732            0 : }
     733              : 
     734              : 
     735              : dunedaq::conffwk::class_t *
     736         5560 : OksConfiguration::get(const std::string& class_name, bool direct_only)
     737              : {
     738         5560 :   OksClass * c = m_kernel->find_class(class_name);
     739              : 
     740         5560 :   if(c == 0) {
     741            2 :     throw dunedaq::conffwk::NotFound(ERS_HERE, "class", class_name.c_str());
     742              :   }
     743              : 
     744         5558 :   dunedaq::conffwk::class_t * d = new dunedaq::conffwk::class_t(c->get_name(), c->get_description(), c->get_file()->get_full_file_name(), c->get_is_abstract());
     745              : 
     746         5558 :   if(direct_only) {
     747            1 :     if(const std::list<std::string *> * classes = c->direct_super_classes()) {
     748            2 :       for(const auto& i : *classes) {
     749            1 :         const_cast< std::vector<std::string>& >(d->p_superclasses).push_back(*i);
     750              :       }
     751              :     }
     752              :   }
     753              :   else {
     754         5557 :     if(const OksClass::FList * classes = c->all_super_classes()) {
     755        10979 :       for(const auto& i : *classes) {
     756         5422 :         const_cast< std::vector<std::string>& >(d->p_superclasses).push_back(i->get_name());
     757              :       }
     758              :     }
     759              :   }
     760              : 
     761         5558 :   if(const OksClass::FList * subclasses = c->all_sub_classes()) {
     762        10980 :     for(const auto& i : *subclasses) {
     763         5422 :       if(direct_only == false || i->has_direct_super_class(c->get_name()) == true) {
     764         5422 :         const_cast< std::vector<std::string>& >(d->p_subclasses).push_back(i->get_name());
     765              :       }
     766              :     }
     767              :   }
     768              : 
     769         5558 :   if(const std::list<OksAttribute *> * attrs = (direct_only ? c->direct_attributes() : c->all_attributes())) {
     770        20491 :     for(const auto& i : *attrs) {
     771        14933 :       OksAttribute::Format format = i->get_format();
     772        14933 :       OksData::Type type = i->get_data_type();
     773              : 
     774        14933 :       const_cast< std::vector<dunedaq::conffwk::attribute_t>& >(d->p_attributes).push_back(
     775        49706 :         dunedaq::conffwk::attribute_t(
     776              :           i->get_name(),
     777              :           (
     778              :             type == OksData::string_type  ? dunedaq::conffwk::string_type :
     779              :             type == OksData::enum_type    ? dunedaq::conffwk::enum_type   :
     780              :             type == OksData::bool_type    ? dunedaq::conffwk::bool_type   :
     781              :             type == OksData::s8_int_type  ? dunedaq::conffwk::s8_type     :
     782              :             type == OksData::u8_int_type  ? dunedaq::conffwk::u8_type     :
     783              :             type == OksData::s16_int_type ? dunedaq::conffwk::s16_type    :
     784              :             type == OksData::u16_int_type ? dunedaq::conffwk::u16_type    :
     785              :             type == OksData::s32_int_type ? dunedaq::conffwk::s32_type    :
     786              :             type == OksData::u32_int_type ? dunedaq::conffwk::u32_type    :
     787              :             type == OksData::s64_int_type ? dunedaq::conffwk::s64_type    :
     788              :             type == OksData::u64_int_type ? dunedaq::conffwk::u64_type    :
     789              :             type == OksData::float_type   ? dunedaq::conffwk::float_type  :
     790              :             type == OksData::double_type  ? dunedaq::conffwk::double_type :
     791              :             type == OksData::date_type    ? dunedaq::conffwk::date_type   :
     792              :             type == OksData::time_type    ? dunedaq::conffwk::time_type   :
     793              :             dunedaq::conffwk::class_type
     794              :           ),
     795              :           i->get_range(),
     796              :           (
     797        14933 :             i->is_integer() == false ? dunedaq::conffwk::na_int_format :
     798              :               (
     799         4907 :                 format == OksAttribute::Dec ? dunedaq::conffwk::dec_int_format :
     800           45 :                 format == OksAttribute::Hex ? dunedaq::conffwk::hex_int_format :
     801              :                 dunedaq::conffwk::oct_int_format
     802              :               )
     803              :           ),
     804        14933 :           i->get_is_no_null(),
     805        14933 :           i->get_is_multi_values(),
     806              :           i->get_init_value(),
     807              :           i->get_description()
     808              :         )
     809              :       );
     810              : 
     811              :     }
     812              :   }
     813              : 
     814         5558 :   if(const std::list<OksRelationship *> * rels = (direct_only ? c->direct_relationships() : c->all_relationships())) {
     815        15555 :     for(const auto& i : *rels) {
     816         9998 :       const_cast< std::vector<dunedaq::conffwk::relationship_t>& >(d->p_relationships).push_back(
     817         9998 :         dunedaq::conffwk::relationship_t(
     818              :           i->get_name(),
     819              :           i->get_type(),
     820         9998 :           (i->get_low_cardinality_constraint() == OksRelationship::Zero),
     821         9998 :           (i->get_high_cardinality_constraint() == OksRelationship::Many),
     822         9998 :           i->get_is_composite(),
     823              :           i->get_description()
     824              :         )
     825              :       );
     826              :     }
     827              :   }
     828              : 
     829         5558 :   return d;
     830              : }
     831              : 
     832              : void
     833           84 : OksConfiguration::get_superclasses(conffwk::fmap<conffwk::fset>& schema)
     834              : {
     835           84 :   schema.clear();
     836              : 
     837           84 :   if(!m_kernel) {
     838              :     return; // throw ( dunedaq::conffwk::Generic( ERS_HERE, "database is not loaded" ) );
     839              :   }
     840              : 
     841           80 :   schema.reserve(m_kernel->classes().size() * 3);
     842              : 
     843         5637 :   for(OksClass::Map::const_iterator i = m_kernel->classes().begin(); i != m_kernel->classes().end(); ++i) {
     844         5557 :     if(const OksClass::FList * scl = i->second->all_super_classes()) {
     845         5557 :       const std::string* name = &conffwk::DalFactory::instance().get_known_class_name_ref(i->second->get_name());
     846              : 
     847         5557 :       auto& subclasses = schema[name];
     848              : 
     849         5557 :       if(!scl->empty()) {
     850         3014 :         subclasses.reserve(scl->size() * 3);
     851         8436 :         for(OksClass::FList::const_iterator j = scl->begin(); j != scl->end(); ++j) {
     852         5422 :           subclasses.insert(&conffwk::DalFactory::instance().get_known_class_name_ref((*j)->get_name()));
     853              :         }
     854              :       }
     855              :     }
     856              :   }
     857              : }
     858              : 
     859              : 
     860              : void
     861           23 : OksConfiguration::create(OksFile * at, const std::string& class_name, const std::string& id, conffwk::ConfigObject& object)
     862              : {
     863           23 :   try {
     864           23 :     m_kernel->set_active_data(at);
     865              :   }
     866            0 :   catch(oks::exception& ex) {
     867            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, ex.what()) );
     868            0 :   }
     869              : 
     870           23 :   OksClass * c = m_kernel->find_class(class_name);
     871              : 
     872           23 :   if(c == nullptr) {
     873            0 :     std::ostringstream text;
     874            0 :     text << "cannot find class \"" << class_name << '\"';
     875            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     876            0 :   }
     877           23 :   else if(id.empty() == false) {
     878           23 :     if(OksObject * obj = c->get_object(id)) {
     879            0 :       std::ostringstream text;
     880            0 :       text << "object \"" << id << '@' << class_name << "\" already exists in file \"" << obj->get_file()->get_full_file_name() << '\"';
     881            0 :       throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     882            0 :     }
     883              :   }
     884              : 
     885           23 :   if(m_kernel->get_test_duplicated_objects_via_inheritance_mode() == false)
     886              :     {
     887            4 :       m_kernel->set_test_duplicated_objects_via_inheritance_mode(true);
     888            4 :       m_kernel->registrate_all_classes();
     889              :     }
     890              : 
     891           23 :   try {
     892           23 :     object = new_object(new OksObject(c, id.c_str()));
     893              :   }
     894            0 :   catch(oks::exception& ex)
     895              :   {
     896            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, "cannot create configuration object", ex ) );
     897            0 :   }
     898           23 : }
     899              : 
     900              : void
     901           23 : OksConfiguration::create(const std::string& at, const std::string& class_name, const std::string& id, conffwk::ConfigObject& object)
     902              : {
     903           23 :   if(at.empty() == true) {
     904            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, "parameter \'at\' (i.e. filename) cannot be empty" ) );
     905              :   }
     906              : 
     907           23 :   if(OksFile * h = m_kernel->find_data_file(at)) {
     908           23 :     return create(h, class_name, id, object);
     909              :   }
     910              :   else {
     911            0 :     std::ostringstream text;
     912            0 :     text << "file \"" << at << "\" is not loaded";
     913            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
     914            0 :   }
     915              : }
     916              : 
     917              : void
     918            0 : OksConfiguration::create(const conffwk::ConfigObject& at, const std::string& class_name, const std::string& id, conffwk::ConfigObject& object)
     919              : {
     920            0 :   create((static_cast<const OksConfigObject *>(at.implementation()))->m_obj->get_file(), class_name, id, object);
     921            0 : }
     922              : 
     923              : void
     924            0 : OksConfiguration::create_notify(OksObject * o, void * p) noexcept
     925              : {
     926            0 :   reinterpret_cast<OksConfiguration *>(p)->m_created.push_back(o);
     927            0 : }
     928              : 
     929              : void
     930            0 : OksConfiguration::change_notify(OksObject * o, void * p) noexcept
     931              : {
     932            0 :   reinterpret_cast<OksConfiguration *>(p)->m_modified.insert(o);
     933            0 : }
     934              : 
     935              : void
     936            0 : OksConfiguration::delete_notify(OksObject * o, void * p) noexcept
     937              : {
     938            0 :   reinterpret_cast<OksConfiguration *>(p)->m_removed[o->GetClass()->get_name()].insert(o->GetId());
     939            0 : }
     940              : 
     941              : 
     942              : struct InheritanceData {
     943              : 
     944              :   InheritanceData(const OksKernel&);
     945              : 
     946            0 :   const OksConfiguration::SMap& data() const { return m_data; }
     947              : 
     948              :   OksConfiguration::SMap m_data;
     949              : 
     950              : };
     951              : 
     952            0 : InheritanceData::InheritanceData(const OksKernel &kernel)
     953              : {
     954            0 :   for (OksClass::Map::const_iterator i = kernel.classes().begin(); i != kernel.classes().end(); ++i)
     955            0 :     if (const OksClass::FList *slist = i->second->all_super_classes())
     956              :       {
     957            0 :         std::set<std::string> &data(m_data[i->second->get_name()]);
     958            0 :         for (const auto &j : *slist)
     959            0 :           data.insert(j->get_name());
     960              :       }
     961            0 : }
     962              : 
     963              : 
     964              :   /**
     965              :    *  The function checks if the object satisfies the subscription
     966              :    *  and adds to changes.
     967              :    *  The actions could be:
     968              :    *   '+' - created
     969              :    *   '~' - changed
     970              :    *   '-' - deleted
     971              :    */
     972              : 
     973              : static void
     974            0 : check(std::vector<conffwk::ConfigurationChange *>& changes,
     975              :       const InheritanceData & inheritance,
     976              :       const std::set<std::string>& class_names,
     977              :       const OksConfiguration::SMap & objects,
     978              :       const std::string& obj_class,
     979              :       const std::string& obj_id,
     980              :       const char action
     981              : ) {
     982              : 
     983            0 :   bool any = (class_names.empty() && objects.empty());
     984              : 
     985              : 
     986              :     // check subscription on objects
     987              :     // 
     988              :     // omi iterator in non-null, if on an object of class 'obj_class'
     989              :     // there is explicit subscription
     990              : 
     991            0 :   OksConfiguration::SMap::const_iterator omi = objects.end();
     992              : 
     993            0 :   if(action != '+') {
     994            0 :     omi = objects.find(obj_class);
     995            0 :     if(omi != objects.end()) {
     996            0 :       std::set<std::string>::const_iterator i = omi->second.find(obj_id);
     997              : 
     998            0 :       if(i != omi->second.end()) {
     999            0 :         conffwk::ConfigurationChange::add(changes, obj_class, obj_id, action);
    1000              :       }
    1001              :     }
    1002              :   }
    1003              : 
    1004              : 
    1005              :     // process the class
    1006              : 
    1007            0 :   if(action == '+' || omi == objects.end()) {
    1008            0 :     if(any || class_names.find(obj_class) != class_names.end()) {
    1009            0 :       conffwk::ConfigurationChange::add(changes, obj_class, obj_id, action);
    1010              :     }
    1011              :   }
    1012              : 
    1013              : 
    1014              :     // process subclasses
    1015              : 
    1016            0 :   OksConfiguration::SMap::const_iterator it = inheritance.data().find(obj_class);
    1017            0 :   if(it != inheritance.data().end()) {
    1018            0 :     for(std::set<std::string>::const_iterator j = it->second.begin(); j != it->second.end(); ++j) {
    1019            0 :       omi = (action != '+' ? objects.find(*j) : objects.end());
    1020              : 
    1021              :         // 1. add objects if criteria is 'any'
    1022              :         // 2. add object of class which has subscription and has no explicit object subscription
    1023              :         // 3. add explicitly subscribed object
    1024              : 
    1025            0 :       if(
    1026            0 :         any ||
    1027              :         (
    1028            0 :           omi == objects.end() &&
    1029            0 :           class_names.find(*j) != class_names.end()
    1030            0 :         ) ||
    1031              :         (
    1032            0 :           omi != objects.end() &&
    1033            0 :           omi->second.find(obj_id) != omi->second.end()
    1034              :         )
    1035              :       ) {
    1036            0 :         conffwk::ConfigurationChange::add(changes, *j, obj_id, action);
    1037              :       }
    1038              :     }
    1039              :   }
    1040            0 : }
    1041              : 
    1042              : 
    1043              : class DestroyGuard1 {
    1044              : 
    1045              :   public:
    1046              : 
    1047            0 :     DestroyGuard1(OksKernel & kernel) : m_kernel(kernel) { ; }
    1048              : 
    1049            0 :     ~DestroyGuard1() {
    1050            0 :       m_kernel.subscribe_delete_object(0, 0);
    1051            0 :     }
    1052              : 
    1053              :   private:
    1054              : 
    1055              :     OksKernel& m_kernel;
    1056              : 
    1057              : };
    1058              : 
    1059              : class DestroyGuard2 {
    1060              : 
    1061              :   public:
    1062              : 
    1063            0 :     DestroyGuard2(OksConfiguration::SMap& removed) : m_removed(removed) { ; }
    1064              : 
    1065            0 :     ~DestroyGuard2() {
    1066            0 :       m_removed.clear();
    1067            0 :     }
    1068              : 
    1069              :   private:
    1070              : 
    1071              :     OksConfiguration::SMap& m_removed;
    1072              : 
    1073              : };
    1074              : 
    1075              : 
    1076              : void
    1077            0 : OksConfiguration::destroy(conffwk::ConfigObject& obj)
    1078              : {
    1079            0 :   OksObject * o((static_cast<const OksConfigObject *>(obj.implementation()))->m_obj);
    1080              : 
    1081            0 :   DestroyGuard2 dg2(m_removed);  // => on exit from method, call m_removed.clear();
    1082              : 
    1083            0 :   InheritanceData inheritance(*m_kernel);
    1084              : 
    1085            0 :   try {
    1086            0 :     m_kernel->subscribe_delete_object(delete_notify, reinterpret_cast<void *>(this));
    1087            0 :     DestroyGuard1 dg1(*m_kernel); // => on exit from try block, call m_kernel->subscribe_delete_object(0, 0);
    1088            0 :     OksObject::destroy(o);
    1089            0 :   }
    1090            0 :   catch(oks::exception& ex) {
    1091            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, ex.what()) );
    1092            0 :   }
    1093              : 
    1094            0 :   if(m_conf) {
    1095            0 :     std::vector<conffwk::ConfigurationChange *> changes;
    1096              : 
    1097            0 :     for(SMap::iterator i = m_removed.begin(); i != m_removed.end(); ++i) {
    1098            0 :       for(std::set<std::string>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
    1099            0 :         check(changes, inheritance, m_class_names, m_objects, i->first, *j, '-');
    1100              :       }
    1101              :     }
    1102              : 
    1103            0 :     if(!changes.empty()) {
    1104            0 :       m_conf->update_cache(changes);
    1105            0 :       conffwk::ConfigurationChange::clear(changes);
    1106              :     }
    1107            0 :   }
    1108            0 : }
    1109              : 
    1110              : bool
    1111            0 : OksConfiguration::is_writable(const std::string& db_name)
    1112              : {
    1113            0 :   if (OksFile * h = m_kernel->find_data_file(db_name))
    1114              :     {
    1115            0 :       try
    1116              :         {
    1117            0 :           if (!m_kernel->get_user_repository_root().empty())
    1118              :             {
    1119            0 :               return oksutils::access::is_writable(*h, OksKernel::get_user_name());
    1120              :             }
    1121              :           else
    1122              :             {
    1123            0 :               return !OksKernel::check_read_only(h);
    1124              :             }
    1125              :         }
    1126            0 :       catch (const std::exception& ex)
    1127              :         {
    1128            0 :           std::ostringstream text;
    1129            0 :           text << "cannot check access status of file \'" << db_name << "\': " << ex.what();
    1130            0 :           throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
    1131            0 :         }
    1132              :     }
    1133              :   else
    1134              :     {
    1135            0 :       throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_no_file_error_text(db_name).c_str() ) );
    1136              :     }
    1137              : }
    1138              : 
    1139              : static std::string
    1140            0 : mk_rm_include_error_text(const std::string &db, const std::string &include, const char *error = 0)
    1141              : {
    1142            0 :   std::ostringstream text;
    1143            0 :   text << "cannot remove include file \'" << include << "\' from \'" << db << '\'';
    1144            0 :   if (error)
    1145            0 :     text << ":\n" << error;
    1146            0 :   return text.str();
    1147            0 : }
    1148              : 
    1149              : void
    1150            0 : OksConfiguration::add_include(const std::string& db_name, const std::string& include)
    1151              : {
    1152            0 :   if(OksFile * h = m_kernel->find_data_file(db_name)) {
    1153            0 :     try {
    1154            0 :       h->add_include_file(include);
    1155              :     }
    1156            0 :     catch(dunedaq::conffwk::Generic& ex) {
    1157            0 :       throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_add_include_error_text(db_name, include).c_str() ), ex );
    1158            0 :     }
    1159            0 :     catch (oks::exception & ex) {
    1160            0 :       throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_add_include_error_text(db_name, include, ex.what()).c_str() ) );
    1161            0 :     }
    1162            0 :     catch (...) {
    1163            0 :       throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_add_include_error_text(db_name, include).c_str() ) );
    1164            0 :     }
    1165              :   }
    1166              :   else {
    1167            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_no_file_error_text(db_name).c_str() ) );
    1168              :   }
    1169            0 : }
    1170              : 
    1171              : void
    1172            0 : OksConfiguration::remove_include(const std::string& db_name, const std::string& include)
    1173              : {
    1174            0 :   InheritanceData inheritance(*m_kernel);
    1175              : 
    1176            0 :   DestroyGuard2 dg2(m_removed);  // => on exit from method, call m_removed.clear();
    1177              : 
    1178            0 :   if(OksFile * h = m_kernel->find_data_file(db_name)) {
    1179            0 :     try {
    1180            0 :       m_kernel->subscribe_delete_object(delete_notify, reinterpret_cast<void *>(this));
    1181            0 :       DestroyGuard1 dg1(*m_kernel); // => on exit from try block, call m_kernel->subscribe_delete_object(0, 0);
    1182            0 :       h->remove_include_file(include);
    1183            0 :     }
    1184            0 :     catch(dunedaq::conffwk::Generic& ex) {
    1185            0 :       throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_rm_include_error_text(db_name, include).c_str() ), ex );
    1186            0 :     }
    1187            0 :     catch (oks::exception & ex) {
    1188            0 :       throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_rm_include_error_text(db_name, include, ex.what()).c_str() ) );
    1189            0 :     }
    1190            0 :     catch (...) {
    1191            0 :       throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_rm_include_error_text(db_name, include).c_str() ) );
    1192            0 :     }
    1193              :   }
    1194              :   else {
    1195            0 :     throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_no_file_error_text(db_name).c_str() ) );
    1196              :   }
    1197              : 
    1198            0 :   std::vector<conffwk::ConfigurationChange *> changes;
    1199              : 
    1200            0 :   for(SMap::iterator i = m_removed.begin(); i != m_removed.end(); ++i) {
    1201            0 :     for(std::set<std::string>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
    1202            0 :       check(changes, inheritance, m_class_names, m_objects, i->first, *j, '-');
    1203              :     }
    1204              :   }
    1205              : 
    1206            0 :   if(!changes.empty()) {
    1207            0 :     m_conf->update_cache(changes);
    1208            0 :     conffwk::ConfigurationChange::clear(changes);
    1209              :   }
    1210            0 : }
    1211              : 
    1212              : 
    1213              : void
    1214            0 : OksConfiguration::get_includes(const std::string& db_name, std::list<std::string>& includes) const
    1215              : {
    1216            0 :   if (db_name.empty())
    1217              :     {
    1218            0 :       for (auto& i : m_kernel->data_files())
    1219              :         {
    1220            0 :           if(i.second->get_parent() == nullptr)
    1221            0 :             includes.push_back(*i.first);
    1222              :         }
    1223              :     }
    1224              :   else
    1225              :     {
    1226            0 :       if (OksFile * h = m_kernel->find_data_file(db_name))
    1227              :         {
    1228            0 :           for (auto& i : h->get_include_files())
    1229              :             {
    1230            0 :               includes.push_back(i);
    1231              :             }
    1232              :         }
    1233              :       else
    1234              :         {
    1235            0 :           throw(dunedaq::conffwk::Generic( ERS_HERE, mk_no_file_error_text(db_name).c_str() ) );
    1236              :         }
    1237              :     }
    1238            0 : }
    1239              : 
    1240              : 
    1241              : void
    1242            3 : OksConfiguration::check_db()
    1243              : {
    1244            3 :   static const std::string version("origin/master");
    1245              : 
    1246            3 :   if (m_fn)
    1247              :     {
    1248            3 :       std::set<OksFile *> ufs, rfs;
    1249              : 
    1250            3 :       try
    1251              :         {
    1252            3 :           m_kernel->get_modified_files(ufs, rfs, version);
    1253            3 :           m_repo_error_count = 0;
    1254              :         }
    1255            0 :       catch(const oks::RepositoryOperationFailed& ex)
    1256              :         {
    1257            0 :           std::ostringstream text;
    1258            0 :           text << "cannot get modified repository files (attempt " << ++m_repo_error_count << "): " << ex.what();
    1259            0 :           ers::error(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
    1260            0 :         }
    1261            0 :       catch(const oks::exception& ex)
    1262              :         {
    1263            0 :           std::ostringstream text;
    1264            0 :           text << "cannot get modified files: " << ex.what();
    1265            0 :           throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
    1266            0 :         }
    1267              : 
    1268            3 :       for (const auto& x : ufs)
    1269              :         {
    1270            0 :           if (x->get_oks_format() == "schema")
    1271              :             {
    1272            0 :               std::ostringstream text;
    1273            0 :               text << "reload of schema files is not supported (\'" << x->get_well_formed_name() << "\')";
    1274            0 :               throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
    1275            0 :             }
    1276              :         }
    1277              : 
    1278            3 :       if (ufs.empty() == false)
    1279              :         {
    1280            0 :           InheritanceData inheritance(*m_kernel);
    1281              : 
    1282            0 :           m_kernel->subscribe_create_object(create_notify, reinterpret_cast<void *>(this));
    1283            0 :           m_kernel->subscribe_change_object(change_notify, reinterpret_cast<void *>(this));
    1284            0 :           m_kernel->subscribe_delete_object(delete_notify, reinterpret_cast<void *>(this));
    1285              : 
    1286            0 :           (*m_pre_fn)(m_conf);
    1287              : 
    1288            0 :           try
    1289              :             {
    1290            0 :               if(!m_kernel->get_user_repository_root().empty())
    1291            0 :                 m_kernel->update_repository(version, OksKernel::RepositoryUpdateType::DiscardChanges);
    1292              : 
    1293            0 :               m_kernel->reload_data(ufs, false);
    1294              :             }
    1295            0 :           catch (oks::exception & ex)
    1296              :             {
    1297            0 :               close_database(false);
    1298            0 :               m_fn = 0;
    1299            0 :               std::ostringstream text;
    1300            0 :               text << "failed to reload updated files:\n" << ex.what();
    1301            0 :               throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
    1302            0 :             }
    1303            0 :           catch (...)
    1304              :             {
    1305            0 :               close_database(false);
    1306            0 :               m_fn = 0;
    1307            0 :               throw ( dunedaq::conffwk::Generic( ERS_HERE, "failed to reload updated files" ) );
    1308            0 :             }
    1309              : 
    1310              : 
    1311            0 :           m_kernel->subscribe_create_object(0, 0);
    1312            0 :           m_kernel->subscribe_change_object(0, 0);
    1313            0 :           m_kernel->subscribe_delete_object(0, 0);
    1314              : 
    1315            0 :           std::vector<conffwk::ConfigurationChange *> changes;
    1316              : 
    1317            0 :             {
    1318            0 :               for (auto& i : m_created)
    1319              :                 {
    1320            0 :                   check(changes, inheritance, m_class_names, m_objects, i->GetClass()->get_name(), i->GetId(), '+');
    1321              : 
    1322            0 :                   std::set<OksObject *>::iterator j = m_modified.find(i);
    1323            0 :                   if (j != m_modified.end())
    1324              :                     {
    1325            0 :                       TLOG_DEBUG(1) <<  "created object " << i << " appears in \'modified\' set, removing..." ;
    1326            0 :                       m_modified.erase(j);
    1327              :                     }
    1328              :                 }
    1329              :             }
    1330              : 
    1331            0 :             {
    1332            0 :               for (auto& i : m_modified)
    1333              :                 {
    1334            0 :                   if (m_kernel->is_dangling(i))
    1335              :                     {
    1336            0 :                       TLOG_DEBUG(1) <<  "object " << (void *)(i) << " is dangling, ignore..." ;
    1337              :                     }
    1338              :                   else
    1339              :                     {
    1340            0 :                       check(changes, inheritance, m_class_names, m_objects, i->GetClass()->get_name(), i->GetId(), '~');
    1341              :                     }
    1342              :                 }
    1343              :             }
    1344              : 
    1345            0 :             {
    1346            0 :               for (auto& i : m_removed)
    1347              :                 {
    1348            0 :                   for (auto& j : i.second)
    1349              :                     {
    1350            0 :                       check(changes, inheritance, m_class_names, m_objects, i.first, j, '-');
    1351              :                     }
    1352              :                 }
    1353              :             }
    1354              : 
    1355            0 :           if (!changes.empty())
    1356              :             {
    1357            0 :               (*m_fn)(changes, m_conf);
    1358            0 :               conffwk::ConfigurationChange::clear(changes);
    1359              :             }
    1360              : 
    1361            0 :           m_created.clear();
    1362            0 :           m_modified.clear();
    1363            0 :           m_removed.clear();
    1364            0 :         }
    1365            3 :     }
    1366              :   else
    1367              :     {
    1368            0 :       throw(dunedaq::conffwk::Generic( ERS_HERE, "no subscription has been done" ) );
    1369              :     }
    1370            3 : }
    1371              : 
    1372              : 
    1373              :   //
    1374              :   // Subscribe on changes by class name
    1375              :   //
    1376              : 
    1377              : void
    1378            3 : OksConfiguration::subscribe(const std::set<std::string>& class_names,
    1379              :                             const SMap& objs,
    1380              :                             ConfigurationImpl::notify cb,
    1381              :                             ConfigurationImpl::pre_notify pre_cb)
    1382              : {
    1383            3 :   m_fn = cb;
    1384            3 :   m_pre_fn = pre_cb;
    1385            3 :   m_class_names = class_names;
    1386            3 :   m_objects = objs;
    1387              : 
    1388            3 :   subscribe();
    1389            3 : }
    1390              : 
    1391              :   // Start subscription thread
    1392              : 
    1393              : void
    1394            3 : OksConfiguration::subscribe()
    1395              : {
    1396            3 :   if(m_check_db_obj == 0) {
    1397            3 :     TLOG_DEBUG( 2) <<  "starting CheckDB thread ..."  ;
    1398            3 :     m_check_db_obj = new OksConfigurationCheckDB(this);
    1399            3 :     m_check_db_thread = new std::thread(std::ref(*m_check_db_obj));
    1400              :   }
    1401            3 : }
    1402              : 
    1403              : 
    1404              :   //
    1405              :   // Unsubscribe
    1406              :   //
    1407              : 
    1408              : void
    1409           80 : OksConfiguration::unsubscribe()
    1410              : {
    1411           80 :   if(m_check_db_obj) {
    1412            3 :     TLOG_DEBUG( 2) <<  "stopping CheckDB thread ..."  ;
    1413            3 :     m_check_db_obj->m_run = false;
    1414            3 :     m_check_db_thread->join(); // wait thread termination
    1415            3 :     delete m_check_db_thread;
    1416            3 :     m_check_db_thread = 0;
    1417            3 :     m_check_db_obj = 0;
    1418            3 :     TLOG_DEBUG( 2) <<  "the CheckDB thread has been terminated"  ;
    1419              :   }
    1420           80 : }
    1421              : 
    1422              : 
    1423              : void
    1424            0 : OksConfiguration::print_profiling_info() noexcept
    1425              : {
    1426            0 :   std::cout <<
    1427              :     "OksConfiguration profiler report:\n"
    1428            0 :     "  number of loaded schema files: " << (m_kernel ? m_kernel->schema_files().size() : 0) << "\n"
    1429            0 :     "  number of loaded data files: " << (m_kernel ? m_kernel->data_files().size() : 0) << "\n"
    1430            0 :     "  number of loaded classes: " << (m_kernel ? m_kernel->classes().size() : 0) << "\n"
    1431            0 :     "  number of loaded objects: " << (m_kernel ? m_kernel->objects().size() : 0) << std::endl;
    1432            0 : }
    1433              : 
    1434              : 
    1435              :   // read OksKernel parameters from environment (silence mode)
    1436              : 
    1437              : void
    1438           80 : OksConfiguration::init_env()
    1439              : {
    1440           80 :   m_oks_kernel_silence = (getenv("OKSCONFLIBS_NO_KERNEL_SILENCE") == nullptr);
    1441           80 : }
        

Generated by: LCOV version 2.0-1