verifier.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import wrappers.modelverse as mv
  2. from commons import get_attributes_of
  3. class Edge(object):
  4. """
  5. Small helper class for association validation.
  6. Stores an edge as a tuple of (source, dest)
  7. """
  8. def __init__(self, src, dest):
  9. self.src = src
  10. self.dest = dest
  11. def __eq__(self, other):
  12. if other.src == self.src and other.dest == self.dest:
  13. return True
  14. return False
  15. def __repr__(self):
  16. return "{}->{}".format(self.src, self.dest)
  17. def _count_occurences(node_type, model):
  18. """ returns the number of occurences of a node with type node_type in a model """
  19. ctr = 0
  20. all_nodes = mv.all_instances(model, "Node")
  21. for node in all_nodes:
  22. typ = mv.read_attrs(model, node)["typeID"]
  23. if typ == node_type:
  24. ctr += 1
  25. return ctr
  26. def verify(instance_model_path):
  27. """
  28. Verify an instance model against all example models (mv folder currently hard-coded)
  29. Performs checks similar to the linguistic conformance check as seen in the MDE class:
  30. 1. Node typing
  31. 2. Node cardinality
  32. 3. Attribute validity
  33. 4. Associations
  34. """
  35. example_models = mv.model_list("models/example")
  36. example_models_full = ["models/example/"+exm for exm in example_models]
  37. # 1. Check if all nodes in instance model are typed by a node in the example models
  38. # For that, first get all available types from example models
  39. print("Verify: checking node typing ...")
  40. all_types = []
  41. for exm in example_models_full:
  42. all_nodes = mv.all_instances(exm, "Node")
  43. for node in all_nodes:
  44. typ = mv.read_attrs(exm, node)["typeID"]
  45. if not typ in all_types:
  46. all_types.append(typ)
  47. #print("Verify: types found in example models: {}".format(all_types))
  48. # Now, check for every element in instance model if it is a valid type
  49. all_nodes = mv.all_instances(instance_model_path, "Node")
  50. for node in all_nodes:
  51. node_typ = mv.read_attrs(instance_model_path, node)["typeID"]
  52. if node_typ not in all_types:
  53. return {"OK":False, "error":"Type {} from instance model not in example models".format(node_typ)}
  54. # 2. Check node cardinality: a node is mandatory in the instance model if it occurs in every
  55. # example model. Additionally, it needs to occur at least n times if it occurs at least n times in every example model.
  56. print("Verify: checking node multiplicity ...")
  57. total_occurences = {k:[] for k in all_types}
  58. for node, occ_list in total_occurences.iteritems():
  59. for exm in example_models_full:
  60. num_occ = _count_occurences(node, exm)
  61. occ_list.append(num_occ)
  62. elem_cardinality = {k:min(v) for k, v in total_occurences.iteritems()}
  63. for el, min_occ in elem_cardinality.iteritems():
  64. if not _count_occurences(el, instance_model_path) >= min_occ:
  65. return {"OK":False, "error":"Node with type {} needs to occur at least {} times".format(el, min_occ)}
  66. return {"OK":True, "error":None}
  67. # 3. Check attribute types: Is every attribute in instance model present in some example model?
  68. print("Verify: checking attributes ...")
  69. all_nodes = mv.all_instances(instance_model_path, "Node")
  70. for node in all_nodes:
  71. node_typ = mv.read_attrs(instance_model_path, node)["type"]
  72. attrs = get_attributes_of(instance_model_path, node_typ)
  73. if len(attrs) == 0:
  74. continue
  75. #print("Attributes of node {} of type {} are: {}".format(node, node_typ, attrs))
  76. # check example models for such an attribute key
  77. for im_attribute in attrs:
  78. found = False
  79. for exm in example_models_full:
  80. if found:
  81. break
  82. exm_attrs = get_attributes_of(exm, node_typ)
  83. for exm_attr in exm_attrs:
  84. if exm_attr.key == im_attribute.key:
  85. #print("Found attribute {} in model {}".format(im_attribute, exm))
  86. found = True
  87. break
  88. if not found:
  89. return {"OK":False, "error":"Attribute {} not found in example models".format(im_attribute)}
  90. # TODO: Attribute mandatory if present in all example model nodes
  91. # 4. Associations
  92. # Check multiplicity: an association needs to occur n>0 times if it occurs n>0 times in every example model
  93. # Check assocation type validity as well
  94. print("Verify: checking associations ...")
  95. all_edges = {k:[] for k in example_models_full}
  96. for exm in example_models_full:
  97. all_nodes = mv.all_instances(exm, "Node")
  98. for node in all_nodes:
  99. node_typ = mv.read_attrs(exm, node)["type"]
  100. out_associations = mv.read_outgoing(exm, node, "Edge")
  101. for assoc in out_associations:
  102. if assoc.startswith("__"):
  103. continue
  104. target = mv.read_association_destination(exm, assoc)[0]
  105. target_typ = mv.read_attrs(exm, target)["type"]
  106. all_edges[exm].append(Edge(node_typ, target_typ))
  107. unique_edges = []
  108. for edge_lst in all_edges.values():
  109. for edge in edge_lst:
  110. if not edge in unique_edges:
  111. unique_edges.append(edge)
  112. edge_ctr = {k:[] for k in unique_edges}
  113. for edge, ctr_lst in edge_ctr.iteritems():
  114. for exm, edges in all_edges.iteritems():
  115. ctr_lst.append(edges.count(edge))
  116. for k, v in edge_ctr.iteritems():
  117. edge_ctr[k] = min(v)
  118. #print(edge_ctr) # {Edge("AP", "Tablet"): 0, Edge("Router", "PC"): 1, ...}
  119. # check if mandatory edges are present in instance model
  120. # first, get all edges in instance model
  121. all_edges = mv.all_instances(instance_model_path, "Edge")
  122. im_edges = []
  123. for edge in all_edges:
  124. if edge.startswith("__"):
  125. continue
  126. edge_src = mv.read_association_source(instance_model_path, edge)[0]
  127. edge_dest = mv.read_association_destination(instance_model_path, edge)[0]
  128. edge_src_typ = mv.read_attrs(instance_model_path, edge_src)["type"]
  129. edge_dest_typ = mv.read_attrs(instance_model_path, edge_dest)["type"]
  130. im_edges.append(Edge(edge_src_typ, edge_dest_typ))
  131. # Check if all edges in instance models are valid (connecting types correspond to example models)
  132. for edge in im_edges:
  133. if edge not in edge_ctr.keys():
  134. return {"OK":False, "error":"Edge {} not valid according to example models".format(edge)}
  135. # now, check if for every mandatory edge, it occurs sufficiently enough
  136. for edge, cnt in edge_ctr.iteritems():
  137. if im_edges.count(edge) < cnt:
  138. return {"OK":False, "error":"Edge {} needs to appear {} times in instance model".format(edge, cnt)}
  139. return {"OK":True, "error":None}