123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- import wrappers.modelverse as mv
- import commons
- class Verifier(object):
- def __init__(self, instance_model):
- self._instance_model = instance_model
- self._example_models = None
- self._available_types = None
- def set_instance_model(self, model):
- self._instance_model = model
- def get_instance_model(self):
- return self._instance_model
- def init(self):
- """
- Inits the verifier. Loads required data from the modelverse
- to avoid reloading it for every step.
- """
- self._example_models = commons.all_example_models()
- self._available_types = commons.get_available_types()
- def verify_node_typing(self):
- """
- Checks if every node in instance model is typed by a node in any example model.
- Should actually not be neccessary since instance modeling only allows types from
- example models.
- """
- # Check for every node in instance model if it has a valid type
- all_nodes = mv.all_instances(self._instance_model, "Node")
- for node in all_nodes:
- node_typ = commons.get_node_type(self._instance_model, node)
- if node_typ not in self._available_types:
- return {"OK": False, "error": "Type {} from instance model not in example models".format(node_typ)}
- return {"OK":True, "error":None, "affected":[]}
- def verify_node_multiplicity(self):
- """
- A node is mandatory in the instance model if it occurs at least once in every example model.
- """
- type_mandatory = {t:False for t in self._available_types}
- for node_type,_ in type_mandatory.iteritems():
- if commons.is_type_mandatory(node_type):
- type_mandatory[node_type] = True
- mandatory_types = [node_type for node_type, mandatory in type_mandatory.iteritems() if mandatory]
- for mand_type in mandatory_types:
- all_of_type = commons.all_nodes_with_type(self._instance_model, mand_type)
- if not all_of_type:
- return {"OK": False, "error": "Mandatory node of type {} not found".format(mand_type), "affected":[]}
- return {"OK":True, "error":None, "affected":[]}
- def _get_attributes_of_all_types(self):
- """
- Helper for attribute check that returns a dictionary of the form {type:[attr_key_1, attr_key_2, ...], ...},
- listing all attributes of every type from example models
- """
- attrs_of_types = {node_type:[] for node_type in self._available_types}
- for exm in self._example_models:
- for node_type, attrs in attrs_of_types.iteritems():
- attrs_of_type_in_exm = [x.key for x in commons.get_all_attributes_of_type(exm, node_type)]
- for attr in attrs_of_type_in_exm:
- if not attr in attrs:
- attrs.append(attr)
- return attrs_of_types
- def verify_attributes(self):
- """
- 1. For every attribute key of a typed node in the instance model, there must be a corresponding
- attribute key in some example model.
- 2. An attribute for a type is mandatory if it occurs in every example model where the associated type node occurs.
- """
- # Check attribute keys for every node in instance model
- all_nodes = mv.all_instances(self._instance_model, "Node")
- for node in all_nodes:
- attrs = commons.get_attributes_of_node(self._instance_model, node)
- if not attrs:
- continue
- node_typ = commons.get_node_type(self._instance_model, node)
- for attr in attrs:
- # check every example model if such an attribute key is present for the specific type
- for exm in self._example_models:
- exm_attrs = commons.get_all_attributes_of_type(exm, node_typ)
- if attr.key in [x.key for x in exm_attrs]:
- break
- else:
- # loop completed without break, so we did not find any key in example models
- return {"OK": False, "error": "No key {} for type {} in example models".format(attr.key, node_typ),
- "affected":[node]}
- # Check if mandatory attributes are present in instance model
- attr_mandatory = {node_type:{} for node_type in self._available_types}
- all_attrs = self._get_attributes_of_all_types()
- for typ_i, attr_list in all_attrs.iteritems():
- for typ_j, dic in attr_mandatory.iteritems():
- if typ_j == typ_i:
- for attr in attr_list:
- dic[attr] = False
- # have dict like {"PC": {"owner":False}, "Router": {"IP":False}, ...}
- # now need to check which one is mandatory and set the boolean accordingly
- for node_type, attr_dict in attr_mandatory.iteritems():
- for attr, _ in attr_dict.iteritems():
- if commons.is_attribute_mandatory(node_type, attr):
- attr_dict[attr] = True
- # for every node in instance model, check if it has the mandatory attributes
- for node in mv.all_instances(self._instance_model, "Node"):
- node_type = commons.get_node_type(self._instance_model, node)
- node_attrs = commons.get_attributes_of_node(self._instance_model, node)
- attr_mand = attr_mandatory[node_type]
- for attr, mand in attr_mand.iteritems():
- if mand:
- if not attr in [x.key for x in node_attrs]:
- return {"OK": False, "error":"Attribute {} for type {} mandatory".format(attr, node_type),
- "affected":[node]}
- return {"OK": True, "error": None, "affected":[]}
- def verify_associations(self):
- """
- 1. An edge between two types is mandatory if in every example model that contains nodes of both types, every
- node is connected with an edge to the other type.
- 2. For every association in the instance model, the types of the source and target must correspond
- to the types of an association in some example model. This check should not be necessary since this
- is already enforced while instance modeling (see im_scene.py, draw_edge() which checks this when trying
- to connect two nodes).
- """
- mandatory_edges = commons.get_mandtory_edges()
- # check if instance model contains the types and the edge
- for edge in mandatory_edges:
- if not commons.model_contains_type(self._instance_model, edge.n1):
- continue
- if not commons.model_contains_type(self._instance_model, edge.n2):
- continue
- # instance model contains both types -> are they connected?
- for node in commons.all_nodes_with_type(self._instance_model, edge.n1):
- if not commons.has_edge_to_type(self._instance_model, node, edge.n2):
- return {"OK":False, "error": "Edge between {} and {} mandatory".format(edge.n1, edge.n2),
- "affected":[]}
- # other way round
- for node in commons.all_nodes_with_type(self._instance_model, edge.n2):
- if not commons.has_edge_to_type(self._instance_model, node, edge.n1):
- return {"OK":False, "error": "Edge between {} and {} mandatory".format(edge.n2, edge.n1),
- "affected":[]}
- # lastly, check if all edges in the instance model are actually valid
- all_edges = mv.all_instances(self._instance_model, "Edge")
- for edge in all_edges:
- src_id = mv.read_association_source(self._instance_model, edge)[0]
- dest_id = mv.read_association_destination(self._instance_model, edge)[0]
- src_type = commons.get_node_type(self._instance_model, src_id)
- dest_type = commons.get_node_type(self._instance_model, dest_id)
- if not commons.is_edge_supported(src_type, dest_type):
- return {"OK":False, "error": "Edge between {} and {} not valid".format(edge.n1, edge.n2),
- "affected":[src_id, dest_id]}
- return {"OK": True, "error": None, "affected":[]}
|