package alien4cloud.tosca.parser.postprocess; import static alien4cloud.utils.AlienUtils.safe; import java.util.Objects; import javax.annotation.Resource; import org.alien4cloud.tosca.model.definitions.Operation; import org.alien4cloud.tosca.model.templates.NodeTemplate; import org.alien4cloud.tosca.model.types.NodeType; import org.springframework.stereotype.Component; import org.yaml.snakeyaml.nodes.Node; import alien4cloud.tosca.context.ToscaContext; import alien4cloud.tosca.parser.ParsingContextExecution; import alien4cloud.tosca.parser.ParsingError; import alien4cloud.tosca.parser.ParsingErrorLevel; import alien4cloud.tosca.parser.impl.ErrorCode; import alien4cloud.tosca.topology.NodeTemplateBuilder; /** * Post process a node template */ @Component public class NodeTemplatePostProcessor implements IPostProcessor<NodeTemplate> { @Resource private ReferencePostProcessor referencePostProcessor; @Resource private CapabilityPostProcessor capabilityPostProcessor; @Resource private RequirementPostProcessor requirementPostProcessor; @Resource private PropertyValueChecker propertyValueChecker; @Resource private TemplateDeploymentArtifactPostProcessor templateDeploymentArtifactPostProcessor; @Resource private ImplementationArtifactPostProcessor implementationArtifactPostProcessor; @Override public void process(final NodeTemplate instance) { // ensure type exists referencePostProcessor.process(new ReferencePostProcessor.TypeReference(instance, instance.getType(), NodeType.class)); final NodeType nodeType = ToscaContext.get(NodeType.class, instance.getType()); if (nodeType == null) { return; // error managed by the reference post processor. } // FIXME we should check that the artifact is defined at the type level. safe(instance.getArtifacts()).values().forEach(templateDeploymentArtifactPostProcessor); // TODO Manage interfaces inputs to copy them to all operations. safe(instance.getInterfaces()).values().stream().flatMap(anInterface -> safe(anInterface.getOperations()).values().stream()) .map(Operation::getImplementationArtifact).filter(Objects::nonNull).forEach(implementationArtifactPostProcessor); // Merge the node template with data coming from the type (default values etc.). NodeTemplate tempObject = NodeTemplateBuilder.buildNodeTemplate(nodeType, instance, false); safe(instance.getCapabilities()).keySet().forEach(s -> { if (!safe(tempObject.getCapabilities()).containsKey(s)) { Node node = ParsingContextExecution.getObjectToNodeMap().get(s); ParsingContextExecution.getParsingErrors() .add(new ParsingError(ParsingErrorLevel.WARNING, ErrorCode.UNKNOWN_CAPABILITY, null, node.getStartMark(), null, node.getEndMark(), s)); } }); instance.setAttributes(tempObject.getAttributes()); instance.setCapabilities(tempObject.getCapabilities()); instance.setProperties(tempObject.getProperties()); instance.setRequirements(tempObject.getRequirements()); instance.setArtifacts(tempObject.getArtifacts()); instance.setInterfaces(tempObject.getInterfaces()); // apply post processor to capabilities defined locally on the element (no need to post-processed the one merged) safe(instance.getCapabilities()).entrySet().forEach(capabilityPostProcessor); safe(instance.getRequirements()).entrySet().forEach(requirementPostProcessor); propertyValueChecker.checkProperties(nodeType, instance.getProperties(), instance.getName()); } }