From e3d4889f91fa65cbaee91a97d7cd01306c5b2bbd Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Fri, 8 Nov 2024 16:43:26 +0100 Subject: [PATCH] Handle 'condition' object-attribute in RHS as well --- transformation/ramify.py | 7 +++---- transformation/rewriter.py | 25 +++++++++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/transformation/ramify.py b/transformation/ramify.py index f07c5d2..35ca8be 100644 --- a/transformation/ramify.py +++ b/transformation/ramify.py @@ -43,9 +43,6 @@ def ramify(state: State, model: UUID, prefix = "RAM_") -> UUID: # We don't add a 'label' attribute (as described in literature on RAMification) # Instead, the names of the objects (which only exist in the scope of the object diagram 'model', and are not visible to the matcher) are used as labels - # Optional constraint on the object - # ramified_scd._create_attribute_link(prefix+class_name, string_modelref, "constraint", optional=True) - for (attr_name, attr_edge) in od.get_attributes(bottom, class_node): # print(' creating attribute', attr_name, "with type String") # Every attribute becomes 'string' type @@ -54,7 +51,9 @@ def ramify(state: State, model: UUID, prefix = "RAM_") -> UUID: # create traceability link bottom.create_edge(ramified_attr_link, attr_edge, RAMIFIES_LABEL) - # Additional constraint that can be specified + # Additional condition that can be specified + # In LHS, this will be a boolean expression (pre-condition) + # In RHS, this is just a piece of action code ramified_scd._create_attribute_link(prefix+class_name, actioncode_modelref, "condition", optional=True) already_ramified.add(class_name) diff --git a/transformation/rewriter.py b/transformation/rewriter.py index 8f97ea1..e0405d7 100644 --- a/transformation/rewriter.py +++ b/transformation/rewriter.py @@ -19,8 +19,8 @@ def preprocess_rule(state, lhs: UUID, rhs: UUID, name_mapping): to_delete = { name for name in bottom.read_keys(lhs) if name not in bottom.read_keys(rhs) and name in name_mapping } to_create = { name for name in bottom.read_keys(rhs) if name not in bottom.read_keys(lhs) - # extremely dirty: - and "GlobalCondition" not in name } + # extremely dirty - should think of a better way + and "GlobalCondition" not in name and not name.endswith("_condition") and not name.endswith(".condition") } common = { name for name in bottom.read_keys(lhs) if name in bottom.read_keys(rhs) and name in name_mapping } return to_delete, to_create, common @@ -66,8 +66,8 @@ def rewrite(state, lhs_m: UUID, rhs_m: UUID, pattern_mm: UUID, lhs_name_mapping: to_delete, to_create, common = preprocess_rule(state, lhs_m, rhs_m, lhs_name_mapping) - print("to_delete:", to_delete) - print("to_create:", to_create) + # print("to_delete:", to_delete) + # print("to_create:", to_create) # to be grown rhs_name_mapping = { name : lhs_name_mapping[name] for name in common } @@ -205,6 +205,23 @@ def rewrite(state, lhs_m: UUID, rhs_m: UUID, pattern_mm: UUID, lhs_name_mapping: # print(msg) raise Exception(msg) + # Finally, we iterate over the (now complete) mapping RHS -> Host, to execute all the user-specified conditions + for rhs_name, host_name in rhs_name_mapping.items(): + host_obj = host_odapi.get(host_name) + rhs_obj = rhs_odapi.get(rhs_name) + rhs_type = rhs_odapi.get_type(rhs_obj) + rhs_type_of_type = rhs_mm_odapi.get_type(rhs_type) + rhs_type_of_type_name = rhs_mm_odapi.get_name(rhs_type_of_type) + if rhs_mm_odapi.cdapi.is_subtype(super_type_name="Class", sub_type_name=rhs_type_of_type_name): + # rhs_obj is an object or link (because association is subtype of class) + python_code = rhs_odapi.get_slot_value_default(rhs_obj, "condition", default="") + simply_exec(python_code, + _globals={ + **bind_api(host_odapi), + 'matched': matched_callback, + }, + _locals={'this': host_obj}) + # Execute global conditions for cond_name, cond in rhs_odapi.get_all_instances("GlobalCondition"): python_code = rhs_odapi.get_slot_value(cond, "condition")