package alien4cloud.tosca.parser.impl.advanced; import java.util.*; import org.springframework.stereotype.Component; import org.yaml.snakeyaml.nodes.MappingNode; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.NodeTuple; import org.yaml.snakeyaml.nodes.ScalarNode; import org.alien4cloud.tosca.model.definitions.FunctionPropertyValue; import org.alien4cloud.tosca.model.templates.Topology; import alien4cloud.tosca.parser.INodeParser; import alien4cloud.tosca.parser.ParsingContextExecution; import alien4cloud.tosca.parser.ParsingError; import alien4cloud.tosca.parser.ParsingErrorLevel; import alien4cloud.tosca.parser.impl.ErrorCode; import lombok.extern.slf4j.Slf4j; @Component @Slf4j public class OuputsParser implements INodeParser<Void> { @Override public Void parse(Node node, ParsingContextExecution context) { Topology topology = (Topology) context.getParent(); if (!(node instanceof MappingNode)) { context.getParsingErrors().add(new ParsingError(ParsingErrorLevel.WARNING, ErrorCode.YAML_MAPPING_NODE_EXPECTED, null, node.getStartMark(), null, node.getEndMark(), null)); return null; } MappingNode mappingNode = (MappingNode) node; Map<String, Set<String>> outputAttributes = null; Map<String, Set<String>> outputProperties = null; Map<String, Map<String, Set<String>>> ouputCapabilityProperties = null; List<NodeTuple> children = mappingNode.getValue(); for (NodeTuple child : children) { Node childValueNode = child.getValueNode(); if (!(childValueNode instanceof MappingNode)) { // not a mapping jut ignore the entry continue; } for (NodeTuple childChild : ((MappingNode) childValueNode).getValue()) { if (childChild.getKeyNode() instanceof ScalarNode && ((ScalarNode) childChild.getKeyNode()).getValue().equals("value")) { // we are only interested by the 'value' node Node outputValueNode = childChild.getValueNode(); // now we have to parse this node INodeParser<?> p = context.getRegistry().get("tosca_function"); FunctionPropertyValue functionPropertyValue = (FunctionPropertyValue) p.parse(outputValueNode, context); String functionName = functionPropertyValue.getFunction(); List<String> params = functionPropertyValue.getParameters(); if (params.size() == 2) { // we need exactly 2 params to be able to do the job : node name & property or attribute name String nodeTemplateName = params.get(0); String nodeTemplatePropertyOrAttributeName = params.get(1); // TODO: should we check they exist ? switch (functionName) { case "get_attribute": outputAttributes = addToMapOfSet(nodeTemplateName, nodeTemplatePropertyOrAttributeName, outputAttributes); break; case "get_property": outputProperties = addToMapOfSet(nodeTemplateName, nodeTemplatePropertyOrAttributeName, outputProperties); break; default: context.getParsingErrors().add(new ParsingError(ParsingErrorLevel.WARNING, ErrorCode.OUTPUTS_UNKNOWN_FUNCTION, null, outputValueNode.getStartMark(), null, outputValueNode.getEndMark(), functionName)); } } else if (params.size() == 3 && functionName.equals("get_property")) { // in case of 3 parameters we only manage capabilities outputs for the moment String nodeTemplateName = params.get(0); String capabilityName = params.get(1); String propertyName = params.get(2); ouputCapabilityProperties = addToMapOfMapOfSet(nodeTemplateName, capabilityName, propertyName, ouputCapabilityProperties); } else { context.getParsingErrors().add(new ParsingError(ParsingErrorLevel.WARNING, ErrorCode.OUTPUTS_BAD_PARAMS_COUNT, null, outputValueNode.getStartMark(), null, outputValueNode.getEndMark(), null)); } } } } topology.setOutputProperties(outputProperties); topology.setOutputAttributes(outputAttributes); topology.setOutputCapabilityProperties(ouputCapabilityProperties); return null; } private Map<String, Set<String>> addToMapOfSet(String key, String value, Map<String, Set<String>> map) { if (map == null) { map = new HashMap<String, Set<String>>(); } Set<String> set = map.get(key); if (set == null) { set = new HashSet<String>(); map.put(key, set); } set.add(value); return map; } private Map<String, Map<String, Set<String>>> addToMapOfMapOfSet(String key1, String key2, String value, Map<String, Map<String, Set<String>>> map) { if (map == null) { map = new HashMap<String, Map<String, Set<String>>>(); } Map<String, Set<String>> map1 = map.get(key1); map.put(key1, addToMapOfSet(key2, value, map1)); return map; } }