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;
}
}