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