def generation(self): self.info("TOSCA diagram generation") topology_template = syntax.get_topology_template( self.tosca_service_template.get_yaml()) # Generate only for TOSCA topology template. if topology_template is None: return # Generate the TOSCA diagram. self.open_file(".dot") self.generate("graph ToscaDiagram {") self.generate(' rankdir="LR"') target_capability_ids = { } # map<requirement_assignment_id,capability_id> connected_capabilities = set() # set<node_name.capability_name> connected_requirements = set() # set<node_name.requirement_name> substitution_mappings = syntax.get_substitution_mappings( topology_template) if substitution_mappings is not None: for capability_name, capability_yaml in syntax.get_capabilities( substitution_mappings).items(): if capability_yaml: if not isinstance(capability_yaml, list): continue # TODO something when capability_yaml is not a list capability_name_id = "topology_template_substitution_mappings_capability_" + normalize_name( capability_name) self.generate( " ", capability_name_id, '[label="', capability_name, '" shape=cds style=filled fillcolor=orange]', sep="", ) self.generate( " ", capability_name_id, " -- ", normalize_name(capability_yaml[0]), "_capability_", normalize_name(capability_yaml[1]), "[style=dotted]", sep="", ) connected_capabilities.add(capability_yaml[0] + "." + capability_yaml[1]) for ( requirement_name, requirement_yaml, ) in syntax.get_substitution_mappings_requirements( substitution_mappings).items(): if requirement_yaml: connected_requirements.add(requirement_yaml[0] + "." + requirement_yaml[1]) substitution_mappings_node_type = syntax.get_node_type( substitution_mappings) self.generate(" subgraph clusterSubstitutionMappings {") self.generate(' label="', substitution_mappings_node_type, '"', sep="") node_templates = syntax.get_node_templates(topology_template) for node_name, node_yaml in node_templates.items(): node_type_requirements = syntax.get_requirements_dict( self.type_system.merge_type(syntax.get_type(node_yaml))) for requirement in syntax.get_requirements_list(node_yaml): for requirement_name, requirement_yaml in requirement.items(): # ACK for Alien4Cloud requirement_name = syntax.get_type_requirement( requirement_yaml, requirement_name) if requirement_yaml: requirement_capability = syntax.get_requirement_capability( node_type_requirements.get(requirement_name)) if requirement_capability is None: self.error( requirement_name + ": capability undefined", requirement_name, ) continue requirement_node = syntax.get_requirement_node_template( requirement_yaml) if requirement_node is None: continue capability_found = False requirement_node_template = node_templates.get( requirement_node) if requirement_node_template is None: self.error( requirement_node + " node template undefined", requirement_node, ) continue for capability_name, capability_yaml in syntax.get_capabilities( self.type_system.merge_node_type( syntax.get_type( requirement_node_template))).items(): if self.type_system.is_derived_from( syntax.get_capability_type( capability_yaml), requirement_capability, ): capability_found = True break if capability_found: target_capability_ids[id(requirement)] = ( self.get_node_name_id(requirement_node) + "_capability_" + normalize_name(capability_name)) connected_capabilities.add(requirement_node + "." + capability_name) connected_requirements.add(node_name + "." + requirement_name) else: self.error( ' capability of type "' + requirement_capability + '" not found', requirement_node_template, ) for node_name, node_yaml in node_templates.items(): node_name_id = self.get_node_name_id(node_name) node_type = syntax.get_type(node_yaml) merged_node_type = self.type_system.merge_type(node_type) self.generate(" subgraph cluster", node_name_id, " {", sep="") self.generate(" color=white") self.generate(' label=""') self.generate( " ", node_name_id, '[label="', node_name, ": ", short_type_name(node_type), '|\l\l\l\l" shape=record style=rounded]', sep="", ) for capability_name, capability_yaml in syntax.get_capabilities( merged_node_type).items(): if (node_name + "." + capability_name in connected_capabilities or node_yaml.get("capabilities", {}).get(capability_name) is not None): self.generate( " ", node_name_id, "_capability_", normalize_name(capability_name), '[label="', capability_name, '" shape=cds style=filled fillcolor=orange]', sep="", ) self.generate( " ", node_name_id, "_capability_", normalize_name(capability_name), " -- ", node_name_id, sep="", ) for requirement_name, requirement_yaml in syntax.get_requirements_dict( merged_node_type).items(): if (node_name + "." + requirement_name in connected_requirements or requirement_yaml.get("occurrences", [1, 1])[0] > 0): self.generate( " ", node_name_id, "_requirement_", normalize_name(requirement_name), '[label="', requirement_name, '" shape=cds style=filled fillcolor=turquoise]', sep="", ) self.generate( " ", node_name_id, " -- ", node_name_id, "_requirement_", normalize_name(requirement_name), sep="", ) self.generate(" }") for node_name, node_yaml in node_templates.items(): node_name_id = self.get_node_name_id(node_name) for requirement in syntax.get_requirements_list(node_yaml): for requirement_name, requirement_yaml in requirement.items(): # ACK for Alien4Cloud requirement_name = syntax.get_type_requirement( requirement_yaml, requirement_name) capability_id = target_capability_ids.get(id(requirement)) if capability_id is not None: self.generate( " ", node_name_id, "_requirement_", normalize_name(requirement_name), " -- ", capability_id, "[style=dotted]", sep="", ) if substitution_mappings is not None: self.generate(" }") for ( requirement_name, requirement_yaml, ) in syntax.get_substitution_mappings_requirements( substitution_mappings).items(): if requirement_yaml: requirement_name_id = "topology_template_substitution_mappings_requirement_" + normalize_name( requirement_name) self.generate( " ", requirement_name_id, '[label="', requirement_name, '" shape=cds style=filled fillcolor=turquoise]', sep="", ) self.generate( " ", normalize_name(requirement_yaml[0]), "_requirement_", normalize_name(requirement_yaml[1]), " -- ", requirement_name_id, "[style=dotted]", sep="", ) self.generate("}") self.close_file()
def generate_UML2_deployment_diagram(self, topology_template): self.generate("@startuml") self.generate("skinparam componentStyle uml2") self.generate() node_templates = get_dict(topology_template, NODE_TEMPLATES) non_containeds = list(node_templates.keys()) containers = {} contained_containers = [] # Iterate over all node templates to find containers. for node_template_name, node_template_yaml in node_templates.items(): merged_node_template_type = self.type_system.merge_node_type( node_template_yaml.get(TYPE)) # Iterate over all capabilities of the node template type. for capability_name, capability_yaml in get_dict( merged_node_template_type, CAPABILITIES).items(): capability_type = get_capability_type(capability_yaml) if self.type_system.is_derived_from( capability_type, "tosca.capabilities.Container"): containers[node_template_name] = containers.get( node_template_name, dict()) try: non_containeds.remove(node_template_name) except ValueError: pass # Iterate over all node templates to find containeds. for node_template_name, node_template_yaml in node_templates.items(): merged_node_template_type = self.type_system.merge_node_type( node_template_yaml.get(TYPE)) # Iterate over all requirements of the node template. for requirement in get_list(node_template_yaml, REQUIREMENTS): for requirement_name, requirement_yaml in requirement.items(): requirement_definition = get_dict( merged_node_template_type, REQUIREMENTS).get(requirement_name) requirement_relationship = syntax.get_requirement_relationship( requirement_definition) requirement_relationship_type = syntax.get_relationship_type( requirement_relationship) if self.type_system.is_derived_from( requirement_relationship_type, "tosca.relationships.HostedOn"): requirement_node = get_requirement_node_template( requirement_yaml) if requirement_node is not None: try: containers[requirement_node][ node_template_name] = containers.get( node_template_name, dict()) except KeyError as e: self.error(e) contained_containers.append(node_template_name) try: non_containeds.remove(node_template_name) except ValueError: pass # TODO: Remove containers contained by other containers. for contained_container_name in contained_containers: if containers.get(contained_container_name) is not None: del containers[contained_container_name] # Iterate over all containers. def get_uml2_kind(tosca_type): uml2_kind = "component" for tt, kind in self.configuration.get(UML2, "kinds").items(): if self.type_system.is_derived_from(tosca_type, tt): uml2_kind = kind break return uml2_kind def generate_container(self, container_name, containeds): node_template = node_templates.get(container_name) node_template_type = node_template.get(TYPE) uml2_kind = get_uml2_kind(node_template_type) node_template_artifacts = get_dict(node_template, ARTIFACTS) if len(containeds) == 0 and len(node_template_artifacts) == 0: self.generate( uml2_kind, ' "', container_name, ": ", short_type_name(node_template_type), '" as node_', normalize_name(container_name), sep="", ) else: self.generate( uml2_kind, ' "', container_name, ": ", short_type_name(node_template_type), '" as node_', normalize_name(container_name), " {", sep="", ) for contained_name, contained_dict in containeds.items(): generate_container(self, contained_name, contained_dict) for artifact_name, artifact_yaml in node_template_artifacts.items( ): artifact_type = syntax.get_artifact_type(artifact_yaml) if artifact_type is None: artifact_type = "Artifact" self.generate( 'artifact "', syntax.get_artifact_file(artifact_yaml), '" <<', artifact_type, ">> as node_", normalize_name(container_name), "_artifact_", normalize_name(artifact_name), sep="", ) self.generate("}") substitution_mappings = topology_template.get(SUBSTITUTION_MAPPINGS) if substitution_mappings: # Create components connected to the capabilities of the substitition mapping. for capability_name, capability_yaml in get_dict( substitution_mappings, CAPABILITIES).items(): self.generate( 'component "a node" as substitution_mappings_capability_', normalize_name(capability_name), sep="", ) substitution_mappings_node_type = substitution_mappings.get( NODE_TYPE) self.generate( get_uml2_kind(substitution_mappings_node_type), ' ": ', substitution_mappings_node_type, '" as substitution_mappings {', sep="", ) for container_name, containeds in containers.items(): generate_container(self, container_name, containeds) for node_template_name in non_containeds: generate_container(self, node_template_name, {}) relationship_templates = get_dict(topology_template, RELATIONSHIP_TEMPLATES) # Iterate over all node templates to draw relationships. for node_template_name, node_template_yaml in node_templates.items(): merged_node_template_type = self.type_system.merge_node_type( node_template_yaml.get(TYPE)) # Iterate over all requirements of the node template. for requirement in get_list(node_template_yaml, REQUIREMENTS): for requirement_name, requirement_yaml in requirement.items(): requirement_relationship_type = None if type(requirement_yaml) == dict: requirement_relationship = syntax.get_requirement_relationship( requirement_yaml) if type(requirement_relationship) == dict: requirement_relationship_type = syntax.get_relationship_type( requirement_relationship) else: relationship_template = relationship_templates.get( requirement_relationship) if relationship_template: requirement_relationship_type = relationship_template.get( TYPE) else: requirement_relationship_type = requirement_relationship if requirement_relationship_type is None: requirement = get_dict(merged_node_template_type, REQUIREMENTS).get( requirement_name, {}) tmp = syntax.get_requirement_relationship(requirement) requirement_relationship_type = syntax.get_relationship_type( tmp) if requirement_relationship_type is None: continue if not self.type_system.is_derived_from( requirement_relationship_type, "tosca.relationships.HostedOn"): requirement_node = get_requirement_node_template( requirement_yaml) if requirement_node: self.generate( "node_", normalize_name(node_template_name), ' "', requirement_name, '" ..> node_', normalize_name(requirement_node), " : <<", short_type_name(requirement_relationship_type), ">>", sep="", ) if substitution_mappings: self.generate("}") # Connect created components to the nodes exported by the capabilities of the substitition mapping. for capability_name, capability_yaml in get_dict( substitution_mappings, CAPABILITIES).items(): if type(capability_yaml) != list: continue # TODO target_node_name = capability_yaml[0] target_capability_name = capability_yaml[1] self.generate( "substitution_mappings_capability_", normalize_name(capability_name), ' "', capability_name, '" ..> node_', normalize_name(target_node_name), sep="", ) merged_substitution_mappings_node_type = self.type_system.merge_node_type( substitution_mappings_node_type) # Get all requirements of the node type of the substitution mapping. all_requirement_declarations = get_dict( merged_substitution_mappings_node_type, REQUIREMENTS) req_idx = 0 # Iterate over all requirements of the substitution mapping. for ( requirement_name, requirement_yaml, ) in syntax.get_substitution_mappings_requirements( substitution_mappings).items(): requirement_capability = syntax.get_requirement_capability( all_requirement_declarations.get(requirement_name)) if requirement_capability is None: continue self.generate( get_uml2_kind(requirement_capability), ' ": ', short_type_name(requirement_capability), '" as substitution_mappings_requirement_', req_idx, sep="", ) requirement_node = requirement_yaml[0] requirement_node_capability = requirement_yaml[1] self.generate( "node_", normalize_name(requirement_node), ' "', normalize_name(requirement_node_capability), '" ..> "', requirement_name, '" substitution_mappings_requirement_', req_idx, sep="", ) req_idx = req_idx + 1 self.generate("@enduml")
def generate_network_diagram(self, topology_template): # network ports # dict<port node name, array of bindable node templates> ports = {} def add_port_binding(port_name, node_name): port_bindings = ports.get(port_name) if port_bindings is None: port_bindings = [] ports[port_name] = port_bindings port_bindings.append(node_name) # Networks # dict<network name, Network> networks = {} def get_network(network_name): network = networks.get(network_name) if network is None: network = Network() networks[network_name] = network return network # iterates over all the requirements of the substitution mapping # in order to create external networks substitution_mapping = topology_template.get( syntax.SUBSTITUTION_MAPPINGS) if substitution_mapping is not None: substitution_mapping_node_type = syntax.get_node_type( substitution_mapping) if substitution_mapping_node_type is not None: node_type = self.type_system.merge_type( substitution_mapping_node_type) node_type_requirements = syntax.get_requirements_dict( node_type) for ( requirement_name, requirement_value, ) in syntax.get_substitution_mappings_requirements( substitution_mapping).items(): requirement_definition = node_type_requirements.get( requirement_name) capability = syntax.get_requirement_capability( requirement_definition) if capability in self.configuration.get( NWDIAG, "linkable_capability_types"): # is a requirement with capability in linkable # capability types # create the Network associated to this external # network requirement network = get_network(requirement_name) # the requirement node is in the external node network.nodes[ requirement_value[0]] = requirement_value[0] # iterates over all the node templates node_templates = topology_template.get(syntax.NODE_TEMPLATES, {}) for node_name, node_yaml in node_templates.items(): # get the node type node_type = node_yaml.get(syntax.TYPE) node_type_type = self.type_system.merge_type(node_type) # Deal with Forwarding nodes which are both a port and a network if node_type in self.configuration.get(NWDIAG, "forwarding_node_types"): # a Forwarding node is a node of its associated Forwarding # network get_network(node_name).nodes[node_name] = node_name # iterate over all the node capabilities # in order to identify node templates which are networks for cap_name, cap_def in node_type_type.get( syntax.CAPABILITIES, {}).items(): cap_def_type = (cap_def.get(syntax.TYPE) if isinstance( cap_def, dict) else cap_def) if cap_def_type in self.configuration.get( NWDIAG, "linkable_capability_types"): # this node template is a network node, # i.e. a node template with a linkable capability get_network(node_name).network_node = node_yaml # iterate over all the requirements of the current node node_type_requirements = syntax.get_requirements_dict( node_type_type) for requirement in syntax.get_requirements_list(node_yaml): for requirement_name, requirement_yaml in requirement.items(): requirement_definition = node_type_requirements.get( requirement_name) capability = syntax.get_requirement_capability( requirement_definition) if capability in self.configuration.get( NWDIAG, "linkable_capability_types"): network_node = syntax.get_requirement_node_template( requirement_yaml) # current node template is a node of the network node get_network(network_node).nodes[node_name] = node_name elif capability in self.configuration.get( NWDIAG, "bindable_capability_types"): binding_node = syntax.get_requirement_node_template( requirement_yaml) add_port_binding(node_name, binding_node) # network diagram generation if len(networks) == 0: # no network node template found self.info("No network diagram generated.") else: self.info("Network diagram generation ...") # network node templates found then # generate the network diagram file self.open_file(".nwdiag") self.generate("{") # iterate over all found networks for network_name, network in networks.items(): self.generate(' network "%s" {' % network_name) network_node = network.network_node if network_node is None: # this is an external network associated to a network # requirement of the substitution mapping network_repr = {} # use default graphical attributes network_label = network_name network_address = "" # no network address else: # this a network node template network_repr = self.get_representation(network_node) network_label = self.resolve_attribute( network_node, network_repr, "label", "\n") network_label = (network_label if network_label != "" else network_name) network_address = self.resolve_attribute( network_node, network_repr, "address", "\n") # '', ') # generate the graphical attributes of the network # TODO: add other graphical attributes font, etc. self.generate(' label = "%s"' % network_label) self.generate(' address = "%s"' % network_address) self.generate(' color = "%s"' % network_repr.get("color", "lightblue")) self.generate(' textcolor = "%s"' % network_repr.get( "textcolor", "black", )) # generate all the ports connected to the network if len(network.nodes) == 0: # no node found # nwdiag tool requires that a network has nodes else an # error is produced! # so generate a graphical note self.generate( ' empty_network_%s[label="This network\nis empty!", shape=note];' % network_name) else: # iterates over of the nodes of the network for port_name, node_name in network.nodes.items(): port_node = node_templates.get(port_name) port_repr = self.get_representation(port_node) port_address = self.resolve_attribute( port_node, port_repr, "address", ", ") bindings = ports.get(node_name, [node_name]) for binding in bindings: bindings = ports.get(binding, [binding]) for binding in bindings: binding_node = node_templates.get(binding) binding_repr = self.get_representation( binding_node) binding_label = self.resolve_attribute( binding_node, binding_repr, "label", "\n") binding_label = (binding_label if binding_label != "" else binding) # generate the graphical node # TODO: add other graphical attributes font, # etc. self.generate( ' "%s"[label="%s", address="%s", shape="%s", color="%s", textcolor="%s", style="%s"%s];' % ( binding, binding_label, port_address, binding_repr.get("shape", "box"), binding_repr.get("color", "white"), binding_repr.get("textcolor", "black"), binding_repr.get("style", "solid"), self.get_icon_attribute( binding_node, binding_repr), )) self.generate(" }") self.generate("}") self.close_file()
def generate_UML2_component_diagram(self, topology_template, with_relationships): self.generate("@startuml") self.generate("skinparam componentStyle uml2") if with_relationships: self.generate("skinparam component {") self.generate(" backgroundColor<<relationship>> White") self.generate("}") self.generate() substitution_mappings = topology_template.get(SUBSTITUTION_MAPPINGS) if substitution_mappings: substitution_mappings_uml_id = SUBSTITUTION_MAPPINGS substitution_mappings_node_type = substitution_mappings.get( NODE_TYPE) merged_substitution_mappings_type = self.type_system.merge_node_type( substitution_mappings_node_type) for capability_name, capability_yaml in get_dict( merged_substitution_mappings_type, CAPABILITIES).items(): capability_uml_id = (substitution_mappings_uml_id + "_" + normalize_name(capability_name)) # Declare an UML interface for the substitution_mappings capability. self.generate('interface "', capability_name, '" as ', capability_uml_id, sep="") self.generate( 'component ": ', substitution_mappings_node_type, '" <<node>> as ', substitution_mappings_uml_id, " {", sep="", ) relationship_templates = get_dict(topology_template, RELATIONSHIP_TEMPLATES) already_generated_interfaces = {} # Iterate over all node templates. node_templates = get_dict(topology_template, NODE_TEMPLATES) for node_template_name, node_template_yaml in node_templates.items(): node_template_type = node_template_yaml.get(TYPE) merged_node_template_type = self.type_system.merge_node_type( node_template_type) node_template_uml_id = "node_" + normalize_name(node_template_name) # Declare an UML component for the node template. self.generate( 'component "', node_template_name, ": ", short_type_name(node_template_type), '" <<node>> as ', node_template_uml_id, sep="", ) # Iterate over all capabilities of the node template. for capability_name, capability_yaml in get_dict( merged_node_template_type, CAPABILITIES).items(): if type(capability_yaml) == dict: capability_occurrences = capability_yaml.get(OCCURRENCES) else: capability_occurrences = None if with_relationships or (capability_occurrences and capability_occurrences[0] > 0): capability_uml_id = (node_template_uml_id + "_" + normalize_name(capability_name)) # Declare an UML interface for the node template capability. self.generate( 'interface "', capability_name, '" as ', capability_uml_id, sep="", ) # Connect the capability UML interface to the node template UML component. self.generate(capability_uml_id, "--", node_template_uml_id) already_generated_interfaces[ capability_uml_id] = capability_uml_id if with_relationships: # Iterate over all requirements of the node template. index = 0 for requirement in get_list(node_template_yaml, REQUIREMENTS): for requirement_name, requirement_yaml in requirement.items( ): requirement_uml_id = ( node_template_uml_id + "_" + normalize_name(requirement_name) + "_relationship" + str(index)) index = index + 1 requirement_node = get_requirement_node_template( requirement_yaml) if requirement_node is None: continue relationship_component_name = "" # No name. relationship_component_type = None if type(requirement_yaml) == dict: requirement_relationship = syntax.get_requirement_relationship( requirement_yaml) if type(requirement_relationship) == dict: relationship_component_type = syntax.get_relationship_type( requirement_relationship) else: relationship_template = relationship_templates.get( requirement_relationship) if relationship_template: relationship_component_name = ( requirement_relationship) relationship_component_type = relationship_template.get( TYPE) else: relationship_component_type = ( requirement_relationship) if relationship_component_type is None: requirement = get_dict(merged_node_template_type, REQUIREMENTS).get( requirement_name, {}) tmp = syntax.get_requirement_relationship( requirement) relationship_component_type = syntax.get_relationship_type( tmp) if relationship_component_type is None: continue # Declare an UML component for the node template requirement relationship. self.generate( 'component "', relationship_component_name, ": ", short_type_name(relationship_component_type), '" <<relationship>> as ', requirement_uml_id, sep="", ) # Declare an UML interface for the node template requirement relationship. self.generate('interface " " as ', requirement_uml_id, "_source", sep="") # Connect the UML interface to the relationship UML component. self.generate( requirement_uml_id, "_source", " -- ", requirement_uml_id, sep="", ) # Connect the node template UML component to the relationship UML component. self.generate( node_template_uml_id, " --( ", requirement_uml_id, "_source", " : ", requirement_name, sep="", ) self.generate() # Iterate over all node templates. for node_template_name, node_template_yaml in node_templates.items(): node_template_uml_id = "node_" + normalize_name(node_template_name) node_template_type = node_template_yaml.get(TYPE) merged_node_template_type = self.type_system.merge_node_type( node_template_type) # Iterate over all requirements of the node template. index = 0 for requirement in get_list(node_template_yaml, REQUIREMENTS): for requirement_name, requirement_yaml in requirement.items(): source_uml_id = node_template_uml_id if with_relationships: source_uml_id = (source_uml_id + "_" + normalize_name(requirement_name) + "_relationship" + str(index)) index = index + 1 requirement_node = get_requirement_node_template( requirement_yaml) if requirement_node is None: continue requirement_node_template = node_templates.get( requirement_node) if requirement_node_template is None: continue requirement_node_type_name = requirement_node_template.get( TYPE) if requirement_node_type_name is None: continue requirement_capability = syntax.get_requirement_capability( get_dict(merged_node_template_type, REQUIREMENTS).get(requirement_name)) capability_found = False for (capability_name, capability_yaml) in get_dict( self.type_system.merge_node_type( requirement_node_type_name), CAPABILITIES, ).items(): if self.type_system.is_derived_from( syntax.get_capability_type(capability_yaml), requirement_capability, ): capability_found = True break if capability_found: target_node_uml_id = "node_" + normalize_name( requirement_node) target_capability_uml_id = ( target_node_uml_id + "_" + normalize_name(capability_name)) if with_relationships: self.generate(source_uml_id, " --( ", target_capability_uml_id, sep="") else: if (already_generated_interfaces.get( target_capability_uml_id) is None): self.generate( 'interface "', capability_name, '" as ', target_capability_uml_id, sep="", ) # Connect the capability UML interface to the node template UML component. self.generate(target_capability_uml_id, "--", target_node_uml_id) already_generated_interfaces[ target_capability_uml_id] = target_capability_uml_id self.generate( source_uml_id, " --( ", target_capability_uml_id, " : ", requirement_name, sep="", ) if substitution_mappings: capabilities = get_dict(substitution_mappings, CAPABILITIES) for capability_name, capability_yaml in get_dict( merged_substitution_mappings_type, CAPABILITIES).items(): capability = capabilities.get(capability_name) if capability is not None: if type(capability) != list: continue # TODO when capability is not a list target_node_uml_id = "node_" + capability[0] target_uml_id = (target_node_uml_id + "_" + normalize_name(capability[1])) if already_generated_interfaces.get(target_uml_id) is None: self.generate( 'interface "', capability_name, '" as ', target_uml_id, sep="", ) # Connect the capability UML interface to the node template UML component. self.generate(target_uml_id, "--", target_node_uml_id) already_generated_interfaces[ target_uml_id] = target_uml_id self.generate("}") for capability_name, capability_yaml in get_dict( merged_substitution_mappings_type, CAPABILITIES).items(): capability_uml_id = (substitution_mappings_uml_id + "_" + normalize_name(capability_name)) # Connect the capability UML interface to the node template UML component. capability = capabilities.get(capability_name) if capability is not None: if type(capability) != list: continue # TODO when capability is not a list target_node_uml_id = "node_" + capability[0] target_uml_id = (target_node_uml_id + "_" + normalize_name(capability[1])) self.generate(capability_uml_id, "--(", target_uml_id) else: self.generate(capability_uml_id, "--", substitution_mappings_uml_id) index = 0 for ( requirement_name, requirement_yaml, ) in syntax.get_substitution_mappings_requirements( substitution_mappings).items(): interface_uml_id = (substitution_mappings_uml_id + "_" + normalize_name(requirement_name) + str(index)) index = index + 1 self.generate('interface "', requirement_name, '" as ', interface_uml_id) if requirement_yaml: source_uml_id = "node_" + normalize_name( requirement_yaml[0]) self.generate( source_uml_id, " --( ", interface_uml_id, " : ", requirement_yaml[1], sep="", ) else: self.generate( substitution_mappings_uml_id, " -- ", interface_uml_id, " : ", requirement_name, ) self.generate("@enduml")