package alien4cloud.tosca.serializer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.alien4cloud.tosca.model.definitions.AbstractPropertyValue;
import org.alien4cloud.tosca.model.definitions.FunctionPropertyValue;
import org.alien4cloud.tosca.model.definitions.PropertyValue;
import org.alien4cloud.tosca.model.definitions.ScalarPropertyValue;
import alien4cloud.paas.exception.NotSupportedException;
public class ToscaPropertySerializerUtils {
private static Pattern ESCAPE_PATTERN = Pattern.compile(".*[,:\\[\\]\\{\\}-].*");
private static Pattern VALID_YAML_PATTERN = Pattern.compile("[a-zA-Z0-9]+");
public static String indent(int indentLevel) {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < indentLevel; i++) {
buffer.append(" ");
}
return buffer.toString();
}
public static String formatTextValue(int indentLevel, String text) {
if (text != null && text.contains("\n")) {
indentLevel++;
StringBuilder indentationBuffer = new StringBuilder();
for (int i = 0; i < indentLevel; i++) {
indentationBuffer.append(" ");
}
String indentation = indentationBuffer.toString();
StringBuilder formattedTextBuffer = new StringBuilder("|\n");
indentation += " ";
String[] lines = text.split("\n");
for (String line : lines) {
formattedTextBuffer.append(indentation).append(line).append("\n");
}
return formattedTextBuffer.toString();
} else {
if (text == null) {
text = "";
} else if (!VALID_YAML_PATTERN.matcher(text).matches()) {
text = "\"" + text + "\"";
}
return text;
}
}
public static String formatPropertyValue(int indentLevel, AbstractPropertyValue propertyValue) {
return ToscaPropertySerializerUtils.formatPropertyValue(true, indentLevel, propertyValue);
}
public static String formatPropertyValue(boolean appendLf, int indentLevel, AbstractPropertyValue propertyValue) {
if (propertyValue instanceof PropertyValue) {
return formatValue(appendLf, indentLevel, ((PropertyValue) propertyValue).getValue());
} else if (propertyValue instanceof FunctionPropertyValue) {
return formatFunctionPropertyValue(appendLf, indentLevel, ((FunctionPropertyValue) propertyValue));
} else {
throw new NotSupportedException("Do not support other types than PropertyValue or FunctionPropertyValue");
}
}
private static String formatValue(int indentLevel, Object value) {
return formatValue(true, indentLevel, value);
}
public static String formatValue(boolean appendLf, int indentLevel, Object value) {
if (isPrimitiveType(value)) {
return formatTextValue(indentLevel, (String) value);
} else if (value instanceof Map) {
return formatMapValue(appendLf, indentLevel, (Map<String, Object>) value);
} else if (value instanceof Object[]) {
return formatListValue(indentLevel, Arrays.asList((Object[]) value));
} else if (value instanceof List) {
return formatListValue(indentLevel, (List<Object>) value);
} else if (value instanceof PropertyValue) {
return formatPropertyValue(appendLf, indentLevel, (PropertyValue) value);
} else {
throw new NotSupportedException("Do not support other types than string map and list");
}
}
private static String formatFunctionPropertyValue(boolean appendLf, int indentLevel, FunctionPropertyValue value) {
indentLevel++;
StringBuilder buffer = new StringBuilder();
if (value.getFunction().equals("get_input")) {
buffer.append("{ ").append(value.getFunction()).append(": ").append(value.getParameters().get(0)).append(" }");
} else {
buffer.append("{ ").append(value.getFunction()).append(": [").append(ToscaSerializerUtils.getCsvToString(value.getParameters())).append("] }");
}
return buffer.toString();
}
private static String formatMapValue(boolean appendFirstLf, int indentLevel, Map<String, Object> value) {
indentLevel++;
StringBuilder buffer = new StringBuilder();
boolean isFirst = true;
for (Map.Entry<String, Object> valueEntry : value.entrySet()) {
if (valueEntry.getValue() != null) {
if (!isFirst || appendFirstLf) {
buffer.append("\n").append(indent(indentLevel));
}
buffer.append(valueEntry.getKey()).append(": ").append(formatValue(indentLevel, valueEntry.getValue()));
if (isFirst) {
isFirst = false;
}
}
}
return buffer.toString();
}
private static String formatListValue(int indentLevel, List<Object> value) {
indentLevel++;
StringBuilder buffer = new StringBuilder();
for (Object element : value) {
if (element != null) {
buffer.append("\n").append(indent(indentLevel)).append("- ").append(formatValue(false, indentLevel, element));
}
}
return buffer.toString();
}
public static String formatProperties(int indentLevel, Map<String, AbstractPropertyValue> properties) {
StringBuilder buffer = new StringBuilder();
for (Map.Entry<String, AbstractPropertyValue> propertyEntry : properties.entrySet()) {
if (propertyEntry.getValue() != null) {
buffer.append("\n").append(indent(indentLevel)).append(propertyEntry.getKey()).append(": ")
.append(formatPropertyValue(indentLevel, propertyEntry.getValue()));
}
}
return buffer.toString();
}
/**
* Render the scalar: when it contain '[' or ']' or '{' or '}' or ':' or '-' or ',', then quote the scalar.
*/
public static String renderScalar(String scalar) {
if (scalar == null) {
return null;
} else if (ESCAPE_PATTERN.matcher(scalar).matches()) {
return "\"" + escapeDoubleQuote(scalar) + "\"";
} else if (scalar.startsWith(" ") || scalar.endsWith(" ")) {
return "\"" + escapeDoubleQuote(scalar) + "\"";
} else {
return scalar;
}
}
private static String escapeDoubleQuote(String scalar) {
if (scalar != null && scalar.contains("\"")) {
// escape double quote
return scalar.replaceAll("\"", "\\\\\"");
}
return scalar;
}
/**
* Check if a property has been defined with a non null and not empty value.
*
* @param properties
* The map of properties in which to look.
* @param property
* The name of the property.
* @return True if a value has been defined, false if not.
*/
public static boolean hasPropertyValue(Map<String, AbstractPropertyValue> properties, String property) {
if (properties == null) {
return false;
}
AbstractPropertyValue propertyValue = properties.get(property);
if (propertyValue == null) {
return false;
}
if (propertyValue instanceof ScalarPropertyValue) {
String value = ((ScalarPropertyValue) propertyValue).getValue();
if (value == null || value.isEmpty()) {
return false;
}
// there is a non-null and not empty property value.
return true;
}
return false;
}
public static Map<String, AbstractPropertyValue> addPropertyValueIfMissing(Map<String, AbstractPropertyValue> properties, String key, String value) {
Map<String, AbstractPropertyValue> copy = new HashMap<>(properties);
if (!copy.containsKey(key) || copy.get(key) == null) {
copy.put(key, new ScalarPropertyValue(value));
}
return copy;
}
private static boolean isPrimitiveType(Object value) {
return value instanceof String || value instanceof Number || value instanceof Boolean;
}
}