DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
object.cpp
Go to the documentation of this file.
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/object.hpp"
9#include "oks/xml.hpp"
10#include "oks/attribute.hpp"
11#include "oks/relationship.hpp"
12#include "oks/class.hpp"
13#include "oks/kernel.hpp"
14#include "oks/index.hpp"
15#include "oks/profiler.hpp"
16#include "oks/cstring.hpp"
17
18#include "oks_utils.hpp"
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23
24#include <iostream>
25#include <sstream>
26#include <stdexcept>
27
28#include "ers/ers.hpp"
29#include "logging/Logging.hpp"
30
31namespace dunedaq {
32namespace oks {
33
34 // names of xml tags and attributes (differed for compact and extended files)
35
36const char OksObject::obj_xml_tag [] = "obj";
37const char OksObject::obj2_xml_tag [] = "o";
38const char OksObject::class_xml_attribute[] = "class";
39const char OksObject::class2_xml_attribute[] = "c";
40const char OksObject::id_xml_attribute[] = "id";
41const char OksObject::id2_xml_attribute[] = "i";
42
43
44 // names of xml tags and attributes (update oks::cmp_strN calls, if touch below lines)
45
46const char OksObject::attribute_xml_tag[] = "attr";
47const char OksObject::relationship_xml_tag[] = "rel";
48const char OksObject::name_xml_attribute[] = "name";
49const char OksObject::type_xml_attribute[] = "type";
50const char OksObject::num_xml_attribute[] = "num";
51const char OksObject::value_xml_attribute[] = "val";
52
53const char OksObject::data_xml_tag[] = "data";
54const char OksObject::ref_xml_tag[] = "ref";
55
56
57 std::string
58 FailedReadObject::fill(const OksObject * o, const std::string& what, const std::string& reason)
59 {
60 std::ostringstream s;
61 s << "Failed to read \'" << what << "\' of object " << o << '\n' << reason;
62 return s.str();
63 }
64
65 std::string
66 FailedCreateObject::fill(const OksObject * o, const std::string& reason)
67 {
68 std::ostringstream s;
69 s << "Failed to create object " << o << '\n' << reason;
70 return s.str();
71 }
72
73 std::string
74 FailedSaveObject::fill(const OksObject * o, const std::string& reason)
75 {
76 std::ostringstream s;
77 s << "Failed to save object " << o << '\n' << reason;
78 return s.str();
79 }
80
81 std::string
82 FailedRenameObject::fill(const OksObject * o, const std::string& reason)
83 {
84 std::ostringstream s;
85 s << "Failed to rename object " << o << '\n' << reason;
86 return s.str();
87 }
88
89 std::string
90 FailedDestoyObject::fill(const OksObject * o, const std::string& reason)
91 {
92 std::ostringstream s;
93 s << "Failed to destroy object " << o << '\n' << reason;
94 return s.str();
95 }
96
97 std::string
98 ObjectSetError::fill(const OksObject * obj, bool is_rel, const std::string& name, const std::string& reason)
99 {
100 std::ostringstream s;
101 s << "Failed to set " << (is_rel ? "relationship" : "attribute") << " \'" << name << "\' of object " << obj << '\n' << reason;
102 return s.str();
103 }
104
105 std::string
106 ObjectGetError::fill(const OksObject * obj, bool is_rel, const std::string& name, const std::string& reason)
107 {
108 std::ostringstream s;
109 s << "Failed to get " << (is_rel ? "relationship" : "attribute") << " \'" << name << "\' of object " << obj << '\n' << reason;
110 return s.str();
111 }
112
113 std::string
114 AddRcrError::fill(const OksObject * obj, const std::string& name, const OksObject * p1, const OksObject * p2)
115 {
116 std::ostringstream s;
117 s << "Object " << obj << " cannot be linked with " << p1 << " via exclusive relationship \'" << name << "\' since it is already referenced by object " << p2;
118 return s.str();
119 }
120
121 std::string
122 ObjectInitError::fill(const OksObject * obj, const std::string& why, const std::string& reason)
123 {
124 std::ostringstream s;
125 s << "Failed to init object " << obj << " because " << why << '\n' << reason;
126 return s.str();
127 }
128
129 std::string
130 ObjectBindError::fill(const OksObject * obj, const OksRelationship * rel, const std::string& why, const std::string& reason)
131 {
132 p_rel = rel;
133 std::ostringstream s;
134 s << "Failed to bind relationship";
135 if(p_rel) { s << " \"" << p_rel->get_name() << '\"'; } else { s << 's'; }
136 s << " of object " << obj << " because:\n" << why;
137 if(!reason.empty()) s << '\n' << reason;
138 return s.str();
139 }
140
141
142
143void
145{
147
148 p_duplicated_object_id_idx = uid.object_id.size();
149
150 std::lock_guard lock(uid.class_id->p_unique_id_mutex);
151
152 std::unique_ptr<char[]> unique_id(new char[p_duplicated_object_id_idx+16]);
153
154 for (unsigned long i = 0; i < 0xFFFFFFFF; ++i)
155 {
156 sprintf(unique_id.get(), "%s^%lu", uid.object_id.c_str(), i);
157 std::string id(unique_id.get());
158 if(uid.class_id->get_object(id) == nullptr)
159 {
160 uid.object_id = id;
161 return;
162 }
163 }
164}
165
166void
168{
169 if (std::vector<OksClass *> * cs = uid.class_id->p_inheritance_hierarchy)
170 {
171 for (std::vector<OksClass *>::const_iterator j = cs->begin(); j != cs->end(); ++j)
172 {
173 OksObject * o = (*j)->get_object(uid.object_id);
174 if (__builtin_expect((o != nullptr), 0))
175 {
176 std::stringstream e;
177 e << "the object " << o << " from file \'" << o->get_file()->get_full_file_name() << "\' "
178 "has ID equal with \'" << uid.object_id << '@' << uid.class_id->get_name() << "\' object and their classes belong to the same inheritance hierarchy "
179 "(the OKS kernel is configured in the \"test-duplicated-objects-within-inheritance-hierarchy\" mode for compatibility with config and DAL tools)";
180 throw oks::FailedCreateObject(this, e.str());
181 }
182 }
183 }
184}
185
186void
188{
189 const OksClass * c = uid.class_id;
190 const std::string & object_id = uid.object_id;
191 const OksKernel * kernel(c->get_kernel());
192
193
194 // do not allow to create an object of ABSTRACT class
195
196 if( __builtin_expect((c->get_is_abstract()), 0) ) {
197 std::ostringstream text;
198 text << "the class \'" << c->get_name() << "\' is abstract";
199 throw oks::FailedCreateObject(this, text.str());
200 }
201
202
203 // do not allow two objects with equal ID in the same class
204
205 if( __builtin_expect((!object_id.empty()), 1) ) {
207 check_ids();
208 }
209
210 OksObject * o = c->get_object(object_id);
211
212 if( __builtin_expect((o != nullptr), 0) ) {
215 if(kernel->get_silence_mode() != true) {
216 std::cerr
217 << "WARNING [OksObject constructor]:\n"
218 " Cannot create object " << o;
219 if(fp) {
220 std::cerr << " while reading file \'" << fp->get_full_file_name() << '\'';
221 }
222 std::cerr
223 << "\n"
224 " Skip above problem since OKS kernel is configured in \'ignore-duplicated-objects\' mode\n"
225 << " Create duplicated object with ID = \'" << uid.object_id << "\'\n";
226 }
227 }
228 else {
229 std::stringstream e;
230 e << "the object was already loaded from file \'" << o->get_file()->get_full_file_name() << '\'';
231 throw oks::FailedCreateObject(this, e.str());
232 }
233 }
234 }
235 else {
237 }
238
239 data = new OksData[c->p_instance_size];
240 p_user_data = nullptr;
241 p_int32_id = 0;
242 p_rcr = nullptr;
243 file = kernel->get_active_data();
244}
245
246void
247OksData::set_init_value(const OksAttribute * a, bool skip_init)
248{
249 bool si = (a->get_init_value().empty() || skip_init);
250
251 if(a->get_is_multi_values() == false) {
252 type = a->get_data_type();
253 if(si) {
254 SetNullValue(a);
255 }
256 else {
258 data.STRING = new OksString(a->get_init_value());
259 }
260 else if(type == OksData::enum_type) {
261 data.ENUMERATION = a->get_enum_value(a->get_init_value());
262 }
263 else {
264 SetValue(a->get_init_value().c_str(), a);
265 }
266 }
267 }
268 else {
269 if(si) {
270 SetValues("", a);
271 }
272 else {
273 SetValues(a->get_init_value().c_str(), a);
274 }
275 }
276}
277
278
279void
280OksObject::init2(bool skip_init)
281{
282 int count = 0;
283 const OksClass * c = uid.class_id;
284
285 if (c->p_all_attributes)
286 {
287 if (skip_init == false)
288 {
289 for (const auto& i : *c->p_all_attributes)
290 data[count++] = i->p_init_data;
291 }
292 else
293 {
294 for (const auto& i : *c->p_all_attributes)
295 data[count++] = i->p_empty_init_data;
296 }
297 }
298
299 if(c->p_all_relationships) {
300 for(const auto& i : *c->p_all_relationships) {
301 OksData& d(data[count++]);
302 if(i->get_high_cardinality_constraint() != OksRelationship::Many) {
303 d.type = OksData::object_type;
304 d.data.OBJECT = nullptr;
305 }
306 else {
307 d.type = OksData::list_type;
308 d.data.LIST = new OksData::List();
309 }
310 }
311 }
312}
313
314void
316{
317 if( __builtin_expect((c->p_indices != nullptr), 0) ) {
318 for(auto& i : *c->p_indices) i.second->insert(this);
319 }
320
321 c->add(this);
322 c->p_kernel->define(this);
323}
324
325void
327{
328 init3(const_cast<OksClass *>(uid.class_id));
330}
331
332#define READ_OBJ_HEADER(F1, S1, F2, S2) \
333 while(true) { \
334 OksXmlAttribute attr(read_params.s); \
335 if(oks::cmp_str1(attr.name(), ">") || oks::cmp_str1(attr.name(), "/")) { break; } \
336 else if(F1(attr.name(), S1)) { \
337 std::shared_lock lock(read_params.oks_kernel->p_schema_mutex); \
338 c = read_params.oks_kernel->find_class(attr.value()); \
339 if( __builtin_expect((c == nullptr), 0) ) { \
340 std::ostringstream text; \
341 text << "cannot find class \"" << attr.value() << "\" (line " \
342 << read_params.s.get_line_no() << ", char " \
343 << read_params.s.get_line_pos() << ')'; \
344 throw std::runtime_error( text.str().c_str() ); \
345 } \
346 } \
347 else if(F2(attr.name(), S2)) id.assign(attr.value(), attr.value_len()); \
348 else { \
349 read_params.s.throw_unexpected_attribute(attr.name()); \
350 } \
351 }
352
353
354void
366
367OksObject *
369{
370 // read 'object' tag header
371
372 try {
373 const char * tag_start(read_params.s.get_tag_start());
374
375 if(memcmp(tag_start, read_params.object_tag, read_params.object_tag_len)) {
376 if(!oks::cmp_str9(tag_start, "/oks-data")) {
377 read_params.s.throw_unexpected_tag(tag_start, read_params.object_tag);
378 }
379 return 0;
380 }
381 }
382 catch (oks::exception & e) {
383 throw oks::FailedRead("start-of-object tag", e);
384 }
385 catch (std::exception & e) {
386 throw oks::FailedRead("start-of-object tag", e.what());
387 }
388
389
390 // read object tag attributes
391
392 OksClass * c(nullptr);
393 std::string& id((const_cast<oks::ReadFileParams&>(read_params)).tmp); // use temporal string for fast assignment
394
395
396 try {
397 if(read_params.format != 'c') {
399 }
400 else {
402 }
403 }
404 catch(oks::exception & e) {
405 throw oks::FailedRead("object header", e);
406 }
407 catch (std::exception & e) {
408 throw oks::FailedRead("object header", e.what());
409 }
410
411 if(!c) {
412 throw oks::BadFileData("object without class", read_params.s.get_line_no(), read_params.s.get_line_pos());
413 }
414
415 try {
416 oks::validate_not_empty(id, "object id");
417 }
418 catch(std::exception& ex) {
419 throw oks::FailedRead("oks object", oks::BadFileData(ex.what(), read_params.s.get_line_no(), read_params.s.get_line_pos()));
420 }
421
422 if(c && read_params.reload_objects) {
423 if(OksObject * o = read_params.reload_objects->pop(c, id)) {
424 o->read_body(read_params, true);
425 return o;
426 }
427 }
428
429
430 // check if this is the end of file
431
432 if(c == nullptr && id.empty()) { return nullptr; }
433
434
435 // create new object
436
437 OksObject * obj = new OksObject(read_params, c, id); // can throw exception
438
439
440 // check if we re-read the database and notify if required
441
442 if(read_params.reload_objects) {
443 read_params.reload_objects->created.push_back(obj);
444 obj->create_notify();
445
446 if(read_params.oks_kernel->get_verbose_mode()) {
447 TLOG_DEBUG(3) << "*** create object " << obj << " while reload data ***";
448 }
449 }
450
451 return obj;
452}
453
454
455void
457{
458 const char * type_str;
459
460 switch (type) {
461 case OksData::s8_int_type: type_str = OksAttribute::s8_int_type ; break;
462 case OksData::u8_int_type: type_str = OksAttribute::u8_int_type ; break;
463 case OksData::s16_int_type: type_str = OksAttribute::s16_int_type ; break;
464 case OksData::u16_int_type: type_str = OksAttribute::u16_int_type ; break;
465 case OksData::s32_int_type: type_str = OksAttribute::s32_int_type ; break;
466 case OksData::u32_int_type: type_str = OksAttribute::u32_int_type ; break;
467 case OksData::s64_int_type: type_str = OksAttribute::s64_int_type ; break;
468 case OksData::u64_int_type: type_str = OksAttribute::u64_int_type ; break;
469 case OksData::float_type: type_str = OksAttribute::float_type ; break;
470 case OksData::double_type: type_str = OksAttribute::double_type ; break;
471 case OksData::bool_type: type_str = OksAttribute::bool_type ; break;
472 case OksData::class_type: type_str = OksAttribute::class_type ; break;
473 case OksData::date_type: type_str = OksAttribute::date_type ; break;
474 case OksData::time_type: type_str = OksAttribute::time_type ; break;
475 case OksData::string_type: type_str = OksAttribute::string_type ; break;
476 case OksData::enum_type: type_str = OksAttribute::enum_type ; break;
477 default: type_str = "unknown";
478
479 }
480
481 std::lock_guard lock(OksKernel::p_parallel_out_mutex);
482 Oks::warning_msg(std::string("Read object \"") + GetId() + '@' + GetClass()->get_name() + '\"')
483 << " file: \"" << params.f->get_full_file_name() << "\" (line: " << params.s.get_line_no() << ", pos: " << params.s.get_line_pos() << ")\n"
484 " convert value from wrong type \"" << (num == -1 ? "single" : "multi") << "-value " << type_str << "\" to \"" << (a.get_is_multi_values() ? "multi" : "single")
485 << "-value " << a.get_type() << "\" as required for attribute \"" << a.get_name() << "\"\n"
486 << " converted value: " << d << std::endl;
487}
488
489void
491{
492 std::lock_guard lock(OksKernel::p_parallel_out_mutex);
493 Oks::warning_msg(std::string("Read object \"") + GetId() + '@' + GetClass()->get_name() + '\"')
494 << " file: \"" << params.f->get_full_file_name() << "\" (line: " << params.s.get_line_no() << ", pos: " << params.s.get_line_pos() << ")\n"
495 " mismatch between relationship \"" << r.get_name() << "\" cardinality and its value (save data file with new schema)." << std::endl;
496}
497
498static void
499__throw_unknown_type(const oks::ReadFileParams& params, const char * atype)
500{
501 std::ostringstream s;
502 s << "Unknown attribute type \"" << atype << '\"';
503 throw oks::BadFileData(s.str(), params.s.get_line_no(), params.s.get_line_pos());
504}
505
506int32_t
508{
509 char * __sanity;
510 params.s.get_num_token('\"');
511 int32_t num = static_cast<int32_t>(strtol(params.s.m_cvt_char->m_buf, &__sanity, 0));
512 if(*__sanity != 0 || errno == ERANGE) OksXmlInputStream::__throw_strto("strtol", __sanity, params.s.m_cvt_char->m_buf, params.s.get_line_no(), params.s.get_line_pos());
513 return num;
514}
515
516
517void
518OksObject::read_body(const oks::ReadFileParams& read_params, bool re_read)
519{
520 std::string& i_name((const_cast<oks::ReadFileParams&>(read_params)).tmp);
521 bool non_silent_mode(!read_params.oks_kernel->get_silence_mode()); // detect if we need to print errors
522
523 OksData dd; // temporal data
524 const OksClass * c = uid.class_id; // pointer to object's class
525
526 bool was_updated = false; // is used when object is re-read from file
527 bool check_re_read = (re_read && read_params.oks_kernel->p_change_object_notify_fn);
528
529 char * __sanity; // used to check mu, token
530
531
532 // set file from which this object was read
533
534 file = read_params.f;
535
536
537 // is used by ReadFrom(relationship)
538
539 const_cast<oks::ReadFileParams&>(read_params).owner = this;
540
541 if( __builtin_expect((read_params.format != 'c'), 1) ) {
542 OksDataInfo::Map::iterator info_i;
543 OksDataInfo * info(0);
544
545
546 // are used when object is re-read from file
547
548 std::list<const OksAttribute *> * read_attributes = nullptr;
549 std::list<const OksRelationship *> * read_relationships = nullptr;
550
551 if( __builtin_expect((check_re_read), 0) ) {
552 if(c->p_all_attributes && !c->p_all_attributes->empty()) {
553 read_attributes = new std::list<const OksAttribute *>();
554 for(auto& i : *c->p_all_attributes)
555 read_attributes->push_back(i);
556 }
557
558 if(c->p_all_relationships && !c->p_all_relationships->empty()) {
559 read_relationships = new std::list<const OksRelationship *>();
560 for(auto& i : *c->p_all_relationships)
561 read_relationships->push_back(i);
562 }
563 }
564 else if( __builtin_expect((c != nullptr), 1) ) {
565 if( __builtin_expect((re_read == true), 0) ) {
566 OksData *d_end = data + c->number_of_all_attributes() + c->number_of_all_relationships();
567 for(OksData *di = data; di < d_end; ++di) {
568 di->Clear();
569 }
570 }
571
572 init2();
573 }
574
575
576 // read object body
577
578 while(true) try {
579
580 const char * tag_start = read_params.s.get_tag_start();
581
582 // check for closing tag
583
584 if(*tag_start == '/' && !memcmp(tag_start + 1, read_params.object_tag, read_params.object_tag_len)) { break; }
585
586
587 // extra check, if the object is empty
588
589 if(oks::cmp_str3(tag_start, "obj")) {
590 read_params.s.seek_position(-5);
591 break;
592 }
593
594
595 // read attribute
596
597 else if(oks::cmp_str4(tag_start, attribute_xml_tag)) {
599 int32_t num = -1; // -1 => no mv-data read
600 const OksAttribute * a(0);
601 OksXmlValue value;
602 bool attr_is_closed(false);
603
604 // read 'oks-attribute' tag attributes
605
606 try {
607
608 bool name_was_read(false);
609
610 while(true) {
611 OksXmlAttribute attr(read_params.s);
612
613 // check for close of tag
614 if(oks::cmp_str1(attr.name(), ">")) { break; }
615
616 if(read_params.format == 'n' && oks::cmp_str1(attr.name(), "/"))
617 {
618 attr_is_closed = true;
619 break;
620 }
621
622 // check for known oks-attribute' attributes
624 name_was_read = true;
625 if( __builtin_expect((c != nullptr), 1) ) {
626 i_name.assign(attr.value(), attr.value_len());
627 info_i = c->p_data_info->find(i_name);
628 if( __builtin_expect((info_i == c->p_data_info->end() || info_i->second->attribute == nullptr), 0) ) {
629 if(non_silent_mode) {
630 std::string msg = std::string("Read object \"") + GetId() + '@' + c->get_name() + '\"';
631 std::lock_guard lock(OksKernel::p_parallel_out_mutex);
632 Oks::warning_msg(msg.c_str()) << " skip attribute \"" << attr.value() << "\", which is not defined in the schema\n";
633 }
634 }
635 else {
636 info = info_i->second;
637 a = info->attribute;
638 }
639 }
640 }
641 else if(oks::cmp_str4(attr.name(), type_xml_attribute)) {
643 if( __builtin_expect((type == OksData::unknown_type), 0) ) {
644 if(
645 attr.value()[0] != 0 &&
646 (
647 (attr.value()[0] == '-' && attr.value_len() != 1) ||
648 (attr.value()[0] != '-')
649 )
650 ) {
651 __throw_unknown_type(read_params,attr.value());
652 }
653 }
654 }
655 else if(read_params.format != 'n' && oks::cmp_str3(attr.name(), num_xml_attribute)) {
656 num = static_cast<int32_t>(strtol(attr.value(), &__sanity, 0));
657 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoul", __sanity, attr.value(), read_params.s.get_line_no(), read_params.s.get_line_pos());
658 }
659 else if(read_params.format == 'n' && oks::cmp_str3(attr.name(), value_xml_attribute)) {
660 value = read_params.s.get_value(attr.p_value_len);
661 }
662 else {
663 read_params.s.throw_unexpected_attribute(attr.name());
664 }
665 }
666
667 if( __builtin_expect((!name_was_read), 0) ) {
668 throw oks::BadFileData("attribute without name", read_params.s.get_line_no(), read_params.s.get_line_pos());
669 }
670
671 if (read_params.format == 'n' && value.is_empty() == true)
672 num = 0;
673 }
674 catch(oks::exception & e) {
675 throw oks::FailedRead("attribute value header", e);
676 }
677 catch (std::exception & e) {
678 throw oks::FailedRead("attribute value header", e.what());
679 }
680
681 // read 'oks-attribute' body
682 if( __builtin_expect((a != nullptr), 1) ) {
683 OksData * d = &data[info->offset];
684 OksData * dx;
685
686 if( __builtin_expect((check_re_read), 0) ) {
687 dx = &dd;
688 read_attributes->remove(a);
689 }
690 else {
691 dx = d;
692 }
693
694
695 // set default type if it was not read from file
696 if( __builtin_expect((type == OksData::unknown_type), 0) ) {
697 type = a->get_data_type();
698 }
699
700
701 try {
702
703 // read value and convert if necessary
704
705 if(num == -1) {
706 if( __builtin_expect((a->get_data_type() != type || a->get_is_multi_values()), 0) ) {
708
709 OksData d2;
710 if(read_params.format != 'n')
711 d2.read(read_params, &a2);
712 else
713 d2.read(&a2, value);
714 d2.cvt(dx, a);
715 if(non_silent_mode) {
716 __report_type_cvt_warning(read_params, *a, *dx, type, num);
717 }
718 }
719 else {
720 if(read_params.format != 'n')
721 dx->read(read_params, a);
722 else
723 dx->read(a, value);
724 }
725 }
726 else {
727 if( __builtin_expect((a->get_data_type() != type || !a->get_is_multi_values()), 0) ) {
729 OksData d2;
730 if(read_params.format != 'n')
731 d2.read(read_params, &a2, num);
732 else
733 {
734 if(attr_is_closed == false)
735 d2.read(&a2, read_params);
736 else
737 d2.Set(new OksData::List());
738 }
739 d2.cvt(dx, a);
740 if(non_silent_mode) {
741 __report_type_cvt_warning(read_params, *a, *dx, type, num);
742 }
743 }
744 else {
745 if(read_params.format != 'n')
746 dx->read(read_params, a, num);
747 else
748 {
749 if(attr_is_closed == false)
750 dx->read(a, read_params);
751 else
752 dx->Set(new OksData::List());
753 }
754 }
755 }
756
757 // check validity range
758
759 dx->check_range(a);
760 }
761 catch (oks::exception & e) {
762 throw oks::FailedReadObject(this, std::string("attribute \"") + a->get_name() + '\"', e);
763 }
764 catch (std::exception & e) {
765 throw oks::FailedReadObject(this, std::string("attribute \"") + a->get_name() + '\"', e.what());
766 }
767
768
769 if( __builtin_expect((check_re_read), 0) ) {
770 if(*dx != *d) {
771 was_updated = true;
772 *d = *dx;
773 }
774 dd.Clear();
775 }
776 }
777 else {
778 try {
780 if(num == -1) {
781 // note, there is no need to read single-value in case of "normal" format
782 if(read_params.format != 'n')
783 OksData(read_params, &a2);
784 }
785 else {
786 if(read_params.format != 'n')
787 OksData(read_params, &a2, num);
788 else
789 OksData(&a2, read_params);
790 }
791 }
792 catch (oks::exception & e) {
793 throw oks::FailedReadObject(this, "dummu attribute", e);
794 }
795 catch (std::exception & e) {
796 throw oks::FailedReadObject(this, "dummu attribute", e.what());
797 }
798 }
799
800
801 // read 'oks-attribute' close tag
802
803 if(read_params.format != 'n')
804 try {
805 const char * eoa_tag_start = read_params.s.get_tag_start();
806
807 if(!oks::cmp_str5(eoa_tag_start, "/attr")) {
808 std::string s("\'/attr\' is expected instead of \'");
809 s += eoa_tag_start;
810 s += '\'';
811 throw std::runtime_error( s.c_str() );
812 }
813 }
814 catch (oks::exception & e) {
815 throw oks::FailedRead(std::string("attribute\'s closing tag"), e);
816 }
817 catch (std::exception & e) {
818 throw oks::FailedRead(std::string("attribute\'s closing tag"), e.what());
819 }
820
821 } // end of "read attribute"
822
823
824 // read relationship
825
826 else if(oks::cmp_str3(tag_start, relationship_xml_tag)) {
827 int32_t num = -1; // -1 => no mv-data read
828 OksRelationship * r(nullptr);
829 OksXmlRelValue value(read_params);
830
831 // read 'oks-relationship' tag attributes
832
833 try {
834 while(true) {
835 OksXmlAttribute attr(read_params.s);
836
837 // check for close of tag
838
839 if(oks::cmp_str1(attr.name(), ">") || (read_params.format == 'n' && oks::cmp_str1(attr.name(), "/"))) { break; }
840
841 // check for known oks-relationship' attributes
842
843 else if(oks::cmp_str4(attr.name(), name_xml_attribute)) {
844 if( __builtin_expect((c != nullptr), 1) ) {
845 i_name.assign(attr.value(), attr.value_len());
846 info_i = c->p_data_info->find(i_name);
847 if( __builtin_expect((info_i == c->p_data_info->end() || info_i->second->relationship == nullptr), 0) ) {
848 if(non_silent_mode) {
849 std::string msg = std::string("Read object \"") + GetId() + '@' + c->get_name() + '\"';
850 std::lock_guard lock(OksKernel::p_parallel_out_mutex);
851 Oks::warning_msg(msg.c_str()) << " skip relationship \"" << attr.value() << "\", which is not defined in the schema\n";
852 }
853 }
854 else {
855 info = info_i->second;
856 r = const_cast<OksRelationship *>(info->relationship);
857 }
858 }
859 continue;
860 }
861 else if(read_params.format == 'n') {
863 value.m_class = uid.class_id->get_kernel()->find_class(attr.value());
864 if( __builtin_expect((value.m_class == nullptr && attr.value_len() > 0), 0) ) {
865 value.m_class_id = new OksString(attr.value(), attr.value_len());
866 }
867 continue;
868 }
869 else if(oks::cmp_str2(attr.name(), id_xml_attribute)) {
870 value.m_value = read_params.s.get_value(attr.p_value_len);
871 continue;
872 }
873 }
874 else {
876 num = static_cast<int32_t>(strtol(attr.value(), &__sanity, 0));
877 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoul", __sanity, attr.value(), read_params.s.get_line_no(), read_params.s.get_line_pos());
878 continue;
879 }
880 }
881
882 read_params.s.throw_unexpected_attribute(attr.name());
883 }
884 }
885 catch(oks::exception & e) {
886 throw oks::FailedRead("relationship value header", e);
887 }
888 catch (std::exception & e) {
889 throw oks::FailedRead("relationship value header", e.what());
890 }
891
892 if (read_params.format == 'n' && value.is_empty() == true)
893 num = 0;
894
895 // read 'oks-relationship' body
896
897 if( __builtin_expect((r != nullptr), 1) ) {
898 OksData *d = &data[info->offset];
899 OksData * dx;
900
901 OksRelationship::CardinalityConstraint cc = r->get_high_cardinality_constraint();
902
903 if( __builtin_expect((check_re_read), 0) ) {
904 dx = &dd;
905 read_relationships->remove(r);
906 }
907 else {
908 dx = d;
909 }
910
911 try {
912 if(num == -1) {
913 if(cc == OksRelationship::Many) {
914 __report_cardinality_cvt_warning(read_params, *r);
915 OksRelationship dummy(*r);
916 OksData d2;
917 if(read_params.format == 'n')
918 d2.read(&dummy, value);
919 else
920 d2.read(read_params, &dummy);
921 d2.ConvertTo(dx, r);
922 }
923 else {
924 if(read_params.format == 'n')
925 dx->read(r, value);
926 else
927 dx->read(read_params, r);
928 }
929 }
930 else {
931 if(cc != OksRelationship::Many) {
932 __report_cardinality_cvt_warning(read_params, *r);
933 OksRelationship dummy(*r);
934 OksData d2;
935 if(read_params.format == 'n')
936 d2.read(&dummy, read_params);
937 else
938 d2.read(read_params, &dummy, num);
939 d2.ConvertTo(dx, r);
940 }
941 else {
942 if(read_params.format == 'n')
943 dx->read(r, read_params);
944 else
945 dx->read(read_params, r, num);
946 }
947 }
948 }
949 catch (oks::exception & e) {
950 throw oks::FailedReadObject(this, std::string("relationship \"") + r->get_name() + '\"', e);
951 }
952 catch (std::exception & e) {
953 throw oks::FailedReadObject(this, std::string("relationship \"") + r->get_name() + '\"', e.what());
954 }
955
956 if(check_re_read) {
957 if(*dx != *d) {
958 was_updated = true;
959 *d = *dx;
960 }
961 dd.Clear();
962 }
963 }
964 else {
965 OksRelationship r("_ _ *** dummy *** _ _"); // temporal relationship to use right OksData constructor call
966
967 try {
968 if(num == -1) {
969 if(read_params.format != 'n')
970 OksData(read_params, &r);
971 }
972 else {
973 if(read_params.format == 'n')
974 OksData(&r, read_params);
975 else
976 OksData(read_params, &r, num);
977 }
978 }
979 catch (oks::exception & e) {
980 throw oks::FailedReadObject(this, "dummu relationship", e);
981 }
982 catch (std::exception & e) {
983 throw oks::FailedReadObject(this, "dummu relationship", e.what());
984 }
985 }
986
987
988 // read 'oks-relationship' close tag
989
990 if(read_params.format != 'n')
991 try {
992 const char * eor_tag_start = read_params.s.get_tag_start();
993
994 if(!oks::cmp_str4(eor_tag_start, "/rel")) {
995 std::string s("\'/rel\' is expected instead of \'");
996 s += eor_tag_start;
997 s += '\'';
998 throw std::runtime_error( s.c_str() );
999 }
1000 }
1001 catch (oks::exception & e) {
1002 throw oks::FailedRead(std::string("relationship\'s closing tag"), e);
1003 }
1004 catch (std::exception & e) {
1005 throw oks::FailedRead(std::string("relationship\'s closing tag"), e.what());
1006 }
1007
1008 } // end of "read relationship"
1009
1010 }
1011
1012 catch (oks::exception & e) {
1013 throw oks::FailedRead(std::string("object \"") + uid.object_id + '@' + c->get_name() + '\"', e);
1014 }
1015 catch (std::exception & e) {
1016 throw oks::FailedRead(std::string("object \"") + uid.object_id + '@' + c->get_name() + '\"', e.what());
1017 }
1018
1019
1020 // check that unread attributes & relationships have default values
1021
1022 if( __builtin_expect((check_re_read), 0) ) {
1023 if(read_attributes) {
1024 if(!read_attributes->empty()) {
1025 for(auto i = read_attributes->begin(); i != read_attributes->end(); i = read_attributes->erase(i)) {
1026 OksData d = (*i)->p_init_data;
1027 try {
1028 OksData *d2(GetAttributeValue((*i)->get_name()));
1029 if(*d2 != d) {
1030 *d2 = d;
1031 was_updated = true;
1032 }
1033 }
1034 catch(oks::exception& ex) {
1035 throw oks::ObjectInitError(this, std::string("cannot reset default value of attribute \"") + (*i)->get_name() + '\"', ex);
1036 }
1037 }
1038 }
1039
1040 delete read_attributes;
1041 }
1042
1043 if(read_relationships) {
1044 if(!read_relationships->empty()) {
1045 for(auto i = read_relationships->begin(); i != read_relationships->end(); i = read_relationships->erase(i)) {
1046 OksData d; d.ReadFrom(*i);
1047 try {
1048 OksData *d2(GetRelationshipValue((*i)->get_name()));
1049 if(d2 && *d2 != d) {
1050 *d2 = d;
1051 was_updated = true;
1052 }
1053 }
1054 catch(oks::exception& ex) {
1055 throw oks::ObjectInitError(this, std::string("cannot reset value of relationship \"") + (*i)->get_name() + '\"', ex);
1056 }
1057 }
1058 }
1059
1060 delete read_relationships;
1061 }
1062 }
1063 }
1064 else {
1065 size_t count(0);
1066
1067 if(c == 0) {
1068 throw std::runtime_error(
1069 " ***** Can't read objects of undefined class *****\n"
1070 " ***** from file saved in non-extended format. *****\n"
1071 " ***** Fix the problem first. Processing terminated. *****\n"
1072 );
1073 }
1074
1075 if(c->p_all_attributes) {
1076 for(const auto& i : *c->p_all_attributes) {
1077 if(check_re_read) {
1078 OksData d;
1079
1080 if(i->get_is_multi_values()) {
1081 d.read(read_params, i, __get_num(read_params));
1082 }
1083 else {
1084 d.read(read_params, i);
1085 }
1086
1087 if(d != data[count]) {
1088 data[count] = d;
1089 was_updated = true;
1090 }
1091 }
1092 else {
1093 if(i->get_is_multi_values()) {
1094 data[count].read(read_params, i, __get_num(read_params));
1095 }
1096 else {
1097 data[count].read(read_params, i);
1098 }
1099 }
1100
1101 count++;
1102 }
1103 }
1104
1105 if(c->p_all_relationships) {
1106 for(const auto& i : *c->p_all_relationships) {
1107 if(check_re_read) {
1108 OksData d;
1109
1110 if(i->get_high_cardinality_constraint() == OksRelationship::Many) {
1111 d.read(read_params, i, __get_num(read_params));
1112 }
1113 else {
1114 d.read(read_params, i);
1115 }
1116
1117 if(d != data[count]) {
1118 data[count] = d;
1119 was_updated = true;
1120 }
1121 }
1122 else {
1123 if(i->get_high_cardinality_constraint() == OksRelationship::Many) {
1124 data[count].read(read_params, i, __get_num(read_params));
1125 }
1126 else {
1127 data[count].read(read_params, i);
1128 }
1129 }
1130
1131 count++;
1132 }
1133 }
1134
1135 // read tag closing object
1136
1137 try {
1138 const char * tag_start = read_params.s.get_tag_start();
1139
1140 if(*tag_start != '/' || memcmp(tag_start + 1, read_params.object_tag, read_params.object_tag_len)) {
1141 std::ostringstream s;
1142 s << "Failed to read obj close tag (\'/" << read_params.object_tag << "\' is expected)";
1143 throw std::runtime_error( s.str().c_str() );
1144 }
1145 }
1146 catch (oks::exception & e) {
1147 throw oks::FailedRead("object close tag", e);
1148 }
1149 catch (std::exception & e) {
1150 throw oks::FailedRead("object close tag", e.what());
1151 }
1152 }
1153
1154 if(was_updated) change_notify();
1155}
1156
1157OksObject::OksObject(const oks::ReadFileParams& read_params, OksClass * c, const std::string& id) : data(nullptr), p_duplicated_object_id_idx(-1)
1158{
1159 if(c) {
1161 }
1162
1163 uid.object_id = id;
1164 uid.class_id = c;
1165
1166 std::shared_lock lock(read_params.oks_kernel->p_schema_mutex); // protect schema and all objects from changes
1167
1168 if(c) {
1169 init1(read_params.f); // can throw exception; to be caught by caller (i.e. OksKernel)
1170 }
1171
1172 read_body(read_params, false);
1173
1174 if(c) {
1175 init3(c);
1176 }
1177}
1178
1179
1180OksObject::OksObject(const OksClass* c, const char *object_id, bool skip_init) : data(nullptr), p_duplicated_object_id_idx(-1)
1181{
1183
1184 if(!c->p_kernel->get_active_data()) {
1185 Oks::error_msg("OksObject::OksObject(const OksClass*, const char *)") << " Can not create new object since there is no active data file\n";
1186 return;
1187 }
1188
1189 uid.class_id = c;
1190 uid.object_id = (object_id ? object_id : "");
1191
1192 try {
1193 init1();
1194 }
1195 catch(oks::exception& ex) {
1196 uid.class_id = nullptr;
1197 throw;
1198 }
1199
1200 init2(skip_init);
1201 init3();
1202
1203 file->set_updated();
1204}
1205
1206OksObject::OksObject(const OksObject& parentObj, const char *object_id) : data(nullptr), p_duplicated_object_id_idx(-1)
1207{
1209
1210 if(!parentObj.uid.class_id->p_kernel->get_active_data()) {
1211 Oks::error_msg("OksObject::OksObject(const OksObject&, const char *)") << " Can not create new object since there is no active data file\n";
1212 return;
1213 }
1214
1215 const OksClass *c = uid.class_id = parentObj.uid.class_id;
1216
1217 uid.object_id = (object_id ? object_id : "");
1218
1219 try {
1220 init1();
1221 }
1222 catch(oks::exception& ex) {
1223 uid.class_id = nullptr;
1224 throw;
1225 }
1226
1227
1228 int count = c->p_instance_size;
1229 int num_of_attr = c->p_all_attributes->size();
1230 int j = 0;
1231
1232 while(j < num_of_attr) {
1233 data[j] = parentObj.data[j];
1234 j++;
1235 }
1236
1237 try {
1238 std::list<OksRelationship *>::iterator i = c->p_all_relationships->begin();
1239
1240 while(j < count) {
1241 const OksRelationship * r = *i;
1242 const char * relationshipName = r->get_name().c_str();
1243
1244 if(parentObj.data[j].type == OksData::list_type) {
1245 data[j].Set(new OksData::List());
1246
1247 if(parentObj.data[j].data.LIST) {
1248 for(const auto& i2 : *parentObj.data[j].data.LIST) {
1249 if(i2->type == OksData::object_type)
1250 AddRelationshipValue(relationshipName, i2->data.OBJECT);
1251 else {
1252 OksData * uid_d = new OksData();
1253 uid_d = i2;
1254 data[j].data.LIST->push_back(uid_d);
1255 }
1256 }
1257 }
1258 }
1259 else {
1260 if(parentObj.data[j].type == OksData::object_type) {
1261 data[j].Set((OksObject *)0);
1262 SetRelationshipValue(relationshipName, parentObj.data[j].data.OBJECT);
1263 }
1264 else
1265 data[j] = parentObj.data[j];
1266 }
1267 ++j;
1268 ++i;
1269 }
1270 }
1271 catch(oks::exception& ex) {
1272 uid.class_id = nullptr;
1273 throw;
1274 }
1275
1276 init3();
1277
1278 file->set_updated();
1279}
1280
1282{
1283 uid.class_id = nullptr;
1284 data = new OksData[offset+1];
1285 memcpy(static_cast<void *>(&data[offset]), static_cast<const void *>(d), sizeof(OksData));
1286}
1287
1288OksObject::OksObject(OksClass * c, const std::string& id, void * user_data, int32_t int32_id, int32_t duplicated_object_id_idx, OksFile * f) :
1289 data (new OksData[c->p_instance_size]),
1290 p_user_data (user_data),
1291 p_int32_id (int32_id),
1292 p_duplicated_object_id_idx (duplicated_object_id_idx),
1293 file (f)
1294
1295{
1296 uid.class_id = c;
1297 uid.object_id = id;
1298
1299 // set OksData type to unknown
1300 if(size_t data_size = c->p_instance_size * sizeof(OksData*)) {
1301 bzero(data, data_size);
1302 }
1303}
1304
1305void
1307{
1308 if(!o->uid.class_id || fast) {
1309 delete o;
1310 return;
1311 }
1312
1313 // check lack of references on object
1314
1315 std::unique_ptr<std::ostringstream> error_text;
1316
1317 const OksClass::Map & classes = o->uid.class_id->p_kernel->classes();
1318
1319 for(OksClass::Map::const_iterator i = classes.begin(); i != classes.end(); ++i) {
1320 OksClass *c(i->second);
1321 if(c->p_all_relationships == nullptr || c->p_all_relationships->empty()) continue;
1322
1323 if(const OksObject::Map * objects = c->objects()) {
1324 for(OksObject::Map::const_iterator j = objects->begin(); j != objects->end(); ++j) {
1325 size_t offset = c->number_of_all_attributes();
1326 for(std::list<OksRelationship *>::iterator k = c->p_all_relationships->begin(); k != c->p_all_relationships->end(); ++k, ++offset) {
1327 OksData * d = j->second->data + offset;
1328 OksObject * ref = nullptr;
1329
1330 if(d->type == OksData::object_type && d->data.OBJECT == o) {
1331 ref = j->second;
1332 }
1333 else if(d->type == OksData::list_type && d->data.LIST != nullptr) {
1334 for(const auto& l : *d->data.LIST) {
1335 if(l->type == OksData::object_type && l->data.OBJECT == o) {
1336 ref = j->second;
1337 break;
1338 }
1339 }
1340 }
1341
1342 if(ref) {
1343 if(!error_text.get()) {
1344 error_text.reset(new std::ostringstream());
1345 *error_text << "since it is referenced by:";
1346 }
1347 *error_text << "\n * object " << ref << " via relationship \"" << (*k)->get_name() << '\"';
1348 }
1349 }
1350 }
1351 }
1352 }
1353
1354 if(error_text.get()) {
1355 throw oks::FailedDestoyObject(o, error_text->str().c_str());
1356 }
1357
1358 try {
1359 o->file->lock();
1360 o->file->set_updated();
1361 }
1362 catch(oks::exception& ex) {
1363 throw oks::FailedDestoyObject(o, ex);
1364 }
1365
1366 delete o;
1367}
1368
1370{
1371 OksClass * c = const_cast<OksClass *>(uid.class_id);
1372
1373 if(!c) {
1374 if(data) {
1375 delete [] data;
1376 }
1377 }
1378 else {
1379 OksKernel * k = c->p_kernel;
1380
1382
1383 TLOG_DEBUG(4) << "destroy object " << this;
1384
1385 static std::mutex s_mutex;
1386 static std::set<OksObject *, std::less<OksObject *> > oset;
1387
1388 if(k->p_close_all == false) {
1389 k->undefine(this);
1390 std::lock_guard lock(s_mutex);
1391 oset.insert(this);
1392 }
1393
1394 delete_notify();
1395
1396 if(data) {
1397 if(c->p_all_relationships && !c->p_all_relationships->empty()) {
1398 OksData *di = data + c->number_of_all_attributes();
1399
1400 for(std::list<OksRelationship *>::iterator i = c->p_all_relationships->begin(); i != c->p_all_relationships->end(); ++i, ++di) {
1401 OksRelationship * r = *i;
1402
1403 if(r->get_is_composite() == false || k->p_close_all == true) continue;
1404
1405 OksData * d = di;
1406
1407 if(d->type == OksData::object_type && d->data.OBJECT) {
1408 OksObject * o = d->data.OBJECT;
1409
1410 if(!k->is_dangling(o)) {
1411 o->remove_RCR(this, r);
1412
1413 bool delete_obj(r->get_is_dependent() && !o->p_rcr);
1414
1415 if(delete_obj) {
1416 std::lock_guard lock(s_mutex);
1417 delete_obj = (oset.find(o) == oset.end());
1418 }
1419
1420 if( delete_obj ) {
1421 delete o;
1422 d->data.OBJECT = nullptr;
1423 }
1424 }
1425 }
1426 else if(d->type == OksData::list_type && d->data.LIST) {
1427 for(const auto& i2 : *d->data.LIST) {
1428 if(i2->type == OksData::object_type && i2->data.OBJECT) {
1429 OksObject * o = i2->data.OBJECT;
1430
1431 if(!k->is_dangling(o)) {
1432 o->remove_RCR(this, r);
1433
1434 bool delete_obj(r->get_is_dependent() && !o->p_rcr);
1435
1436 if(delete_obj) {
1437 std::lock_guard lock(s_mutex);
1438 delete_obj = (oset.find(o) == oset.end());
1439 }
1440
1441 if( delete_obj ) {
1442 delete o;
1443 i2->data.OBJECT = nullptr;
1444 }
1445 }
1446 }
1447 }
1448 }
1449 }
1450 }
1451
1452 if(c->p_indices) {
1453 for(const auto& i : *c->p_indices)
1454 i.second->remove_obj(this);
1455 }
1456
1457 int count = c->p_instance_size;
1458 while(count--) data[count].Clear();
1459
1460 delete[] data;
1461
1462 if(k->p_close_all == false) {
1463 try {
1464 c->remove(this);
1465 }
1466 catch(oks::exception& ex) {
1467 Oks::error_msg("OksObject::~OksObject()") << ex.what() << std::endl;
1468 }
1469 }
1470 }
1471
1472 if(p_rcr) {
1473 for(std::list<OksRCR *>::const_iterator i = p_rcr->begin(); i != p_rcr->end(); ++i) {
1474 delete *i;
1475 }
1476
1477 delete p_rcr;
1478 }
1479
1480 if(k->p_close_all == false) {
1481 std::lock_guard lock(s_mutex);
1482 oset.erase(this);
1483 }
1484 }
1485}
1486
1487
1488void
1489OksObject::set_file(OksFile * f, bool update_owner)
1490{
1491 if(file != f) {
1492 try {
1493 if(update_owner) {
1494 file->lock();
1495 file->set_updated();
1496 }
1497
1498 f->lock();
1499 f->set_updated();
1500
1501 file = f;
1502 }
1503 catch(oks::exception& ex) {
1504 throw oks::CanNotSetFile(0, this, *f, ex);
1505 }
1506 }
1507}
1508
1509
1510void
1511OksObject::set_id(const std::string &new_id)
1512{
1513 if(new_id == uid.object_id) return;
1514
1515 try {
1516 oks::validate_not_empty(new_id, "object id");
1517 }
1518 catch(std::exception& ex) {
1519 throw oks::FailedRenameObject(this, ex.what());
1520 }
1521
1522 OksClass *c = const_cast<OksClass *>(uid.class_id);
1523
1524 if(c->get_object(new_id)) {
1525 throw oks::FailedRenameObject(this, "the object with such identity already exists");
1526 }
1527
1528
1529 // build set of updated files and list of updated objects
1530
1531 std::set<OksFile *> updated_files;
1532 std::list<OksObject *> updated_objects;
1533
1534 updated_files.insert(file);
1535 updated_objects.push_back(this);
1536
1537 const OksClass::Map & classes = GetClass()->get_kernel()->classes();
1538
1539 for(OksClass::Map::const_iterator i = classes.begin(); i != classes.end(); ++i) {
1540 const OksClass * c(i->second);
1541 const OksObject::Map * objs = c->objects();
1542 size_t d_end = c->p_instance_size;
1543 size_t d_begin = c->p_all_attributes->size();
1544 if(objs && (d_end != d_begin)) {
1545 for(OksObject::Map::const_iterator j = objs->begin(); j != objs->end(); ++j) {
1546 OksObject * o(j->second);
1547
1548 // avoid multiple notification, when renamed object contains references to self
1549 if(o != this) {
1550 for(size_t k = d_begin; k != d_end && o; ++k) {
1551 const OksData & d = o->data[k];
1552 if(d.type == OksData::object_type && d.data.OBJECT == this) {
1553 updated_objects.push_back(o);
1554 updated_files.insert(o->file);
1555 o = nullptr; // break loop
1556 }
1557 else if(d.type == OksData::list_type && d.data.LIST) {
1558 const OksData::List & list = *d.data.LIST;
1559 for(OksData::List::const_iterator l = list.begin(); l != list.end(); ++l) {
1560 OksData * d2 = *l;
1561 if(d2->type == OksData::object_type && d2->data.OBJECT == this) {
1562 updated_objects.push_back(o);
1563 updated_files.insert(o->file);
1564 o = nullptr; // break loop
1565 break;
1566 }
1567 }
1568 }
1569 }
1570 }
1571 }
1572 }
1573 }
1574
1575 try {
1576 for(std::set<OksFile *>::const_iterator i = updated_files.begin(); i != updated_files.end(); ++i) {
1577 (*i)->lock();
1578 }
1579 }
1580 catch(oks::exception& ex) {
1581 throw oks::FailedRenameObject(this, ex);
1582 }
1583
1584 try {
1585 c->remove(this); // remove object from hash table
1586 uid.object_id = new_id; // change id
1587 c->add(this); // add object to hash table
1588 }
1589 catch(oks::exception& ex) {
1590 throw oks::FailedRenameObject(this, ex);
1591 }
1592
1593 for(std::set<OksFile *>::const_iterator i = updated_files.begin(); i != updated_files.end(); ++i) {
1594 (*i)->set_updated();
1595 }
1596
1597 if(get_change_notify()) {
1598 for(std::list<OksObject *>::const_iterator i = updated_objects.begin(); i != updated_objects.end(); ++i) {
1599 (*i)->change_notify();
1600 }
1601 }
1602}
1603
1604bool
1606{
1607 if (o1 == o2)
1608 return true;
1609
1610 if (o1 == nullptr || o2 == nullptr)
1611 return false;
1612
1613 return (o1->uid.class_id->get_name() == o2->uid.class_id->get_name() && o1->uid.object_id == o2->uid.object_id);
1614}
1615
1616bool
1618{
1619 if (are_equal_fast(this, &o) == false)
1620 return false;
1621
1623
1624 size_t count(0);
1625
1626 while (count < uid.class_id->p_instance_size)
1627 {
1628 if (data[count] == o.data[count])
1629 count++;
1630 else
1631 return false;
1632 }
1633
1634 return true;
1635}
1636
1637
1638std::ostream&
1639operator<<(std::ostream& s, const OksObject * o)
1640{
1641 s << '\"';
1642
1643 if(o)
1644 s << o->GetId() << '@' << o->GetClass()->get_name();
1645 else
1646 s << "(null-obj)";
1647
1648 s << '\"';
1649
1650 return s;
1651}
1652
1653
1654std::ostream&
1655operator<<(std::ostream& s, const OksObject& o)
1656{
1658
1659 const OksClass * c = o.uid.class_id;
1660
1661 s << "Object " << &o << std::endl;
1662
1663 OksData * di = o.data;
1664
1665
1666 // print attributes
1667
1668 {
1669 const std::list<OksAttribute *> * alist = c->all_attributes();
1670
1671 if(alist && !alist->empty()) {
1672 s << " Attributes are:\n";
1673
1674 for(std::list<OksAttribute *>::const_iterator i = alist->begin(); i != alist->end(); ++i) {
1675 if((*i)->is_integer() && (*i)->get_format() != OksAttribute::Dec) {
1676 s.setf(((*i)->get_format() == OksAttribute::Hex ? std::ios::hex : std::ios::oct), std::ios::basefield);
1677 s.setf(std::ios::showbase);
1678 }
1679
1680 s << " " << (*i)->get_name() << ": " << *di++ << std::endl;
1681
1682 if((*i)->is_integer() && (*i)->get_format() != OksAttribute::Dec) {
1683 s.setf(std::ios::dec, std::ios::basefield);
1684 s.unsetf(std::ios::showbase);
1685 }
1686 }
1687 }
1688 else
1689 s << " There are no attributes\n";
1690 }
1691
1692
1693 // print relationships
1694
1695 {
1696 const std::list<OksRelationship *> * rlist = c->all_relationships();
1697
1698 if(rlist && !rlist->empty()) {
1699 s << " Relationships are:\n";
1700
1701 for(std::list<OksRelationship *>::const_iterator i = rlist->begin(); i != rlist->end(); ++i)
1702 s << " " << (*i)->get_name() << ": " << *di++ << std::endl;
1703 }
1704 else
1705 s << " There are no relationships\n";
1706 }
1707
1708 return s;
1709}
1710
1711
1712 //
1713 // Remove dangling objects before writing to file
1714 // Avoid unnecessary additional checks
1715 //
1716
1717static bool
1718trim_dangling(OksData & d, const OksKernel & kernel)
1719{
1720 if (d.type == OksData::object_type)
1721 {
1722 if (d.data.OBJECT && kernel.is_dangling(d.data.OBJECT))
1723 {
1724 d.data.OBJECT = nullptr;
1725 }
1726
1727 return (d.data.OBJECT != nullptr);
1728 }
1729 else if(d.type == OksData::list_type)
1730 {
1731 if (d.data.LIST)
1732 {
1733 for (OksData::List::iterator i = d.data.LIST->begin(); i != d.data.LIST->end();)
1734 {
1735 OksData * d2 = *i;
1736 if (d2->type == OksData::object_type)
1737 {
1738 if (d2->data.OBJECT == nullptr || kernel.is_dangling(d2->data.OBJECT))
1739 {
1740 i = d.data.LIST->erase(i);
1741 delete d2;
1742 continue;
1743 }
1744 }
1745 ++i;
1746 }
1747
1748 return (!d.data.LIST->empty());
1749 }
1750 else
1751 return false;
1752 }
1753
1754 return true;
1755}
1756
1757
1758void
1760{
1761 const std::string * class_name = nullptr;
1762 const std::string * object_id = nullptr;
1763
1764 if(d.type == OksData::object_type)
1765 {
1766 class_name = &d.data.OBJECT->GetClass()->get_name();
1767 object_id = &d.data.OBJECT->GetId();
1768 }
1769 else if(d.type == OksData::uid_type)
1770 {
1771 class_name = &d.data.UID.class_id->get_name();
1772 object_id = d.data.UID.object_id;
1773 }
1774 else
1775 {
1776 class_name = d.data.UID2.class_id;
1777 object_id = d.data.UID2.object_id;
1778 }
1779
1780 xmls.put_attribute(class_xml_attribute, sizeof(class_xml_attribute)-1, class_name->c_str());
1781 xmls.put_attribute(id_xml_attribute, sizeof(id_xml_attribute)-1, object_id->c_str());
1782}
1783
1784void
1785OksObject::put(OksXmlOutputStream& xmls, bool force_defaults) const
1786{
1788
1789 try
1790 {
1791 const OksClass * class_id = uid.class_id;
1792
1793 xmls.put_start_tag(obj_xml_tag, sizeof(obj_xml_tag)-1);
1794
1795 xmls.put_attribute(class_xml_attribute, sizeof(class_xml_attribute)-1, class_id->get_name().c_str());
1796 xmls.put_attribute(id_xml_attribute, sizeof(id_xml_attribute)-1, uid.object_id.c_str());
1797
1798 xmls.put_eol();
1799
1800 int count = 0;
1801
1802 if (auto alist = class_id->all_attributes())
1803 {
1804 for (const auto& a : *alist)
1805 {
1806 OksData& d = data[count++];
1807
1808 // store all attributes with value != initial, or date/time types which default values = now(), or non-numbers or numbers with non-zero values
1809 if (force_defaults || d != a->p_init_data || a->p_data_type == OksData::date_type || a->p_data_type == OksData::time_type || (a->get_init_value().empty() == false && (a->get_is_multi_values() == true || a->is_number() == false || a->get_init_value().size() > 1 || a->get_init_value()[0] != '0')))
1810 {
1811 xmls.put_raw(' ');
1813 xmls.put_attribute(name_xml_attribute, sizeof(name_xml_attribute) - 1, a->get_name().c_str());
1814 xmls.put_attribute(type_xml_attribute, sizeof(type_xml_attribute) - 1, a->get_type().c_str());
1815
1816 if (a->is_integer() && a->get_format() != OksAttribute::Dec)
1817 {
1818 xmls.get_stream().setf((a->get_format() == OksAttribute::Hex ? std::ios::hex : std::ios::oct), std::ios::basefield);
1819 xmls.get_stream().setf(std::ios::showbase);
1820 }
1821
1822 if (a->get_is_multi_values() == false)
1823 {
1825 xmls.put_end_tag();
1826 }
1827 else
1828 {
1829 if (d.data.LIST->empty())
1830 {
1831 xmls.put_end_tag();
1832 }
1833 else
1834 {
1835 if(a->p_ordered)
1836 d.sort();
1837
1838 xmls.put_eol();
1839
1840 for (const auto& x : *d.data.LIST)
1841 {
1842 xmls.put_raw(' ');
1843 xmls.put_raw(' ');
1844 xmls.put_start_tag(data_xml_tag, sizeof(data_xml_tag) - 1);
1846 xmls.put_end_tag();
1847 }
1848
1849 xmls.put_raw(' ');
1851 }
1852 }
1853
1854 if (a->is_integer() && a->get_format() != OksAttribute::Dec)
1855 {
1856 xmls.get_stream().setf(std::ios::dec, std::ios::basefield);
1857 xmls.get_stream().unsetf(std::ios::showbase);
1858 }
1859 }
1860 }
1861 }
1862
1863 if (const std::list<OksRelationship *> * rlist = class_id->all_relationships())
1864 {
1865 for (const auto& r : *rlist)
1866 {
1867 OksData& rel_data = data[count++];
1868
1869 if (trim_dangling(rel_data, *class_id->p_kernel))
1870 {
1871 xmls.put_raw(' ');
1873 xmls.put_attribute(name_xml_attribute, sizeof(name_xml_attribute) - 1, r->get_name().c_str());
1874
1875 if (r->get_high_cardinality_constraint() != OksRelationship::Many)
1876 {
1877 put_object_attributes(xmls, rel_data);
1878 xmls.put_end_tag();
1879 }
1880 else
1881 {
1882 if(r->p_ordered)
1883 rel_data.sort();
1884
1885 xmls.put_eol();
1886
1887 for (const auto& x : *rel_data.data.LIST)
1888 {
1889 xmls.put_raw(' ');
1890 xmls.put_raw(' ');
1891 xmls.put_start_tag(ref_xml_tag, sizeof(ref_xml_tag) - 1);
1892 put_object_attributes(xmls, *x);
1893 xmls.put_end_tag();
1894 }
1895
1896 xmls.put_raw(' ');
1898 }
1899 }
1900 }
1901 }
1902
1903 xmls.put_last_tag(obj_xml_tag, sizeof(obj_xml_tag) - 1);
1904 }
1905 catch (oks::exception & ex)
1906 {
1907 throw(oks::FailedSaveObject(this, ex));
1908 }
1909 catch (std::ios_base::failure & ex)
1910 {
1911 throw(oks::FailedSaveObject(this, std::string("caught std::ios_base::failure exception \"") + ex.what() + '\"'));
1912 }
1913 catch (std::exception & ex)
1914 {
1915 throw(oks::FailedSaveObject(this, std::string("caught std::exception \"") + ex.what() + '\"'));
1916 }
1917 catch (...)
1918 {
1919 throw(oks::FailedSaveObject(this, "unknown reason"));
1920 }
1921}
1922
1923OksData *
1924OksObject::GetAttributeValue(const std::string& name) const
1925{
1926 OksDataInfo::Map::const_iterator i = uid.class_id->p_data_info->find(name);
1927
1928 if(i == uid.class_id->p_data_info->end()) {
1929 std::ostringstream text;
1930 text << "object " << this << " has no attribute \"" << name << '\"';
1931 throw oks::ObjectGetError(this, false, name, text.str());
1932 }
1933
1934 return GetAttributeValue(i->second);
1935}
1936
1937
1938void
1940{
1941 size_t offset = odi->offset;
1942 const OksAttribute * a = odi->attribute;
1943 OksData d2; // can be needed by type conversion
1944
1945 if(data[offset].type != d->type) {
1946 if(uid.class_id->get_kernel()->get_silence_mode() == false) {
1947 Oks::warning_msg("OksObject::SetAttributeValue(const OksDataInfo *, OksData *)")
1948 << " * ODI attribute name: \'" << a->get_name() << "\'\n"
1949 " * ODI data offset: \'" << offset << "\'\n"
1950 " * OKS data (new): \'" << *d << "\' type: " << (int)d->type << "\n"
1951 " * OKS data (old): \'" << data[offset] << "\' type: " << (int)data[offset].type << "\n"
1952 " Object " << this << ":\n"
1953 " Convert attribute \"" << a->get_name() << "\" value since the OksData::type is invalid\n";
1954 }
1955
1956 d->cvt(&d2, a);
1957 d=&d2;
1958 }
1959
1960 try {
1961 d->check_range(a);
1962 }
1963 catch(oks::AttributeReadError & ex) {
1964 throw oks::ObjectSetError(this, false, a->get_name(), ex);
1965 }
1966 catch(oks::AttributeRangeError & ex) {
1967 throw oks::ObjectSetError(this, false, a->get_name(), ex);
1968 }
1969
1970 check_file_lock(a, 0);
1971
1972
1973 // set value and update index if any
1974
1975 {
1976 OksIndex * i = nullptr;
1977
1978 if(uid.class_id->p_indices) {
1979 OksIndex::Map::iterator j = uid.class_id->p_indices->find(a);
1980 if(j != uid.class_id->p_indices->end()) {
1981 i = j->second;
1982 }
1983 }
1984
1985 if(i) i->remove_obj(this);
1986 data[offset] = *d;
1987 if(i) i->insert(this);
1988 }
1989
1990 notify();
1991}
1992
1993
1994void
1995OksObject::SetAttributeValue(const std::string& name, OksData *d)
1996{
1997 OksDataInfo::Map::iterator i = uid.class_id->p_data_info->find(name);
1998
1999 if(i == uid.class_id->p_data_info->end()) {
2000 std::ostringstream text;
2001 text << "object " << this << " has no attribute \"" << name << '\"';
2002 throw oks::ObjectSetError(this, false, name, text.str());
2003 }
2004
2005 SetAttributeValue(i->second, d);
2006}
2007
2008OksData *
2009OksObject::GetRelationshipValue(const std::string& name) const
2010{
2011 OksDataInfo::Map::iterator i = uid.class_id->p_data_info->find(name);
2012
2013 if(i == uid.class_id->p_data_info->end()) {
2014 std::ostringstream text;
2015 text << "object " << this << " has no relationship \"" << name << '\"';
2016 throw oks::ObjectGetError(this, false, name, text.str());
2017 }
2018
2019 return GetRelationshipValue(i->second);
2020}
2021
2022
2023void
2025{
2026 if(!o && r->get_low_cardinality_constraint() != OksRelationship::Zero) {
2027 throw oks::ObjectSetError(
2028 this, true, r->get_name(),
2029 "set to (null) is not allowed since the relationship has non-zero low cardinality constraint"
2030 );
2031 }
2032}
2033
2034
2035void
2037{
2038 if(!class_type) return;
2039
2040 const OksClass * rel_class_type = r->p_class_type;
2041
2042 if(class_type != rel_class_type) {
2043 OksClass::FList * super_classes = class_type->p_all_super_classes;
2044
2045 if(super_classes && !super_classes->empty()) {
2046 for(const auto& i : *super_classes) {
2047 if(rel_class_type == i) return;
2048 }
2049 }
2050
2051 std::ostringstream text;
2052 text << "set to an object of class \"" << class_type->get_name() << "\" is not allowed since the relationship's class type is \""
2053 << r->get_type() << "\" and the class \"" << class_type->get_name() << "\" has no such superclass";
2054 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2055 }
2056}
2057
2058
2059void
2060OksObject::SetRelationshipValue(const OksDataInfo *odi, OksData *d, bool skip_non_null_check)
2061{
2062 const OksRelationship * r = odi->relationship;
2063 size_t offset = odi->offset;
2064
2065 if(
2066 (data[offset].type != d->type) &&
2067 ( (d->type == OksData::list_type) || (data[offset].type == OksData::list_type) )
2068 ) {
2069 std::ostringstream text;
2070 text << "OKS data type is invalid: must be " << (data[offset].type == OksData::object_type ? "an object)\n" : "a list); ")
2071 << "offset: " << offset << "; new: \'" << *d << "\'; old:" << data[offset] << '\'';
2072 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2073 }
2074
2075 // used to update RCRs
2076
2077 OksObject::FSet added_objs;
2078 OksObject::FSet removed_objs;
2079
2080 if(d->type == OksData::object_type) {
2081 OksObject * add_obj = d->data.OBJECT;
2082 OksObject * rm_obj = (data[offset].type == OksData::object_type ? data[offset].data.OBJECT : 0);
2083
2084 if(add_obj != rm_obj) {
2085 if(add_obj) added_objs.insert(add_obj);
2086 if(rm_obj) removed_objs.insert(rm_obj);
2087 }
2088 else {
2089 return; // new and old values are equal, nothing to do
2090 }
2091
2092 if(skip_non_null_check == false) check_non_null(r, d->data.OBJECT);
2093 check_class_type(r, d->data.OBJECT);
2094 }
2095 else if(d->type == OksData::list_type && d->data.LIST) {
2096 if(d->data.LIST->empty()) {
2097 if(r->get_low_cardinality_constraint() != OksRelationship::Zero && skip_non_null_check == false) {
2098 throw oks::ObjectSetError(
2099 this, true, r->get_name(),
2100 "set to empty list is not allowed since the relationship has non-zero low cardinality constraint"
2101 );
2102 }
2103 }
2104
2105 for(const auto& i : *d->data.LIST) {
2106 if(i->type != OksData::object_type && i->type != OksData::uid2_type && i->type != OksData::uid_type) {
2107 throw oks::ObjectSetError(this, true, r->get_name(), "list contains non-objects");
2108 }
2109
2110 if(
2111 (i->type == OksData::object_type && !i->data.OBJECT) ||
2112 (i->type == OksData::uid2_type && !i->data.UID2.object_id) ||
2113 (i->type == OksData::uid_type && !i->data.UID.object_id)
2114 ) {
2115 throw oks::ObjectSetError(this, true, r->get_name(), "list contains (null) object");
2116 }
2117
2118 if(i->type == OksData::object_type) {
2119 if(OksObject * o2 = i->data.OBJECT) {
2120 check_class_type(r, o2);
2121 added_objs.insert(o2);
2122 }
2123 }
2124 }
2125 }
2126 else {
2127 throw oks::ObjectSetError(
2128 this, true, r->get_name(),
2129 "the OKS data type is invalid (must be a list of objects or an object)"
2130 );
2131 }
2132
2133 check_file_lock(0, r);
2134
2135
2136 // put old value to objects removed from relationship
2137
2138 if(data[offset].type == OksData::list_type && data[offset].data.LIST) {
2139 for(const auto& i : *data[offset].data.LIST) {
2140 if(i->type == OksData::object_type && i->data.OBJECT) {
2141 removed_objs.insert(i->data.OBJECT);
2142 }
2143 }
2144 }
2145
2146
2147 // remove RCRs
2148
2149 for(const auto& i : removed_objs) {
2150 if(added_objs.find(i) == added_objs.end()) {
2151 TLOG_DEBUG(4) << "object " << i << " was removed from relationship";
2152 i->remove_RCR(this, r);
2153 }
2154 }
2155
2156
2157 // add RCRs
2158
2159 for(OksObject::FSet::const_iterator i = added_objs.begin(); i != added_objs.end(); ++i) {
2160 OksObject * add_obj = *i;
2161 if(removed_objs.find(add_obj) == removed_objs.end()) {
2162 TLOG_DEBUG(4) << "object " << add_obj << " was added to relationship";
2163 try {
2164 add_obj->add_RCR(this, r);
2165 }
2166 catch(oks::exception& ex) {
2167
2168 // reset updated RCRs
2169
2170 for(OksObject::FSet::const_iterator j = added_objs.begin(); j != i; ++j) {
2171 if(removed_objs.find(*j) == removed_objs.end()) {
2172 (*j)->remove_RCR(this, r);
2173 }
2174 }
2175
2176 for(OksObject::FSet::const_iterator j = removed_objs.begin(); j != removed_objs.end(); ++j) {
2177 if(added_objs.find(*j) == added_objs.end()) {
2178 try { (*j)->add_RCR(this, r); } catch (oks::exception&) { ; }
2179 }
2180 }
2181
2182 throw oks::ObjectSetError(this, true, r->get_name(), ex);
2183 }
2184 }
2185 }
2186
2187 data[offset] = *d;
2188
2189 notify();
2190}
2191
2192
2193void
2194OksObject::SetRelationshipValue(const std::string& name, OksData *d, bool skip_non_null_check)
2195{
2196 OksDataInfo::Map::iterator i = uid.class_id->p_data_info->find(name);
2197
2198 if(i == uid.class_id->p_data_info->end()) {
2199 std::ostringstream text;
2200 text << "object " << this << " has no relationship \"" << name << '\"';
2201 throw oks::ObjectSetError(this, true, name, text.str());
2202 }
2203
2204 SetRelationshipValue(i->second, d, skip_non_null_check);
2205}
2206
2207
2208void
2210{
2211 const OksRelationship *r = odi->relationship;
2212 OksData& d(data[odi->offset]);
2213
2214 if( r->get_high_cardinality_constraint() == OksRelationship::Many ) {
2215 std::ostringstream text;
2216 text << "cannot set value " << object << " since the relationship has \'many\' high cardinality constraint";
2217 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2218 }
2219
2220 if(!object) {
2221 check_non_null(r, object);
2222 }
2223 else {
2224 check_class_type(r, object);
2225 }
2226
2227 check_file_lock(0, r);
2228
2229 if((d.type == OksData::object_type) && d.data.OBJECT) {
2230 d.data.OBJECT->remove_RCR(this, r);
2231 }
2232
2233 if(object) {
2234 try {
2235 object->add_RCR(this, r);
2236 }
2237 catch(oks::exception& ex) {
2238 // restore RCR and throw exception
2239 if((d.type == OksData::object_type) && d.data.OBJECT)
2240 try { d.data.OBJECT->add_RCR(this, r); } catch(oks::exception& ex2) { ; }
2241 throw oks::ObjectSetError(this, true, r->get_name(), ex);
2242 }
2243 }
2244
2245 d.Set(object);
2246
2247 notify();
2248}
2249
2250
2251void
2252OksObject::SetRelationshipValue(const std::string& name, OksObject *o)
2253{
2254 OksDataInfo::Map::iterator i = uid.class_id->p_data_info->find(name);
2255
2256 if(i == uid.class_id->p_data_info->end()) {
2257 std::ostringstream text;
2258 text << "object " << this << " has no relationship \"" << name << '\"';
2259 throw oks::ObjectSetError(this, true, name, text.str());
2260 }
2261
2262 SetRelationshipValue(i->second, o);
2263}
2264
2265
2266
2267static bool
2269{
2270 if(d->type == OksData::object_type && d2->type == OksData::object_type)
2271 return ((d2->data.OBJECT == d->data.OBJECT) ? true : false);
2272
2273 const std::string& object_id =
2274 d->type == OksData::object_type ? d->data.OBJECT->GetId() :
2275 d->type == OksData::uid2_type ? *(static_cast<std::string*>(d->data.UID2.object_id)) :
2276 *(static_cast<std::string*>(d->data.UID.object_id));
2277
2278 const std::string& object_id2 =
2279 d2->type == OksData::object_type ? d2->data.OBJECT->GetId() :
2280 d2->type == OksData::uid2_type ? *(static_cast<std::string*>(d2->data.UID2.object_id)) :
2281 *(static_cast<std::string*>(d2->data.UID.object_id));
2282
2283 if(object_id != object_id2) return false;
2284
2285 const OksClass *pclass_id =
2286 d->type == OksData::object_type ? d->data.OBJECT->GetClass() :
2287 d->type == OksData::uid_type ? d->data.UID.class_id :
2288 0;
2289
2290 const OksClass *pclass_id2 =
2291 d2->type == OksData::object_type ? d2->data.OBJECT->GetClass() :
2292 d2->type == OksData::uid_type ? d2->data.UID.class_id :
2293 0;
2294
2295 if(pclass_id && pclass_id2) return (pclass_id == pclass_id2 ? true : false);
2296
2297 const std::string& class_id =
2298 (pclass_id ? pclass_id->get_name() : *(static_cast<std::string*>(d->data.UID2.class_id)));
2299
2300 const std::string& class_id2 =
2301 (pclass_id2 ? pclass_id2->get_name() : *(static_cast<std::string*>(d2->data.UID2.class_id)));
2302
2303 return (class_id == class_id2 ? true : false);
2304}
2305
2306
2307void
2309{
2310 const OksRelationship * r = odi->relationship;
2311 size_t offset = odi->offset;
2312
2313 if(!object) {
2314 throw oks::ObjectSetError(this, true, r->get_name(), "the (null) value is not allowed");
2315 }
2316
2317 check_class_type(r, object);
2318
2319 if( r->get_high_cardinality_constraint() != OksRelationship::Many ) {
2320 std::ostringstream text;
2321 text << "cannot add value " << object << " since the relationship has no \'many\' high cardinality constraint";
2322 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2323 }
2324
2325 try {
2326 object->add_RCR(this, r);
2327 }
2328 catch(oks::exception& ex) {
2329 throw oks::ObjectSetError(this, true, r->get_name(), ex);
2330 }
2331
2332 check_file_lock(0, r);
2333
2334 data[offset].data.LIST->push_back(new OksData(object));
2335
2336 notify();
2337}
2338
2339
2340void
2341OksObject::AddRelationshipValue(const std::string& name, OksObject *object)
2342{
2343 OksDataInfo::Map::iterator i = uid.class_id->p_data_info->find(name);
2344
2345 if(i == uid.class_id->p_data_info->end()) {
2346 std::ostringstream text;
2347 text << "object " << this << " has no relationship \"" << name << '\"';
2348 throw oks::ObjectSetError(this, true, name, text.str());
2349 }
2350
2351 AddRelationshipValue(i->second, object);
2352}
2353
2354
2355void
2357{
2358 const OksRelationship * r = odi->relationship;
2359
2360 if(!object) {
2361 throw oks::ObjectSetError(this, true, r->get_name(), "cannot remove (null) object");
2362 }
2363
2364 if(r->get_high_cardinality_constraint() != OksRelationship::Many) {
2365 std::ostringstream text;
2366 text << "cannot remove object " << object << " since the relationship has no \'many\' high cardinality constraint";
2367 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2368 }
2369
2370 OksData d(object);
2371 size_t offset = odi->offset;
2372 OksData::List * list = data[offset].data.LIST;
2373
2374 for(OksData::List::iterator i = list->begin(); i != list->end();) {
2375 OksData * d2 = *i;
2376 if(cmp_data(d2, &d)) {
2377 check_file_lock(0, r);
2378 object->remove_RCR(this, r);
2379 list->erase(i);
2380 delete d2;
2381 notify();
2382 return;
2383 }
2384 else ++i;
2385 }
2386
2387 std::ostringstream text;
2388 text << "cannot remove object " << object << " since the relationship\'s value has no such object";
2389 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2390}
2391
2392
2393void
2394OksObject::RemoveRelationshipValue(const std::string& name, OksObject * object)
2395{
2396 OksDataInfo::Map::iterator i = uid.class_id->p_data_info->find(name);
2397
2398 if(i == uid.class_id->p_data_info->end()) {
2399 std::ostringstream text;
2400 text << "object " << this << " has no relationship \"" << name << '\"';
2401 throw oks::ObjectSetError(this, true, name, text.str());
2402 }
2403
2404 RemoveRelationshipValue(i->second, object);
2405}
2406
2407void
2408OksObject::SetRelationshipValue(const std::string& name, const std::string& class_id, const std::string& object_id)
2409{
2410 OksDataInfo::Map::iterator i = uid.class_id->p_data_info->find(name);
2411
2412 if(i == uid.class_id->p_data_info->end()) {
2413 std::ostringstream text;
2414 text << "object " << this << " has no relationship \"" << name << '\"';
2415 throw oks::ObjectSetError(this, true, name, text.str());
2416 }
2417
2418 OksDataInfo * odi = i->second;
2419
2420
2421 const OksRelationship * r = odi->relationship;
2422 size_t offset = odi->offset;
2423
2424 if(object_id.empty() || class_id.empty()) {
2425 check_non_null(r, 0);
2426 check_file_lock(0, r);
2427
2428 if( (data[offset].type == OksData::object_type) && data[offset].data.OBJECT ) {
2429 data[offset].data.OBJECT->remove_RCR(this, r);
2430 }
2431
2432 data[offset].Set((OksObject *)0);
2433
2434 notify();
2435
2436 return;
2437 }
2438
2439 OksClass *c = uid.class_id->p_kernel->find_class(class_id);
2440
2441 if(c) {
2442 check_class_type(r, c);
2443 }
2444 else if(r->get_type() != class_id) {
2445 std::ostringstream text;
2446 text << "cannot set value \"" << object_id << '@' << class_id << "\" since the class \"" << class_id
2447 << "\" is not defined and it is impossible to check its validity for given type of relationship";
2448 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2449 }
2450
2451 if(r->get_high_cardinality_constraint() == OksRelationship::Many) {
2452 std::ostringstream text;
2453 text << "cannot set object \"" << object_id << '@' << class_id << "\" since the relationship has \'many\' high cardinality constraint";
2454 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2455 }
2456
2457 OksObject *o = nullptr;
2458
2459 if(c) o = c->get_object(object_id);
2460
2461 if(o) {
2462 SetRelationshipValue(name, o);
2463 }
2464 else {
2465 check_file_lock(0, r);
2466
2467 if( (data[offset].type == OksData::object_type) && data[offset].data.OBJECT ) {
2468 data[offset].data.OBJECT->remove_RCR(this, r);
2469 }
2470
2471 data[offset].Set(class_id, object_id);
2472
2473 notify();
2474 }
2475}
2476
2477
2478void
2479OksObject::AddRelationshipValue(const std::string& name, const std::string& class_id, const std::string& object_id)
2480{
2481 OksDataInfo::Map::iterator i = uid.class_id->p_data_info->find(name);
2482
2483 if(i == uid.class_id->p_data_info->end()) {
2484 std::ostringstream text;
2485 text << "object " << this << " has no relationship \"" << name << '\"';
2486 throw oks::ObjectSetError(this, true, name, text.str());
2487 }
2488
2489 OksDataInfo * odi = i->second;
2490 const OksRelationship * r = odi->relationship;
2491
2492 if(class_id.empty() || object_id.empty()) {
2493 throw oks::ObjectSetError(this, true, r->get_name(), "cannot add (null) object");
2494 }
2495
2496 const std::string& r_class_type = r->get_type();
2497 size_t offset = odi->offset;
2498
2499 OksClass *c = uid.class_id->p_kernel->find_class(class_id);
2500
2501 if(c) {
2502 check_class_type(r, c);
2503 }
2504 else if(r_class_type != class_id) {
2505 std::ostringstream text;
2506 text << "cannot add value \"" << object_id << '@' << class_id << "\" since the class \"" << class_id
2507 << "\" is not defined and it is impossible to check its validity for given type of relationship";
2508 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2509 }
2510
2511 if(r->get_high_cardinality_constraint() != OksRelationship::Many) {
2512 std::ostringstream text;
2513 text << "cannot add object \"" << object_id << '@' << class_id << "\" since the relationship has no \'many\' high cardinality constraint";
2514 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2515 }
2516
2517 OksObject *o = nullptr;
2518
2519 if(c) o = c->get_object(object_id);
2520
2521 if(o) {
2522 AddRelationshipValue(odi, o);
2523 }
2524 else {
2525 check_file_lock(0, r);
2526 data[offset].data.LIST->push_back(new OksData(class_id, object_id));
2527 notify();
2528 }
2529}
2530
2531
2532void
2533OksObject::RemoveRelationshipValue(const std::string& name, const std::string& class_id, const std::string& object_id)
2534{
2535 OksDataInfo::Map::iterator i = uid.class_id->p_data_info->find(name);
2536
2537 if(i == uid.class_id->p_data_info->end()) {
2538 std::ostringstream text;
2539 text << "object " << this << " has no relationship \"" << name << '\"';
2540 throw oks::ObjectSetError(this, true, name, text.str());
2541 }
2542
2543 OksDataInfo * odi = i->second;
2544 const OksRelationship * r = odi->relationship;
2545
2546 if(object_id.empty() || class_id.empty()) {
2547 throw oks::ObjectSetError(this, true, r->get_name(), "cannot remove (null) object");
2548 }
2549
2550 if( r->get_high_cardinality_constraint() != OksRelationship::Many ) {
2551 std::ostringstream text;
2552 text << "cannot remove object \"" << object_id << '@' << class_id << "\" since the relationship has no \'many\' high cardinality constraint";
2553 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2554 }
2555
2556 size_t offset = odi->offset;
2557 OksData d(class_id, object_id);
2558 OksData::List * list = data[offset].data.LIST;
2559
2560 for(OksData::List::iterator j = list->begin(); j != list->end();) {
2561 OksData * d2 = *j;
2562 if(cmp_data(d2, &d)) {
2563 check_file_lock(0, r);
2564 list->erase(j);
2565 delete d2;
2566 notify();
2567 return;
2568 }
2569 else ++j;
2570 }
2571
2572 std::ostringstream text;
2573 text << "cannot remove object \"" << object_id << '@' << class_id << "\" since the relationship\'s value has no such object";
2574 throw oks::ObjectSetError(this, true, r->get_name(), text.str());
2575}
2576
2577
2578void
2580{
2581 if(r->get_is_composite() == false) return;
2582
2583 TLOG_DEBUG(4) << "object " << this << " adds RCR to object " << o << " throught relationship \"" << r->get_name() << '\"';
2584
2585 if(!p_rcr) {
2586 p_rcr = new std::list<OksRCR *>();
2587 }
2588 else {
2589 for(const auto& i : *p_rcr) {
2590 if(i->relationship == r) {
2591 if(i->obj == o) {
2592 TLOG_DEBUG(4) << "[this=" << this << ", o=" << o << ", r=\"" << r->get_name() << "\"]: such RCR was already set.";
2593 return;
2594 }
2595 else if(r->get_is_exclusive()) {
2596 throw oks::AddRcrError(this, r->get_name(), o, i->obj);
2597 }
2598 }
2599 }
2600 }
2601
2602 p_rcr->push_back(new OksRCR(o, r));
2603}
2604
2605
2606void
2608{
2609 TLOG_DEBUG(4) << "object " << this << " removes RCR from object " << o << " through " << r->get_name();
2610
2611 if(r->get_is_composite() == false || !p_rcr) return;
2612
2613 for(std::list<OksRCR *>::iterator i = p_rcr->begin(); i != p_rcr->end(); ++i) {
2614 OksRCR *rcr = *i;
2615
2616 if(rcr->obj == o && rcr->relationship == r) {
2617 p_rcr->erase(i);
2618 delete rcr;
2619 break;
2620 }
2621 }
2622
2623 if(p_rcr->empty()) {
2624 delete p_rcr;
2625 p_rcr = nullptr;
2626 }
2627}
2628
2629
2630void
2632{
2633 const OksClass * c(0);
2634 OksObject * o(0);
2635
2636 if(d->type == OksData::uid_type) {
2637 if(d->data.UID.class_id && !d->data.UID.object_id->empty()) {
2638 c = d->data.UID.class_id;
2639 o = c->get_object(d->data.UID.object_id);
2640 }
2641 else {
2642 d->Set((OksObject *)0);
2643 return;
2644 }
2645 }
2646 else {
2647 if(d->data.UID2.class_id->empty() || d->data.UID2.object_id->empty()) {
2648 d->Set((OksObject *)0);
2649 return;
2650 }
2651
2652 c = info.k->find_class(*d->data.UID2.class_id);
2653
2654 if(c) {
2655 o = c->get_object(d->data.UID2.object_id);
2656 }
2657 else {
2658 std::ostringstream text;
2659 text << "Class of object " << *d << " is not defined";
2660 throw oks::ObjectBindError(info.o, d, info.r, true, text.str(), "");
2661 }
2662 }
2663
2664 if(c != info.r->p_class_type) {
2665 if(const OksClass::FList * slist = c->all_super_classes()) {
2666 for(OksClass::FList::const_iterator i = slist->begin(); i != slist->end(); ++i) {
2667 if(info.r->p_class_type == *i) {
2668 goto check_passed;
2669 }
2670 }
2671 }
2672
2673 {
2674 std::ostringstream text;
2675 text << "The relationship has class type \"" << info.r->get_type() << "\" and the referenced object " << *d << " is not of that class or derived one";
2676 throw oks::ObjectBindError(info.o, d, info.r, true, text.str(), "");
2677 }
2678
2679 check_passed: ;
2680 }
2681
2682 if(!o) {
2683 std::ostringstream text;
2684 text << "Cannot find object " << *d;
2685 throw oks::ObjectBindError(info.o, d, info.r, false, text.str(), "");
2686 }
2687
2688 try {
2689 d->Set(o);
2690 o->add_RCR(info.o, info.r);
2691 }
2692 catch(oks::exception& ex) {
2693 std::ostringstream text;
2694 text << "Failed to set relationship value " << o;
2695 throw oks::ObjectBindError(info.o, d, info.r, true, text.str(), ex);
2696 }
2697}
2698
2699
2701 std::ostringstream * p_warnings; // in 99.999% cases there is no need to call the constructor
2702 unsigned int p_warnings_count;
2703
2706
2707 void add(const OksData& d, const OksRelationship * r);
2708 void add(const OksRelationship * r);
2709 std::ostringstream& add();
2710};
2711
2712std::ostringstream&
2714{
2715 if(p_warnings_count != 0) (*p_warnings) << '\n';
2716 else {p_warnings = new std::ostringstream();}
2718 return *p_warnings;
2719}
2720
2721
2722void
2724{
2725 add() << " * object " << d << " via relationship \"" << r->get_name() << '\"';
2726}
2727
2728void
2730{
2731 add() << " * relationship \"" << r->get_name() << "\" has non-zero low cardinality constraint, but it is empty";
2732}
2733
2734
2735void
2737{
2738 const OksClass * c = uid.class_id;
2739
2740 if(c->p_all_relationships->empty()) return; // if class has no relationships then nothing to do
2741
2742 BindInfo info;
2743 info.k = c->p_kernel;
2744 info.o = this;
2745
2746 OksData * d(data + c->number_of_all_attributes());
2747
2748 BindWarning warnings;
2749
2750 for (auto & i : (*c->p_all_relationships))
2751 {
2752 info.r = i;
2753
2754 if(d->type == OksData::object_type)
2755 {
2756 if (i->get_low_cardinality_constraint() == OksRelationship::One && d->data.OBJECT == nullptr) { warnings.add(i); }
2757 }
2758 else if (d->type == OksData::uid_type)
2759 {
2760 if (d->data.UID.object_id == nullptr)
2761 {
2762 if (i->get_low_cardinality_constraint() == OksRelationship::One) { warnings.add(i); }
2763 }
2764
2765 try
2766 {
2767 bind(d, info);
2768 }
2769 catch (oks::ObjectBindError& ex)
2770 {
2771 if (ex.p_is_error) { throw; }
2772 else { warnings.add(*ex.p_data, ex.p_rel); }
2773 }
2774 }
2775 else if (d->type == OksData::list_type)
2776 {
2777 if (d->data.LIST->empty())
2778 {
2779 if (i->get_low_cardinality_constraint() == OksRelationship::One) { warnings.add(i); }
2780 }
2781 else
2782 {
2783 for (const auto& i2 : *d->data.LIST)
2784 {
2785 if (i2->type == OksData::uid_type || i2->type == OksData::uid2_type)
2786 {
2787 try
2788 {
2789 bind(i2, info);
2790 }
2791 catch (oks::ObjectBindError& ex)
2792 {
2793 if (ex.p_is_error) { throw; }
2794 else { warnings.add(*ex.p_data, ex.p_rel); }
2795 }
2796 }
2797 }
2798 }
2799 }
2800 else if (d->type == OksData::uid2_type)
2801 {
2802 if (i->get_low_cardinality_constraint() == OksRelationship::One && d->data.UID2.object_id == nullptr) { warnings.add(i); }
2803 try
2804 {
2805 bind(d, info);
2806 }
2807 catch (oks::ObjectBindError& ex)
2808 {
2809 if (ex.p_is_error) { throw; }
2810 else { warnings.add(*ex.p_data, ex.p_rel); }
2811 }
2812 }
2813
2814 d++;
2815 }
2816
2817 if(warnings.p_warnings_count)
2818 {
2819 std::ostringstream text;
2820 const char * s1(warnings.p_warnings_count == 1 ? "is" : "are");
2821 const char * s2(warnings.p_warnings_count == 1 ? "" : "s");
2822 text << "There " << s1 << " " << warnings.p_warnings_count << " unresolved reference" << s2 << " from object " << this
2823 << '\n' << warnings.p_warnings->str();
2824 throw oks::ObjectBindError(this, 0, 0, false, text.str(), "");
2825 }
2826}
2827
2828
2829void
2831{
2832 const size_t num_of_attrs (uid.class_id->number_of_all_attributes());
2833 const size_t num_of_rels (uid.class_id->number_of_all_relationships());
2834
2835 bool verbose = GetClass()->get_kernel()->get_verbose_mode();
2836
2837 for(size_t i = 0; i < num_of_rels; ++i) {
2838 OksData *d = &data[i + num_of_attrs];
2839
2840 if(d) {
2841 if(d->type == OksData::object_type) {
2842 OksObject * o = d->data.OBJECT;
2843
2844 if(o && o->file == f) {
2845 if(verbose)
2846 std::cout << "- unbind_file(\'" << f->get_full_file_name() << "\') in " << this << ": replace " << *d;
2847
2848 d->Set(o->GetClass(), o->GetId());
2849
2850 if(verbose) std::cout << " by " << *d << std::endl;
2851 }
2852 }
2853 else if(d->type == OksData::list_type && d->data.LIST) {
2854 for(const auto& j : *d->data.LIST) {
2855 if(j && j->type == OksData::object_type) {
2856 OksObject * o = j->data.OBJECT;
2857
2858 if(o && o->file == f) {
2859 if(verbose)
2860 std::cout << "+ unbind_file(\'" << f->get_full_file_name() << "\') in " << this << ": replace " << *j;
2861
2862 j->Set(o->GetClass(), o->GetId());
2863
2864 if(verbose) std::cout << " by " << *j << std::endl;
2865 }
2866 }
2867 }
2868 }
2869 }
2870 }
2871}
2872
2875{
2876 return uid.class_id->p_kernel->p_change_object_notify_fn;
2877}
2878
2882
2883void
2885{
2886 OksKernel * k = uid.class_id->p_kernel;
2887
2890 }
2891}
2892
2896
2897void
2899{
2900 OksKernel * k = uid.class_id->p_kernel;
2903 }
2904}
2905
2909
2910void
2912{
2913 OksKernel * k = uid.class_id->p_kernel;
2914
2917 }
2918}
2919
2920bool
2921OksObject::check_links_and_report(const OksObject * o2, const std::set<OksFile *>& includes, const std::string& name, const char * msg) const
2922{
2923 if(get_file() != o2->get_file()) {
2924 if(includes.find(o2->get_file()) == includes.end()) {
2925 if(GetClass()->get_kernel()->get_silence_mode() == false) {
2926 std::cerr <<
2927 msg << ": no files inclusion path between referenced objects:\n"
2928 " object " << this << " from file \"" << get_file()->get_full_file_name() << "\" via relationship \"" << name << "\"\n"
2929 " has reference to object " << o2 << " from file \"" << o2->get_file()->get_full_file_name() << "\";\n"
2930 " file \"" << get_file()->get_full_file_name() << "\" includes " << includes.size() << " files:\n";
2931
2932 for(std::set<OksFile *>::const_iterator j = includes.begin(); j != includes.end(); ++j) {
2933 std::cerr << " * \'" << (*j)->get_full_file_name() << "\'\n";
2934 }
2935
2936 }
2937
2938 return false;
2939 }
2940 }
2941
2942 return true;
2943}
2944
2945static void
2946test_dangling_references(const OksObject * obj, const OksData& d, const OksRelationship& r, std::string& result)
2947{
2948 if(d.type == OksData::uid_type || d.type == OksData::uid2_type) {
2949 std::ostringstream text;
2950
2951 if(result.empty()) {
2952 text << " * object " << obj << " has dangling references:\n";
2953 }
2954
2955 text << " - object " << d << " referenced via \'" << r.get_name() << "\'\n";
2956
2957 result += text.str();
2958 }
2959}
2960
2961std::string
2963{
2964 unsigned short l1 = GetClass()->number_of_all_attributes();
2965 unsigned short l2 = l1 + GetClass()->number_of_all_relationships();
2966
2967 std::list<OksRelationship *>::const_iterator ri = GetClass()->all_relationships()->begin();
2968
2969 std::string result;
2970
2971 while(l1 < l2) {
2972 OksDataInfo odi(l1, *ri);
2973 OksData * d(GetRelationshipValue(&odi));
2974
2975 if(d->type == OksData::list_type) {
2976 for(OksData::List::const_iterator li = d->data.LIST->begin(); li != d->data.LIST->end(); ++li) {
2977 test_dangling_references(this, **li, **ri, result);
2978 }
2979 }
2980 else {
2981 test_dangling_references(this, *d, **ri, result);
2982 }
2983
2984 ++l1;
2985 ++ri;
2986 }
2987
2988 return result;
2989}
2990
2991
2992bool
2993OksObject::is_consistent(const std::set<OksFile *>& includes, const char * msg) const
2994{
2995 unsigned short l1 = GetClass()->number_of_all_attributes();
2996 unsigned short l2 = l1 + GetClass()->number_of_all_relationships();
2997
2998 std::list<OksRelationship *>::const_iterator ri = GetClass()->all_relationships()->begin();
2999
3000 bool return_value = true;
3001
3002 while(l1 < l2) {
3003 OksDataInfo odi(l1, *ri);
3004 OksData * d(GetRelationshipValue(&odi));
3005
3006 if(d->type == OksData::object_type) {
3007 if(OksObject * o2 = d->data.OBJECT) {
3008 check_links_and_report(o2, includes, odi.relationship->get_name(), msg);
3009 }
3010 }
3011 else if(d->type == OksData::list_type) {
3012 for(OksData::List::const_iterator li = d->data.LIST->begin(); li != d->data.LIST->end(); ++li) {
3013 if((*li)->type == OksData::object_type) {
3014 if(OksObject * o2 = (*li)->data.OBJECT) {
3015 check_links_and_report(o2, includes, odi.relationship->get_name(), msg);
3016 }
3017 }
3018 }
3019 }
3020
3021 if(d->IsConsistent(odi.relationship, this, "ERROR") == false) {
3022 return_value = false;
3023 }
3024
3025 ++l1;
3026 ++ri;
3027 }
3028
3029 // check inclusion of the schema file
3030
3031 if(includes.find(GetClass()->get_file()) == includes.end()) {
3032 if(GetClass()->get_kernel()->get_silence_mode() == false) {
3033 std::cerr <<
3034 "ERROR: the schema file is not included for object " << this << ".\n"
3035 " The data file \"" << get_file()->get_full_file_name() << "\" containg above object\n"
3036 " cannot be loaded or edited without inclusion of additional files.\n"
3037 " The file shall explicitly or implicitly (i.e. via other included files) include schema file\n"
3038 " \"" << GetClass()->get_file()->get_full_file_name() << "\" defining class \"" << GetClass()->get_name() << "\".\n";
3039 }
3040
3041 return false;
3042 }
3043
3044
3045 return return_value;
3046}
3047
3048
3058
3059
3060static void _references(const OksObject * obj, unsigned long recursion_depth, RefData& data);
3061
3062
3063static void
3064insert2refs(const OksObject *o, unsigned long recursion_depth, RefData& data)
3065{
3066 recursion_depth--;
3067
3068 std::pair<OksObject::FSet::iterator,bool> ret = data.tested_objs.insert(const_cast<OksObject *>(o));
3069
3070 if(ret.second==true) {
3071 if(data.classes == nullptr || data.classes->find(const_cast<OksClass *>(o->GetClass())) != data.classes->end()) {
3072 data.refs.insert(const_cast<OksObject *>(o));
3073 }
3074 o->SetTransientData((void *)recursion_depth);
3075 _references(o, recursion_depth, data);
3076 }
3077 else if(o->GetTransientData() < (void *)recursion_depth) {
3078 o->SetTransientData((void *)recursion_depth);
3079 _references(o, recursion_depth, data);
3080 }
3081}
3082
3083static void
3084_references(const OksObject * obj, unsigned long recursion_depth, RefData& data)
3085{
3086 if(recursion_depth == 0) return;
3087
3088 size_t l1 = obj->GetClass()->number_of_all_attributes();
3089 size_t l2 = l1 + obj->GetClass()->number_of_all_relationships();
3090
3091 while(l1 < l2) {
3092 OksDataInfo odi(l1, (OksRelationship *)0);
3093 OksData * d(obj->GetRelationshipValue(&odi));
3094
3095 if(d->type == OksData::object_type) {
3096 if(OksObject * o2 = d->data.OBJECT) {
3097 insert2refs(o2, recursion_depth, data);
3098 }
3099 }
3100 else if(d->type == OksData::list_type) {
3101 for(OksData::List::const_iterator li = d->data.LIST->begin(); li != d->data.LIST->end(); ++li) {
3102 if((*li)->type == OksData::object_type) {
3103 if(OksObject * o2 = (*li)->data.OBJECT) {
3104 insert2refs(o2, recursion_depth, data);
3105 }
3106 }
3107 }
3108 }
3109
3110 ++l1;
3111 }
3112}
3113
3114void
3115OksObject::references(OksObject::FSet& refs, unsigned long recursion_depth, bool add_self, oks::ClassSet * classes) const
3116{
3117 struct RefData data(refs, classes);
3118
3119 std::lock_guard lock(uid.class_id->p_kernel->p_objects_refs_mutex);
3120
3121 OksObject::FSet tested_objs;
3122
3123 if(add_self) {
3124 insert2refs(this, recursion_depth + 1, data);
3125 }
3126
3127 _references(this, recursion_depth, data);
3128
3129 TLOG_DEBUG(2) << "OksObject::references(" << this << ", " << recursion_depth << ") returns " << refs.size() << " objects";
3130}
3131
3132
3134OksObject::get_all_rels(const std::string& name) const
3135{
3136 bool any_name = (name == "*");
3137
3138 OksObject::FList * result = nullptr;
3139
3140 const OksClass::Map& all_classes(GetClass()->get_kernel()->classes());
3141
3142 for(OksClass::Map::const_iterator i = all_classes.begin(); i != all_classes.end(); ++i) {
3143 OksClass * c(i->second);
3144 if(any_name || c->find_relationship(name) != nullptr) {
3145 if(const OksObject::Map * objs = i->second->objects()) {
3146 for(OksObject::Map::const_iterator j = objs->begin(); j != objs->end(); ++j) {
3147 OksObject *o(j->second);
3148 unsigned short l1, l2;
3149
3150 if(any_name) {
3151 l1 = c->number_of_all_attributes();
3152 l2 = l1 + c->number_of_all_relationships();
3153 }
3154 else {
3155 l1 = c->data_info(name)->offset;
3156 l2 = l1+1;
3157 }
3158
3159 while(l1 < l2) {
3160 OksDataInfo odi(l1, (OksRelationship *)0);
3161 OksData * d(o->GetRelationshipValue(&odi));
3162
3163 if(d->type == OksData::object_type) {
3164 if(this == d->data.OBJECT) {
3165 if(!result) result = new OksObject::FList();
3166 result->push_back(o);
3167 break;
3168 }
3169 }
3170 else if(d->type == OksData::list_type) {
3171 bool found = false;
3172 for(OksData::List::const_iterator li = d->data.LIST->begin(); li != d->data.LIST->end(); ++li) {
3173 OksData * lid(*li);
3174 if(lid->type == OksData::object_type) {
3175 if(this == lid->data.OBJECT) {
3176 if(!result) result = new OksObject::FList();
3177 result->push_back(o);
3178 found = true;
3179 break; // exit given relationship value iterator
3180 }
3181 }
3182 }
3183 if(found) break; //exit relationships iterator for given object
3184 }
3185 ++l1;
3186 }
3187 }
3188 }
3189 }
3190 }
3191
3192 return result;
3193}
3194
3195void
3197{
3198 try {
3199 file->lock();
3200 }
3201 catch(oks::exception& ex) {
3202 throw oks::ObjectSetError(this, (a == nullptr), (a ? a->get_name() : r->get_name()), ex);
3203 }
3204}
3205
3206} // namespace oks
3207} // namespace dunedaq
static std::string fill(const OksObject *obj, const std::string &name, const OksObject *p1, const OksObject *p2)
Definition object.cpp:114
Failed move item to file.
Definition kernel.hpp:281
static std::string fill(const OksObject *o, const std::string &reason)
Definition object.cpp:66
static std::string fill(const OksObject *o, const std::string &reason)
Definition object.cpp:90
static std::string fill(const OksObject *o, const std::string &what, const std::string &reason)
Definition object.cpp:58
static std::string fill(const OksObject *o, const std::string &reason)
Definition object.cpp:82
static std::string fill(const OksObject *o, const std::string &reason)
Definition object.cpp:74
std::string fill(const OksObject *obj, const OksRelationship *rel, const std::string &why, const std::string &reason)
Definition object.cpp:130
const OksRelationship * p_rel
Definition object.hpp:308
static std::string fill(const OksObject *obj, bool is_rel, const std::string &name, const std::string &reason)
Definition object.cpp:106
static std::string fill(const OksObject *obj, const std::string &why, const std::string &reason)
Definition object.cpp:122
static std::string fill(const OksObject *obj, bool is_rel, const std::string &name, const std::string &reason)
Definition object.cpp:98
OKS attribute class.
static const char * s8_int_type
static const char * u32_int_type
static const char * u8_int_type
static const char * time_type
static const char * s64_int_type
bool get_is_multi_values() const noexcept
static const char * bool_type
const std::string & get_type() const noexcept
Get attribute string type.
const std::string & get_name() const noexcept
out stream operator
static const char * class_type
static const char * string_type
static const char * enum_type
static const char * s32_int_type
static const char * s16_int_type
OksData::Type get_data_type() const noexcept
static const char * u64_int_type
static const char * double_type
const std::string & get_init_value() const noexcept
const std::string * get_enum_value(const char *s, size_t length) const
Returns pointer on internal enumerator data equal to given string, if such string is defined in attri...
static const char * u16_int_type
static const char * date_type
static const char * float_type
static OksData::Type get_data_type(const std::string &type) noexcept
Converts string to attribute OKS data type.
The OKS class.
Definition class.hpp:205
OksKernel * p_kernel
Definition class.hpp:958
const std::list< OksAttribute * > * all_attributes() const noexcept
Definition class.hpp:480
size_t number_of_all_relationships() const noexcept
Definition class.hpp:1055
std::list< OksClass *, boost::fast_pool_allocator< OksClass * > > FList
Definition class.hpp:240
OksKernel * get_kernel() const noexcept
Definition class.hpp:338
const std::string & get_name() const noexcept
Definition class.hpp:368
size_t number_of_all_attributes() const noexcept
Definition class.hpp:1041
OksClass(const std::string &name, OksKernel *kernel, bool transient=false)
Create OKS class.
Definition class.cpp:80
friend class OksObject
Definition class.hpp:206
std::map< const char *, OksClass *, SortStr > Map
Definition class.hpp:238
OksFile * get_file() const noexcept
Definition class.hpp:343
const std::list< OksRelationship * > * all_relationships() const noexcept
Definition class.hpp:590
Provides interface to the OKS XML schema and data files.
Definition file.hpp:345
void lock()
Lock OKS file.
Definition file.cpp:1017
const std::string & get_full_file_name() const
Definition file.hpp:528
OksObject * remove_obj(OksObject *)
Definition index.cpp:99
Provides interface to the OKS kernel.
Definition kernel.hpp:582
OksObject::notify_obj p_change_object_notify_fn
Definition kernel.hpp:2166
OksFile * get_active_data() const
Get active OKS data file.
Definition kernel.hpp:1486
bool is_dangling(OksClass *class_ptr) const
Check pointer on oks class.
Definition kernel.cpp:4643
static std::mutex p_parallel_out_mutex
Definition kernel.hpp:2051
bool get_verbose_mode() const
Get status of verbose mode. The method returns true, if the verbose mode is switched 'On'.
Definition kernel.hpp:670
bool get_test_duplicated_objects_via_inheritance_mode() const
Get status of test inherited duplicated objects mode. The method returns true, if the mode is switche...
Definition kernel.hpp:770
OksObject::notify_obj p_delete_object_notify_fn
Definition kernel.hpp:2169
bool get_allow_duplicated_objects_mode() const
Get status of duplicated objects mode. The method returns true, if the duplicated objects mode is swi...
Definition kernel.hpp:746
const OksClass::Map & classes() const
Get classes.
Definition kernel.hpp:1772
void * p_delete_object_notify_param
Definition kernel.hpp:2170
void undefine(OksObject *o)
Definition kernel.hpp:2154
void * p_change_object_notify_param
Definition kernel.hpp:2167
OksObject::notify_obj p_create_object_notify_fn
Definition kernel.hpp:2163
bool get_silence_mode() const
Get status of silence mode. The method returns true, if the silence mode is switched 'On'....
Definition kernel.hpp:691
std::shared_mutex p_schema_mutex
Definition kernel.hpp:2050
void * p_create_object_notify_param
Definition kernel.hpp:2164
OksObject describes instance of OksClass.
Definition object.hpp:841
struct dunedaq::oks::OksObject::OksUid uid
friend class OksClass
Definition object.hpp:842
static void destroy(OksObject *obj, bool fast=false)
Destroy OKS object.
Definition object.cpp:1306
void AddRelationshipValue(const std::string &name, OksObject *object)
Add object value to multi-value relationship by name.
Definition object.cpp:2341
void RemoveRelationshipValue(const std::string &name, OksObject *object)
Remove object value from multi-value relationship by name.
Definition object.cpp:2394
void __report_type_cvt_warning(const oks::ReadFileParams &, const OksAttribute &, const OksData &, const OksData::Type, int32_t) const
Definition object.cpp:456
void check_file_lock(const OksAttribute *, const OksRelationship *)
Definition object.cpp:3196
void put(OksXmlOutputStream &, bool force_defaults) const
Definition object.cpp:1785
std::list< OksRCR * > * p_rcr
Definition object.hpp:1411
OksData * GetRelationshipValue(const std::string &) const
Get value of relationship by name.
Definition object.cpp:2009
static const char class2_xml_attribute[]
Definition object.hpp:1523
static const char relationship_xml_tag[]
Definition object.hpp:1521
friend struct OksData
Definition object.hpp:843
void references(OksObject::FSet &refs, unsigned long recursion_depth, bool add_self=false, oks::ClassSet *classes=0) const
Definition object.cpp:3115
OksFile * get_file() const
Definition object.hpp:1018
void init1(const OksFile *=0)
Definition object.cpp:187
static const char attribute_xml_tag[]
Definition object.hpp:1520
static const char obj2_xml_tag[]
Definition object.hpp:1519
friend class OksIndex
Definition object.hpp:845
static void put_object_attributes(OksXmlOutputStream &, const OksData &)
Definition object.cpp:1759
void __report_cardinality_cvt_warning(const oks::ReadFileParams &, const OksRelationship &) const
Definition object.cpp:490
static const char value_xml_attribute[]
Definition object.hpp:1530
std::string report_dangling_references() const
Definition object.cpp:2962
void SetRelationshipValue(const std::string &name, OksData *data, bool skip_non_null_check=false)
Set value of relationship by name.
Definition object.cpp:2194
void read_body(const oks::ReadFileParams &, bool)
Definition object.cpp:518
int32_t __get_num(const oks::ReadFileParams &params)
Definition object.cpp:507
void add_RCR(OksObject *, const OksRelationship *)
Definition object.cpp:2579
void check_class_type(const OksRelationship *, const OksClass *)
Definition object.cpp:2036
std::unordered_set< OksObject *, oks::hash_obj_ptr, oks::equal_obj_ptr > FSet
Definition object.hpp:871
static const char id_xml_attribute[]
Definition object.hpp:1524
void set_file(OksFile *file, bool update_owner=true)
Move object to different file.
Definition object.cpp:1489
static const char obj_xml_tag[]
Definition object.hpp:1518
friend class OksKernel
Definition object.hpp:844
void(* notify_obj)(OksObject *, void *)
Definition object.hpp:853
static OksObject * read(const oks::ReadFileParams &)
Definition object.cpp:368
FList * get_all_rels(const std::string &name="*") const
Return objects referencing this one via relationship with given name.
Definition object.cpp:3134
void * GetTransientData() const
Get transient user data associated with given object. Return data set using SetTransientData() method...
Definition object.hpp:1348
void check_non_null(const OksRelationship *, const OksObject *)
Definition object.cpp:2024
void unbind_file(const OksFile *)
Definition object.cpp:2830
OksObject(const OksClass *oks_class, const char *object_id=0, bool skip_init=false)
OKS object constructor.
Definition object.cpp:1180
static const char id2_xml_attribute[]
Definition object.hpp:1525
static const char num_xml_attribute[]
Definition object.hpp:1528
std::list< OksObject *, boost::fast_pool_allocator< OksObject * > > FList
Definition object.hpp:882
const OksClass * GetClass() const
Definition object.hpp:995
static bool are_equal_fast(const OksObject *o1, const OksObject *o2)
The fast equal method.
Definition object.cpp:1605
static const char class_xml_attribute[]
Definition object.hpp:1522
static void bind(OksData *, const BindInfo &)
Definition object.cpp:2631
static const char name_xml_attribute[]
Definition object.hpp:1526
void set_id(const std::string &id)
Set object ID.
Definition object.cpp:1511
void remove_RCR(OksObject *, const OksRelationship *) noexcept
Definition object.cpp:2607
static const char type_xml_attribute[]
Definition object.hpp:1527
notify_obj get_change_notify() const
Definition object.cpp:2874
std::unordered_map< const std::string *, OksObject *, oks::hash_str, oks::equal_str > Map
Definition object.hpp:870
static const char data_xml_tag[]
Definition object.hpp:1531
void init2(bool skip_init=false)
Definition object.cpp:280
bool is_consistent(const std::set< OksFile * > &, const char *msg) const
Definition object.cpp:2993
void SetAttributeValue(const std::string &name, OksData *data)
Set value of attribute by name.
Definition object.cpp:1995
bool check_links_and_report(const OksObject *, const std::set< OksFile * > &, const std::string &, const char *) const
Definition object.cpp:2921
bool operator==(const OksObject &) const
The equality operator.
Definition object.cpp:1617
void SetTransientData(void *d) const
Set transient user data associated with given object. Such data are not stored on file and only exist...
Definition object.hpp:1340
static const char ref_xml_tag[]
Definition object.hpp:1532
const std::string & GetId() const
Definition object.hpp:1000
int32_t p_duplicated_object_id_idx
Definition object.hpp:1414
OksData * GetAttributeValue(const std::string &name) const
Get value of attribute by name.
Definition object.cpp:1924
const std::string & get_name() const noexcept
Class OKS string.
Definition object.hpp:374
void throw_unexpected_attribute(const char *what)
Definition xml.cpp:289
unsigned long get_line_no() const
Definition xml.hpp:415
void throw_unexpected_tag(const char *what, const char *expected=0)
Definition xml.cpp:266
unsigned long get_line_pos() const
Definition xml.hpp:416
OksXmlValue get_value(unsigned int len)
Definition xml.hpp:421
void seek_position(std::streamoff off)
Definition xml.hpp:411
static void __throw_strto(const char *f, const char *where, const char *what, unsigned long line_no, unsigned long line_pos)
Definition xml.cpp:625
const char * get_tag_start()
Definition xml.cpp:490
void put_last_tag(const char *, size_t len)
Definition xml.cpp:209
void put_attribute(const char *, size_t len, const char *)
Definition xml.cpp:225
void put_start_tag(const char *, size_t len)
Definition xml.cpp:176
std::ostream & get_stream() const
Definition xml.hpp:126
static std::ostream & warning_msg(const char *)
Definition kernel.cpp:568
static std::ostream & error_msg(const char *)
Definition kernel.cpp:561
virtual const char * what() const noexcept
double offset
#define OSK_PROFILING(FID, K)
Definition defs.hpp:102
#define TLOG_DEBUG(lvl,...)
Definition Logging.hpp:112
bool cmp_str1(const char *s1, const char s2[2])
Definition cstring.hpp:14
bool cmp_str4(const char *s1, const char s2[5])
Definition cstring.hpp:34
bool cmp_str9(const char *s1, const char s2[10])
Definition cstring.hpp:74
static void _references(const OksObject *obj, unsigned long recursion_depth, RefData &data)
Definition object.cpp:3084
static void insert2refs(const OksObject *o, unsigned long recursion_depth, RefData &data)
Definition object.cpp:3064
static void test_dangling_references(const OksObject *obj, const OksData &d, const OksRelationship &r, std::string &result)
Definition object.cpp:2946
void validate_not_empty(const std::string &value, const char *name)
std::ostream & operator<<(std::ostream &s, const oks::exception &ex)
std::unordered_set< const OksClass *, oks::hash_class_ptr, oks::equal_class_ptr > ClassSet
Definition object.hpp:825
bool cmp_str2(const char *s1, const char s2[3])
Definition cstring.hpp:18
bool cmp_str5(const char *s1, const char s2[6])
Definition cstring.hpp:42
static bool trim_dangling(OksData &d, const OksKernel &kernel)
Definition object.cpp:1718
static void __throw_unknown_type(const oks::ReadFileParams &params, const char *atype)
Definition object.cpp:499
bool cmp_str3(const char *s1, const char s2[4])
Definition cstring.hpp:26
static bool cmp_data(OksData *d, OksData *d2)
Definition object.cpp:2268
Including Qt Headers.
Definition module.cpp:16
msgpack::object obj
Definition ral.hpp:35
#define READ_OBJ_HEADER(F1, S1, F2, S2)
Definition object.cpp:332
std::ostringstream & add()
Definition object.cpp:2713
std::ostringstream * p_warnings
Definition object.cpp:2701
void add(const OksData &d, const OksRelationship *r)
Definition object.cpp:2723
unsigned int p_warnings_count
Definition object.cpp:2702
Struct OKS data information.
Definition object.hpp:347
const OksAttribute * attribute
Definition object.hpp:360
const OksRelationship * relationship
Definition object.hpp:361
the structure to pass common parameters to various read() methods of OksData and OksObject class
Definition object.hpp:454
void Set(int8_t c)
Definition object.hpp:548
void sort(bool ascending=true)
void SetNullValue(const OksAttribute *a)
void cvt(OksData *to, const OksAttribute *attr) const
Convert data to new type.
union dunedaq::oks::OksData::Data data
std::list< OksData *, boost::fast_pool_allocator< OksData * > > List
Definition object.hpp:460
void SetValue(const char *s, const OksAttribute *a)
void read(const oks::ReadFileParams &, const OksAttribute *, int32_t)
private methods which can be used by OksObject class only
void SetValues(const char *, const OksAttribute *a)
enum dunedaq::oks::OksData::Type type
void ConvertTo(OksData *, const OksRelationship *) const
void check_range(const OksAttribute *a) const
Check range of data.
void set_init_value(const OksAttribute *attr, bool skip_init)
Set value defined by initial value of attribute.
Definition object.cpp:247
The struct OksRCR describes Reverse Composite Relationship (i.e. back reference from child to composi...
Definition object.hpp:767
OksObject * obj
Definition object.hpp:778
const OksRelationship * relationship
Definition object.hpp:779
size_t value_len() const
Definition xml.hpp:309
OksXmlInputStream & s
Definition oks_utils.hpp:54
ReloadObjects * reload_objects
Definition oks_utils.hpp:58
oks::ClassSet * classes
Definition object.cpp:3052
OksObject::FSet tested_objs
Definition object.cpp:3051
OksObject::FSet & refs
Definition object.cpp:3050
RefData(OksObject::FSet &r, oks::ClassSet *cs)
Definition object.cpp:3054
OksObject * pop(const OksClass *c, const std::string &id)
Definition kernel.cpp:3189
std::vector< OksObject * > created
Definition oks_utils.hpp:42
const OksClass * class_id
Definition object.hpp:505
struct dunedaq::oks::OksData::Data::@266171337063116272021017117226020166361213322350 UID
struct dunedaq::oks::OksData::Data::@226266061051241020017305361066131172152317024337 UID2