package org.alien4cloud.tosca.editor.processors.nodetemplate; import java.util.Iterator; import java.util.Map; import javax.inject.Inject; import alien4cloud.tosca.topology.NodeTemplateBuilder; import org.alien4cloud.tosca.catalog.index.IToscaTypeSearchService; import org.alien4cloud.tosca.editor.EditionContextManager; import org.alien4cloud.tosca.editor.operations.nodetemplate.ReplaceNodeOperation; import org.alien4cloud.tosca.editor.processors.IEditorOperationProcessor; import org.alien4cloud.tosca.model.templates.NodeTemplate; import org.alien4cloud.tosca.model.templates.SubstitutionTarget; import org.alien4cloud.tosca.model.templates.Topology; import org.alien4cloud.tosca.model.types.NodeType; import org.springframework.stereotype.Component; import alien4cloud.paas.wf.WorkflowsBuilderService; import alien4cloud.topology.TopologyService; import alien4cloud.topology.TopologyServiceCore; import lombok.extern.slf4j.Slf4j; /** * Replace the type of a node template by another compatible type (inherited or that fulfills the same used capabilities and requirements). */ @Slf4j @Component public class ReplaceNodeProcessor implements IEditorOperationProcessor<ReplaceNodeOperation> { @Inject private IToscaTypeSearchService toscaTypeSearchService; @Inject private TopologyService topologyService; @Inject private WorkflowsBuilderService workflowBuilderService; @Override public void process(ReplaceNodeOperation operation) { Topology topology = EditionContextManager.getTopology(); // Retrieve existing node template Map<String, NodeTemplate> nodeTemplates = TopologyServiceCore.getNodeTemplates(topology); NodeTemplate oldNodeTemplate = TopologyServiceCore.getNodeTemplate(topology.getId(), operation.getNodeName(), nodeTemplates); String[] splittedId = operation.getNewTypeId().split(":"); NodeType newType = toscaTypeSearchService.find(NodeType.class, splittedId[0], splittedId[1]); // Load the new type to the topology in order to update its dependencies newType = topologyService.loadType(topology, newType); // Build the new one NodeTemplate newNodeTemplate = NodeTemplateBuilder.buildNodeTemplate(newType, oldNodeTemplate, false); newNodeTemplate.setName(operation.getNodeName()); newNodeTemplate.setName(oldNodeTemplate.getName()); newNodeTemplate.setRelationships(oldNodeTemplate.getRelationships()); // Put the new one in the topology nodeTemplates.put(oldNodeTemplate.getName(), newNodeTemplate); // Unload and remove old node template topologyService.unloadType(topology, oldNodeTemplate.getType()); // remove the node from the workflows workflowBuilderService.removeNode(topology, oldNodeTemplate.getName(), oldNodeTemplate); // FIXME we should remove outputs/inputs, others here ? if (topology.getSubstitutionMapping() != null) { removeNodeTemplateSubstitutionTargetMapEntry(oldNodeTemplate.getName(), topology.getSubstitutionMapping().getCapabilities()); removeNodeTemplateSubstitutionTargetMapEntry(oldNodeTemplate.getName(), topology.getSubstitutionMapping().getRequirements()); } log.debug("Replacing the node template<{}> with <{}> bound to the node type <{}> on the topology <{}> .", oldNodeTemplate.getName(), oldNodeTemplate.getName(), operation.getNewTypeId(), topology.getId()); // add the new node to the workflow workflowBuilderService.addNode(workflowBuilderService.buildTopologyContext(topology), oldNodeTemplate.getName(), newNodeTemplate); } private void removeNodeTemplateSubstitutionTargetMapEntry(String nodeTemplateName, Map<String, SubstitutionTarget> substitutionTargets) { if (substitutionTargets == null) { return; } Iterator<Map.Entry<String, SubstitutionTarget>> capabilities = substitutionTargets.entrySet().iterator(); while (capabilities.hasNext()) { Map.Entry<String, SubstitutionTarget> e = capabilities.next(); if (e.getValue().getNodeTemplateName().equals(nodeTemplateName)) { capabilities.remove(); } } } }