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