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
|