package org.alien4cloud.tosca.editor.processors.nodetemplate; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.alien4cloud.tosca.editor.EditionContextManager; import org.alien4cloud.tosca.editor.operations.nodetemplate.DeleteNodeOperation; import org.alien4cloud.tosca.model.definitions.DeploymentArtifact; import org.alien4cloud.tosca.model.templates.NodeTemplate; import org.alien4cloud.tosca.model.templates.RelationshipTemplate; import org.alien4cloud.tosca.model.templates.SubstitutionTarget; import org.alien4cloud.tosca.model.templates.Topology; import org.springframework.stereotype.Component; import com.google.common.collect.Lists; import alien4cloud.component.repository.ArtifactRepositoryConstants; import alien4cloud.component.repository.IFileRepository; import alien4cloud.paas.wf.WorkflowsBuilderService; import alien4cloud.topology.TopologyService; import alien4cloud.topology.TopologyServiceCore; import alien4cloud.topology.TopologyUtils; import lombok.extern.slf4j.Slf4j; /** * Process a {@link DeleteNodeOperation} */ @Slf4j @Component public class DeleteNodeProcessor extends AbstractNodeProcessor<DeleteNodeOperation> { @Resource private TopologyService topologyService; @Resource private IFileRepository artifactRepository; @Resource private WorkflowsBuilderService workflowBuilderService; @Override protected void processNodeOperation(DeleteNodeOperation operation, NodeTemplate template) { Topology topology = EditionContextManager.getTopology(); Map<String, NodeTemplate> nodeTemplates = TopologyServiceCore.getNodeTemplates(topology); // FIXME cleanup files on the github repository / This way we can commit or revert if not saved. // FIXME we SHOULD we delegate all this processing to the save operation as we don't support undo on disk. // Clean up internal repository Map<String, DeploymentArtifact> artifacts = template.getArtifacts(); if (artifacts != null) { for (Map.Entry<String, DeploymentArtifact> artifactEntry : artifacts.entrySet()) { DeploymentArtifact artifact = artifactEntry.getValue(); if (ArtifactRepositoryConstants.ALIEN_ARTIFACT_REPOSITORY.equals(artifact.getArtifactRepository())) { this.artifactRepository.deleteFile(artifact.getArtifactRef()); } } } List<String> typesTobeUnloaded = Lists.newArrayList(); // Clean up dependencies of the topology typesTobeUnloaded.add(template.getType()); if (template.getRelationships() != null) { for (RelationshipTemplate relationshipTemplate : template.getRelationships().values()) { typesTobeUnloaded.add(relationshipTemplate.getType()); } } topologyService.unloadType(topology, typesTobeUnloaded.toArray(new String[typesTobeUnloaded.size()])); removeRelationShipReferences(operation.getNodeName(), topology); nodeTemplates.remove(operation.getNodeName()); removeOutputs(operation.getNodeName(), topology); if (topology.getSubstitutionMapping() != null) { removeNodeTemplateSubstitutionTargetMapEntry(operation.getNodeName(), topology.getSubstitutionMapping().getCapabilities()); removeNodeTemplateSubstitutionTargetMapEntry(operation.getNodeName(), topology.getSubstitutionMapping().getRequirements()); } // group members removal TopologyUtils.updateGroupMembers(topology, template, operation.getNodeName(), null); // update the workflows workflowBuilderService.removeNode(topology, operation.getNodeName(), template); log.debug("Removed node template <{}> from the topology <{}> .", operation.getNodeName(), topology.getId()); } /** * Remove a nodeTemplate outputs in a topology */ private void removeOutputs(String nodeTemplateName, Topology topology) { if (topology.getOutputProperties() != null) { topology.getOutputProperties().remove(nodeTemplateName); } if (topology.getOutputAttributes() != null) { topology.getOutputAttributes().remove(nodeTemplateName); } } 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(); } } } /** * Remove all relationships in nodes where the target was the removed node. * * @param removedNode The name of the removed node * @param topology The topology in which to remove the references. */ private void removeRelationShipReferences(String removedNode, Topology topology) { Map<String, NodeTemplate> nodeTemplates = topology.getNodeTemplates(); List<String> keysToRemove = Lists.newArrayList(); for (String key : nodeTemplates.keySet()) { NodeTemplate nodeTemp = nodeTemplates.get(key); if (nodeTemp.getRelationships() == null) { continue; } keysToRemove.clear(); for (String key2 : nodeTemp.getRelationships().keySet()) { RelationshipTemplate relTemp = nodeTemp.getRelationships().get(key2); if (relTemp == null) { continue; } if (relTemp.getTarget() != null && relTemp.getTarget().equals(removedNode)) { keysToRemove.add(key2); } } for (String relName : keysToRemove) { nodeTemplates.get(key).getRelationships().remove(relName); } } } }