123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- import wrappers.modelverse as mv
- from commons import get_attributes_of
- class Edge(object):
- """
- Small helper class for association validation.
- Stores an edge as a tuple of (source, dest)
- """
- def __init__(self, src, dest):
- self.src = src
- self.dest = dest
- def __eq__(self, other):
- if other.src == self.src and other.dest == self.dest:
- return True
- return False
- def __repr__(self):
- return "{}->{}".format(self.src, self.dest)
- def _count_occurences(node_type, model):
- """ returns the number of occurences of a node with type node_type in a model """
- ctr = 0
- all_nodes = mv.all_instances(model, "Node")
- for node in all_nodes:
- typ = mv.read_attrs(model, node)["typeID"]
- if typ == node_type:
- ctr += 1
- return ctr
- def verify(instance_model_path):
- """
- Verify an instance model against all example models (mv folder currently hard-coded)
- Performs checks similar to the linguistic conformance check as seen in the MDE class:
- 1. Node typing
- 2. Node cardinality
- 3. Attribute validity
- 4. Associations
- """
- example_models = mv.model_list("models/example")
- example_models_full = ["models/example/"+exm for exm in example_models]
- # 1. Check if all nodes in instance model are typed by a node in the example models
- # For that, first get all available types from example models
- print("Verify: checking node typing ...")
- all_types = []
- for exm in example_models_full:
- all_nodes = mv.all_instances(exm, "Node")
- for node in all_nodes:
- typ = mv.read_attrs(exm, node)["typeID"]
- if not typ in all_types:
- all_types.append(typ)
- #print("Verify: types found in example models: {}".format(all_types))
- # Now, check for every element in instance model if it is a valid type
- all_nodes = mv.all_instances(instance_model_path, "Node")
- for node in all_nodes:
- node_typ = mv.read_attrs(instance_model_path, node)["typeID"]
- if node_typ not in all_types:
- return {"OK":False, "error":"Type {} from instance model not in example models".format(node_typ)}
- # 2. Check node cardinality: a node is mandatory in the instance model if it occurs in every
- # example model. Additionally, it needs to occur at least n times if it occurs at least n times in every example model.
- print("Verify: checking node multiplicity ...")
- total_occurences = {k:[] for k in all_types}
- for node, occ_list in total_occurences.iteritems():
- for exm in example_models_full:
- num_occ = _count_occurences(node, exm)
- occ_list.append(num_occ)
- elem_cardinality = {k:min(v) for k, v in total_occurences.iteritems()}
- for el, min_occ in elem_cardinality.iteritems():
- if not _count_occurences(el, instance_model_path) >= min_occ:
- return {"OK":False, "error":"Node with type {} needs to occur at least {} times".format(el, min_occ)}
- return {"OK":True, "error":None}
- # 3. Check attribute types: Is every attribute in instance model present in some example model?
- print("Verify: checking attributes ...")
- all_nodes = mv.all_instances(instance_model_path, "Node")
- for node in all_nodes:
- node_typ = mv.read_attrs(instance_model_path, node)["type"]
- attrs = get_attributes_of(instance_model_path, node_typ)
- if len(attrs) == 0:
- continue
- #print("Attributes of node {} of type {} are: {}".format(node, node_typ, attrs))
- # check example models for such an attribute key
- for im_attribute in attrs:
- found = False
- for exm in example_models_full:
- if found:
- break
- exm_attrs = get_attributes_of(exm, node_typ)
- for exm_attr in exm_attrs:
- if exm_attr.key == im_attribute.key:
- #print("Found attribute {} in model {}".format(im_attribute, exm))
- found = True
- break
- if not found:
- return {"OK":False, "error":"Attribute {} not found in example models".format(im_attribute)}
- # TODO: Attribute mandatory if present in all example model nodes
- # 4. Associations
- # Check multiplicity: an association needs to occur n>0 times if it occurs n>0 times in every example model
- # Check assocation type validity as well
- print("Verify: checking associations ...")
- all_edges = {k:[] for k in example_models_full}
- for exm in example_models_full:
- all_nodes = mv.all_instances(exm, "Node")
- for node in all_nodes:
- node_typ = mv.read_attrs(exm, node)["type"]
- out_associations = mv.read_outgoing(exm, node, "Edge")
- for assoc in out_associations:
- if assoc.startswith("__"):
- continue
- target = mv.read_association_destination(exm, assoc)[0]
- target_typ = mv.read_attrs(exm, target)["type"]
- all_edges[exm].append(Edge(node_typ, target_typ))
- unique_edges = []
- for edge_lst in all_edges.values():
- for edge in edge_lst:
- if not edge in unique_edges:
- unique_edges.append(edge)
- edge_ctr = {k:[] for k in unique_edges}
- for edge, ctr_lst in edge_ctr.iteritems():
- for exm, edges in all_edges.iteritems():
- ctr_lst.append(edges.count(edge))
- for k, v in edge_ctr.iteritems():
- edge_ctr[k] = min(v)
- #print(edge_ctr) # {Edge("AP", "Tablet"): 0, Edge("Router", "PC"): 1, ...}
- # check if mandatory edges are present in instance model
- # first, get all edges in instance model
- all_edges = mv.all_instances(instance_model_path, "Edge")
- im_edges = []
- for edge in all_edges:
- if edge.startswith("__"):
- continue
- edge_src = mv.read_association_source(instance_model_path, edge)[0]
- edge_dest = mv.read_association_destination(instance_model_path, edge)[0]
- edge_src_typ = mv.read_attrs(instance_model_path, edge_src)["type"]
- edge_dest_typ = mv.read_attrs(instance_model_path, edge_dest)["type"]
- im_edges.append(Edge(edge_src_typ, edge_dest_typ))
- # Check if all edges in instance models are valid (connecting types correspond to example models)
- for edge in im_edges:
- if edge not in edge_ctr.keys():
- return {"OK":False, "error":"Edge {} not valid according to example models".format(edge)}
- # now, check if for every mandatory edge, it occurs sufficiently enough
- for edge, cnt in edge_ctr.iteritems():
- if im_edges.count(edge) < cnt:
- return {"OK":False, "error":"Edge {} needs to appear {} times in instance model".format(edge, cnt)}
- return {"OK":True, "error":None}
|