def draw_reachability_graph(self, rg_graph): '''draw the reachability graph ''' states_dict = rg_graph.states_dict edges_dict = rg_graph.edges_dict G = pgv.AGraph(directed=True, strict=False) for state_id in states_dict: state = states_dict[state_id] if state.reachability: G.add_node(state_id, shape="circle") else: G.add_node(state_id, shape="circle", color='blue') for edge_id in edges_dict: edge = edges_dict[edge_id] source = edge.source target = edge.target edge_label = edge.label if edge.reachability: G.add_edge(source, target, label=edge_label) else: G.add_edge(source, target, label=edge_label, color='blue') # print G.string() # print dot file to standard output png_name = self.get_png_name() # G.write("Rg"+png_name + ".dot") G.layout('dot') # layout with dot G.draw("Rg" + "_" + rg_graph.name + png_name + ".png") # write to file # G.draw("Rg" + png_name + ".bmp") # write to file log.show_info("the Reachability Diagram is created." + " name:" + rg_graph.name)
def get_parallel_process(self, activity): '''get the parallel process (action and object node) in the fork and join. ''' nodes_dict = activity.nodes_dict num = 0 for node_id in nodes_dict: node = nodes_dict[node_id] # if it is fork if node.xmi_type == uml_element.Types.FORK_NODE: num += 1 # set the parallel_num of fork node.parallel_num = num # change the name of fork node.name = "parallel" + str(num) actions, objects = self._get_actions_objects( node, num, activity, False) # set the parallel as True and the parallel_num for action in actions: action.parallel = True action.parallel_num = num log.show_info( "the action:%s is in parallel_num:%d process" % (action.name, num)) for object_node in objects: object_node.parallel = True object_node.parallel_num = num log.show_info( "the object node:%s is in parallel_num:%d process" % (object_node.name, num))
def get_tokens_num(self, merge, activity): '''first, judge if the incomings of the merge from the different parallel_num, if yes set the tokens to the number of the incomings. ''' edges_dict = activity.edges_dict # the number of the place's tokens tokens_num = 1 # the number of the parallel parallel_num = 0 # for the edge, which edge.parallel is True edges = [] for incoming in merge.incomings: edge_id = incoming.xmi_idref edge = edges_dict[edge_id] if edge.parallel: edges.append(edge) else: log.show_warn("the merge in the fork has a incoming," + \ "but the incoming is not from the fork, the incoming comes from the outside") if len(edges) > 1: first_edge = edges[0] parallel_num = first_edge.parallel_num for edge in edges: # the edges come from the same fork, but different parallels if edge.parallel_num != parallel_num: tokens_num += 1 if tokens_num > 1: self.set_tokens(merge, tokens_num) log.show_info("the merge has %d tokens. name:%s, id:%s" % (tokens_num, str(merge.name), str(merge.xmi_id)))
def action_has_more_outgoings(self, activity): """ if a action has more than one outgoing. if yes, create one decision after the action. yes: return True no: return False """ nodes_dict = activity.nodes_dict edges_dict = activity.edges_dict ret = False ids = [] for node_id in nodes_dict: node = nodes_dict[node_id] if isinstance(node, uml_element.ExecutableNode): # the control flow number incomings control_flow_num = 0 outgoings = node.outgoings # judge it is a control flow or a object flow for outgoing in outgoings: edge_id = outgoing.xmi_idref edge = edges_dict[edge_id] # it is control flow if edge.xmi_type == uml_element.Types.CONTROL_FLOW: control_flow_num += 1 if control_flow_num > 1: log.show_info( "the action name:%s,id:%s has %d control flow outgoings" % (str(node.name), node.xmi_id, control_flow_num) ) ids.append(node_id) ret = True if ret: for node_id in ids: self._create_decision(node_id, activity) return ids
def get_tokens_num(self, merge, activity): """first, judge if the incomings of the merge from the different parallel_num, if yes set the tokens to the number of the incomings. """ edges_dict = activity.edges_dict # the number of the place's tokens tokens_num = 1 # the number of the parallel parallel_num = 0 # for the edge, which edge.parallel is True edges = [] for incoming in merge.incomings: edge_id = incoming.xmi_idref edge = edges_dict[edge_id] if edge.parallel: edges.append(edge) else: log.show_warn( "the merge in the fork has a incoming," + "but the incoming is not from the fork, the incoming comes from the outside" ) if len(edges) > 1: first_edge = edges[0] parallel_num = first_edge.parallel_num for edge in edges: # the edges come from the same fork, but different parallels if edge.parallel_num != parallel_num: tokens_num += 1 if tokens_num > 1: self.set_tokens(merge, tokens_num) log.show_info("the merge has %d tokens. name:%s, id:%s" % (tokens_num, str(merge.name), str(merge.xmi_id)))
def action_has_more_outgoings(self, activity): ''' if a action has more than one outgoing. if yes, create one decision after the action. yes: return True no: return False ''' nodes_dict = activity.nodes_dict edges_dict = activity.edges_dict ret = False ids = [] for node_id in nodes_dict: node = nodes_dict[node_id] if isinstance(node, uml_element.ExecutableNode): # the control flow number incomings control_flow_num = 0 outgoings = node.outgoings # judge it is a control flow or a object flow for outgoing in outgoings: edge_id = outgoing.xmi_idref edge = edges_dict[edge_id] # it is control flow if edge.xmi_type == uml_element.Types.CONTROL_FLOW: control_flow_num += 1 if control_flow_num > 1: log.show_info( "the action name:%s,id:%s has %d control flow outgoings" % (str(node.name), node.xmi_id, control_flow_num)) ids.append(node_id) ret = True if ret: for node_id in ids: self._create_decision(node_id, activity) return ids
def draw_petri_net(self, petri_net): '''draw Petri Net from the 3 dicts ''' places_dict = petri_net.places_dict transitions_dict = petri_net.transitions_dict arcs_dict = petri_net.arcs_dict # G=pgv.AGraph(directed=True,strict=True,splines="polyline") # G = pgv.AGraph(directed=True, strict=True, splines=False) G = pgv.AGraph(directed=True, strict=True) G.graph_attr['label'] = petri_net.label + petri_net.probs for pt_id in places_dict: place = places_dict[pt_id] place_xlabel = place.xlabel G.add_node(pt_id, shape="circle", label="", xlabel=place_xlabel) for pt_id in transitions_dict: transition = transitions_dict[pt_id] # get the max number of the incomings and outgoings number = max(len(transition.incomings), len(transition.outgoings)) transition_width = 0.5 * number transition_xlabel = transition.xlabel transition_type = transition.transition_type # Deterministic transitions are drawn as black filled rectangles. if transition_type == petri_net_element.TransitionTypes.DETERMINISTIC_TRANSITION: G.add_node(pt_id, shape="box", style="filled", label="", \ xlabel=transition_xlabel, height=0.3, \ width=transition_width, fillcolor="#000000") # color:black # Exponential transitions are drawn as empty rectangles. elif transition_type == petri_net_element.TransitionTypes.EXPONENTIAL_TRANSITION: G.add_node(pt_id, shape="box", label="", xlabel=transition_xlabel, height=0.3, width=transition_width, fillcolor="#000000") # color:black # Immediate transitions are drawn as thin bars. elif transition_type == petri_net_element.TransitionTypes.IMMEDIATE_TRANSITION: G.add_node(pt_id, shape="box", style="filled", label="", xlabel=transition_xlabel, height=0.08, width=transition_width, fillcolor="#000000") # color:black else: log.show_error("the transition type is not defined") for pt_id in arcs_dict: arc = arcs_dict[pt_id] source = arc.source target = arc.target G.add_edge(source, target) # draw the arc with probability # if arc.prob == 1: # G.add_edge(source, target) # else: # G.add_edge(source, target, label=arc.prob) # print G.string() # print dot file to standard output png_name = self.get_png_name() # G.write("Pt"+png_name + ".dot") G.layout('dot') # layout with dot G.draw("Pt" + "_" + petri_net.name + png_name + ".png") # write to file log.show_info("the Petri Net Diagram is created.name:%s" % petri_net.name)
def get_matrix(self, petri_net): '''get the net matrix of the Petri-Net. the way to change the number of a matrix in numpy matrix[0][0] = 1 or matrix[0,0] = 1 ''' places_dict = petri_net.places_dict transitions_dict = petri_net.transitions_dict arcs_dict = petri_net.arcs_dict p_num = len(places_dict) t_num = len(transitions_dict) # create the matrix matrix = np.zeros((p_num, t_num)) for p_id in places_dict: # "s1"-->1, "s12"-->12 row_str = p_id[1:] # if it is "p1", also id_changed is True, the place can be enabled if row_str.isdigit(): row = int(row_str) place = places_dict[p_id] incomings = place.incomings for incoming in incomings: arc_id = incoming arc = arcs_dict[arc_id] source = arc.source t_id = source col_str = t_id[1:] # if it is "t1", also id_changed is True, the transition can fire if col_str.isdigit(): col = int(col_str) matrix[row - 1, col - 1] = 1 outgoings = place.outgoings for outgoing in outgoings: arc_id = outgoing arc = arcs_dict[arc_id] target = arc.target t_id = target # if it is "t1", also id_changed is True, the transition can fire col_str = t_id[1:] if col_str.isdigit(): col = int(col_str) matrix[row - 1, col - 1] = -1 log.show_info("the matrix of the Petri-Net, see below." + " name:" + petri_net.name) petri_net.matrix = matrix print matrix return matrix
def _add_control_flow(self, node1, node2, activity): """add one control flow from node1 to node2. """ edges_dict = activity.edges_dict # get the edge_id, and create a edge edge_id = self._get_new_id("edge", edges_dict) edge = uml_element.ControlFlow( edge_id, uml_element.Types.CONTROL_FLOW, edge_id, node2.xmi_id, node1.xmi_id, None ) # node1.outgoings and node2.incomings outgoing = uml_element.Outgoing(edge_id) node1.outgoings.append(outgoing) incoming = uml_element.Incoming(edge_id) node2.incomings.append(incoming) # put the edge to the edge_dict edges_dict[edge_id] = edge # shwo info log.show_info("one control flow is created from %s to %s." % (str(node1.name), str(node2.name)))
def activity_analyse(self): '''start analyze ''' activity_analyser = ActivityDiagramAnalyser() activitys_dict = self.model.activitys_dict num = len(activitys_dict) log.show_info("the model has %d activities" % num) for activity in activitys_dict.values(): activity_analyser.show_activity_details(activity, show=False) activity_analyser.get_init_final_num(activity) activity_analyser.check_names(activity) activity_analyser.analyze_object_flow(activity) activity_analyser.action_has_more_incomings(activity) activity_analyser.action_has_more_outgoings(activity) activity_analyser.get_parallel_edges(activity) activity_analyser.fork_has_more_incomings(activity) activity_analyser.check_probability(activity) activity_analyser.get_parallel_process(activity) activity_analyser.show_activity_details(activity, show=False)
def _add_control_flow(self, node1, node2, activity): '''add one control flow from node1 to node2. ''' edges_dict = activity.edges_dict # get the edge_id, and create a edge edge_id = self._get_new_id("edge", edges_dict) edge = uml_element.ControlFlow(edge_id, uml_element.Types.CONTROL_FLOW, edge_id, node2.xmi_id, node1.xmi_id, None) # node1.outgoings and node2.incomings outgoing = uml_element.Outgoing(edge_id) node1.outgoings.append(outgoing) incoming = uml_element.Incoming(edge_id) node2.incomings.append(incoming) # put the edge to the edge_dict edges_dict[edge_id] = edge # shwo info log.show_info("one control flow is created from %s to %s." % (str(node1.name), str(node2.name)))
def _get_cf_prob_from_text(self, guard): """get the cf_prob from text of guard. for example: [...prob:0.25] [...prob=0.25] [...pro:0.25] [...pro=0.25] [...pr:0.25] [...pr=0.25] """ prob = 1 if guard is None: # cf_prob is default 1, also edge.prob =1 return 1 # delete the " " guard_body = guard.body.replace(" ", "") possibles = ["prob:", "prob=", "pro:", "pro=", "pr:", "pr="] index = -1 for possible_str in possibles: # find it from right index = guard_body.rfind(possible_str) if index != -1: # the length num = len(possible_str) break if index != -1: # find the number_str, such as "0.5" prob_str = guard_body[(index + num) :] try: # str to float prob = float(prob_str) except ValueError: log.show_error("the prob is invalid,Please modify it " + prob_str) # if it is less than 0 or more than one if (prob <= 0.0) or (prob > 1.0): log.show_error("the prob should be a number between 0 and 1") # if it is not default one if prob != 1: # show info log.show_info("the guard:%s, has cf_prob:%f" % (guard_body, prob)) return prob
def _get_cf_prob_from_text(self, guard): '''get the cf_prob from text of guard. for example: [...prob:0.25] [...prob=0.25] [...pro:0.25] [...pro=0.25] [...pr:0.25] [...pr=0.25] ''' prob = 1 if guard is None: # cf_prob is default 1, also edge.prob =1 return 1 # delete the " " guard_body = guard.body.replace(' ', '') possibles = ["prob:", "prob=", "pro:", "pro=", "pr:", "pr="] index = -1 for possible_str in possibles: # find it from right index = guard_body.rfind(possible_str) if index != -1: # the length num = len(possible_str) break if index != -1: # find the number_str, such as "0.5" prob_str = guard_body[(index + num):] try: # str to float prob = float(prob_str) except ValueError: log.show_error("the prob is invalid,Please modify it " + prob_str) # if it is less than 0 or more than one if (prob <= 0.0) or (prob > 1.0): log.show_error("the prob should be a number between 0 and 1") # if it is not default one if prob != 1: # show info log.show_info("the guard:%s, has cf_prob:%f" % (guard_body, prob)) return prob
def set_time(self, str_time, base_element, time_type, model): '''set the time property of action ''' for activity_id in model.activitys_dict: activity = model.activitys_dict[activity_id] nodes_dict = activity.nodes_dict if base_element in nodes_dict: node = nodes_dict[base_element] time = self.get_time(str_time) # it is not immediate node.immediate = False if time_type == "const": node.deterministic = True elif time_type == "exp": node.exponential = True else: log.show_warn("the type of the time is not defined.type:%s" % time_type) # set it to default deterministic node.deterministic = True node.time = time log.show_info("the action has time property.name:%s,id:%s,time:%s" % (str(node.name), node.xmi_id, str_time)) break
def set_time(self, str_time, base_element, time_type, model): """set the time property of action """ for activity_id in model.activitys_dict: activity = model.activitys_dict[activity_id] nodes_dict = activity.nodes_dict if base_element in nodes_dict: node = nodes_dict[base_element] time = self.get_time(str_time) # it is not immediate node.immediate = False if time_type == "const": node.deterministic = True elif time_type == "exp": node.exponential = True else: log.show_warn("the type of the time is not defined.type:%s" % time_type) # set it to default deterministic node.deterministic = True node.time = time log.show_info( "the action has time property.name:%s,id:%s,time:%s" % (str(node.name), node.xmi_id, str_time) ) break
def get_parallel_process(self, activity): """get the parallel process (action and object node) in the fork and join. """ nodes_dict = activity.nodes_dict num = 0 for node_id in nodes_dict: node = nodes_dict[node_id] # if it is fork if node.xmi_type == uml_element.Types.FORK_NODE: num += 1 # set the parallel_num of fork node.parallel_num = num # change the name of fork node.name = "parallel" + str(num) actions, objects = self._get_actions_objects(node, num, activity, False) # set the parallel as True and the parallel_num for action in actions: action.parallel = True action.parallel_num = num log.show_info("the action:%s is in parallel_num:%d process" % (action.name, num)) for object_node in objects: object_node.parallel = True object_node.parallel_num = num log.show_info("the object node:%s is in parallel_num:%d process" % (object_node.name, num))
def analyze_object_flow(self, activity): """analyze the object flow between node1 and node2. """ log.show_info("object flow analyze starts...") edges_dict = activity.edges_dict # object flow number num = 0 # dictionary changed size during iteration for edge in edges_dict.values(): # if it is object flow if edge.xmi_type == uml_element.Types.OBJECT_FLOW: num += 1 # get the node1, node2 from the edge node1, node2 = self._get_nodes_from_edge(edge, activity) # anylyse the node1 and node2 self._analyse_nodes(node1, node2, activity) # show the number of object edge log.show_info("the activity diagram has %d object flow" % num) log.show_info("object flow analyze completed.")
def analyze_object_flow(self, activity): '''analyze the object flow between node1 and node2. ''' log.show_info("object flow analyze starts...") edges_dict = activity.edges_dict # object flow number num = 0 # dictionary changed size during iteration for edge in edges_dict.values(): # if it is object flow if edge.xmi_type == uml_element.Types.OBJECT_FLOW: num += 1 # get the node1, node2 from the edge node1, node2 = self._get_nodes_from_edge(edge, activity) # anylyse the node1 and node2 self._analyse_nodes(node1, node2, activity) # show the number of object edge log.show_info("the activity diagram has %d object flow" % num) log.show_info("object flow analyze completed.")
start_time = time.clock() # the path of the xml xml_path = examples.get_xml_path() # create the main object act_to_pt = ActivityDiagramToPetriNet() # load xml and parsing act_to_pt.load_xml(xml_path) # start activity_analyse act_to_pt.activity_analyse() # transform_to_pt to Petri net act_to_pt.transform_to_pt() act_to_pt.petri_net_analyse() # draw PT net and reachability_graph_element act_to_pt.create_diagram() # control, getReachabilityGraph act_to_pt.get_reachability_graph() # start petri_net_reachability_analyse act_to_pt.petri_net_reachability_analyse() # show .reachability_graph details act_to_pt.reachability_graph_analyse() # draw PT net and reachability_graph_element act_to_pt.create_diagram() act_to_pt.show_summary(True) end_time = time.clock() log.show_info("completed in " + str(end_time - start_time) + "s")
def _analyse_nodes(self, node1, node2, activity): """for example: situation: 1. action1(with(out) pout)-->action2 (with(out) pin) 2. action1-->object-->action2(or control) 3. action1 with pin-->control node #pass 4. control node(fork,decision,merge)-->action2 with pin #pass 5. control node(fork,decision,merge)-->object-->action2(or control) 6. control node-->control node #pass 7. object node-->... #pass if action1 has no control flow, add one control flow between action1 and action2. """ # if node1 and node2 are actions # 1.situation if isinstance(node1, uml_element.ExecutableNode) and isinstance(node2, uml_element.ExecutableNode): log.show_info("1.situation: action to action") # if node1 has no control flow if not self._has_outgoing_control_flow(node1, activity): # add one control flow from action1 to action2 self._add_control_flow(node1, node2, activity) # if node1 is a action, and node2 is a object_node # 2.situation elif isinstance(node1, uml_element.ExecutableNode) and isinstance(node2, uml_element.ObjectNode): log.show_info("2.situation: action to object node") # if node1 has no control flow if not self._has_outgoing_control_flow(node1, activity): node3 = self._get_object_next_node(node2, activity) # if node3 not None if node3: self._add_control_flow(node1, node3, activity) # if node1 is a action with pout, and node2 is a control # 3.situation elif isinstance(node1, uml_element.ExecutableNode) and isinstance(node2, uml_element.ControlNode): log.show_info("3.situation: action to control node") # pass # if node1 is control_node, node2 is a action with pin # 4.situation elif isinstance(node1, uml_element.ControlNode) and isinstance(node2, uml_element.ExecutableNode): log.show_info("4.situation: control node to action") # pass # if node1 is control_node, node2 is object_node # 5.situation elif isinstance(node1, uml_element.ControlNode) and isinstance(node2, uml_element.ObjectNode): log.show_info("5.situation: control node to object node") node3 = self._get_object_next_node(node2, activity) if node3: # add one control flow from node1 to node3 self._add_control_flow(node1, node3, activity) # if node1 is control_node, node2 is control_node # 6.situation elif isinstance(node1, uml_element.ControlNode) and isinstance(node2, uml_element.ControlNode): log.show_info("6.situation: control node to control node") # TODO # pass # if node1 is object node # 7.situation elif isinstance(node1, uml_element.ObjectNode): pass else: log.show_warn("a object flow from node1 to node2," "but the 2 nodes's situation are not defined")
def xml_parse(self, xml_path): '''start the parsing @param xml_path: the path of the xml @attention: the different between windows and Linux ''' # use minidom to open the xml try: DOMTree = minidom.parse(xml_path) # collection = DOMTree.documentElement except IOError: log.show_error("the xml is wrong") # get the root tag of the xml root = DOMTree.documentElement # get the tag: <xmi:Documentation> # get the exporter(Magic Draw or EA) and exporterVersion documentation = self.get_child_nodes(root, "xmi:Documentation")[0] exporter, export_version = self.get_exporter_version(documentation) log.show_info("exporter:" + exporter + ".exportVersion:" + export_version) # get <uml:Model /> model_node = self.get_child_nodes(root, "uml:Model")[0] # the 4 parameters: xmi_id, xmi_type, name, activitys_dict xmi_id, name, xmi_type = self.get_id_name_type(model_node) activitys_dict = {} # create the model model = uml_element.Model(xmi_id, xmi_type, name, activitys_dict) # get <packagedElement> # packaged_elements = self.get_child_nodes(model_node, "packagedElement") packaged_elements = model_node.getElementsByTagName("packagedElement") InstanceSpecification_nodes = [] activity_id = None for packaged_element in packaged_elements: xmi_id, name, xmi_type = self.get_id_name_type(packaged_element) # get the activity diagram "uml:Activity" if xmi_type == uml_element.Types.ACTIVITY: # xmi_id:ActivityNode (class UmlActivityDiagramElement.ActivityNode) nodes_dict = {} # xmi_id:ActivityEdge (class uml_activity_diagram_element.ActivityEdge) edges_dict = {} # Result and Argument pins_dict = {} # create activity activity = uml_element.Activity(xmi_id, xmi_type, name, nodes_dict, edges_dict, pins_dict) # put it in the activitys_dict activitys_dict[xmi_id] = activity # activity_id activity_id = xmi_id # get all the nodes nodes = self.get_child_nodes(packaged_element, "node") # get every node for node in nodes: # get the id, name, type of the node xmi_id, name, xmi_type = self.get_id_name_type(node) # get behavior behavior = self.get_behavior(node) # get incomings of the node incomings = self.get_incomings(node) # get outgoings of the node outgoings = self.get_outgoings(node) # get the results of the node results = self.get_results(node, xmi_id) # get the arguments of the node arguments = self.get_arguments(node, xmi_id) # create node object self.create_node_object(nodes_dict, xmi_id, xmi_type, name, \ incomings, outgoings, results, arguments, behavior) # put all the results and arguments in the pins_dict # if not all empty if (results or arguments): self.__set_pins_dict(pins_dict, results, arguments) # get all the edges edges = self.get_child_nodes(packaged_element, "edge") # get every node for edge in edges: # get the id,name,type of the edge xmi_id, name, xmi_type = self.get_id_name_type(edge) # get the target, source of the edge target, source = self.get_target_source(edge) # get the guard of the edge guard = self.get_guard(edge) # create edge object self.create_edge_object(edges_dict, xmi_id, xmi_type, name, \ target, source, guard) # <packagedElement name="UserData" xmi:type="uml:InstanceSpecification" xmi:id="EAID_C3D4C"/> elif xmi_type == "uml:InstanceSpecification": InstanceSpecification_node = uml_element.InstanceSpecification_node(xmi_id, xmi_type, name, [], []) InstanceSpecification_nodes.append(InstanceSpecification_node) for InstanceSpecification_node in InstanceSpecification_nodes: model.activitys_dict[activity_id].nodes_dict[InstanceSpecification_node.xmi_id] = InstanceSpecification_node if exporter == "MagicDraw UML": # time parser data_times = self.get_child_nodes(root, "Data:Time") for data_time in data_times: str_time, base_element , time_type = self.get_time_base_element(data_time) self.set_time(str_time, base_element, time_type, model) # for from EA imported xml thecustomprofile_times = self.get_child_nodes(root, "thecustomprofile:time") for thecustomprofile_time in thecustomprofile_times: str_time, base_element, time_type = self.get_time_base_element(thecustomprofile_time) self.set_time(str_time, base_element, time_type, model) elif exporter == "Enterprise Architect": # get the tag "time" for EA extension = self.get_child_nodes(root, "xmi:Extension")[0] elements = self.get_child_nodes(extension, "elements")[0] element_tags = self.get_child_nodes(elements, "element") for element in element_tags: tags = self.get_child_nodes(element, "tags") if len(tags) > 0: tags = tags[0] tag_elements = self.get_child_nodes(tags, "tag") for tag in tag_elements: if tag.hasAttribute("name"): name = tag.getAttribute("name") if name == "time": if tag.hasAttribute("value"): str_time = tag.getAttribute("value") base_element = element.getAttribute("xmi:idref") # TODO self.set_time(str_time, base_element, "exp", model) else: log.show_error("the exporter is not supported in the code") return model
''' Created on 27.11.2015 @author: Kai ''' from activity_diagram_to_ptnet import ActivityDiagramToPetriNet import log import examples import time start = time.clock() # the path of the xml xml_path = examples.get_xml_path() # create the main object act_to_pt = ActivityDiagramToPetriNet() # load xml and parsing act_to_pt.load_xml(xml_path) # start activity_analyse act_to_pt.activity_analyse() # transform_to_pt to Petri net act_to_pt.transform_to_epf() end = time.clock() log.show_info("completed in " + str(end - start) + "s")
def get_petri_type(self, petri_net): '''get the type of Petri-Net @see: http://www.informatik.uni-hamburg.de/TGI/PetriNets/classification/ -Place/Transition (P/T) Nets *(Ordinary) Petri Nets (PN) ~1-safe Net Systems ~Free Choice Nets: @1 S-Systems State Machines (SM): @2 T-System Marked Graphs (MG): @3 Structural Free Choice Extensions: ps: 1: A Free Choice Net is an ordinary Petri Net such that every arc from a place is either a unique outgoing arc or a unique incoming arc to a transition 1a.if two transitions share a common input place then they have no other input places 1b.If two places share a common transition then they have no other transition --here algorithm 2: A State Machine is a Petri Net where every transition has only one input place and one output place 3: A Marked Graph is a pure (ordinary) Petri Net system where every place has only one input transition and one output transition ''' petri_type = [] places_dict = petri_net.places_dict transitions_dict = petri_net.transitions_dict arcs_dict = petri_net.arcs_dict free_choice = True state_machines = True marked_graphs = True for t_id in transitions_dict: transition = transitions_dict[t_id] incomings = transition.incomings outgoings = transition.outgoings in_num = len(incomings) out_num = len(outgoings) if in_num > 1: state_machines = False # if it is free_choice for incoming in incomings: arc = arcs_dict[incoming] p_id = arc.source place = places_dict[p_id] if len(place.outgoings) > 1: # the place has another transition free_choice = False marked_graphs = False break # if not free_choice,break. it is neither state_machines nor marked_graphs if not free_choice: break elif out_num > 1: state_machines = False # it is free_choice, see if it is marked_graphs if free_choice: for p_id in places_dict: place = places_dict[p_id] incomings = place.incomings outgoings = place.outgoings in_num = len(incomings) out_num = len(outgoings) if in_num > 1 or out_num > 1: marked_graphs = False break if free_choice: if state_machines and marked_graphs: petri_type.append(petri_net_element.PetriNetTypes.STATE_MACHINES) petri_type.append(petri_net_element.PetriNetTypes.MARKED_GRAPHS) log.show_info("the type of the transformed Petri-Net is state_machines, "\ "and also marked_graphs. name:%s" % petri_net.name) elif state_machines and not marked_graphs: petri_type.append(petri_net_element.PetriNetTypes.STATE_MACHINES) log.show_info("the type of the transformed Petri-Net is state_machines."\ + " name:%s" % petri_net.name) elif not state_machines and marked_graphs: petri_type.append(petri_net_element.PetriNetTypes.MARKED_GRAPHS) log.show_info("the type of the transformed Petri-Net is marked_graphs."\ + " name:%s" % petri_net.name) else: petri_type.append(petri_net_element.PetriNetTypes.FREE_CHOICE) log.show_info("the type of the transformed Petri-Net is free_choice, "\ "it is neither state_machines nor marked_graphs."\ + " name:%s" % petri_net.name) else: petri_type.append(petri_net_element.PetriNetTypes.NOT_FREE_CHOICE) log.show_info("the type of the transformed Petri-Net is not free_choice."\ + " name:%s" % petri_net.name) return petri_type
def xml_parse(self, xml_path): """start the parsing @param xml_path: the path of the xml @attention: the different between windows and Linux """ # use minidom to open the xml try: DOMTree = minidom.parse(xml_path) # collection = DOMTree.documentElement except IOError: log.show_error("the xml is wrong") # get the root tag of the xml root = DOMTree.documentElement # get the tag: <xmi:Documentation> # get the exporter(Magic Draw or EA) and exporterVersion documentation = self.get_child_nodes(root, "xmi:Documentation")[0] exporter, export_version = self.get_exporter_version(documentation) log.show_info("exporter:" + exporter + ".exportVersion:" + export_version) # get <uml:Model /> model_node = self.get_child_nodes(root, "uml:Model")[0] # the 4 parameters: xmi_id, xmi_type, name, activitys_dict xmi_id, name, xmi_type = self.get_id_name_type(model_node) activitys_dict = {} # create the model model = uml_element.Model(xmi_id, xmi_type, name, activitys_dict) # get <packagedElement> # packaged_elements = self.get_child_nodes(model_node, "packagedElement") packaged_elements = model_node.getElementsByTagName("packagedElement") InstanceSpecification_nodes = [] activity_id = None for packaged_element in packaged_elements: xmi_id, name, xmi_type = self.get_id_name_type(packaged_element) # get the activity diagram "uml:Activity" if xmi_type == uml_element.Types.ACTIVITY: # xmi_id:ActivityNode (class UmlActivityDiagramElement.ActivityNode) nodes_dict = {} # xmi_id:ActivityEdge (class uml_activity_diagram_element.ActivityEdge) edges_dict = {} # Result and Argument pins_dict = {} # create activity activity = uml_element.Activity(xmi_id, xmi_type, name, nodes_dict, edges_dict, pins_dict) # put it in the activitys_dict activitys_dict[xmi_id] = activity # activity_id activity_id = xmi_id # get all the nodes nodes = self.get_child_nodes(packaged_element, "node") # get every node for node in nodes: # get the id, name, type of the node xmi_id, name, xmi_type = self.get_id_name_type(node) # get behavior behavior = self.get_behavior(node) # get incomings of the node incomings = self.get_incomings(node) # get outgoings of the node outgoings = self.get_outgoings(node) # get the results of the node results = self.get_results(node, xmi_id) # get the arguments of the node arguments = self.get_arguments(node, xmi_id) # create node object self.create_node_object( nodes_dict, xmi_id, xmi_type, name, incomings, outgoings, results, arguments, behavior ) # put all the results and arguments in the pins_dict # if not all empty if results or arguments: self.__set_pins_dict(pins_dict, results, arguments) # get all the edges edges = self.get_child_nodes(packaged_element, "edge") # get every node for edge in edges: # get the id,name,type of the edge xmi_id, name, xmi_type = self.get_id_name_type(edge) # get the target, source of the edge target, source = self.get_target_source(edge) # get the guard of the edge guard = self.get_guard(edge) # create edge object self.create_edge_object(edges_dict, xmi_id, xmi_type, name, target, source, guard) # <packagedElement name="UserData" xmi:type="uml:InstanceSpecification" xmi:id="EAID_C3D4C"/> elif xmi_type == "uml:InstanceSpecification": InstanceSpecification_node = uml_element.InstanceSpecification_node(xmi_id, xmi_type, name, [], []) InstanceSpecification_nodes.append(InstanceSpecification_node) for InstanceSpecification_node in InstanceSpecification_nodes: model.activitys_dict[activity_id].nodes_dict[InstanceSpecification_node.xmi_id] = InstanceSpecification_node if exporter == "MagicDraw UML": # time parser data_times = self.get_child_nodes(root, "Data:Time") for data_time in data_times: str_time, base_element, time_type = self.get_time_base_element(data_time) self.set_time(str_time, base_element, time_type, model) # for from EA imported xml thecustomprofile_times = self.get_child_nodes(root, "thecustomprofile:time") for thecustomprofile_time in thecustomprofile_times: str_time, base_element, time_type = self.get_time_base_element(thecustomprofile_time) self.set_time(str_time, base_element, time_type, model) elif exporter == "Enterprise Architect": # get the tag "time" for EA extension = self.get_child_nodes(root, "xmi:Extension")[0] elements = self.get_child_nodes(extension, "elements")[0] element_tags = self.get_child_nodes(elements, "element") for element in element_tags: tags = self.get_child_nodes(element, "tags") if len(tags) > 0: tags = tags[0] tag_elements = self.get_child_nodes(tags, "tag") for tag in tag_elements: if tag.hasAttribute("name"): name = tag.getAttribute("name") if name == "time": if tag.hasAttribute("value"): str_time = tag.getAttribute("value") base_element = element.getAttribute("xmi:idref") # TODO self.set_time(str_time, base_element, "exp", model) else: log.show_error("the exporter is not supported in the code") return model
def _analyse_nodes(self, node1, node2, activity): '''for example: situation: 1. action1(with(out) pout)-->action2 (with(out) pin) 2. action1-->object-->action2(or control) 3. action1 with pin-->control node #pass 4. control node(fork,decision,merge)-->action2 with pin #pass 5. control node(fork,decision,merge)-->object-->action2(or control) 6. control node-->control node #pass 7. object node-->... #pass if action1 has no control flow, add one control flow between action1 and action2. ''' # if node1 and node2 are actions # 1.situation if (isinstance(node1, uml_element.ExecutableNode) and \ isinstance(node2, uml_element.ExecutableNode)): log.show_info("1.situation: action to action") # if node1 has no control flow if not self._has_outgoing_control_flow(node1, activity): # add one control flow from action1 to action2 self._add_control_flow(node1, node2, activity) # if node1 is a action, and node2 is a object_node # 2.situation elif (isinstance(node1, uml_element.ExecutableNode) and isinstance(node2, uml_element.ObjectNode)): log.show_info("2.situation: action to object node") # if node1 has no control flow if not self._has_outgoing_control_flow(node1, activity): node3 = self._get_object_next_node(node2, activity) # if node3 not None if node3: self._add_control_flow(node1, node3, activity) # if node1 is a action with pout, and node2 is a control # 3.situation elif (isinstance(node1, uml_element.ExecutableNode) and isinstance(node2, uml_element.ControlNode)): log.show_info("3.situation: action to control node") # pass # if node1 is control_node, node2 is a action with pin # 4.situation elif (isinstance(node1, uml_element.ControlNode) and isinstance(node2, uml_element.ExecutableNode)): log.show_info("4.situation: control node to action") # pass # if node1 is control_node, node2 is object_node # 5.situation elif (isinstance(node1, uml_element.ControlNode) and isinstance(node2, uml_element.ObjectNode)): log.show_info("5.situation: control node to object node") node3 = self._get_object_next_node(node2, activity) if node3: # add one control flow from node1 to node3 self._add_control_flow(node1, node3, activity) # if node1 is control_node, node2 is control_node # 6.situation elif (isinstance(node1, uml_element.ControlNode) and isinstance(node2, uml_element.ControlNode)): log.show_info("6.situation: control node to control node") # TODO # pass # if node1 is object node # 7.situation elif isinstance(node1, uml_element.ObjectNode): pass else: log.show_warn("a object flow from node1 to node2," "but the 2 nodes's situation are not defined")