verifier.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import wrappers.modelverse as mv
  2. import commons
  3. class Verifier(object):
  4. def __init__(self, instance_model):
  5. self._instance_model = instance_model
  6. self._example_models = None
  7. self._available_types = None
  8. def set_instance_model(self, model):
  9. self._instance_model = model
  10. def get_instance_model(self):
  11. return self._instance_model
  12. def init(self):
  13. """
  14. Inits the verifier. Loads required data from the modelverse
  15. to avoid reloading it for every step.
  16. """
  17. self._example_models = commons.all_example_models()
  18. self._available_types = commons.get_available_types()
  19. def verify_node_typing(self):
  20. """
  21. Checks if every node in instance model is typed by a node in any example model.
  22. Should actually not be neccessary since instance modeling only allows types from
  23. example models.
  24. """
  25. # Check for every node in instance model if it has a valid type
  26. all_nodes = mv.all_instances(self._instance_model, "Node")
  27. for node in all_nodes:
  28. node_typ = commons.get_node_type(self._instance_model, node)
  29. if node_typ not in self._available_types:
  30. return {"OK": False, "error": "Type {} from instance model not in example models".format(node_typ)}
  31. return {"OK":True, "error":None, "affected":[]}
  32. def verify_node_multiplicity(self):
  33. """
  34. A node is mandatory in the instance model if it occurs at least once in every example model.
  35. """
  36. type_mandatory = {t:False for t in self._available_types}
  37. for node_type,_ in type_mandatory.iteritems():
  38. if commons.is_type_mandatory(node_type):
  39. type_mandatory[node_type] = True
  40. mandatory_types = [node_type for node_type, mandatory in type_mandatory.iteritems() if mandatory]
  41. for mand_type in mandatory_types:
  42. all_of_type = commons.all_nodes_with_type(self._instance_model, mand_type)
  43. if not all_of_type:
  44. return {"OK": False, "error": "Mandatory node of type {} not found".format(mand_type), "affected":[]}
  45. return {"OK":True, "error":None, "affected":[]}
  46. def _get_attributes_of_all_types(self):
  47. """
  48. Helper for attribute check that returns a dictionary of the form {type:[attr_key_1, attr_key_2, ...], ...},
  49. listing all attributes of every type from example models
  50. """
  51. attrs_of_types = {node_type:[] for node_type in self._available_types}
  52. for exm in self._example_models:
  53. for node_type, attrs in attrs_of_types.iteritems():
  54. attrs_of_type_in_exm = [x.key for x in commons.get_all_attributes_of_type(exm, node_type)]
  55. for attr in attrs_of_type_in_exm:
  56. if not attr in attrs:
  57. attrs.append(attr)
  58. return attrs_of_types
  59. def verify_attributes(self):
  60. """
  61. 1. For every attribute key of a typed node in the instance model, there must be a corresponding
  62. attribute key in some example model.
  63. 2. An attribute for a type is mandatory if it occurs in every example model where the associated type node occurs.
  64. """
  65. # Check attribute keys for every node in instance model
  66. all_nodes = mv.all_instances(self._instance_model, "Node")
  67. for node in all_nodes:
  68. attrs = commons.get_attributes_of_node(self._instance_model, node)
  69. if not attrs:
  70. continue
  71. node_typ = commons.get_node_type(self._instance_model, node)
  72. for attr in attrs:
  73. # check every example model if such an attribute key is present for the specific type
  74. for exm in self._example_models:
  75. exm_attrs = commons.get_all_attributes_of_type(exm, node_typ)
  76. if attr.key in [x.key for x in exm_attrs]:
  77. break
  78. else:
  79. # loop completed without break, so we did not find any key in example models
  80. return {"OK": False, "error": "No key {} for type {} in example models".format(attr.key, node_typ),
  81. "affected":[node]}
  82. # Check if mandatory attributes are present in instance model
  83. attr_mandatory = {node_type:{} for node_type in self._available_types}
  84. all_attrs = self._get_attributes_of_all_types()
  85. for typ_i, attr_list in all_attrs.iteritems():
  86. for typ_j, dic in attr_mandatory.iteritems():
  87. if typ_j == typ_i:
  88. for attr in attr_list:
  89. dic[attr] = False
  90. # have dict like {"PC": {"owner":False}, "Router": {"IP":False}, ...}
  91. # now need to check which one is mandatory and set the boolean accordingly
  92. for node_type, attr_dict in attr_mandatory.iteritems():
  93. for attr, _ in attr_dict.iteritems():
  94. if commons.is_attribute_mandatory(node_type, attr):
  95. attr_dict[attr] = True
  96. # for every node in instance model, check if it has the mandatory attributes
  97. for node in mv.all_instances(self._instance_model, "Node"):
  98. node_type = commons.get_node_type(self._instance_model, node)
  99. node_attrs = commons.get_attributes_of_node(self._instance_model, node)
  100. attr_mand = attr_mandatory[node_type]
  101. for attr, mand in attr_mand.iteritems():
  102. if mand:
  103. if not attr in [x.key for x in node_attrs]:
  104. return {"OK": False, "error":"Attribute {} for type {} mandatory".format(attr, node_type),
  105. "affected":[node]}
  106. return {"OK": True, "error": None, "affected":[]}
  107. def verify_associations(self):
  108. """
  109. 1. An edge between two types is mandatory if in every example model that contains nodes of both types, every
  110. node is connected with an edge to the other type.
  111. 2. For every association in the instance model, the types of the source and target must correspond
  112. to the types of an association in some example model. This check should not be necessary since this
  113. is already enforced while instance modeling (see im_scene.py, draw_edge() which checks this when trying
  114. to connect two nodes).
  115. """
  116. mandatory_edges = commons.get_mandtory_edges()
  117. # check if instance model contains the types and the edge
  118. for edge in mandatory_edges:
  119. if not commons.model_contains_type(self._instance_model, edge.n1):
  120. continue
  121. if not commons.model_contains_type(self._instance_model, edge.n2):
  122. continue
  123. # instance model contains both types -> are they connected?
  124. for node in commons.all_nodes_with_type(self._instance_model, edge.n1):
  125. if not commons.has_edge_to_type(self._instance_model, node, edge.n2):
  126. return {"OK":False, "error": "Edge between {} and {} mandatory".format(edge.n1, edge.n2),
  127. "affected":[]}
  128. # other way round
  129. for node in commons.all_nodes_with_type(self._instance_model, edge.n2):
  130. if not commons.has_edge_to_type(self._instance_model, node, edge.n1):
  131. return {"OK":False, "error": "Edge between {} and {} mandatory".format(edge.n2, edge.n1),
  132. "affected":[]}
  133. # lastly, check if all edges in the instance model are actually valid
  134. all_edges = mv.all_instances(self._instance_model, "Edge")
  135. for edge in all_edges:
  136. src_id = mv.read_association_source(self._instance_model, edge)[0]
  137. dest_id = mv.read_association_destination(self._instance_model, edge)[0]
  138. src_type = commons.get_node_type(self._instance_model, src_id)
  139. dest_type = commons.get_node_type(self._instance_model, dest_id)
  140. if not commons.is_edge_supported(src_type, dest_type):
  141. return {"OK":False, "error": "Edge between {} and {} not valid".format(edge.n1, edge.n2),
  142. "affected":[src_id, dest_id]}
  143. return {"OK": True, "error": None, "affected":[]}