Line data Source code
1 : /* File: io_export_model_traversal.c; Copyright and License: see below */
2 :
3 : #include "io_export_model_traversal.h"
4 : #include "u8/u8_trace.h"
5 : #include "entity/data_diagram.h"
6 : #include "entity/data_classifier.h"
7 : #include <stdint.h>
8 : #include <stdio.h>
9 : #include <stdlib.h>
10 :
11 0 : void io_export_model_traversal_init( io_export_model_traversal_t *this_,
12 : data_database_reader_t *db_reader,
13 : data_visible_set_t *input_data,
14 : data_stat_t *io_export_stat,
15 : io_element_writer_t *out_element_writer )
16 : {
17 0 : U8_TRACE_BEGIN();
18 0 : assert( NULL != db_reader );
19 0 : assert( NULL != io_export_stat );
20 0 : assert( NULL != out_element_writer );
21 :
22 0 : (*this_).db_reader = db_reader;
23 0 : (*this_).export_stat = io_export_stat;
24 0 : (*this_).element_writer = out_element_writer;
25 :
26 0 : universal_array_list_init ( &((*this_).written_id_set),
27 : sizeof((*this_).written_id_set_buf)/sizeof(data_id_t),
28 0 : &((*this_).written_id_set_buf),
29 : sizeof(data_id_t),
30 : ((char*)(&((*this_).written_id_set_buf[1])))-((char*)(&((*this_).written_id_set_buf[0]))),
31 : (void (*)(void *, const void *)) &data_id_copy,
32 : (bool (*)(const void *, const void *)) &data_id_equals,
33 : (void (*)(void *)) &data_id_destroy
34 : );
35 :
36 0 : io_export_interaction_traversal_init( &((*this_).interaction_helper),
37 : db_reader,
38 : input_data,
39 : &((*this_).written_id_set),
40 : io_export_stat,
41 : out_element_writer
42 : );
43 0 : U8_TRACE_END();
44 0 : }
45 :
46 0 : void io_export_model_traversal_destroy( io_export_model_traversal_t *this_ )
47 : {
48 0 : U8_TRACE_BEGIN();
49 :
50 0 : io_export_interaction_traversal_destroy ( &((*this_).interaction_helper) );
51 :
52 0 : universal_array_list_destroy ( &((*this_).written_id_set) );
53 :
54 0 : (*this_).db_reader = NULL;
55 0 : (*this_).export_stat = NULL;
56 0 : (*this_).element_writer = NULL;
57 :
58 0 : U8_TRACE_END();
59 0 : }
60 :
61 0 : u8_error_t io_export_model_traversal_walk_model_nodes ( io_export_model_traversal_t *this_ )
62 : {
63 0 : U8_TRACE_BEGIN();
64 0 : u8_error_t write_err = U8_ERROR_NONE;
65 :
66 : {
67 : u8_error_t data_err;
68 : data_classifier_iterator_t classifier_iterator;
69 0 : universal_array_list_clear( &((*this_).written_id_set) );
70 :
71 : /* init the iterator */
72 0 : data_classifier_iterator_init_empty( &classifier_iterator );
73 0 : data_err = data_database_reader_get_all_classifiers ( (*this_).db_reader, true, &classifier_iterator );
74 0 : if ( data_err != U8_ERROR_NONE )
75 : {
76 0 : write_err |= data_err;
77 : }
78 : else
79 : {
80 0 : while( data_classifier_iterator_has_next( &classifier_iterator ) && ( write_err==0 ) )
81 : {
82 0 : data_err = data_classifier_iterator_next( &classifier_iterator, &((*this_).temp_classifier) );
83 0 : if ( data_err != U8_ERROR_NONE )
84 : {
85 0 : write_err |= data_err;
86 : }
87 : else
88 : {
89 0 : const data_id_t classifier_id = data_classifier_get_data_id( &((*this_).temp_classifier) );
90 0 : data_classifier_destroy( &((*this_).temp_classifier) );
91 :
92 0 : write_err |= io_export_model_traversal_private_walk_node( this_,
93 0 : DATA_ID_VOID,
94 0 : DATA_ID_VOID,
95 : classifier_id,
96 : 0 /* initial recursion_depth */
97 : );
98 : }
99 : }
100 : }
101 0 : data_err = data_classifier_iterator_destroy( &classifier_iterator );
102 0 : if ( data_err != U8_ERROR_NONE )
103 : {
104 0 : write_err |= data_err;
105 : }
106 : }
107 :
108 0 : U8_TRACE_END_ERR( write_err );
109 0 : return write_err;
110 : }
111 :
112 0 : u8_error_t io_export_model_traversal_private_walk_node( io_export_model_traversal_t *this_,
113 : data_id_t host_id,
114 : data_id_t containment_relationship_id,
115 : data_id_t classifier_id,
116 : unsigned int recursion_depth )
117 : {
118 0 : U8_TRACE_BEGIN();
119 0 : assert( recursion_depth <= IO_EXPORT_MODEL_TRAVERSAL_MAX_TREE_DEPTH );
120 0 : assert( data_id_is_valid( &classifier_id ) );
121 0 : data_id_trace( &classifier_id );
122 0 : u8_error_t write_err = U8_ERROR_NONE;
123 :
124 : /* initially define flags and attributes */
125 0 : bool duplicate_classifier
126 0 : = ( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &classifier_id ) );
127 0 : bool is_classifier_compliant_here = false; /* a default value */
128 :
129 : /* the id-sets needed on the stack during recursion */
130 : data_small_set_t contained_classifiers;
131 0 : data_small_set_init( &contained_classifiers );
132 : data_small_set_t containment_relations;
133 0 : data_small_set_init( &containment_relations );
134 :
135 : /* tasks before recursion */
136 0 : if ( ! duplicate_classifier )
137 : {
138 0 : const u8_error_t data_err_1
139 0 : = ( ! data_id_is_valid( &host_id ) )
140 : ? U8_ERROR_NONE
141 0 : : data_database_reader_get_classifier_by_id( (*this_).db_reader,
142 : data_id_get_row_id( &host_id ),
143 : &((*this_).temp_host)
144 : );
145 : const u8_error_t data_err_2
146 0 : = data_database_reader_get_classifier_by_id( (*this_).db_reader,
147 : data_id_get_row_id( &classifier_id ),
148 : &((*this_).temp_classifier)
149 : );
150 :
151 0 : if (( data_err_1 != U8_ERROR_NONE )||( data_err_2 != U8_ERROR_NONE ))
152 : {
153 0 : write_err |= data_err_1 | data_err_2;
154 : }
155 : else
156 : {
157 : /* update flags and attributes */
158 0 : const data_classifier_type_t host_type
159 0 : = ( ! data_id_is_valid( &host_id ) )
160 : ? DATA_CLASSIFIER_TYPE_PACKAGE /* a uml:Model (the out-most model element) is a uml:Package*/
161 0 : : data_classifier_get_main_type( &((*this_).temp_host) );
162 0 : const data_classifier_type_t classifier_type = data_classifier_get_main_type( &((*this_).temp_classifier) );
163 :
164 : /* fake and export interactions in which the current node is participant first */
165 : /* recursion trick: If classifier is nested, this block is evaluated
166 : * 1x for the nested classifier and 1x for same classifier at the toplevel model package
167 : */
168 : {
169 : /* write the relationships that can be stated after the classifier or in the toplevel package */
170 0 : write_err |= io_export_model_traversal_private_fake_interactions_of_node( this_,
171 : host_type,
172 0 : &((*this_).temp_classifier)
173 : );
174 : /* check if the classifier is already written */
175 : duplicate_classifier
176 0 : =( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &classifier_id ) );
177 : }
178 :
179 0 : is_classifier_compliant_here = io_element_writer_can_classifier_nest_classifier( (*this_).element_writer,
180 : host_type,
181 : classifier_type
182 : );
183 0 : if (( recursion_depth == 0 )&&( !is_classifier_compliant_here ))
184 : {
185 : /* fallback, there is no other place to put the classifier */
186 0 : is_classifier_compliant_here = true;
187 : }
188 :
189 0 : if (( ! duplicate_classifier )&&( is_classifier_compliant_here ))
190 : {
191 : /* add this classifier to the already written elements */
192 0 : write_err |= universal_array_list_append( &((*this_).written_id_set), &classifier_id );
193 : /* if this classifier was found via a containment_relationship, */
194 : /* add this containment_relationship to the already written elements */
195 0 : if ( data_id_is_valid( &containment_relationship_id ) )
196 : {
197 0 : write_err |= universal_array_list_append( &((*this_).written_id_set), &containment_relationship_id );
198 : }
199 :
200 : /* walk node which is not a duplicate */
201 0 : write_err |= io_export_model_traversal_private_begin_node( this_,
202 : host_type,
203 0 : &((*this_).temp_classifier)
204 : );
205 :
206 0 : write_err |= io_export_model_traversal_private_iterate_node_features( this_, &((*this_).temp_classifier) );
207 :
208 0 : write_err |= io_export_model_traversal_private_get_containments( this_,
209 0 : &((*this_).temp_classifier),
210 : &contained_classifiers,
211 : &containment_relations
212 : );
213 : }
214 : }
215 :
216 0 : if ( data_id_is_valid( &host_id ) )
217 : {
218 0 : data_classifier_destroy( &((*this_).temp_host) );
219 : }
220 0 : data_classifier_destroy( &((*this_).temp_classifier) );
221 : }
222 :
223 : /* do recursion, all required data is stored on the stack now */
224 0 : if (( ! duplicate_classifier )&&( is_classifier_compliant_here ))
225 : {
226 0 : write_err |= io_export_model_traversal_private_walk_containments( this_,
227 : classifier_id,
228 : &contained_classifiers,
229 : &containment_relations,
230 : recursion_depth
231 : );
232 : }
233 :
234 : /* tasks after recursion */
235 : {
236 0 : const u8_error_t data_err_3
237 0 : = ( ! data_id_is_valid( &host_id ) )
238 : ? U8_ERROR_NONE
239 0 : : data_database_reader_get_classifier_by_id( (*this_).db_reader,
240 : data_id_get_row_id( &host_id ),
241 : &((*this_).temp_host)
242 : );
243 : const u8_error_t data_err_4
244 0 : = data_database_reader_get_classifier_by_id( (*this_).db_reader,
245 : data_id_get_row_id( &classifier_id ),
246 : &((*this_).temp_classifier)
247 : );
248 :
249 0 : if (( data_err_3 != U8_ERROR_NONE )||( data_err_4 != U8_ERROR_NONE ))
250 : {
251 0 : write_err |= data_err_3 | data_err_4;
252 : }
253 : else
254 : {
255 0 : const data_classifier_type_t host_type_2
256 0 : = ( ! data_id_is_valid( &host_id ) )
257 : ? DATA_CLASSIFIER_TYPE_PACKAGE /* a uml:Model is a uml:Package*/
258 0 : : data_classifier_get_main_type( &((*this_).temp_host) );
259 0 : const data_classifier_t *host_2
260 0 : = ( ! data_id_is_valid( &host_id ) )
261 : ? NULL
262 0 : : &((*this_).temp_host);
263 :
264 0 : if (( ! duplicate_classifier )&&( is_classifier_compliant_here ))
265 : {
266 : /* write the relationships that can be nested within the classifier */
267 0 : write_err |= io_export_model_traversal_private_iterate_node_relationships( this_,
268 : false,
269 0 : &((*this_).temp_classifier), /* inside here */
270 0 : &((*this_).temp_classifier)
271 : );
272 :
273 0 : write_err |= io_export_model_traversal_private_end_node( this_,
274 : host_type_2,
275 0 : &((*this_).temp_classifier)
276 : );
277 : }
278 :
279 : /* recursion trick: If from- and to- classifiers are nested, this block is evaluated
280 : * 1x for the nested from-/to- classifier and 1x for same classifier at the toplevel model package
281 : */
282 : {
283 : /* write the relationships that can be stated after the classifier or in the toplevel package */
284 0 : write_err |= io_export_model_traversal_private_iterate_node_relationships( this_,
285 : true,
286 : host_2, /* outside now */
287 0 : &((*this_).temp_classifier)
288 : );
289 : }
290 : }
291 :
292 0 : if ( data_id_is_valid( &host_id ) )
293 : {
294 0 : data_classifier_destroy( &((*this_).temp_host) );
295 : }
296 0 : data_classifier_destroy( &((*this_).temp_classifier) );
297 : }
298 :
299 0 : data_small_set_destroy( &contained_classifiers );
300 0 : data_small_set_destroy( &containment_relations );
301 :
302 0 : U8_TRACE_END_ERR( write_err );
303 0 : return write_err;
304 : }
305 :
306 0 : u8_error_t io_export_model_traversal_private_begin_node ( io_export_model_traversal_t *this_,
307 : data_classifier_type_t host_type,
308 : const data_classifier_t *classifier )
309 : {
310 0 : U8_TRACE_BEGIN();
311 0 : assert( classifier != NULL );
312 0 : u8_error_t write_err = U8_ERROR_NONE;
313 :
314 0 : write_err |= io_element_writer_start_classifier( (*this_).element_writer, host_type, classifier );
315 0 : write_err |= io_element_writer_assemble_classifier( (*this_).element_writer, host_type, classifier );
316 :
317 0 : U8_TRACE_END_ERR( write_err );
318 0 : return write_err;
319 : }
320 :
321 0 : u8_error_t io_export_model_traversal_private_get_containments( io_export_model_traversal_t *this_,
322 : const data_classifier_t *classifier,
323 : data_small_set_t *io_contained_classifiers,
324 : data_small_set_t *io_containment_relations )
325 : {
326 0 : U8_TRACE_BEGIN();
327 0 : assert( classifier != NULL );
328 0 : assert( io_contained_classifiers != NULL );
329 0 : assert( io_containment_relations != NULL );
330 0 : u8_error_t result = U8_ERROR_NONE;
331 :
332 0 : const data_id_t classifier_id = data_classifier_get_data_id( classifier );
333 0 : data_id_trace( &classifier_id );
334 :
335 : /* search containments in relationships */
336 : data_relationship_iterator_t rel_iterator;
337 0 : result |= data_relationship_iterator_init_empty( &rel_iterator );
338 0 : result |= data_database_reader_get_relationships_by_classifier_id( (*this_).db_reader,
339 : data_classifier_get_row_id( classifier ),
340 : &rel_iterator
341 : );
342 :
343 0 : while ( data_relationship_iterator_has_next( &rel_iterator ) )
344 : {
345 : /* get relationship */
346 0 : result |= data_relationship_iterator_next( &rel_iterator, &((*this_).temp_relationship) );
347 0 : if ( data_relationship_is_valid( &((*this_).temp_relationship) ) )
348 : {
349 0 : const data_id_t from_classifier_id = data_relationship_get_from_classifier_data_id( &((*this_).temp_relationship) );
350 0 : const bool container_is_this = data_id_equals( &from_classifier_id, &classifier_id );
351 0 : const bool is_containment
352 0 : = ( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == data_relationship_get_main_type( &((*this_).temp_relationship) ) );
353 0 : if ( container_is_this && is_containment )
354 : {
355 0 : const data_id_t relationship_id = data_relationship_get_data_id( &((*this_).temp_relationship) );
356 0 : const data_id_t from_feature_id = data_relationship_get_from_feature_data_id( &((*this_).temp_relationship) );
357 0 : const data_id_t to_feature_id = data_relationship_get_to_feature_data_id( &((*this_).temp_relationship) );
358 0 : const data_id_t to_classifier_id = data_relationship_get_to_classifier_data_id( &((*this_).temp_relationship) );
359 0 : if ( data_id_is_valid( &from_feature_id ) )
360 : {
361 0 : U8_TRACE_INFO("Anomaly: A feature of this classifier contains something");
362 : }
363 0 : else if ( data_id_is_valid( &to_feature_id ) )
364 : {
365 0 : U8_TRACE_INFO("Anomaly: This classifier contains a feature");
366 : }
367 0 : else if ( data_id_equals( &to_classifier_id, &classifier_id ) )
368 : {
369 0 : U8_TRACE_INFO("Anomaly: This classifier contains itself");
370 : }
371 0 : else if ( data_small_set_contains( io_contained_classifiers, to_classifier_id ) )
372 : {
373 0 : U8_TRACE_INFO("Anomaly: This classifier contains a child twice");
374 : }
375 : else
376 : {
377 0 : data_small_set_add_obj ( io_contained_classifiers, to_classifier_id );
378 0 : data_small_set_add_obj ( io_containment_relations, relationship_id );
379 : }
380 : }
381 : }
382 : else
383 : {
384 0 : assert( false );
385 : }
386 : }
387 0 : result |= data_relationship_iterator_destroy( &rel_iterator );
388 :
389 0 : U8_TRACE_END_ERR( result );
390 0 : return result;
391 : }
392 :
393 0 : u8_error_t io_export_model_traversal_private_walk_containments ( io_export_model_traversal_t *this_,
394 : data_id_t host_id,
395 : const data_small_set_t *contained_classifiers,
396 : const data_small_set_t *containment_relations,
397 : unsigned int recursion_depth )
398 : {
399 0 : U8_TRACE_BEGIN();
400 0 : assert( contained_classifiers != NULL );
401 0 : assert( containment_relations != NULL );
402 0 : data_id_trace( &host_id );
403 0 : u8_error_t write_err = U8_ERROR_NONE;
404 :
405 : /* do recursion */
406 0 : if ( recursion_depth < IO_EXPORT_MODEL_TRAVERSAL_MAX_TREE_DEPTH )
407 : {
408 0 : const uint32_t children = data_small_set_get_count ( contained_classifiers );
409 0 : U8_TRACE_INFO_INT( "Children: ", children );
410 0 : assert( children == data_small_set_get_count ( containment_relations ) );
411 0 : for ( uint32_t index = 0; index < children; index ++ )
412 : {
413 0 : const data_id_t child = data_small_set_get_id ( contained_classifiers, index );
414 0 : const data_id_t c_rel = data_small_set_get_id ( containment_relations, index );
415 0 : write_err |= io_export_model_traversal_private_walk_node( this_, host_id, c_rel, child, recursion_depth+1 );
416 : }
417 : }
418 :
419 0 : U8_TRACE_END_ERR( write_err );
420 0 : return write_err;
421 : }
422 :
423 0 : u8_error_t io_export_model_traversal_private_end_node ( io_export_model_traversal_t *this_,
424 : data_classifier_type_t host_type,
425 : const data_classifier_t *classifier )
426 : {
427 0 : U8_TRACE_BEGIN();
428 0 : assert( classifier != NULL );
429 0 : u8_error_t write_err = U8_ERROR_NONE;
430 :
431 0 : write_err |= io_element_writer_end_classifier( (*this_).element_writer, host_type, classifier );
432 :
433 0 : U8_TRACE_END_ERR( write_err );
434 0 : return write_err;
435 : }
436 :
437 0 : u8_error_t io_export_model_traversal_private_iterate_node_features ( io_export_model_traversal_t *this_,
438 : const data_classifier_t *classifier )
439 : {
440 0 : U8_TRACE_BEGIN();
441 0 : assert( classifier != NULL );
442 0 : assert( data_classifier_is_valid( classifier ) );
443 0 : u8_error_t write_err = U8_ERROR_NONE;
444 0 : u8_error_t data_err = U8_ERROR_NONE;
445 :
446 : /* iterate over all features */
447 : data_feature_iterator_t feature_iterator;
448 0 : data_err |= data_feature_iterator_init_empty( &feature_iterator );
449 0 : data_err |= data_database_reader_get_features_by_classifier_id( (*this_).db_reader,
450 : data_classifier_get_row_id( classifier ),
451 : &feature_iterator
452 : );
453 :
454 0 : while ( data_feature_iterator_has_next( &feature_iterator ) )
455 : {
456 : /* get feature */
457 0 : data_err |= data_feature_iterator_next( &feature_iterator, &((*this_).temp_from_feature) );
458 0 : if ( data_feature_is_valid( &((*this_).temp_from_feature) ) )
459 : {
460 0 : const bool is_lifeline
461 0 : =( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type( &((*this_).temp_from_feature) ) );
462 :
463 0 : if ( ! is_lifeline )
464 : {
465 0 : const data_classifier_type_t classifier_type = data_classifier_get_main_type( classifier );
466 0 : write_err |= io_element_writer_start_feature( (*this_).element_writer, classifier_type,
467 0 : &((*this_).temp_from_feature)
468 : );
469 0 : write_err |= io_element_writer_assemble_feature( (*this_).element_writer,
470 : classifier,
471 0 : &((*this_).temp_from_feature)
472 : );
473 0 : write_err |= io_element_writer_end_feature( (*this_).element_writer,
474 : classifier_type,
475 0 : &((*this_).temp_from_feature)
476 : );
477 : }
478 : /* else: */
479 : /* lifelines are handled in io_export_model_traversal_private_fake_interactions_of_node */
480 : }
481 : else
482 : {
483 0 : assert( false );
484 : }
485 : }
486 0 : data_err |= data_feature_iterator_destroy( &feature_iterator );
487 :
488 0 : U8_TRACE_END_ERR( write_err | data_err );
489 0 : return write_err | data_err;
490 : }
491 :
492 0 : u8_error_t io_export_model_traversal_private_iterate_node_relationships ( io_export_model_traversal_t *this_,
493 : bool nested_to_foreign_node,
494 : const data_classifier_t *host,
495 : const data_classifier_t *classifier )
496 : {
497 0 : U8_TRACE_BEGIN();
498 0 : assert( classifier != NULL );
499 0 : assert( data_classifier_is_valid( classifier ) );
500 0 : u8_error_t write_err = U8_ERROR_NONE;
501 0 : u8_error_t data_err = U8_ERROR_NONE;
502 :
503 0 : const data_classifier_type_t host_type
504 0 : = (host==NULL) ? DATA_CLASSIFIER_TYPE_PACKAGE : data_classifier_get_main_type( host ); /* a uml:Model is a uml:Package*/
505 0 : const data_id_t classifier_id = data_classifier_get_data_id( classifier );
506 :
507 : /* iterate over all relationships */
508 : data_relationship_iterator_t rel_iterator;
509 0 : data_err |= data_relationship_iterator_init_empty( &rel_iterator );
510 0 : data_err |= data_database_reader_get_relationships_by_classifier_id( (*this_).db_reader,
511 : data_classifier_get_row_id( classifier ),
512 : &rel_iterator
513 : );
514 :
515 0 : while ( data_relationship_iterator_has_next( &rel_iterator ) )
516 : {
517 : /* get relationship */
518 0 : data_err |= data_relationship_iterator_next( &rel_iterator, &((*this_).temp_relationship) );
519 0 : if ( data_relationship_is_valid( &((*this_).temp_relationship) ) )
520 : {
521 : /* determine if the relationship is a duplicate */
522 0 : const data_id_t relation_id = data_relationship_get_data_id( &((*this_).temp_relationship) );
523 0 : const bool duplicate_relationship
524 0 : = ( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &relation_id ) );
525 0 : if ( ! duplicate_relationship )
526 : {
527 0 : const data_id_t from_classifier_id = data_relationship_get_from_classifier_data_id( &((*this_).temp_relationship) );
528 0 : const bool source_already_written
529 0 : = ( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &from_classifier_id ) );
530 0 : const data_id_t to_classifier_id = data_relationship_get_to_classifier_data_id( &((*this_).temp_relationship) );
531 0 : const bool destination_already_written
532 0 : = ( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &to_classifier_id ) );
533 :
534 0 : const data_relationship_type_t r_type = data_relationship_get_main_type( &((*this_).temp_relationship) );
535 : const bool is_relationship_compliant_here
536 0 : = io_element_writer_can_classifier_nest_relationship( (*this_).element_writer, host_type, r_type );
537 0 : const data_id_t from_feature_id = data_relationship_get_from_feature_data_id( &((*this_).temp_relationship) );
538 0 : const bool from_here
539 0 : = ( ( ! data_id_is_valid( &from_feature_id ) )
540 0 : && ( data_id_equals( &from_classifier_id, &classifier_id ) ) );
541 :
542 : /* nested_to_foreign_node is kind of yellow or even red emergency node:
543 : * source_already_written and possibly destination_already_written must have passed
544 : * to ensure that there is no other solution;
545 : * either (yellow) is_relationship_compliant_here
546 : * or (red) nesting to package shall be true.
547 : */
548 0 : const bool foreign_yellow_ok
549 0 : = nested_to_foreign_node && source_already_written && is_relationship_compliant_here;
550 0 : const bool foreign_red_ok
551 0 : = nested_to_foreign_node && source_already_written && destination_already_written
552 0 : && ( host_type == DATA_CLASSIFIER_TYPE_PACKAGE );
553 :
554 : /* in uml, the source is the dependant, the destination has no link to the source
555 : */
556 0 : const bool local_ok = ( ! nested_to_foreign_node ) && is_relationship_compliant_here && from_here;
557 :
558 0 : if ( local_ok || foreign_yellow_ok || foreign_red_ok )
559 : {
560 : /* add the relationship to the duplicates list */
561 0 : write_err |= universal_array_list_append( &((*this_).written_id_set), &relation_id );
562 :
563 : /* get the element types at both ends of the relationship */
564 0 : data_classifier_init_empty( &((*this_).temp_from_classifier) );
565 0 : data_feature_init_empty( &((*this_).temp_from_feature) );
566 0 : data_classifier_init_empty( &((*this_).temp_to_classifier) );
567 0 : data_feature_init_empty( &((*this_).temp_to_feature) );
568 :
569 : const u8_error_t d_err
570 0 : = io_export_model_traversal_private_get_relationship_ends( this_,
571 : classifier,
572 0 : &((*this_).temp_relationship),
573 : &((*this_).temp_from_classifier),
574 : &((*this_).temp_from_feature),
575 : &((*this_).temp_to_classifier),
576 : &((*this_).temp_to_feature)
577 : );
578 :
579 0 : if ( d_err == U8_ERROR_NONE )
580 : {
581 : /* destination classifier found, print the relation */
582 0 : write_err |= io_element_writer_start_relationship( (*this_).element_writer, host_type, &((*this_).temp_relationship) );
583 0 : write_err |= io_element_writer_assemble_relationship( (*this_).element_writer,
584 : host,
585 0 : &((*this_).temp_relationship),
586 0 : &((*this_).temp_from_classifier),
587 0 : &((*this_).temp_from_feature),
588 0 : &((*this_).temp_to_classifier),
589 0 : &((*this_).temp_to_feature)
590 : );
591 0 : write_err |= io_element_writer_end_relationship( (*this_).element_writer, host_type, &((*this_).temp_relationship) );
592 : }
593 : else
594 : {
595 0 : write_err |= d_err;
596 : }
597 :
598 0 : data_classifier_destroy( &((*this_).temp_from_classifier) );
599 0 : data_feature_destroy( &((*this_).temp_from_feature) );
600 0 : data_classifier_destroy( &((*this_).temp_to_classifier) );
601 0 : data_feature_destroy( &((*this_).temp_to_feature) );
602 : }
603 : }
604 : }
605 : else
606 : {
607 0 : assert( false );
608 : }
609 : }
610 0 : data_err |= data_relationship_iterator_destroy( &rel_iterator );
611 :
612 0 : U8_TRACE_END_ERR( write_err | data_err );
613 0 : return write_err | data_err;
614 : }
615 :
616 0 : u8_error_t io_export_model_traversal_private_get_relationship_ends( io_export_model_traversal_t *this_,
617 : const data_classifier_t *classifier,
618 : const data_relationship_t *relation,
619 : data_classifier_t *out_from_c,
620 : data_feature_t *out_from_f,
621 : data_classifier_t *out_to_c,
622 : data_feature_t *out_to_f )
623 : {
624 0 : U8_TRACE_BEGIN();
625 0 : assert( classifier != NULL );
626 0 : assert( relation != NULL );
627 0 : assert( out_from_c != NULL );
628 0 : assert( out_from_f != NULL );
629 0 : assert( out_to_c != NULL );
630 0 : assert( out_to_f != NULL );
631 0 : u8_error_t data_err = U8_ERROR_NONE;
632 :
633 : {
634 : /* get from classifier */
635 0 : const data_row_t from_classifier_row_id = data_relationship_get_from_classifier_row_id( relation );
636 0 : if ( from_classifier_row_id == data_classifier_get_row_id ( classifier ) )
637 : {
638 0 : data_classifier_replace( out_from_c, classifier );
639 : }
640 : else
641 : {
642 0 : data_err |= data_database_reader_get_classifier_by_id( (*this_).db_reader,
643 : from_classifier_row_id,
644 : out_from_c
645 : );
646 : }
647 :
648 : /* get from feature */
649 0 : const data_row_t from_feature_row_id = data_relationship_get_from_feature_row_id( relation );
650 0 : if ( from_feature_row_id != DATA_ROW_VOID )
651 : {
652 0 : data_err |= data_database_reader_get_feature_by_id( (*this_).db_reader,
653 : from_feature_row_id,
654 : out_from_f
655 : );
656 : }
657 : else
658 : {
659 0 : data_feature_init_empty( out_from_f );
660 : }
661 :
662 : /* get to classifier */
663 0 : const data_row_t to_classifier_row_id = data_relationship_get_to_classifier_row_id( relation );
664 0 : if ( to_classifier_row_id == data_classifier_get_row_id ( classifier ) )
665 : {
666 0 : data_classifier_replace( out_to_c, classifier );
667 : }
668 : else
669 : {
670 0 : data_err |= data_database_reader_get_classifier_by_id( (*this_).db_reader,
671 : to_classifier_row_id,
672 : out_to_c
673 : );
674 : }
675 :
676 : /* get to feature */
677 0 : const data_row_t to_feature_row_id = data_relationship_get_to_feature_row_id( relation );
678 0 : if ( to_feature_row_id != DATA_ROW_VOID )
679 : {
680 0 : data_err |= data_database_reader_get_feature_by_id( (*this_).db_reader,
681 : to_feature_row_id,
682 : out_to_f
683 : );
684 : }
685 : else
686 : {
687 0 : data_feature_init_empty( out_to_f );
688 : }
689 : }
690 :
691 0 : if ( data_err != U8_ERROR_NONE )
692 : {
693 0 : U8_LOG_ERROR_INT( "A relationship references classifier(s) and/or feature(s) that do not exist:",
694 : data_relationship_get_row_id ( relation )
695 : );
696 : }
697 0 : U8_TRACE_END_ERR( data_err );
698 0 : return data_err;
699 : }
700 :
701 0 : u8_error_t io_export_model_traversal_private_fake_interactions_of_node ( io_export_model_traversal_t *this_,
702 : data_classifier_type_t nesting_type,
703 : const data_classifier_t *classifier )
704 : {
705 0 : U8_TRACE_BEGIN();
706 0 : assert( classifier != NULL );
707 0 : assert( data_classifier_is_valid( classifier ) );
708 0 : u8_error_t write_err = U8_ERROR_NONE;
709 0 : u8_error_t data_err = U8_ERROR_NONE;
710 :
711 0 : const data_id_t classifier_id = data_classifier_get_data_id( classifier );
712 :
713 : /* iterate over all features, search for lifelines */
714 : data_feature_iterator_t feature_iterator;
715 0 : data_err |= data_feature_iterator_init_empty( &feature_iterator );
716 0 : data_err |= data_database_reader_get_features_by_classifier_id( (*this_).db_reader,
717 : data_classifier_get_row_id( classifier ),
718 : &feature_iterator
719 : );
720 :
721 0 : while ( data_feature_iterator_has_next( &feature_iterator ) )
722 : {
723 : /* get feature */
724 0 : data_err |= data_feature_iterator_next( &feature_iterator, &((*this_).temp_from_feature) );
725 0 : if ( data_feature_is_valid( &((*this_).temp_from_feature) ) )
726 : {
727 : /* determine if the feature is a duplicate */
728 0 : const data_id_t feature_id = data_feature_get_data_id( &((*this_).temp_from_feature) );
729 0 : const bool duplicate_feature
730 0 : = ( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &feature_id ) );
731 :
732 : /* determine if the feature is a lifeline */
733 0 : const data_feature_type_t feat_type = data_feature_get_main_type( &((*this_).temp_from_feature) );
734 0 : const bool is_lifeline = ( feat_type == DATA_FEATURE_TYPE_LIFELINE );
735 :
736 0 : if (( ! duplicate_feature )&&( is_lifeline )) /* just an optimization, checked again by (*this_).interaction_helper */
737 : {
738 : static const data_classifier_type_t FAKE_INTERACTION
739 : = DATA_CLASSIFIER_TYPE_CLASS; /* interaction is subclass of class */
740 : const bool is_interaction_compliant_here
741 0 : = io_element_writer_can_classifier_nest_classifier( (*this_).element_writer, nesting_type, FAKE_INTERACTION );
742 :
743 0 : if ( is_interaction_compliant_here )
744 : {
745 0 : write_err |= io_export_interaction_traversal_iterate_classifier_occurrences( &((*this_).interaction_helper),
746 : nesting_type,
747 : classifier_id
748 : );
749 : }
750 : }
751 : }
752 : else
753 : {
754 0 : assert( false );
755 : }
756 : }
757 0 : data_err |= data_feature_iterator_destroy( &feature_iterator );
758 :
759 0 : U8_TRACE_END_ERR( write_err | data_err );
760 0 : return write_err | data_err;
761 : }
762 :
763 :
764 : /*
765 : Copyright 2020-2024 Andreas Warnke
766 :
767 : Licensed under the Apache License, Version 2.0 (the "License");
768 : you may not use this file except in compliance with the License.
769 : You may obtain a copy of the License at
770 :
771 : http://www.apache.org/licenses/LICENSE-2.0
772 :
773 : Unless required by applicable law or agreed to in writing, software
774 : distributed under the License is distributed on an "AS IS" BASIS,
775 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
776 : See the License for the specific language governing permissions and
777 : limitations under the License.
778 : */
|