LCOV - code coverage report
Current view: top level - oks/src - class.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 26.9 % 1138 306
Test Date: 2025-12-21 13:07:08 Functions: 36.9 % 84 31

            Line data    Source code
       1              : #define _OksBuildDll_
       2              : 
       3              : #include "oks/class.hpp"
       4              : #include "oks/xml.hpp"
       5              : #include "oks/relationship.hpp"
       6              : #include "oks/method.hpp"
       7              : #include "oks/kernel.hpp"
       8              : #include "oks/object.hpp"
       9              : #include "oks/index.hpp"
      10              : #include "oks/profiler.hpp"
      11              : #include "oks/cstring.hpp"
      12              : 
      13              : #include "ers/ers.hpp"
      14              : #include "logging/Logging.hpp"
      15              : 
      16              : #include <stdlib.h>
      17              : 
      18              : #include <string>
      19              : #include <algorithm>
      20              : #include <stdexcept>
      21              : 
      22              : namespace dunedaq {
      23              : namespace oks {
      24              : 
      25              : const char OksClass::class_xml_tag[]        = "class";
      26              : const char OksClass::name_xml_attr[]        = "name";
      27              : const char OksClass::description_xml_attr[] = "description";
      28              : const char OksClass::is_abstract_xml_attr[] = "is-abstract";
      29              : const char OksClass::superclass_xml_attr[]  = "superclass";
      30              : 
      31              : 
      32              : OksClass::NotifyFN       OksClass::create_notify_fn;
      33              : OksClass::ChangeNotifyFN OksClass::change_notify_fn;
      34              : OksClass::NotifyFN       OksClass::delete_notify_fn;
      35              : 
      36              :   std::string
      37            0 :   CannotFindSuperClass::fill(const OksClass& c, const std::string& name) noexcept
      38              :   {
      39            0 :     return std::string("cannot find superclass \'") + name + "\' of class \'" + c.get_name() + '\'';
      40              :   }
      41              : 
      42              :   std::string
      43            0 :   AttributeConversionFailed::fill(const OksAttribute& a, const OksObject * o, const std::string& reason) noexcept
      44              :   {
      45            0 :     std::ostringstream s;
      46            0 :     s << "failed to convert \'" << a.get_name() << "\" value of object " << o <<  " because:\n" + reason;
      47            0 :     return s.str();
      48            0 :   }
      49              : 
      50              :   std::string
      51            0 :   CannotRegisterClass::fill(const OksClass& c, const std::string& what, const std::string& reason) noexcept
      52              :   {
      53            0 :     return std::string("cannot register class \'") + c.get_name() + "\' " + what + "because:\n" + reason;
      54              :   }
      55              : 
      56              :   std::string
      57            0 :   CannotDestroyClass::fill(const OksClass& c, const std::string& reason) noexcept
      58              :   {
      59            0 :     return std::string("cannot destroy class \'") + c.get_name() + "\' because:\n" + reason;
      60              :   }
      61              : 
      62              :   std::string
      63            0 :   ObjectOperationFailed::fill(const OksClass& c, const std::string& oid, const char * op, const std::string& reason) noexcept
      64              :   {
      65            0 :     return std::string("cannot ") + op + " object \'" + oid + "\' in class \'" + c.get_name() + "\' because:\n" + reason;
      66              :   }
      67              : 
      68              :   std::string
      69            0 :   SetOperationFailed::fill(const char * op, const std::string& reason) noexcept
      70              :   {
      71            0 :     return std::string("method \'") + op + "()\' failed because:\n" + reason;
      72              :   }
      73              : 
      74              : 
      75            0 : OksClass::OksClass(const std::string& nm, OksKernel * k, bool t) :
      76            0 :   p_name                  (nm),
      77            0 :   p_super_classes         (0),
      78            0 :   p_attributes            (0),
      79            0 :   p_relationships         (0),
      80            0 :   p_methods               (0),
      81            0 :   p_abstract              (false),
      82            0 :   p_transient             (t),
      83            0 :   p_to_be_deleted         (false),
      84            0 :   p_all_super_classes     (0),
      85            0 :   p_all_sub_classes       (0),
      86            0 :   p_all_attributes        (0),
      87            0 :   p_all_relationships     (0),
      88            0 :   p_all_methods           (0),
      89            0 :   p_inheritance_hierarchy (0),
      90            0 :   p_kernel                (k),
      91            0 :   p_instance_size         (0),
      92            0 :   p_data_info             (0),
      93            0 :   p_objects               (0),
      94            0 :   p_indices               (0)
      95              : {
      96            0 :   OSK_PROFILING(OksProfiler::ClassConstructor, p_kernel)
      97              : 
      98            0 :   if(p_transient == false && p_kernel)
      99              :     {
     100            0 :       oks::validate_not_empty(p_name, "class name");
     101              : 
     102            0 :       std::unique_lock lock(p_kernel->p_kernel_mutex);
     103            0 :       p_kernel->k_add(this);
     104            0 :     }
     105            0 : }
     106              : 
     107              : 
     108            0 : OksClass::OksClass(const std::string& nm, const std::string& d, bool a, OksKernel * k, bool t) :
     109            0 :   p_name                  (nm),
     110            0 :   p_description           (d),
     111            0 :   p_super_classes         (0),
     112            0 :   p_attributes            (0),
     113            0 :   p_relationships         (0),
     114            0 :   p_methods               (0),
     115            0 :   p_abstract              (a),
     116            0 :   p_transient             (t),
     117            0 :   p_to_be_deleted         (false),
     118            0 :   p_all_super_classes     (0),
     119            0 :   p_all_sub_classes       (0),
     120            0 :   p_all_attributes        (0),
     121            0 :   p_all_relationships     (0),
     122            0 :   p_all_methods           (0),
     123            0 :   p_inheritance_hierarchy (0),
     124            0 :   p_kernel                (k),
     125            0 :   p_instance_size         (0),
     126            0 :   p_data_info             (0),
     127            0 :   p_objects               (0),
     128            0 :   p_indices               (0)
     129              : {
     130            0 :   OSK_PROFILING(OksProfiler::ClassConstructor, p_kernel)
     131              : 
     132            0 :   if(p_transient == false && p_kernel)
     133              :     {
     134            0 :       oks::validate_not_empty(p_name, "class name");
     135              : 
     136            0 :       std::unique_lock lock(p_kernel->p_kernel_mutex);
     137            0 :       p_kernel->k_add(this);
     138            0 :     }
     139            0 : }
     140              : 
     141              : 
     142            0 : OksClass::OksClass (OksKernel * kernel, const std::string& name, const std::string& description, bool is_abstract) :
     143            0 :   p_name                  (name),
     144            0 :   p_description           (description),
     145            0 :   p_super_classes         (0),
     146            0 :   p_attributes            (0),
     147            0 :   p_relationships         (0),
     148            0 :   p_methods               (0),
     149            0 :   p_abstract              (is_abstract),
     150            0 :   p_transient             (false),
     151            0 :   p_to_be_deleted         (false),
     152            0 :   p_all_super_classes     (0),
     153            0 :   p_all_sub_classes       (0),
     154            0 :   p_all_attributes        (0),
     155            0 :   p_all_relationships     (0),
     156            0 :   p_all_methods           (0),
     157            0 :   p_inheritance_hierarchy (0),
     158            0 :   p_file                  (kernel->p_active_schema),
     159            0 :   p_kernel                (kernel),
     160            0 :   p_instance_size         (0),
     161            0 :   p_data_info             (0),
     162            0 :   p_objects               (0),
     163            0 :   p_indices               (0)
     164              : {
     165            0 :   OSK_PROFILING(OksProfiler::ClassConstructor, p_kernel)
     166            0 :   p_kernel->p_classes[p_name.c_str()] = this;
     167            0 : }
     168              : 
     169              : 
     170              : void
     171            0 : OksClass::destroy(OksClass *c)
     172              : {
     173              :     // obtain write mutex, if non-transient class is registered in the oks kernel
     174              : 
     175            0 :   if(!c->p_transient && c->p_kernel) {
     176            0 :     std::unique_lock lock(c->p_kernel->p_kernel_mutex);
     177              : 
     178            0 :     try {
     179            0 :       c->p_file->lock();
     180            0 :       c->p_file->set_updated();
     181              :     }
     182            0 :     catch(oks::exception& ex) {
     183            0 :       throw oks::CannotDestroyClass(*c, ex);
     184            0 :     }
     185              : 
     186            0 :     delete c;
     187            0 :   }
     188              : 
     189              :     // destroy class without get write mutex
     190              : 
     191              :   else {
     192            0 :     delete c;
     193              :   }
     194            0 : }
     195              : 
     196              : template<class T>
     197              :   void
     198        22228 :   OksClass::destroy_list(T list)
     199              :   {
     200        22228 :     if (list)
     201              :       {
     202        29206 :         for (const auto &x : *list)
     203        18997 :           delete x;
     204              : 
     205        10209 :         delete list;
     206              :       }
     207        22228 :   }
     208              : 
     209              : template<class T>
     210              :   void
     211        11114 :   OksClass::destroy_map(T map)
     212              :   {
     213        11114 :     if (map)
     214              :       {
     215        30487 :         for (const auto &x : *map)
     216        24930 :           delete x.second;
     217              : 
     218         5557 :         delete map;
     219              :       }
     220        11114 :   }
     221              : 
     222         5557 : OksClass::~OksClass()
     223              : {
     224         5557 :   OSK_PROFILING(OksProfiler::ClassDestructor, p_kernel)
     225              : 
     226         5557 :     TLOG_DEBUG(2) << "destruct " << (p_transient ? "TRANSIENT" : "NORMAL") << " class \'" << get_name() << '\'' ;
     227              : 
     228              :   // ~OksIndex() removes 'SELF' from OksClass and deletes 'indices' when there is no an index in it
     229         5557 :   while (p_indices)
     230            0 :     delete (*(p_indices->begin())).second;
     231              : 
     232         5557 :   destroy_map(p_objects);
     233         5557 :   destroy_map(p_data_info);
     234              : 
     235         5557 :   if (!p_transient && p_kernel)
     236              :     {
     237         5557 :       p_kernel->k_remove(this);
     238              : 
     239         5557 :       if (p_all_super_classes)
     240        10979 :         for (const auto &c : *p_all_super_classes)
     241              :           {
     242         5422 :             if (p_kernel->is_dangling(c) || c->p_to_be_deleted)
     243         5422 :               continue;
     244              : 
     245            0 :             c->create_sub_classes();
     246              : 
     247            0 :             if (OksClass::change_notify_fn)
     248            0 :               (*OksClass::change_notify_fn)(c, ChangeSubClassesList, (const void*) &p_name);
     249              :           }
     250              : 
     251         5557 :       if (p_all_sub_classes)
     252        10979 :         for (const auto &c : *p_all_sub_classes)
     253              :           {
     254         5422 :             if (p_kernel->is_dangling(c) || c->p_to_be_deleted)
     255         5422 :               continue;
     256              : 
     257            0 :             try
     258              :               {
     259            0 :                 c->registrate_class_change(ChangeSuperClassesList, (const void*) &p_name, false);
     260              :               }
     261            0 :             catch (oks::exception &ex)
     262              :               {
     263            0 :                 std::cerr << "internal OKS error: registrate_class_change() failed during \'" << get_name() << "\' class destruction\ncaused by: " << ex.what() << std::endl;
     264            0 :               }
     265              :           }
     266              :     }
     267              : 
     268         5557 :   destroy_list(p_super_classes);
     269         5557 :   destroy_list(p_attributes);
     270         5557 :   destroy_list(p_relationships);
     271         5557 :   destroy_list(p_methods);
     272              : 
     273         5557 :   if (!p_transient)
     274              :     {
     275         5557 :       delete p_all_super_classes;
     276         5557 :       delete p_all_sub_classes;
     277         5557 :       delete p_all_attributes;
     278         5557 :       delete p_all_relationships;
     279         5557 :       delete p_all_methods;
     280         5557 :       delete p_inheritance_hierarchy;
     281              :     }
     282         5557 : }
     283              : 
     284              : 
     285              : void
     286            0 : OksClass::set_file(OksFile * f, bool update_owner)
     287              : {
     288            0 :   if(p_file != f) {
     289            0 :     try {
     290            0 :       if(update_owner) {
     291            0 :         p_file->lock();
     292            0 :         p_file->set_updated();
     293              :       }
     294              : 
     295            0 :       f->lock();
     296            0 :       f->set_updated();
     297              : 
     298            0 :       p_file = f;
     299              :     }
     300            0 :     catch(oks::exception& ex) {
     301            0 :       throw oks::CanNotSetFile(this, 0, *f, ex);
     302            0 :     }
     303              :   }
     304            0 : }
     305              : 
     306              : 
     307              : bool
     308            0 : OksClass::compare_without_methods(const OksClass & c) const noexcept
     309              : {
     310            0 :   if(this == &c) return true;
     311              : 
     312            0 :   if(
     313            0 :         (p_name != c.p_name) ||
     314            0 :         (p_description != c.p_description) ||
     315            0 :         (p_abstract != c.p_abstract)
     316              :   ) return false;
     317              :   
     318              :   
     319            0 :   int l1 = (p_attributes == 0) ? 0 : p_attributes->size();
     320            0 :   int l2 = (c.p_attributes == 0) ? 0 : c.p_attributes->size();
     321              :   
     322            0 :   if(l1 != l2) return false;
     323              : 
     324            0 :   if(l1 > 0) {
     325            0 :     std::list<OksAttribute *>::const_iterator i1 = p_attributes->begin();
     326            0 :     std::list<OksAttribute *>::const_iterator i2 = c.p_attributes->begin();
     327              :     
     328            0 :     for(;i1 != p_attributes->end();++i1, ++i2)
     329            0 :       if( !(*(*i1) == *(*i2)) ) return false;
     330              :   }
     331              : 
     332            0 :   l1 = (p_relationships == 0) ? 0 : p_relationships->size();
     333            0 :   l2 = (c.p_relationships == 0) ? 0 : c.p_relationships->size();
     334              :  
     335            0 :   if(l1 != l2) return false;
     336              :   
     337            0 :   if(l1 > 0) {
     338            0 :     std::list<OksRelationship *>::const_iterator i1 = p_relationships->begin();
     339            0 :     std::list<OksRelationship *>::const_iterator i2 = c.p_relationships->begin();
     340              :     
     341            0 :     for(;i1 != p_relationships->end();++i1, ++i2)
     342            0 :       if( !(*(*i1) == *(*i2)) ) return false;
     343              :   }
     344              :   
     345            0 :   l1 = (p_super_classes == 0) ? 0 : p_super_classes->size();
     346            0 :   l2 = (c.p_super_classes == 0) ? 0 : c.p_super_classes->size();
     347              :  
     348            0 :   if(l1 != l2) return false;
     349              : 
     350            0 :   if(l1 > 0) {
     351            0 :     std::list<std::string *>::const_iterator i1 = p_super_classes->begin();
     352            0 :     std::list<std::string *>::const_iterator i2 = c.p_super_classes->begin();
     353              :     
     354            0 :     for(;i1 != p_super_classes->end();++i1, ++i2)
     355            0 :       if( !(*(*i1) == *(*i2)) ) return false;
     356              :   }
     357              :   
     358              :   return true;
     359              : }
     360              : 
     361              : bool
     362            0 : OksClass::operator!=(const OksClass &c) const
     363              : {
     364            0 :   if(this == &c) return false;
     365              : 
     366            0 :   if(compare_without_methods(c) == false) return true;
     367              :   
     368            0 :   int l1 = (p_methods == 0) ? 0 : p_methods->size();
     369            0 :   int l2 = (c.p_methods == 0) ? 0 : c.p_methods->size();
     370              :   
     371            0 :   if(l1 != l2) return true;
     372              : 
     373            0 :   if(l1 > 0) {
     374            0 :     std::list<OksMethod *>::const_iterator i1 = p_methods->begin();
     375            0 :     std::list<OksMethod *>::const_iterator i2 = c.p_methods->begin();
     376              :     
     377            0 :     for(;i1 != p_methods->end();++i1, ++i2)
     378            0 :       if( !(*(*i1) == *(*i2)) ) return true;
     379              :   }
     380              : 
     381              :   return false;
     382              : }
     383              : 
     384              : 
     385              : std::ostream&
     386            0 : operator<<(std::ostream& s, const OksClass& c)
     387              : {
     388            0 :   OSK_PROFILING(OksProfiler::ClassOperatorOut, c.p_kernel)
     389              : 
     390            0 :   s     << "Class name: \"" << c.p_name << "\"\n"
     391            0 :            " has description: \"" << c.p_description << "\"\n"
     392            0 :         << (c.p_abstract == true ? " is abstract\n" : " is not abstract\n");
     393              : 
     394            0 :   if(c.p_super_classes) {
     395            0 :     s << "The class has superclasses:\n";
     396            0 :     for(std::list<std::string *>::const_iterator i = c.p_super_classes->begin(); i != c.p_super_classes->end(); ++i) {
     397            0 :       s << " - " << *(*i) << std::endl;
     398              :     }
     399              :   }
     400              :   else
     401            0 :     s << "The class has no superclasses\n";
     402              : 
     403              : 
     404            0 :   if(c.p_attributes) {
     405            0 :     s << "The attributes are:\n";
     406            0 :     for(std::list<OksAttribute *>::const_iterator i = c.p_attributes->begin(); i != c.p_attributes->end(); ++i) {
     407            0 :       s << *(*i);
     408              :     }
     409              :   }
     410              :   else
     411            0 :     s << "There are no attributes\n";
     412              : 
     413              : 
     414            0 :   if(c.p_relationships) {
     415            0 :     s << "The relationships are:\n";
     416            0 :     for(std::list<OksRelationship *>::const_iterator i = c.p_relationships->begin(); i != c.p_relationships->end(); ++i) {
     417            0 :       s << *(*i);
     418              :     }
     419              :  }
     420              :   else
     421            0 :     s << "There are no relationships\n";
     422              : 
     423              : 
     424            0 :   if(c.p_methods) {
     425            0 :     s << "The methods are:\n";
     426            0 :     for(std::list<OksMethod *>::const_iterator i = c.p_methods->begin(); i != c.p_methods->end(); ++i) {
     427            0 :       s << *(*i);
     428              :     }
     429              :   }
     430              :   else
     431            0 :     s << "There are no methods\n";
     432              : 
     433              : 
     434            0 :   if(c.p_objects) {
     435            0 :     OksObject::SMap sorted;
     436              : 
     437            0 :     s << "The objects are:\n";
     438              : 
     439            0 :     for(OksObject::Map::iterator i = c.p_objects->begin(); i != c.p_objects->end(); ++i) {
     440            0 :       sorted[i->first] = i->second;
     441              :     }
     442              : 
     443            0 :     for(OksObject::SMap::iterator i = sorted.begin(); i != sorted.end(); ++i) {
     444            0 :       s << *(i->second);
     445              :     }
     446            0 :   }
     447              :   else
     448            0 :     s << "There are no objects\n";
     449              : 
     450              : 
     451            0 :   s << "End of Class \"" << c.p_name << "\"\n";
     452              :   
     453            0 :   return s;
     454            0 : }
     455              : 
     456              : 
     457              : void
     458            0 : OksClass::save(OksXmlOutputStream& s) const
     459              : {
     460            0 :   try {
     461            0 :     s.put_raw(' ');
     462            0 :     s.put_start_tag(class_xml_tag, sizeof(class_xml_tag)-1);
     463            0 :     s.put_attribute(name_xml_attr, sizeof(name_xml_attr)-1, p_name.c_str());
     464              :   
     465              :     // store non-empty description only
     466            0 :     if (!p_description.empty())
     467            0 :       s.put_attribute(description_xml_attr, sizeof(description_xml_attr)-1, p_description.c_str());
     468              : 
     469              :     // store abstract attribute only when the class is abstract
     470            0 :     if (p_abstract)
     471            0 :       s.put_attribute(is_abstract_xml_attr, sizeof(is_abstract_xml_attr)-1, oks::xml::bool2str(p_abstract));
     472              : 
     473            0 :     s.put_raw('>');
     474            0 :     s.put_raw('\n');
     475              : 
     476            0 :     if (p_super_classes)
     477            0 :       for(const auto& i : *p_super_classes) {
     478            0 :         s.put_raw(' ');
     479            0 :         s.put_raw(' ');
     480            0 :         s.put_start_tag(superclass_xml_attr, sizeof(superclass_xml_attr)-1);
     481            0 :         s.put_attribute(name_xml_attr, sizeof(name_xml_attr)-1, i->c_str());
     482            0 :         s.put_end_tag();
     483              :       }
     484              : 
     485            0 :     if (p_attributes)
     486            0 :       for (const auto &i : *p_attributes)
     487            0 :         i->save(s);
     488              : 
     489            0 :     if (p_relationships)
     490            0 :       for (const auto &i : *p_relationships)
     491            0 :         i->save(s);
     492              : 
     493            0 :     if (p_methods)
     494            0 :       for (const auto &i : *p_methods)
     495            0 :         i->save(s);
     496              : 
     497            0 :     s.put_raw(' ');
     498            0 :     s.put_last_tag(class_xml_tag, sizeof(class_xml_tag)-1);
     499            0 :     s.put_raw('\n');
     500              :   }
     501              : 
     502            0 :   catch (oks::exception & e) {
     503            0 :     throw oks::FailedSave("oks-class", p_name, e);
     504            0 :   }
     505              : 
     506            0 :   catch (std::exception & e) {
     507            0 :    throw oks::FailedSave("oks-class", p_name, e.what());
     508            0 :   }
     509              : 
     510            0 : }
     511              : 
     512              : 
     513         5697 : OksClass::OksClass(OksXmlInputStream& s, OksKernel * k) :
     514         5697 :   p_super_classes         (0),
     515         5697 :   p_attributes            (0),
     516         5697 :   p_relationships         (0),
     517         5697 :   p_methods               (0),
     518         5697 :   p_abstract              (false),
     519         5697 :   p_transient             (false),
     520         5697 :   p_to_be_deleted         (false),
     521         5697 :   p_all_super_classes     (0),
     522         5697 :   p_all_sub_classes       (0),
     523         5697 :   p_all_attributes        (0),
     524         5697 :   p_all_relationships     (0),
     525         5697 :   p_all_methods           (0),
     526         5697 :   p_inheritance_hierarchy (0),
     527         5697 :   p_kernel                (k),
     528         5697 :   p_instance_size         (0),
     529         5697 :   p_data_info             (0),
     530         5697 :   p_objects               (0),
     531         5697 :   p_indices               (0)
     532              : {
     533              : 
     534              :     // read 'relationship' tag header
     535              : 
     536         5697 :   {
     537         5697 :     try {
     538         5697 :       const char * tag_start = s.get_tag_start();
     539              : 
     540         5697 :       if(strcmp(tag_start, class_xml_tag)) {
     541          140 :         if(!strcmp(tag_start, "/oks-schema")) {
     542          140 :           goto end_of_stream; // re-throw of exception takes too much time; go to is better
     543              :         }
     544            0 :         s.throw_unexpected_tag(tag_start, class_xml_tag);
     545              :       }
     546              :     }
     547            0 :     catch (oks::exception & e) {
     548            0 :       throw oks::FailedRead("oks-class tag", e);
     549            0 :     }
     550            0 :     catch (std::exception & e) {
     551            0 :       throw oks::FailedRead("oks-class tag", e.what());
     552            0 :     }
     553              :   }
     554              : 
     555              :     // read class attributes
     556              : 
     557        13942 :   try {
     558        22327 :     while(true) {
     559        13942 :       OksXmlAttribute attr(s);
     560              : 
     561              :         // check for close of tag
     562              : 
     563        13942 :       if(oks::cmp_str1(attr.name(), ">")) { break; }
     564              : 
     565              :         // check for known oks-class' attributes
     566              : 
     567         8385 :       else if(oks::cmp_str4(attr.name(), name_xml_attr)) p_name.assign(attr.value(), attr.value_len());
     568         2828 :       else if(oks::cmp_str11(attr.name(), description_xml_attr)) p_description.assign(attr.value(), attr.value_len());
     569         1296 :       else if(oks::cmp_str11(attr.name(), is_abstract_xml_attr)) p_abstract = oks::xml::str2bool(attr.value());
     570              :       else {
     571            0 :         s.throw_unexpected_tag(attr.name(), "oks-class\' attribute");
     572              :       }
     573         8385 :     }
     574              :   }
     575            0 :   catch (oks::exception & e) {
     576            0 :     throw oks::FailedRead("oks-class description", e);
     577            0 :   }
     578            0 :   catch (std::exception & e) {
     579            0 :     throw oks::FailedRead("oks-class description", e.what());
     580            0 :   }
     581              : 
     582              : 
     583         5557 :   try {
     584         5557 :     oks::validate_not_empty(p_name, "class name");
     585              :   }
     586            0 :   catch(std::exception& ex) {
     587            0 :     throw oks::FailedRead("oks class", oks::BadFileData(ex.what(), s.get_line_no(), s.get_line_pos()));
     588            0 :   }
     589              : 
     590              : 
     591              :     // read class body
     592              : 
     593        24554 :   while(true) {
     594              : 
     595        24554 :     try {
     596              : 
     597        24554 :       const char * tag_start = s.get_tag_start();
     598              : 
     599              :         // check for closing tag and exit loop
     600              : 
     601        24554 :       if(oks::cmp_str6(tag_start, "/class")) { break; }
     602              : 
     603              : 
     604              :         // create superclass
     605              : 
     606        18997 :       else if(oks::cmp_str10(tag_start, superclass_xml_attr)) {
     607         3322 :         unsigned long scl_pos = s.get_line_no();
     608         3322 :         try {
     609         3322 :           OksXmlAttribute attr(s);
     610              : 
     611         3322 :           if(!p_super_classes) p_super_classes = new std::list<std::string *>();
     612         3322 :           std::string * scl = new std::string(attr.value(), attr.value_len());
     613         3322 :           if(has_direct_super_class(*scl))
     614              :             {
     615            0 :               std::ostringstream text;
     616            0 :               text << "second inclusion of super-class \"" + *scl + "\" at line " << scl_pos;
     617            0 :               delete scl;
     618            0 :               throw std::runtime_error(text.str().c_str());
     619            0 :             }
     620         3322 :           p_super_classes->push_back(scl);
     621              : 
     622         3322 :           OksXmlAttribute attr2(s);
     623              :         }
     624            0 :         catch (oks::exception & e) {
     625            0 :           throw oks::FailedRead(std::string("a superclass-name of class \"") + p_name + '\"', e);
     626            0 :         }
     627            0 :         catch (std::exception & e) {
     628            0 :           throw oks::FailedRead(std::string("a superclass-name of class \"") + p_name + '\"', e.what());
     629            0 :         }
     630              :       }
     631              : 
     632              : 
     633              :         // create attribute from stream and check attribute status
     634              : 
     635        15675 :       else if(oks::cmp_str9(tag_start, "attribute")) {
     636         8607 :         unsigned long attr_pos = s.get_line_no();
     637         8607 :         try {
     638         8607 :           if(!p_attributes) p_attributes = new std::list<OksAttribute *>();
     639         8607 :           OksAttribute * a = new OksAttribute(s, this);
     640         8607 :           if(find_direct_attribute(a->get_name()) != nullptr)
     641              :             {
     642            0 :               std::ostringstream text;
     643            0 :               text << "redefinition of attribute with name \"" + a->get_name() + "\" at line " << attr_pos;
     644            0 :               delete a;
     645            0 :               throw std::runtime_error(text.str().c_str());
     646            0 :             }
     647         8607 :           p_attributes->push_back(a);
     648              :         }
     649            0 :         catch (oks::exception & e) {
     650            0 :           throw oks::FailedRead(std::string("an attribute of class \"") + p_name + '\"', e);
     651            0 :         }
     652            0 :         catch (std::exception & e) {
     653            0 :           throw oks::FailedRead(std::string("an attribute of class \"") + p_name + '\"', e.what());
     654            0 :         }
     655              :       }
     656              : 
     657              : 
     658              :         // create relationship from stream and check relationship status
     659              : 
     660         7068 :       else if(oks::cmp_str12(tag_start, "relationship")) {
     661         4672 :         unsigned long rel_pos = s.get_line_no();
     662         4672 :         try {
     663         4672 :           if(!p_relationships) p_relationships= new std::list<OksRelationship *>();
     664         4672 :           OksRelationship * r = new OksRelationship(s,this);
     665         4672 :           if(find_direct_relationship(r->get_name()) != nullptr)
     666              :             {
     667            0 :               std::ostringstream text;
     668            0 :               text << "redefinition of relationship with name \"" + r->get_name() + "\" at line " << rel_pos;
     669            0 :               delete r;
     670            0 :               throw std::runtime_error(text.str().c_str());
     671            0 :             }
     672         4672 :           p_relationships->push_back(r);
     673              :         }
     674            0 :         catch (oks::exception & e) {
     675            0 :           throw oks::FailedRead(std::string("a relationship of class \"") + p_name + '\"', e);
     676            0 :         }
     677            0 :         catch (std::exception & e) {
     678            0 :           throw oks::FailedRead(std::string("a relationship of class \"") + p_name + '\"', e.what());
     679            0 :         }
     680              :       }
     681              : 
     682              : 
     683              :         // create method from stream and check method status
     684              : 
     685         2396 :       else if(oks::cmp_str6(tag_start, "method")) {
     686         2396 :         unsigned long method_pos = s.get_line_no();
     687         2396 :         try {
     688         2396 :           if(!p_methods) p_methods = new std::list<OksMethod *>();
     689         2396 :           OksMethod * m = new OksMethod(s,this);
     690         2396 :           if(find_direct_method(m->get_name()) != nullptr)
     691              :             {
     692            0 :               std::ostringstream text;
     693            0 :               text << "redefinition of method with name \"" + m->get_name() + "\" at line " << method_pos;
     694            0 :               delete m;
     695            0 :               throw std::runtime_error(text.str().c_str());
     696            0 :             }
     697         2396 :           p_methods->push_back(m);
     698              :         }
     699            0 :         catch (oks::exception & e) {
     700            0 :           throw oks::FailedRead(std::string("a method of class \"") + p_name + '\"', e);
     701            0 :         }
     702            0 :         catch (std::exception & e) {
     703            0 :           throw oks::FailedRead(std::string("a method of class \"") + p_name + '\"', e.what());
     704            0 :         }
     705              :       }
     706              : 
     707              : 
     708              :         // report error if red something differnt from above
     709              :         // and set bad status of constructor (suppose 'name' can't be empty)
     710              : 
     711              :       else {
     712            0 :         s.throw_unexpected_tag(tag_start);
     713              :       }
     714              : 
     715              :     }
     716            0 :     catch (oks::FailedRead & e) {
     717            0 :       throw;  // re-throw attribute, relationship or method exception
     718            0 :     }
     719            0 :     catch (oks::exception & e) {
     720            0 :       throw oks::FailedRead(std::string("a tag of class \"") + p_name + '\"', e);
     721            0 :     }
     722            0 :     catch (std::exception & e) {
     723            0 :       throw oks::FailedRead(std::string("a tag of class \"") + p_name + '\"', e.what());
     724            0 :     }
     725              : 
     726              :   }
     727              :   
     728         5557 :   return;
     729              : 
     730              : 
     731          140 : end_of_stream:
     732              :   
     733          140 :   throw oks::EndOfXmlStream("oks-schema");
     734          280 : }
     735              : 
     736              : 
     737              : /******************************************************************************/
     738              : /****************************** OKS SUPERCLASSES ******************************/
     739              : /******************************************************************************/
     740              : 
     741              : OksClass *
     742            0 : OksClass::find_super_class(const std::string& nm) const noexcept
     743              : {
     744            0 :   if(p_all_super_classes && !p_all_super_classes->empty()) {
     745            0 :     for(FList::const_iterator i = p_all_super_classes->begin(); i != p_all_super_classes->end(); ++i) {
     746            0 :       if((*i)->get_name() == nm) return *i;
     747              :     }
     748              :   }
     749              : 
     750              :   return 0;
     751              : }
     752              : 
     753              : bool
     754         3322 : OksClass::has_direct_super_class(const std::string& nm) const noexcept
     755              : {
     756         3322 :   if(p_super_classes) {
     757         3639 :     for(std::list<std::string *>::const_iterator i = p_super_classes->begin(); i != p_super_classes->end(); ++i)
     758          317 :       if(nm == *(*i)) return true;
     759              :   }
     760              : 
     761              :   return false;
     762              : }
     763              : 
     764              : 
     765              : void
     766            0 : OksClass::lock_file(const char * fname)
     767              : {
     768            0 :   if(p_kernel) {
     769            0 :     try {
     770            0 :       p_file->lock();
     771              :     }
     772            0 :     catch(oks::exception& ex) {
     773            0 :       throw oks::SetOperationFailed(fname, ex);
     774            0 :     }
     775              :   }
     776            0 : }
     777              : 
     778              : 
     779              : void
     780            0 : OksClass::set_description(const std::string& s)
     781              : {
     782            0 :   if(p_description != s) {
     783            0 :     lock_file("OksClass::set_description");
     784              : 
     785            0 :     p_description = s;
     786              : 
     787            0 :     if(p_kernel) {
     788            0 :       p_file->set_updated();
     789            0 :       if(OksClass::change_notify_fn) {
     790            0 :         (*OksClass::change_notify_fn)(this, ChangeDescription, 0);
     791              :       }
     792              :     }
     793              :   }
     794            0 : }
     795              : 
     796              : 
     797              : void
     798            0 : OksClass::set_is_abstract(bool b)
     799              : {
     800            0 :   if(p_abstract != b) {
     801            0 :     lock_file("OksClass::set_is_abstract");
     802              : 
     803            0 :     p_abstract = b;
     804              : 
     805            0 :     if(p_kernel) {
     806            0 :       p_file->set_updated();
     807            0 :       if(OksClass::change_notify_fn) {
     808            0 :         (*OksClass::change_notify_fn)(this, ChangeIsAbstaract, 0);
     809              :       }
     810              :     }
     811              :   }
     812            0 : }
     813              : 
     814              : 
     815              :   // Function to report problem with arguments of swap(...) methods
     816              : 
     817              : static void
     818            0 : check_and_report_empty_parameter(const char * fname, bool b1, bool b2)
     819              : {
     820            0 :   if(b1) {
     821            0 :     throw oks::SetOperationFailed(fname, "First parameter is (null)");
     822              :   }
     823              : 
     824            0 :   if(b2) {
     825            0 :     throw oks::SetOperationFailed(fname, "Second parameter is (null)");
     826              :   }
     827            0 : }
     828              : 
     829              : 
     830              :   // Function to report problem with found items of swap(...) methods
     831              : 
     832              : static void
     833            0 : check_and_report_found_items(const char * fname, const char * item_type,
     834              :                              const std::string& item1_name, const std::string& item2_name,
     835              :                              const std::string& class_name, bool b1, bool b2)
     836              : {
     837            0 :   struct {
     838              :     bool b;
     839              :     const std::string * name;
     840              :   } info[] = {
     841              :     {b1, &item1_name},
     842              :     {b2, &item2_name}
     843            0 :   };
     844              : 
     845            0 :   for(int i = 0; i < 2; ++i) {
     846            0 :     if(info[i].b) {
     847            0 :       std::string text("cannot find direct ");
     848            0 :       text += item_type;
     849            0 :       text += " \"";
     850            0 :       text += *info[i].name;
     851            0 :       text += "\" in class \"";
     852            0 :       text += class_name;
     853            0 :       text += '\"';
     854            0 :       throw oks::SetOperationFailed(fname, text);
     855            0 :     }
     856              :   }
     857            0 : }
     858              : 
     859              : static std::string
     860            0 : add_super_class_error(const std::string& c1, const std::string& c2)
     861              : {
     862            0 :   return (std::string("cannot add superclass \"") + c1 + "\" to class \"" + c2 + '\"');
     863              : }
     864              : 
     865              : 
     866              : void
     867            0 : OksClass::k_add_super_class(const std::string& nm)
     868              : {
     869            0 :   if(!p_super_classes) {
     870            0 :     p_super_classes = new std::list<std::string *>();
     871              :   }
     872              : 
     873            0 :   p_super_classes->push_back((new std::string(nm)));
     874            0 : }
     875              : 
     876              : 
     877              : void
     878            0 : OksClass::add_super_class(const std::string& nm)
     879              : {
     880            0 :   if(!p_super_classes) {
     881            0 :     p_super_classes = new std::list<std::string *>();
     882              :   }
     883              :   else {
     884            0 :     if( has_direct_super_class(nm) ) {
     885            0 :       std::string text(add_super_class_error(nm, p_name));
     886            0 :       text += " because class \"" + p_name + "\" already has such superclass.";
     887            0 :       throw oks::SetOperationFailed("OksClass::add_super_class", text);
     888            0 :     }
     889              :   }
     890              : 
     891            0 :   if(nm == p_name) {
     892            0 :     std::string text(add_super_class_error(nm, p_name));
     893            0 :     text += " because names of classes are the same.";
     894            0 :     throw oks::SetOperationFailed("OksClass::add_super_class", text);
     895            0 :   }
     896              : 
     897            0 :   if(p_kernel) {
     898            0 :     OksClass * nmc = p_kernel->find_class(nm);
     899            0 :     if(nmc) {
     900            0 :       if(nmc->has_direct_super_class(p_name)) {
     901            0 :         std::string text(add_super_class_error(nm, p_name));
     902            0 :         text += " because class \"" + nm + "\" is already direct superclass of \"" + p_name + "\".";
     903            0 :         throw oks::SetOperationFailed("OksClass::add_super_class", text);
     904            0 :       }
     905            0 :       else if(nmc->find_super_class(p_name)) {
     906            0 :         std::string text(add_super_class_error(nm, p_name));
     907            0 :         text += " because class \"" + nm + "\" is already non-direct superclass of \"" + p_name + "\".";
     908            0 :         throw oks::SetOperationFailed("OksClass::add_super_class", text);
     909            0 :       }
     910              :     }
     911              :   }
     912              : 
     913            0 :   lock_file("OksClass::add_super_class");
     914              : 
     915            0 :   p_super_classes->push_back((new std::string(nm)));
     916              : 
     917            0 :   registrate_class_change(ChangeSuperClassesList, (const void *)&nm);
     918            0 : }
     919              : 
     920              : static std::string
     921            0 : remove_super_class_error(const std::string& c1, const std::string& c2)
     922              : {
     923            0 :   return (std::string("cannot remove superclass \"") + c1 + "\" from class \"" + c2 + '\"');
     924              : }
     925              : 
     926              : void
     927            0 : OksClass::remove_super_class(const std::string& nm)
     928              : {
     929            0 :   if( !p_super_classes ) {
     930            0 :     std::string text(remove_super_class_error(nm, p_name));
     931            0 :     text += " because class \"" + p_name + "\" has no superclasses at all.";
     932            0 :     throw oks::SetOperationFailed("OksClass::remove_super_class", text);
     933            0 :   }
     934              : 
     935              : 
     936            0 :   for(std::list<std::string *>::iterator i = p_super_classes->begin(); i != p_super_classes->end(); ++i) {
     937            0 :     std::string * si(*i);
     938            0 :     if(nm == *si) {
     939            0 :       lock_file("OksClass::remove_super_class");
     940              : 
     941            0 :       p_super_classes->erase(i);
     942            0 :       delete si;
     943              : 
     944            0 :       if(p_super_classes->empty()) {
     945            0 :         delete p_super_classes;
     946            0 :         p_super_classes = 0;
     947              :       }
     948              : 
     949            0 :       registrate_class_change(ChangeSuperClassesList, (const void *)&nm);
     950              : 
     951            0 :       return;
     952              :     }
     953              :   }
     954              : 
     955            0 :   std::string text(remove_super_class_error(nm, p_name));
     956            0 :   text += " because class \"" + p_name + "\" has no superclass with this name.";
     957            0 :   throw oks::SetOperationFailed("OksClass::remove_super_class", text);
     958            0 : }
     959              : 
     960              : 
     961              : void
     962            0 : OksClass::swap_super_classes(const std::string& c1, const std::string& c2)
     963              : {
     964            0 :   const char * fname = "OksClass::swap_super_classes()";
     965              : 
     966              : 
     967              :     // if classs are equal, return success
     968              : 
     969            0 :   if(c1 == c2) return;
     970              : 
     971              : 
     972              :     // check that an class name is not empty
     973              : 
     974            0 :   check_and_report_empty_parameter(fname, c1.empty(), c2.empty());
     975              : 
     976              : 
     977              :     // find requested classes in the directed classs list
     978              : 
     979            0 :   std::list<std::string *>::iterator i1 = p_super_classes->end();
     980            0 :   std::list<std::string *>::iterator i2 = p_super_classes->end();
     981              : 
     982            0 :   for(std::list<std::string *>::iterator i = p_super_classes->begin(); i != p_super_classes->end(); ++i) {
     983            0 :     if(*(*i) == c1) i1 = i;
     984            0 :     else if(*(*i) == c2) i2 = i;
     985              :   }
     986              : 
     987              :     // check that the classes were found
     988              : 
     989            0 :   check_and_report_found_items(
     990            0 :     "OksClass::swap_super_classes", "superclass", c1, c2, p_name,
     991            0 :     (i1 == p_super_classes->end()), (i2 == p_super_classes->end())
     992              :   );
     993              : 
     994              : 
     995              :     // replace the classs and make notification
     996              : 
     997            0 :   lock_file("OksClass::swap_super_classes");
     998              : 
     999            0 :   std::string * s1 = *i1;
    1000            0 :   std::string * s2 = *i2;
    1001              : 
    1002            0 :   *i1 = s2;
    1003            0 :   *i2 = s1;
    1004              : 
    1005            0 :   registrate_class_change(ChangeSuperClassesList, 0);
    1006              : }
    1007              : 
    1008              : 
    1009              : /******************************************************************************/
    1010              : /******************************* OKS ATTRIBUTES *******************************/
    1011              : /******************************************************************************/
    1012              : 
    1013              : OksAttribute *
    1014        15476 : OksClass::find_direct_attribute(const std::string& _name) const noexcept
    1015              : {
    1016        15476 :   if(p_attributes) {
    1017        30110 :     for(std::list<OksAttribute *>::const_iterator i = p_attributes->begin(); i != p_attributes->end(); ++i)
    1018        17855 :       if(_name == (*i)->get_name()) return *i;
    1019              :   }
    1020              : 
    1021              :   return 0;
    1022              : }
    1023              : 
    1024              : 
    1025              : OksAttribute *
    1026         6869 : OksClass::find_attribute(const std::string& _name) const noexcept
    1027              : {
    1028         6869 :   if(p_all_attributes) {
    1029        25747 :     for(std::list<OksAttribute *>::const_iterator i = p_all_attributes->begin(); i != p_all_attributes->end(); ++i)
    1030        19004 :       if(_name == (*i)->get_name()) return *i;
    1031              :     
    1032         6743 :     return 0;
    1033              :   }
    1034              :   else
    1035            0 :     return find_direct_attribute(_name);
    1036              : }
    1037              : 
    1038              : 
    1039              : void
    1040            0 : OksClass::k_add(OksAttribute * attribute)
    1041              : {
    1042            0 :   if(!p_attributes) {
    1043            0 :     p_attributes = new std::list<OksAttribute *>();
    1044              :   }
    1045              : 
    1046            0 :   p_attributes->push_back(attribute);
    1047            0 :   attribute->p_class = this;
    1048            0 : }
    1049              : 
    1050              : 
    1051              : void
    1052            0 : OksClass::add(OksAttribute * attribute)
    1053              : {
    1054            0 :   const char * fname = "OksClass::add(OksAttribute *)";
    1055              : 
    1056            0 :   if(!p_attributes) {
    1057            0 :     p_attributes = new std::list<OksAttribute *>();
    1058              :   }
    1059              :   else {
    1060            0 :     if(find_direct_attribute(attribute->get_name()) != 0) {
    1061            0 :       std::ostringstream text;
    1062            0 :       text << "cannot add attribute \"" << attribute->get_name() << "\" to class \"" << p_name << "\"\n"
    1063            0 :               "because the class already has attribute with this name.\n";
    1064            0 :       throw oks::SetOperationFailed(fname, text.str());
    1065            0 :     }
    1066              :   }
    1067              : 
    1068            0 :   lock_file("OksClass::add[OksAttribute]");
    1069              : 
    1070            0 :   p_attributes->push_back(attribute);
    1071            0 :   attribute->p_class = this;
    1072              : 
    1073            0 :   registrate_class_change(ChangeAttributesList, (const void *)attribute);
    1074            0 : }
    1075              : 
    1076              : 
    1077              : void
    1078            0 : OksClass::swap(const OksAttribute * a1, const OksAttribute * a2)
    1079              : {
    1080            0 :   const char * fname = "OksClass::swap(const OksAttribute *, const OksAttribute *)";
    1081              : 
    1082              : 
    1083              :     // if attributes are equal, return success
    1084              : 
    1085            0 :   if(a1 == a2) return;
    1086              : 
    1087              : 
    1088              :     // check that an attributes is not (null)
    1089              : 
    1090            0 :   check_and_report_empty_parameter(fname, (a1 == 0), (a2 == 0));
    1091              : 
    1092              : 
    1093              :     // find requested attributes in the directed attributes list
    1094              : 
    1095            0 :   std::list<OksAttribute *>::iterator i1 = p_attributes->end();
    1096            0 :   std::list<OksAttribute *>::iterator i2 = p_attributes->end();
    1097              : 
    1098            0 :   for(std::list<OksAttribute *>::iterator i = p_attributes->begin(); i != p_attributes->end(); ++i) {
    1099            0 :     if((*i) == a1) i1 = i;
    1100            0 :     else if((*i) == a2) i2 = i;
    1101              :   }
    1102              : 
    1103              :     // check that the attributes were found
    1104              : 
    1105            0 :   check_and_report_found_items(
    1106            0 :     fname, "attribute", a1->get_name(), a2->get_name(), p_name,
    1107            0 :     (i1 == p_attributes->end()), (i2 == p_attributes->end())
    1108              :   );
    1109              : 
    1110              : 
    1111              :     // check that the file can be locked
    1112              : 
    1113            0 :   lock_file("OksClass::swap[OksAttribute]");
    1114              : 
    1115              : 
    1116              :     // replace the attributes and make notification
    1117              : 
    1118            0 :   *i1 = const_cast<OksAttribute *>(a2);
    1119            0 :   *i2 = const_cast<OksAttribute *>(a1);
    1120              : 
    1121            0 :   registrate_class_change(ChangeAttributesList, 0);
    1122              : }
    1123              : 
    1124              : void
    1125            0 : OksClass::remove(const OksAttribute *attribute)
    1126              : {
    1127            0 :   const char * fname = "OksClass::remove(OksAttribute *)";
    1128              : 
    1129            0 :   if(!p_attributes) {
    1130            0 :     std::ostringstream text;
    1131            0 :     text << "cannot remove attribute \"" << attribute->get_name() << "\" from class \"" << p_name << "\"\n"
    1132            0 :             "because the class has no attributes.\n";
    1133            0 :     throw oks::SetOperationFailed(fname, text.str());
    1134            0 :   }
    1135              : 
    1136            0 :   for(std::list<OksAttribute *>::iterator i = p_attributes->begin(); i != p_attributes->end(); ++i) {
    1137            0 :     if(attribute == *i) {
    1138            0 :       lock_file("OksClass::remove[OksAttribute]");
    1139              : 
    1140            0 :       p_attributes->erase(i);
    1141            0 :       delete const_cast<OksAttribute *>(attribute);
    1142              : 
    1143            0 :       if(p_attributes->empty()) {
    1144            0 :         delete p_attributes;
    1145            0 :         p_attributes = 0;
    1146              :       }
    1147              : 
    1148            0 :       registrate_class_change(ChangeAttributesList, 0);
    1149              : 
    1150            0 :       return;
    1151              :     }
    1152              :   }
    1153              : 
    1154            0 :   std::ostringstream text;
    1155            0 :   text << "cannot remove attribute \"" << attribute->get_name() << "\" from class \"" << p_name << "\"\n"
    1156            0 :           "because the class has no such attribute with this name.\n";
    1157            0 :   throw oks::SetOperationFailed(fname, text.str());
    1158            0 : }
    1159              : 
    1160              : 
    1161              : OksClass *
    1162            0 : OksClass::source_class(const OksAttribute *a) const noexcept
    1163              : {
    1164            0 :   return a->p_class;
    1165              : }
    1166              : 
    1167              : 
    1168              : /******************************************************************************/
    1169              : /***************************** OKS  RELATIONSHIPS *****************************/
    1170              : /******************************************************************************/
    1171              : 
    1172              : OksRelationship *
    1173        10079 : OksClass::find_direct_relationship(const std::string& _name) const noexcept
    1174              : {
    1175        10079 :   if(p_relationships) {
    1176        20486 :     for(std::list<OksRelationship *>::const_iterator i = p_relationships->begin(); i != p_relationships->end(); ++i)
    1177        12662 :       if(_name == (*i)->get_name()) return *i;
    1178              :   }
    1179              : 
    1180              :   return 0;
    1181              : }
    1182              : 
    1183              : OksRelationship *
    1184         5407 : OksClass::find_relationship(const std::string& _name) const noexcept
    1185              : {
    1186         5407 :   if(p_all_relationships) {
    1187        20010 :     for(std::list<OksRelationship *>::const_iterator i = p_all_relationships->begin(); i != p_all_relationships->end(); ++i)
    1188        14603 :       if(_name == (*i)->get_name()) return *i;
    1189              :   
    1190         5407 :     return 0;
    1191              :   }
    1192              :   else
    1193            0 :     return find_direct_relationship(_name);
    1194              : }
    1195              : 
    1196              : void
    1197            0 : OksClass::k_add(OksRelationship * relationship)
    1198              : {
    1199            0 :   if(!p_relationships) {
    1200            0 :     p_relationships = new std::list<OksRelationship *>();
    1201              :   }
    1202              : 
    1203            0 :   p_relationships->push_back(relationship);
    1204            0 :   relationship->p_class = this;
    1205            0 : }
    1206              : 
    1207              : void
    1208            0 : OksClass::add(OksRelationship * relationship)
    1209              : {
    1210            0 :   const char * fname = "OksClass::add(OksRelationship *)";
    1211              : 
    1212            0 :   if(!p_relationships) {
    1213            0 :     p_relationships = new std::list<OksRelationship *>();
    1214              :   }
    1215              :   else {
    1216            0 :     if(find_direct_relationship(relationship->get_name())) {
    1217            0 :       std::ostringstream text;
    1218            0 :       text << "cannot add relationship \"" << relationship->get_name() << "\" to class \"" << p_name << "\"\n"
    1219            0 :               "because the class already has relationship with this name.\n";
    1220            0 :       throw oks::SetOperationFailed(fname, text.str());
    1221            0 :     }
    1222              :   }
    1223              : 
    1224            0 :   lock_file("OksClass::add[OksRelationship]");
    1225              : 
    1226            0 :   p_relationships->push_back(relationship);
    1227            0 :   relationship->p_class = this;
    1228              :   
    1229            0 :   registrate_class_change(ChangeRelationshipsList, (const void *)relationship);
    1230            0 : }
    1231              : 
    1232              : void
    1233            0 : OksClass::remove(const OksRelationship * relationship, bool call_delete)
    1234              : {
    1235            0 :   const char * fname = "OksClass::remove(OksRelationship *)";
    1236              :   
    1237            0 :   if(!p_relationships) {
    1238            0 :     std::ostringstream text;
    1239            0 :     text << "cannot remove relationship \"" << relationship->get_name() << "\" from class \"" << p_name << "\"\n"
    1240            0 :             "because the class has no relationships.\n";
    1241            0 :     throw oks::SetOperationFailed(fname, text.str());
    1242            0 :   }
    1243              : 
    1244            0 :   for(std::list<OksRelationship *>::iterator i = p_relationships->begin(); i != p_relationships->end(); ++i) {
    1245            0 :     if(relationship == *i) {
    1246            0 :       lock_file("OksClass::remove[OksRelationship]");
    1247              : 
    1248            0 :       p_relationships->erase(i);
    1249            0 :       if(call_delete) {
    1250            0 :         delete const_cast<OksRelationship *>(relationship);
    1251              :       }
    1252              : 
    1253            0 :       if(p_relationships->empty()) {
    1254            0 :         delete p_relationships;
    1255            0 :         p_relationships = 0;
    1256              :       }
    1257              :   
    1258            0 :       registrate_class_change(ChangeRelationshipsList, 0);
    1259              : 
    1260            0 :       return;
    1261              :     }
    1262              :   }
    1263              : 
    1264            0 :   std::ostringstream text;
    1265            0 :   text << "cannot remove relationship \"" << relationship->get_name() << "\" from class \"" << p_name << "\"\n"
    1266            0 :           "because the class has no such relationship with this name.\n";
    1267            0 :   throw oks::SetOperationFailed(fname, text.str());
    1268            0 : }
    1269              : 
    1270              : 
    1271              : void
    1272            0 : OksClass::swap(const OksRelationship * r1, const OksRelationship * r2)
    1273              : {
    1274            0 :   const char * fname = "OksClass::swap(const OksRelationship *, const OksRelationship *)";
    1275              : 
    1276              : 
    1277              :     // if relationships are equal, return success
    1278              : 
    1279            0 :   if(r1 == r2) return;
    1280              : 
    1281              : 
    1282              :     // check that an relationships is not (null)
    1283              : 
    1284            0 :   check_and_report_empty_parameter(fname, (r1 == 0), (r2 == 0));
    1285              : 
    1286              : 
    1287              :     // find requested relationships in the directed relationships list
    1288              : 
    1289            0 :   std::list<OksRelationship *>::iterator i1 = p_relationships->end();
    1290            0 :   std::list<OksRelationship *>::iterator i2 = p_relationships->end();
    1291              : 
    1292            0 :   for(std::list<OksRelationship *>::iterator i = p_relationships->begin(); i != p_relationships->end(); ++i) {
    1293            0 :     if((*i) == r1) i1 = i;
    1294            0 :     else if((*i) == r2) i2 = i;
    1295              :   }
    1296              : 
    1297              :     // check that the relationships were found
    1298              : 
    1299            0 :   check_and_report_found_items(
    1300            0 :     fname, "relationship", r1->get_name(), r2->get_name(), p_name,
    1301            0 :     (i1 == p_relationships->end()), (i2 == p_relationships->end())
    1302              :   );
    1303              : 
    1304              :     // check that the file can be locked
    1305              : 
    1306            0 :   lock_file("OksClass::swap[OksRelationship]");
    1307              : 
    1308              :     // replace the relationships and make notification
    1309              : 
    1310            0 :   *i1 = const_cast<OksRelationship *>(r2);
    1311            0 :   *i2 = const_cast<OksRelationship *>(r1);
    1312              : 
    1313            0 :   registrate_class_change(ChangeRelationshipsList, 0);
    1314              : }
    1315              : 
    1316              : 
    1317              : OksClass*
    1318            0 : OksClass::source_class(const OksRelationship *r) const noexcept
    1319              : {
    1320            0 :   return r->p_class;
    1321              : }
    1322              : 
    1323              : 
    1324              : /******************************************************************************/
    1325              : /******************************** OKS  METHODS ********************************/
    1326              : /******************************************************************************/
    1327              : 
    1328              : 
    1329              : OksMethod *
    1330         9905 : OksClass::find_direct_method(const std::string& _name) const noexcept
    1331              : {
    1332         9905 :   if(p_methods) {
    1333        15815 :     for(std::list<OksMethod *>::const_iterator i = p_methods->begin(); i != p_methods->end(); ++i)
    1334        10084 :       if(_name == (*i)->get_name()) return *i;
    1335              :   }
    1336              : 
    1337              :   return 0;
    1338              : }
    1339              : 
    1340              : OksMethod *
    1341         6404 : OksClass::find_method(const std::string& _name) const noexcept
    1342              : {
    1343         6404 :   if(p_all_methods) {
    1344        19220 :     for(std::list<OksMethod *>::const_iterator i = p_all_methods->begin(); i != p_all_methods->end(); ++i)
    1345        13060 :       if(_name == (*i)->get_name()) return *i;
    1346              : 
    1347         6160 :     return 0;
    1348              :   }
    1349              :   else 
    1350            0 :     return find_direct_method(_name);
    1351              : }
    1352              :   
    1353              : void
    1354            0 : OksClass::add(OksMethod * method)
    1355              : {
    1356            0 :   const char * fname = "OksClass::add(OksMethod *)";
    1357              : 
    1358            0 :   if(!p_methods) {
    1359            0 :     p_methods = new std::list<OksMethod *>();
    1360              :   }
    1361              :   else {
    1362            0 :     if(find_direct_method(method->get_name())) {
    1363            0 :       std::ostringstream text;
    1364            0 :       text << "cannot add method \"" << method->get_name() << "\" to class \"" << p_name << "\"\n"
    1365            0 :               "because the class already has method with this name.\n";
    1366            0 :       throw oks::SetOperationFailed(fname, text.str());
    1367            0 :     }
    1368              :   }
    1369              : 
    1370              :     // check that the file can be locked
    1371              : 
    1372            0 :   lock_file("OksClass::add[OksMethod]");
    1373              : 
    1374            0 :   p_methods->push_back(method);
    1375            0 :   method->p_class = this;
    1376              : 
    1377            0 :   registrate_class_change(ChangeMethodsList, (const void *)method);
    1378            0 : }
    1379              : 
    1380              : void
    1381            0 : OksClass::remove(const OksMethod * method)
    1382              : {
    1383            0 :   const char * fname = "OksClass::remove(OksMethod *)";
    1384              : 
    1385            0 :   if(!p_methods) {
    1386            0 :     std::ostringstream text;
    1387            0 :     text << "cannot remove method \"" << method->get_name() << "\" from class \"" << p_name << "\"\n"
    1388            0 :             "because the class has no methods.\n";
    1389            0 :     throw oks::SetOperationFailed(fname, text.str());
    1390            0 :   }
    1391              : 
    1392            0 :   for(std::list<OksMethod *>::iterator i = p_methods->begin(); i != p_methods->end(); ++i) {
    1393            0 :     if(method == *i) {
    1394            0 :       lock_file("OksClass::remove[OksMethod]");
    1395              : 
    1396            0 :       p_methods->erase(i);
    1397            0 :       delete const_cast<OksMethod *>(method);
    1398              : 
    1399            0 :       if(p_methods->empty()) {
    1400            0 :         delete p_methods;
    1401            0 :         p_methods = 0;
    1402              :       }
    1403              : 
    1404            0 :       registrate_class_change(ChangeMethodsList, 0);
    1405              : 
    1406            0 :       return;
    1407              :     }
    1408              :   }
    1409              : 
    1410            0 :   std::ostringstream text;
    1411            0 :   text << "cannot remove method \"" << method->get_name() << "\" from class \"" << p_name << "\"\n"
    1412            0 :           "because the class has no such method with this name.\n";
    1413            0 :   throw oks::SetOperationFailed(fname, text.str());
    1414            0 : }
    1415              : 
    1416              : void
    1417            0 : OksClass::swap(const OksMethod * m1, const OksMethod * m2)
    1418              : {
    1419            0 :   const char * fname = "OksClass::swap(const OksMethod *, const OksMethod *)";
    1420              : 
    1421              : 
    1422              :     // if methods are equal, return success
    1423              : 
    1424            0 :   if(m1 == m2) return;
    1425              : 
    1426              : 
    1427              :     // check that an methods is not (null)
    1428              : 
    1429            0 :   check_and_report_empty_parameter(fname, (m1 == 0), (m2 == 0));
    1430              : 
    1431              : 
    1432              :     // find requested methods in the directed methods list
    1433              : 
    1434            0 :   std::list<OksMethod *>::iterator i1 = p_methods->end();
    1435            0 :   std::list<OksMethod *>::iterator i2 = p_methods->end();
    1436              : 
    1437            0 :   for(std::list<OksMethod *>::iterator i = p_methods->begin(); i != p_methods->end(); ++i) {
    1438            0 :     if((*i) == m1) i1 = i;
    1439            0 :     else if((*i) == m2) i2 = i;
    1440              :   }
    1441              : 
    1442              :     // check that the methods were found
    1443              : 
    1444            0 :   check_and_report_found_items(
    1445            0 :     fname, "method", m1->get_name(), m2->get_name(), p_name,
    1446            0 :     (i1 == p_methods->end()), (i2 == p_methods->end())
    1447              :   );
    1448              : 
    1449              :     // check that the file can be locked
    1450              : 
    1451            0 :   lock_file("OksClass::swap[OksMethod]");
    1452              : 
    1453              :     // replace the methods and make notification
    1454              : 
    1455            0 :   *i1 = const_cast<OksMethod *>(m2);
    1456            0 :   *i2 = const_cast<OksMethod *>(m1);
    1457              : 
    1458            0 :   registrate_class_change(ChangeMethodsList, 0);
    1459              : }
    1460              : 
    1461              : 
    1462              : OksClass*
    1463            0 : OksClass::source_class(const OksMethod *m) const noexcept
    1464              : {
    1465            0 :   return m->p_class;
    1466              : }
    1467              : 
    1468              : 
    1469              : /******************************************************************************/
    1470              : /******************************** OKS  OBJECTS ********************************/
    1471              : /******************************************************************************/
    1472              : 
    1473              : size_t
    1474            0 : OksClass::number_of_objects() const noexcept
    1475              : {
    1476            0 :   return (!p_objects ? 0 : p_objects->size());
    1477              : }
    1478              : 
    1479              : 
    1480              :         //
    1481              :         // Creates list of class instances and instances of
    1482              :         // all subclasses
    1483              :         //
    1484              : 
    1485              : std::list<OksObject *> *
    1486           45 : OksClass::create_list_of_all_objects() const noexcept
    1487              : {
    1488           45 :   std::list<OksObject *> * olist = 0;
    1489              : 
    1490              :     // add instances of class
    1491              : 
    1492           45 :   if(p_objects && !p_objects->empty()) {
    1493           45 :     olist = new std::list<OksObject *>();
    1494              : 
    1495          215 :     for(OksObject::Map::const_iterator i = p_objects->begin(); i != p_objects->end(); ++i)
    1496          170 :       olist->push_back((*i).second);
    1497              :   }
    1498              : 
    1499              :     // build iterator over subclasses
    1500              : 
    1501           45 :   if(p_all_sub_classes) {
    1502           68 :     for(FList::const_iterator j = p_all_sub_classes->begin(); j != p_all_sub_classes->end(); ++j) {
    1503           23 :       OksClass *sc = *j;
    1504              : 
    1505              :          // add instances of subclass
    1506              : 
    1507           23 :       if(sc->p_objects && !sc->p_objects->empty()) {
    1508            2 :         if(!olist) olist = new std::list<OksObject *>();
    1509              : 
    1510            4 :         for(OksObject::Map::const_iterator i = sc->p_objects->begin(); i != sc->p_objects->end(); ++i)
    1511            2 :           olist->push_back((*i).second);
    1512              :       }
    1513              :     }
    1514              :   }
    1515              : 
    1516           45 :   return olist;
    1517              : }
    1518              : 
    1519              : 
    1520              : OksObject*
    1521        13217 : OksClass::get_object(const std::string& id) const noexcept
    1522              : {
    1523        13217 :   std::shared_lock lock(p_mutex);  // protect p_objects
    1524              : 
    1525        13217 :   if(p_objects) {
    1526        13217 :     OksObject::Map::const_iterator i = p_objects->find(&id);
    1527        13216 :     if(i != p_objects->end()) return i->second;
    1528              :   }
    1529              : 
    1530              :   return nullptr;
    1531        13216 : }
    1532              : 
    1533              : 
    1534              : /******************************************************************************/
    1535              : /****************************** PRIVATE  METHODS ******************************/
    1536              : /******************************************************************************/
    1537              : 
    1538              : void
    1539         4333 : OksClass::add(OksObject *object)
    1540              : {
    1541         4333 :   std::unique_lock lock(p_mutex);  // protect p_objects
    1542              : 
    1543         4333 :   if(!p_objects->insert(std::pair<const std::string *,OksObject *>(&object->uid.object_id,object) ).second) {
    1544            0 :     throw oks::ObjectOperationFailed(*this, object->uid.object_id, "add", "object already exists");
    1545              :   }
    1546         4334 : }
    1547              : 
    1548              : void
    1549            0 : OksClass::remove(OksObject *object)
    1550              : {
    1551            0 :   std::unique_lock lock(p_mutex);  // protect p_objects
    1552              : 
    1553            0 :   if(!p_objects) {
    1554            0 :     throw oks::ObjectOperationFailed(*this, object->uid.object_id, "remove", "OKS Kernel is not inited");
    1555              :   }
    1556              : 
    1557            0 :   OksObject::Map::iterator i = p_objects->find(&object->uid.object_id);
    1558              : 
    1559            0 :   if(i != p_objects->end()) p_objects->erase(i);
    1560              :   else {
    1561            0 :     throw oks::ObjectOperationFailed(*this, object->uid.object_id, "remove", "object does not exist");
    1562              :   }
    1563            0 : }
    1564              : 
    1565         6112 : inline void add_if_not_found(OksClass::FList& clist, OksClass *c)
    1566              : {
    1567        10827 :   for(OksClass::FList::const_iterator i = clist.begin(); i != clist.end(); ++i) {
    1568         4715 :     if(*i == c) return;
    1569              :   }
    1570         6112 :   clist.push_back(c);
    1571              : }
    1572              : 
    1573              : 
    1574              : void
    1575        12322 : OksClass::add_super_classes(FList * clist) const
    1576              : {
    1577        12322 :   if(p_super_classes) {
    1578        11838 :     for(std::list<std::string *>::const_iterator i = p_super_classes->begin(); i != p_super_classes->end(); ++i) {
    1579         6112 :       if(OksClass * c = p_kernel->find_class(**i)) {
    1580         6112 :         c->add_super_classes(clist);
    1581         6112 :         add_if_not_found(*clist, c);
    1582              :       }
    1583              :       else {
    1584            0 :         throw oks::CannotFindSuperClass(*this, **i);
    1585              :       }
    1586              :     }
    1587              :   }
    1588        12322 : }
    1589              : 
    1590              : 
    1591              : void
    1592         6210 : OksClass::create_super_classes()
    1593              : {
    1594         6210 :   if(!p_all_super_classes) p_all_super_classes = new FList();
    1595          653 :   else p_all_super_classes->clear();
    1596              : 
    1597         6210 :   add_super_classes(p_all_super_classes);
    1598              : 
    1599              : #ifndef ERS_NO_DEBUG
    1600         6210 :   if(ers::debug_level() >= 5) {
    1601          242 :     std::ostringstream text;
    1602          242 :     text << "found " << p_all_super_classes->size() << " superclass(es) in class \'" << get_name() << "\':\n";
    1603          242 :     if(p_all_super_classes->size()) {
    1604          350 :       for(FList::iterator i = p_all_super_classes->begin(); i != p_all_super_classes->end(); ++i) {
    1605          216 :         text << " - class \'" << (*i)->get_name() << "\'\n";
    1606              :       }
    1607              :     }
    1608              : 
    1609          242 :     TLOG_DEBUG(5) << text.str();
    1610          242 :   }
    1611              : #endif
    1612         6210 : }
    1613              : 
    1614              : 
    1615              : void
    1616            0 : OksClass::create_sub_classes()
    1617              : {
    1618            0 :   if(!p_all_sub_classes) p_all_sub_classes = new FList();
    1619            0 :   else p_all_sub_classes->clear();
    1620              : 
    1621            0 :   if(!p_kernel->p_classes.empty()) {
    1622            0 :     for(Map::iterator i = p_kernel->p_classes.begin(); i != p_kernel->p_classes.end(); ++i) {
    1623            0 :       OksClass *c = i->second;
    1624              : 
    1625            0 :       if(const FList* scl = c->p_all_super_classes) {
    1626            0 :         for(FList::const_iterator j = scl->begin(); j != scl->end(); ++j) {
    1627            0 :           if(*j == this) { p_all_sub_classes->push_back(c); break; }
    1628              :         }
    1629              :       }
    1630              :     }
    1631              :   }
    1632            0 : }
    1633              : 
    1634              : 
    1635              : inline const char *
    1636            0 : bool2value_type(bool v)
    1637              : {
    1638            0 :   return (v ? "multi-value" : "single-value");
    1639              : }
    1640              : 
    1641              :   // skip differency between enum and string
    1642              : 
    1643              : inline bool
    1644            0 : are_types_different(const OksAttribute * a1, const OksAttribute * a2)
    1645              : {
    1646            0 :   static const std::string __enum_str__("enum");
    1647            0 :   static const std::string __string_str__("string");
    1648              : 
    1649            0 :   const std::string& s1 = a1->get_type();
    1650            0 :   const std::string& s2 = a2->get_type();
    1651              : 
    1652            0 :   return (
    1653            0 :     !((s1 == s2) || ((s1 == __enum_str__ && s2 == __string_str__) || (s1 == __string_str__ && s2 == __enum_str__)))
    1654            0 :   );
    1655              : }
    1656              : 
    1657              : void
    1658         6210 : OksClass::create_attributes()
    1659              : {
    1660         6210 :   if(p_attributes)
    1661        12573 :     for(const auto& x : *p_attributes)
    1662         8887 :       x->set_init_data();
    1663              : 
    1664         6210 :   if(!p_all_attributes) p_all_attributes = new std::list<OksAttribute *>();
    1665          653 :   else p_all_attributes->clear();
    1666              : 
    1667         6210 :   if(p_all_super_classes) {
    1668        12322 :     for(FList::iterator i = p_all_super_classes->begin(); i != p_all_super_classes->end(); ++i) {
    1669         6112 :       OksClass * c(*i);
    1670         6112 :       if(c->p_attributes) {
    1671         9281 :         for(std::list<OksAttribute *>::iterator i2 = c->p_attributes->begin(); i2 != c->p_attributes->end(); ++i2) {
    1672         6869 :           OksAttribute * a(*i2);
    1673         6869 :           OksAttribute * a1 = find_direct_attribute(a->get_name());
    1674         6869 :           OksAttribute * a2 = find_attribute(a->get_name());
    1675         6869 :           if( a1 == 0 && a2 == 0 ) {
    1676         6469 :             p_all_attributes->push_back(a);
    1677              :           }
    1678          400 :           else if( !p_kernel->p_silence ) {
    1679            0 :             if(a1) {
    1680            0 :               TLOG_DEBUG(1) << "in class \'" << get_name() << "\' direct attribute \'" << a1->get_name() <<
    1681            0 :                            "\' overrides one coming from superclass \'" << a->p_class->get_name() << '\'';
    1682            0 :               if(are_types_different(a1, a)) {
    1683            0 :                 Oks::warning_msg("OksClass::create_attributes()")
    1684            0 :                   << "  found attribute \'" << a->get_name() << "\' types conflict in class \'" << get_name() << "\':\n"
    1685            0 :                   << "  type of attribute in superclass \'" << a->p_class->get_name() << "\' is \'" << a->get_type() << "\'\n"
    1686            0 :                   << "  type of attribute in class \'" << get_name() << "\' is \'" << a1->get_type() << "\'\n";
    1687              :               }
    1688              : 
    1689            0 :               if(a1->get_is_multi_values() != a->get_is_multi_values()) {
    1690            0 :                 Oks::warning_msg("OksClass::create_attributes()")
    1691            0 :                   << "  found attribute \'" << a->get_name() << "\' types conflict in class \'" << get_name() << "\':\n"
    1692            0 :                   << "  attribute in superclass \'" << a->p_class->get_name() << "\' is " << bool2value_type(a->get_is_multi_values()) << "\n"
    1693            0 :                   << "  attribute in class \'" << get_name() << "\' is \'" << bool2value_type(a1->get_is_multi_values()) << "\'\n";
    1694              :               }
    1695              :             }
    1696            0 :             else if(a2) { 
    1697            0 :               TLOG_DEBUG(1) << "in class \'" << get_name() << "\' attribute \'" << a2->get_name() <<
    1698            0 :                            "\' from superclass \'" << a2->p_class->get_name() << "\' overrides one coming from superclass \'" << a->p_class->get_name() << '\'';
    1699            0 :               if(are_types_different(a2, a)) {
    1700            0 :                 Oks::warning_msg("OksClass::create_attributes()")
    1701            0 :                   << "  found attribute \'" << a->get_name() << "\' types conflict in class \'" << get_name() << "\':\n"
    1702            0 :                   << "  type of attribute in superclass \'" << a->p_class->get_name() << "\' is \'" << a->get_type() << "\'\n"
    1703            0 :                   << "  type of attribute in superclass \'" << a2->p_class->get_name() << "\' is \'" << a2->get_type() << "\'\n";
    1704              :               }
    1705              : 
    1706            0 :               if(a2->get_is_multi_values() != a->get_is_multi_values()) {
    1707            0 :                 Oks::warning_msg("OksClass::create_attributes()")
    1708            0 :                   << "  found attribute \'" << a->get_name() << "\' types conflict in class \'" << get_name() << "\':\n"
    1709            0 :                   << "  attribute in superclass \'" << a->p_class->get_name() << "\' is " << bool2value_type(a->get_is_multi_values()) << "\n"
    1710            0 :                   << "  attribute in superclass \'" << get_name() << "\' is \'" << bool2value_type(a2->get_is_multi_values()) << "\'\n";
    1711              :               }
    1712              :             }
    1713              :           }
    1714              :         }
    1715              :       }
    1716              :     }
    1717              :   }
    1718              : 
    1719         6210 :   if(p_attributes) {
    1720        12573 :     for(std::list<OksAttribute *>::iterator i = p_attributes->begin(); i != p_attributes->end(); ++i) {
    1721         8887 :       p_all_attributes->push_back(*i);
    1722              :     }
    1723              :   }
    1724         6210 : }
    1725              : 
    1726              : 
    1727              : 
    1728              : inline const char *
    1729            0 : card2string(OksRelationship::CardinalityConstraint cc) 
    1730              : {
    1731            0 :   return (cc == OksRelationship::One ? "one object" : "many objects");
    1732              : }
    1733              : 
    1734              : void
    1735         6210 : OksClass::create_relationships()
    1736              : {
    1737         6210 :   if(!p_all_relationships ) p_all_relationships = new std::list<OksRelationship *>();
    1738          653 :   else p_all_relationships->clear();
    1739              : 
    1740         6210 :   if(p_all_super_classes) {
    1741        12322 :     for(FList::iterator i = p_all_super_classes->begin(); i != p_all_super_classes->end(); ++i) {
    1742         6112 :       OksClass * c(*i);
    1743         6112 :       if(c->p_relationships) {
    1744         7118 :         for(std::list<OksRelationship *>::iterator i2 = c->p_relationships->begin(); i2 != c->p_relationships->end(); ++i2) {
    1745         5407 :           OksRelationship * r = *i2;
    1746         5407 :           OksRelationship * r1 = find_direct_relationship(r->get_name());
    1747         5407 :           OksRelationship * r2 = find_relationship(r->get_name());
    1748              : 
    1749         5407 :           if(!r->p_class_type) { r->p_class_type = p_kernel->find_class(r->p_rclass); }
    1750              : 
    1751         5407 :           if( r1 == 0 && r2 == 0) {
    1752         5402 :             p_all_relationships->push_back(r);
    1753              :           }
    1754              :           else {
    1755            5 :             if(r1) {
    1756            5 :               TLOG_DEBUG(1) << "in class \'" << get_name() << "\' direct relationship \'" << r1->get_name() <<
    1757            5 :                            "\' overrides one coming from superclass \'" << r->p_class->get_name() << '\'';
    1758            5 :               if(r1->get_high_cardinality_constraint() != r->get_high_cardinality_constraint()) {
    1759            0 :                 Oks::warning_msg("OksClass::create_relationships()")
    1760            0 :                   << "  found relationship \'" << r->get_name() << "\' cardinality conflict in class \'" << get_name() << "\':\n"
    1761            0 :                   << "  relationship in superclass \'" << r->p_class->get_name() << "\' allows " << card2string(r->get_high_cardinality_constraint()) << "\n"
    1762            0 :                   << "  relationship in class \'" << get_name() << "\' allows " <<  card2string(r1->get_high_cardinality_constraint()) << std::endl;
    1763              :               }
    1764              :             }
    1765            0 :             else if(r2) {
    1766            0 :               TLOG_DEBUG(1) << "in class \'" << get_name() << "\' relationship \'" << r2->get_name() <<
    1767            0 :                            "\' from superclass \'" << r2->p_class->get_name() << "\' overrides one coming from superclass \'" << r->p_class->get_name() << '\'';
    1768            0 :               if(r2->get_high_cardinality_constraint() != r->get_high_cardinality_constraint()) {
    1769            0 :                 Oks::warning_msg("OksClass::create_relationships()")
    1770            0 :                   << "  found relationship \'" << r->get_name() << "\' cardinality conflict in class \'" << get_name() << "\':\n"
    1771            0 :                   << "  relationship in superclass \'" << r->p_class->get_name() << "\' allows " << card2string(r->get_high_cardinality_constraint()) << "\n"
    1772            0 :                   << "  relationship in superclass \'" << r2->p_class->get_name() << "\' allows " <<  card2string(r2->get_high_cardinality_constraint()) << std::endl;
    1773              :               }
    1774              :             }
    1775              :           }
    1776              :         }
    1777              :       }
    1778              :     }
    1779              :   }
    1780              : 
    1781         6210 :   if(p_relationships) {
    1782         7266 :     for(std::list<OksRelationship *>::iterator i = p_relationships->begin(); i != p_relationships->end(); ++i) {
    1783         4848 :       OksRelationship * r = *i;
    1784              : 
    1785         4848 :       if(!r->p_class_type) {
    1786         4271 :         r->p_class_type = p_kernel->find_class(r->p_rclass);
    1787              :       }
    1788              : 
    1789         4848 :       p_all_relationships->push_back(r);
    1790              :     }
    1791              :   }
    1792         6210 : }
    1793              : 
    1794              : 
    1795              : void
    1796         6210 : OksClass::create_methods()
    1797              : {
    1798         6210 :   if(!p_all_methods) p_all_methods = new std::list<OksMethod *>();
    1799          653 :   else p_all_methods->clear();
    1800              : 
    1801         6210 :   if(p_all_super_classes) {
    1802        12322 :     for(FList::iterator i = p_all_super_classes->begin(); i != p_all_super_classes->end(); ++i) {
    1803         6112 :       std::list<OksMethod *>::iterator i2;
    1804         6112 :       if((*i)->p_methods) {
    1805        10907 :         for(i2 = (*i)->p_methods->begin(); i2 != (*i)->p_methods->end(); ++i2) {
    1806         7509 :           if(
    1807        13913 :             find_direct_method((*i2)->get_name()) == 0 &&
    1808         6404 :             find_method((*i2)->get_name()) == 0
    1809              :           ) {
    1810         6160 :             p_all_methods->push_back(*i2);
    1811              :           }
    1812              :         }
    1813              :       }
    1814              :     }
    1815              :   }
    1816              : 
    1817         6210 :   if(p_methods) {
    1818         4987 :     for(std::list<OksMethod *>::iterator i = p_methods->begin(); i != p_methods->end(); ++i) {
    1819         3236 :       p_all_methods->push_back(*i);
    1820              :     }
    1821              :   }
    1822         6210 : }
    1823              : 
    1824              : 
    1825              :     // Updates the values of the instances of the class and all their subclasses
    1826              :     // in case of a change of the attribute's type or multi values cardinality
    1827              : 
    1828              : void
    1829            0 : OksClass::registrate_attribute_change(OksAttribute *a)
    1830              : {
    1831            0 :   OSK_PROFILING(OksProfiler::ClassRegistrateAttributeChange, p_kernel)
    1832              : 
    1833            0 :   FList::iterator i;
    1834            0 :   if(p_all_sub_classes) i = p_all_sub_classes->begin();
    1835              : 
    1836              :   OksClass * c(this);
    1837              : 
    1838            0 :   do {
    1839            0 :     if(c->p_objects && !c->p_objects->empty()) {
    1840            0 :       for(OksObject::Map::const_iterator i2 = c->p_objects->begin(); i2 != c->p_objects->end(); ++i2) {
    1841            0 :         OksObject *o(i2->second);
    1842            0 :         OksData newData;
    1843            0 :         OksData *oldData = &o->data[((*(c->p_data_info))[a->p_name])->offset];
    1844              : 
    1845            0 :         try {
    1846            0 :           oldData->cvt(&newData, a);
    1847            0 :           oldData->Clear();
    1848            0 :           memcpy(static_cast<void *>(oldData), static_cast<void *>(&newData), sizeof(OksData));
    1849            0 :           newData.Clear2(); // Do not free !
    1850              :         }
    1851            0 :         catch(oks::AttributeReadError & ex) {
    1852            0 :           std::ostringstream text;
    1853            0 :           text << "attribute \'" << a->get_name() << "\' change converting object " << o << ' ';
    1854            0 :           throw oks::CannotRegisterClass(*this, text.str(), ex);
    1855            0 :         }
    1856            0 :       }
    1857              :     }
    1858            0 :   } while(p_all_sub_classes && i != p_all_sub_classes->end() && (c = *(i++)));
    1859            0 : }
    1860              : 
    1861              : 
    1862              :     // Updates the values of the instances of the class and all their subclasses
    1863              :     // in case of a change of the relationship's class type or a cardinality
    1864              : 
    1865              : void
    1866            0 : OksClass::registrate_relationship_change(OksRelationship *r)
    1867              : {
    1868            0 :   OSK_PROFILING(OksProfiler::ClassRegistrateRelationshipChange, p_kernel)
    1869              : 
    1870            0 :   FList::iterator i;
    1871            0 :   if(p_all_sub_classes) i = p_all_sub_classes->begin();
    1872              : 
    1873              :   OksClass * c(this);
    1874              : 
    1875            0 :   do {
    1876            0 :     if(c->p_objects && !c->p_objects->empty()) {
    1877            0 :       for(OksObject::Map::const_iterator i2 = c->p_objects->begin(); i2 != c->p_objects->end(); ++i2) {
    1878            0 :         OksObject *o(i2->second);
    1879            0 :         OksData newData;
    1880            0 :         OksData *oldData = &o->data[((*(c->p_data_info))[r->p_name])->offset];
    1881              : 
    1882            0 :         oldData->ConvertTo(&newData, r);
    1883            0 :         oldData->Clear();
    1884            0 :         memcpy(static_cast<void *>(oldData), static_cast<void *>(&newData), sizeof(OksData));
    1885            0 :         newData.Clear2(); // Do not free !
    1886            0 :       }
    1887              :     }
    1888            0 :   } while(p_all_sub_classes && i != p_all_sub_classes->end() && (c = *(i++)));
    1889            0 : }
    1890              : 
    1891              : 
    1892              : void
    1893         6210 : OksClass::registrate_instances()
    1894              : {
    1895         6210 :   OSK_PROFILING(OksProfiler::ClassRegistrateInstances, p_kernel)
    1896              : 
    1897         6210 :   OksDataInfo::Map * dInfo = new OksDataInfo::Map();
    1898              : 
    1899         6210 :   size_t dInfoLength = 0;
    1900         6210 :   bool thereAreChanges = false;
    1901              :                 
    1902         6210 :   if(!p_all_attributes->empty()) {
    1903        19603 :     for(std::list<OksAttribute *>::iterator i = p_all_attributes->begin(); i != p_all_attributes->end(); ++i) {
    1904        15356 :       OksAttribute *a = *i;
    1905        15356 :       if(!thereAreChanges) {
    1906         4519 :         OksDataInfo::Map::const_iterator x = p_data_info->find(a->get_name());
    1907         4519 :         if( x == p_data_info->end() || x->second->attribute == nullptr || x->second->offset != dInfoLength || !(*(x->second->attribute) == *a) ) {
    1908         4095 :           thereAreChanges = true;
    1909              :         }
    1910              :       }
    1911              : 
    1912        15356 :       (*dInfo)[a->get_name()] = new OksDataInfo(dInfoLength++, a);
    1913              :     }
    1914              :   }
    1915              :       
    1916         6210 :   if(!p_all_relationships->empty()) {
    1917        13192 :     for(std::list<OksRelationship *>::iterator i = p_all_relationships->begin(); i != p_all_relationships->end(); ++i) {
    1918        10250 :       OksRelationship *r = *i;
    1919        10250 :       if(!thereAreChanges) {
    1920         1150 :         OksDataInfo::Map::const_iterator x = p_data_info->find(r->get_name());
    1921         1150 :         if( x == p_data_info->end() || x->second->relationship == nullptr || x->second->offset != dInfoLength || !(*(x->second->relationship) == *r) ) {
    1922          898 :           thereAreChanges = true;
    1923              :         }
    1924              :       }
    1925              : 
    1926        10250 :       (*dInfo)[r->get_name()] = new OksDataInfo(dInfoLength++, r);
    1927              :     }
    1928              :   }
    1929              : 
    1930         6210 :   if(thereAreChanges == true) {
    1931         4993 :     if(p_objects && !p_objects->empty()) {
    1932            0 :       for(OksObject::Map::const_iterator i = p_objects->begin(); i != p_objects->end(); ++i) {
    1933            0 :         OksObject       *o = (*i).second;
    1934            0 :         OksData * data = new OksData[dInfoLength];
    1935            0 :         size_t count = 0;
    1936              : 
    1937            0 :         if(!p_all_attributes->empty()) {
    1938            0 :                 for(std::list<OksAttribute *>::iterator i2 = p_all_attributes->begin(); i2 != p_all_attributes->end(); ++i2) {
    1939            0 :             OksAttribute * a = *i2;
    1940              :           
    1941            0 :             OksDataInfo::Map::const_iterator x = p_data_info->find(a->get_name());
    1942              : 
    1943            0 :             if(x != p_data_info->end() && x->second->attribute) {
    1944            0 :               OksData *oldData(&o->data[x->second->offset]);
    1945              : 
    1946            0 :               if(*(x->second->attribute) == *a) {
    1947            0 :                 memcpy(static_cast<void *>(&data[count++]), static_cast<void *>(oldData), sizeof(OksData));
    1948            0 :                 oldData->type = OksData::unknown_type;
    1949              :               }
    1950              :               else {
    1951            0 :                 try {
    1952            0 :                   oldData->cvt(&data[count++], a);
    1953              :                 }
    1954            0 :                 catch(oks::AttributeReadError & ex) {
    1955            0 :                   throw oks::AttributeConversionFailed(*a, o, ex);
    1956            0 :                 }
    1957              :               }
    1958              :             }
    1959              :                 }
    1960              :         }
    1961              : 
    1962            0 :         if(!p_all_relationships->empty()) {
    1963            0 :                 for(std::list<OksRelationship *>::iterator i2 = p_all_relationships->begin(); i2 != p_all_relationships->end(); ++i2) {
    1964            0 :             OksRelationship *r = *i2;
    1965              : 
    1966            0 :             OksDataInfo::Map::const_iterator x = p_data_info->find(r->get_name());
    1967              : 
    1968            0 :             if(x != p_data_info->end() && x->second->relationship) {
    1969            0 :               OksData *oldData = &o->data[x->second->offset];
    1970              : 
    1971            0 :               if(*(x->second->relationship) == *r) {
    1972            0 :                 memcpy(static_cast<void *>(&data[count++]), static_cast<void *>(oldData), sizeof(OksData));
    1973            0 :                 oldData->type = OksData::unknown_type;
    1974              :               }
    1975              :               else
    1976            0 :                 oldData->ConvertTo(&data[count++], r);
    1977              :             }
    1978              :                 }
    1979              :         }
    1980              : 
    1981            0 :         int n = p_instance_size;
    1982            0 :         while(n--) o->data[n].Clear();
    1983            0 :         delete o->data;
    1984              : 
    1985            0 :         o->data = data;
    1986              :       }
    1987              :     }
    1988              :   }
    1989              :                 
    1990         6210 :   if(!p_data_info->empty()) {
    1991          868 :     for(OksDataInfo::Map::iterator i = p_data_info->begin(); i != p_data_info->end(); ++i) {
    1992          676 :       delete i->second;
    1993              :     }
    1994              :   }
    1995              : 
    1996         6210 :   delete p_data_info;
    1997              :                 
    1998         6210 :   p_data_info = dInfo;
    1999         6210 :   p_instance_size = dInfoLength;
    2000         6210 : }
    2001              : 
    2002              : 
    2003              : void
    2004         9560 : OksClass::registrate_class(bool skip_registered)
    2005              : {
    2006         9560 :   OSK_PROFILING(OksProfiler::ClassRegistrateClass, p_kernel)
    2007              : 
    2008         9560 :   {
    2009         9560 :     if(!p_data_info) p_data_info = new OksDataInfo::Map();
    2010         9560 :     if(!p_objects) {
    2011         6853 :       p_objects = new OksObject::Map( (p_abstract == false) ? 1024 : 1 );
    2012              :     }
    2013              :   }
    2014              : 
    2015         9560 :   if(!p_data_info->empty() && skip_registered) {
    2016         3350 :     TLOG_DEBUG(4) << "skip already registered " << get_name();
    2017         3350 :     return;
    2018              :   }
    2019              : 
    2020         6210 :   try {
    2021         6210 :     create_super_classes();
    2022         6210 :     create_attributes();
    2023         6210 :     create_relationships();
    2024         6210 :     create_methods();
    2025              : 
    2026         6210 :     registrate_instances();
    2027              :   }
    2028            0 :   catch(oks::exception& ex) {
    2029            0 :     throw oks::CannotRegisterClass(*this, "", ex);
    2030            0 :   }
    2031         9560 : }
    2032              : 
    2033              : 
    2034              : void
    2035            0 : OksClass::registrate_class_change(ChangeType changeType, const void *parameter, bool update_file)
    2036              : {
    2037            0 :   if(!p_kernel) return;
    2038              : 
    2039            0 :   OSK_PROFILING(OksProfiler::ClassRegistrateClassChange, p_kernel)
    2040              : 
    2041            0 :   try {
    2042            0 :     if(update_file) p_file->set_updated();
    2043              : 
    2044            0 :     FList superclasses;
    2045              : 
    2046            0 :     if(changeType == ChangeSuperClassesList && !p_all_super_classes->empty())
    2047            0 :       for(FList::iterator i2 = p_all_super_classes->begin(); i2 != p_all_super_classes->end(); ++i2) {
    2048            0 :         superclasses.push_back(*i2);
    2049              :       }
    2050              : 
    2051            0 :     FList::iterator i;
    2052            0 :     if(p_all_sub_classes) i = p_all_sub_classes->begin();
    2053              : 
    2054              :     OksClass *c = this;
    2055              : 
    2056            0 :     do {
    2057            0 :       switch(changeType) {
    2058            0 :         case ChangeSuperClassesList:
    2059            0 :           c->create_super_classes();                 
    2060            0 :           c->create_attributes();
    2061            0 :           c->create_relationships();
    2062            0 :           c->create_methods();
    2063              :           break;
    2064              :   
    2065            0 :         case ChangeAttributesList:
    2066            0 :           c->create_attributes();
    2067              :           break;
    2068              :   
    2069            0 :         case ChangeRelationshipsList:
    2070            0 :           c->create_relationships();
    2071              :           break;
    2072              :   
    2073            0 :         case ChangeMethodsList:
    2074            0 :           c->create_methods();
    2075              :           break;
    2076              :                         
    2077            0 :         default:
    2078            0 :           continue;
    2079              :       }
    2080              :         
    2081            0 :       if(changeType != ChangeMethodsList) c->registrate_instances();
    2082            0 :     } while(p_all_sub_classes && i != p_all_sub_classes->end() && (c = *(i++)));
    2083              : 
    2084              : 
    2085            0 :     if(changeType == ChangeSuperClassesList) {
    2086            0 :       if(!p_all_super_classes->empty())
    2087            0 :         for(FList::iterator i2 = p_all_super_classes->begin(); i2 != p_all_super_classes->end(); ++i2)
    2088            0 :           if(find(superclasses.begin(), superclasses.end(), *i2) == superclasses.end()) {
    2089            0 :             superclasses.push_back(*i2);
    2090              :           }
    2091              : 
    2092            0 :       for(FList::const_iterator i2 = superclasses.begin(); i2 != superclasses.end(); ++i2) {
    2093            0 :         c = *i2;
    2094              : 
    2095            0 :         if(p_kernel->is_dangling(c) || c->p_to_be_deleted) continue;
    2096              : 
    2097            0 :         c->create_sub_classes();
    2098              : 
    2099            0 :         if(OksClass::change_notify_fn)
    2100            0 :           (*OksClass::change_notify_fn)(c, ChangeSubClassesList, 0);
    2101              :       }
    2102            0 :       superclasses.clear();
    2103              :     }
    2104              : 
    2105            0 :     if(OksClass::change_notify_fn) {
    2106            0 :       if(p_all_sub_classes) i = p_all_sub_classes->begin();
    2107              :       c = this;
    2108              :                         
    2109            0 :       do (*OksClass::change_notify_fn)(c, changeType, parameter);
    2110            0 :       while(p_all_sub_classes && i != p_all_sub_classes->end() && (c = *(i++)));
    2111              :     }
    2112            0 :   }
    2113            0 :   catch(oks::exception& ex) {
    2114            0 :     throw oks::CannotRegisterClass(*this, "change ", ex);
    2115            0 :   }
    2116            0 : }
    2117              : 
    2118              : bool
    2119         9560 : OksClass::check_relationships(std::ostringstream & out, bool print_file_name) const noexcept
    2120              : {
    2121         9560 :   bool found_problems = false;
    2122              : 
    2123         9560 :   if(const std::list<OksRelationship *> * rels = direct_relationships())
    2124              :     {
    2125        12116 :       for(auto & x : *rels)
    2126              :         {
    2127         8043 :           if(x->get_class_type() == nullptr)
    2128              :             {
    2129            0 :               if(found_problems == false)
    2130              :                 {
    2131            0 :                   found_problems = true;
    2132            0 :                   out << " * there are problems with class \"" << get_name() << '\"';
    2133            0 :                   if(print_file_name)
    2134              :                     {
    2135            0 :                       out << " from file \"" << get_file()->get_full_file_name() << '\"';
    2136              :                     }
    2137            0 :                   out << ":\n";
    2138              :                 }
    2139              : 
    2140            0 :               out << "   - class type \"" << x->get_type() << "\" of relationship \"" << x->get_name() << "\" is not loaded\n";
    2141              :             }
    2142              :         }
    2143              :     }
    2144              : 
    2145         9560 :   return found_problems;
    2146              : }
    2147              : 
    2148              : } // namespace oks
    2149              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1