package alien4cloud.tosca.serializer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.alien4cloud.tosca.model.definitions.DeploymentArtifact;
import org.alien4cloud.tosca.model.definitions.Interface;
import org.alien4cloud.tosca.model.definitions.Operation;
import org.alien4cloud.tosca.model.definitions.ScalarPropertyValue;
import org.alien4cloud.tosca.model.definitions.constraints.*;
import org.alien4cloud.tosca.model.templates.Capability;
import org.alien4cloud.tosca.model.templates.NodeTemplate;
import org.alien4cloud.tosca.model.templates.Topology;
import org.apache.commons.collections4.CollectionUtils;
import com.google.common.collect.Sets;
import alien4cloud.paas.wf.*;
/**
* Tools for serializing in YAML/TOSCA. ALl methods should be static but did not found how to use statics from velocity.
*/
public class ToscaSerializerUtils {
public boolean collectionIsNotEmpty(Collection<?> c) {
return c != null && !c.isEmpty();
}
public boolean mapIsNotEmpty(Map<?, ?> m) {
return m != null && !m.isEmpty();
}
/**
* Render a description. If the string contain CRLF, then render a multiline literal preserving indentation.
*/
public String renderDescription(String description, String identation) throws IOException {
if (description != null && description.contains("\n")) {
BufferedReader br = new BufferedReader(new StringReader(description));
StringWriter sw = new StringWriter();
sw.write("|");
sw.write("\n");
String line = br.readLine();
boolean isFirst = true;
while (line != null) {
if (isFirst) {
isFirst = false;
} else {
sw.write("\n");
}
sw.write(identation);
sw.write(line);
line = br.readLine();
}
return sw.toString();
} else {
return description;
}
}
/**
* Check if the map is not null, not empty and contains at least one not null value.
* This function is recursive:
* <ul>
* <li>if a map entry is a also a map, then we'll look for non null values in it (recursively).
* <li>if a map entry is a collection, then will return true if the collection is not empty.
* <li>if a map entry is a ScalarPropertyValue, then will return true if the value is not null.
* </ul>
*/
public boolean mapIsNotEmptyAndContainsNotnullValues(Map<?, ?> m) {
if (mapIsNotEmpty(m)) {
for (Object o : m.values()) {
if (o != null) {
if (o instanceof Map<?, ?>) {
if (mapIsNotEmptyAndContainsNotnullValues((Map<?, ?>) o)) {
return true;
}
} else if (o instanceof Collection<?>) {
if (!((Collection<?>) o).isEmpty()) {
return true;
}
} else if (o instanceof ScalarPropertyValue) {
if (((ScalarPropertyValue) o).getValue() != null) {
return true;
}
} else {
return true;
}
}
}
}
return false;
}
public static String getCsvToString(Collection<?> list) {
return getCsvToString(list, false);
}
public static String getCsvToString(Collection<?> list, boolean renderScalar) {
StringBuilder sb = new StringBuilder();
boolean isFirst = true;
if (list != null) {
for (Object o : list) {
if (isFirst) {
isFirst = false;
} else {
sb.append(", ");
}
if (renderScalar) {
sb.append(ToscaPropertySerializerUtils.renderScalar(o.toString()));
} else {
sb.append(o.toString());
}
}
}
return sb.toString();
}
public boolean hasCapabilitiesContainingNotNullProperties(NodeTemplate nodeTemplate) {
Map<String, Capability> capabilities = nodeTemplate.getCapabilities();
if (capabilities == null || capabilities.isEmpty()) {
return false;
}
for (Capability capability : capabilities.values()) {
if (capability == null) {
continue;
}
if (mapIsNotEmptyAndContainsNotnullValues(capability.getProperties())) {
return true;
}
}
return false;
}
public boolean doesInterfacesContainsImplementedOperation(Map<String, Interface> interfaces) {
if (interfaces == null || interfaces.isEmpty()) {
return false;
}
for (Interface interfaze : interfaces.values()) {
if (doesInterfaceContainsImplementedOperation(interfaze)) {
return true;
}
}
return false;
}
public boolean doesInterfaceContainsImplementedOperation(Interface interfaze) {
if (interfaze == null) {
return false;
}
Map<String, Operation> operations = interfaze.getOperations();
if (operations == null || operations.isEmpty()) {
return false;
}
for (Operation operation : operations.values()) {
if (isOperationImplemented(operation)) {
return true;
}
}
return false;
}
public boolean isOperationImplemented(Operation operation) {
if (operation == null) {
return false;
}
if (operation.getImplementationArtifact() != null) {
return true;
}
return false;
}
public String renderConstraint(AbstractPropertyConstraint c) {
StringBuilder builder = new StringBuilder();
if (c instanceof GreaterOrEqualConstraint) {
builder.append("greater_or_equal: ");
builder.append(ToscaPropertySerializerUtils.renderScalar(((GreaterOrEqualConstraint) c).getGreaterOrEqual()));
} else if (c instanceof GreaterThanConstraint) {
builder.append("greater_than: ");
builder.append(ToscaPropertySerializerUtils.renderScalar(((GreaterThanConstraint) c).getGreaterThan()));
} else if (c instanceof LessOrEqualConstraint) {
builder.append("less_or_equal: ");
builder.append(ToscaPropertySerializerUtils.renderScalar(((LessOrEqualConstraint) c).getLessOrEqual()));
} else if (c instanceof LessThanConstraint) {
builder.append("less_than: ");
builder.append(ToscaPropertySerializerUtils.renderScalar(((LessThanConstraint) c).getLessThan()));
} else if (c instanceof LengthConstraint) {
builder.append("length: ");
builder.append(((LengthConstraint) c).getLength());
} else if (c instanceof MaxLengthConstraint) {
builder.append("max_length: ");
builder.append(((MaxLengthConstraint) c).getMaxLength());
} else if (c instanceof MinLengthConstraint) {
builder.append("min_length: ");
builder.append(((MinLengthConstraint) c).getMinLength());
} else if (c instanceof PatternConstraint) {
builder.append("pattern: ");
builder.append(ToscaPropertySerializerUtils.renderScalar(((PatternConstraint) c).getPattern()));
} else if (c instanceof EqualConstraint) {
builder.append("equal: ");
builder.append(ToscaPropertySerializerUtils.renderScalar(((EqualConstraint) c).getEqual()));
} else if (c instanceof InRangeConstraint) {
builder.append("in_range: ");
builder.append("[");
builder.append(getCsvToString(((InRangeConstraint) c).getInRange(), true));
builder.append("]");
} else if (c instanceof ValidValuesConstraint) {
builder.append("valid_values: ");
builder.append("[");
builder.append(getCsvToString(((ValidValuesConstraint) c).getValidValues(), true));
builder.append("]");
}
return builder.toString();
}
public boolean isNodeActivityStep(AbstractStep abstractStep) {
return abstractStep instanceof NodeActivityStep;
}
public String getActivityLabel(AbstractActivity activity) {
if (activity instanceof OperationCallActivity) {
return "call_operation";
} else if (activity instanceof SetStateActivity) {
return "set_state";
} else if (activity instanceof DelegateWorkflowActivity) {
return "delegate";
} else {
return activity.getClass().getSimpleName();
}
}
public boolean canRenderInlineActivityArgs(AbstractActivity activity) {
// if return false, the renderer will call getActivityArgsMap, elsewhere getActivityArg
return true;
}
public String getInlineActivityArg(AbstractActivity activity) {
if (activity instanceof OperationCallActivity) {
OperationCallActivity callActivity = (OperationCallActivity) activity;
return callActivity.getInterfaceName() + "." + callActivity.getOperationName();
} else if (activity instanceof SetStateActivity) {
SetStateActivity stateActivity = (SetStateActivity) activity;
return stateActivity.getStateName();
} else if (activity instanceof DelegateWorkflowActivity) {
DelegateWorkflowActivity delegateWorkflowActivity = (DelegateWorkflowActivity) activity;
return delegateWorkflowActivity.getWorkflowName();
} else {
return "void";
}
}
// sample map for complex activity that can not be rendered simply
public Map<String, String> getActivityArgsMap(AbstractActivity activity) {
Map<String, String> args = new HashMap<String, String>();
args.put("arg1", "value1");
args.put("arg2", "value2");
return args;
}
public static boolean hasRepositories(Topology topology) {
// we don't support node types in Editor context, just check the node templates
if (topology.getNodeTemplates() != null && CollectionUtils.isNotEmpty(topology.getNodeTemplates().values())) {
for (NodeTemplate node : topology.getNodeTemplates().values()) {
if (node.getArtifacts() != null && CollectionUtils.isNotEmpty(node.getArtifacts().values())) {
for (DeploymentArtifact artifact : node.getArtifacts().values()) {
if (artifact.getRepositoryName() != null && artifact.getRepositoryURL() != null) {
return true;
}
}
}
}
}
return false;
}
public static String formatRepositories(Topology topology) {
StringBuilder buffer = new StringBuilder();
Set<String> repositoriesName = Sets.newHashSet();
for (NodeTemplate node : topology.getNodeTemplates().values()) {
if (node.getArtifacts() != null && CollectionUtils.isNotEmpty(node.getArtifacts().values())) {
for (DeploymentArtifact artifact : node.getArtifacts().values()) {
if (artifact.getRepositoryURL() != null && !repositoriesName.contains(artifact.getRepositoryName())) {
repositoriesName.add(artifact.getRepositoryName());
buffer.append(" ").append(artifact.getRepositoryName()).append(":");
buffer.append("\n").append(formatRepository(artifact, 2)).append("\n");
}
}
}
}
buffer.setLength(buffer.length() - 1);
return buffer.toString();
}
public static String formatRepository(DeploymentArtifact value, int indent) {
StringBuilder buffer = new StringBuilder();
String spaces = ToscaPropertySerializerUtils.indent(indent);
buffer.append(spaces).append("url: ").append(value.getRepositoryURL());
buffer.append("\n").append(spaces).append("type: ").append(value.getArtifactRepository());
if (value.getRepositoryCredential() != null && value.getRepositoryCredential().containsKey("token")) {
buffer.append("\n").append(spaces).append("credential:");
spaces += " ";
buffer.append("\n").append(spaces).append("token: ").append(value.getRepositoryCredential().get("token"));
if (value.getRepositoryCredential().containsKey("user")) {
buffer.append("\n").append(spaces).append("user: ").append(value.getRepositoryCredential().get("user"));
}
}
return buffer.toString();
}
public static String formatArtifact(DeploymentArtifact value, int indent) {
String spaces = ToscaPropertySerializerUtils.indent(indent);
StringBuilder buffer = new StringBuilder();
buffer.append(spaces).append("file: ").append(value.getArtifactRef());
if (value.getArtifactType() != null) {
buffer.append("\n").append(spaces).append("type: ").append(value.getArtifactType());
}
if (value.getRepositoryName() != null) {
buffer.append("\n").append(spaces).append("repository: ").append(value.getRepositoryName());
}
return buffer.toString();
}
}