package alien4cloud.paas.wf.util;
import java.util.Map;
import org.alien4cloud.tosca.model.types.AbstractInheritableToscaType;
import org.alien4cloud.tosca.model.types.NodeType;
import org.alien4cloud.tosca.model.types.RelationshipType;
import org.alien4cloud.tosca.model.definitions.Interface;
import org.alien4cloud.tosca.model.definitions.Operation;
import org.alien4cloud.tosca.model.templates.NodeTemplate;
import org.alien4cloud.tosca.model.templates.RelationshipTemplate;
import alien4cloud.paas.wf.AbstractStep;
import alien4cloud.paas.wf.DelegateWorkflowActivity;
import alien4cloud.paas.wf.NodeActivityStep;
import alien4cloud.paas.wf.OperationCallActivity;
import alien4cloud.paas.wf.SetStateActivity;
import alien4cloud.paas.wf.Workflow;
import alien4cloud.paas.wf.WorkflowsBuilderService.TopologyContext;
import alien4cloud.tosca.normative.NormativeComputeConstants;
import alien4cloud.tosca.normative.NormativeRelationshipConstants;
public class WorkflowUtils {
private static final String NETWORK_TYPE = "tosca.nodes.Network";
private static String getRootHostNode(String nodeId, TopologyContext topologyContext) {
NodeTemplate nodeTemplate = topologyContext.getTopology().getNodeTemplates().get(nodeId);
if (nodeTemplate == null) {
return null;
}
NodeType nodeType = (NodeType) topologyContext.findElement(NodeType.class, nodeTemplate.getType());
if (isOfType(nodeType, NormativeComputeConstants.COMPUTE_TYPE)) {
return nodeId;
} else {
if (nodeTemplate.getRelationships() != null) {
for (RelationshipTemplate relationshipTemplate : nodeTemplate.getRelationships().values()) {
RelationshipType relationshipType = (RelationshipType) topologyContext.findElement(RelationshipType.class, relationshipTemplate.getType());
if (isOfType(relationshipType, NormativeRelationshipConstants.HOSTED_ON)) {
return getRootHostNode(relationshipTemplate.getTarget(), topologyContext);
}
}
}
return null;
}
}
public static boolean isStandardWorkflow(Workflow workflow) {
return Workflow.INSTALL_WF.equals(workflow.getName()) || Workflow.UNINSTALL_WF.equals(workflow.getName());
}
/**
* Compute the wf in order to ensure that all step are tagged with the hostId property.
* <p/>
* The hostId is the first (and normally unique) compute found in the ascendency.
*/
public static void fillHostId(Workflow wf, TopologyContext topologyContext) {
wf.getHosts().clear();
for (AbstractStep step : wf.getSteps().values()) {
if (step instanceof NodeActivityStep) {
NodeActivityStep dstep = (NodeActivityStep) step;
String hostId = WorkflowUtils.getRootHostNode(dstep.getNodeId(), topologyContext);
dstep.setHostId(hostId);
if (hostId != null) {
wf.getHosts().add(hostId);
}
}
}
}
/**
* @return the parentId of the node : the id of the node it's hostedOn (if exists).
*/
public static String getParentId(Workflow wf, String nodeId, TopologyContext topologyContext) {
NodeTemplate nodeTemplate = topologyContext.getTopology().getNodeTemplates().get(nodeId);
if (nodeTemplate != null && nodeTemplate.getRelationships() != null) {
for (RelationshipTemplate relationshipTemplate : nodeTemplate.getRelationships().values()) {
RelationshipType relationshipType = topologyContext.findElement(RelationshipType.class, relationshipTemplate.getType());
if (isOfType(relationshipType, NormativeRelationshipConstants.HOSTED_ON)) {
return relationshipTemplate.getTarget();
}
}
}
return null;
}
/**
* @return the operation browsing the type hierarchy
* FIXME: should we browse hierarchy ? what about order ?
*/
public static Operation getOperation(String nodeTypeName, String interfaceName, String operationName, TopologyContext topologyContext) {
NodeType nodeType = topologyContext.findElement(NodeType.class, nodeTypeName);
if (nodeType == null) {
return null;
}
if (nodeType.getInterfaces() == null) {
return getOperationInSuperTypes(nodeType, interfaceName, operationName, topologyContext);
}
Interface interfaceType = nodeType.getInterfaces().get(interfaceName);
if (interfaceType == null) {
return getOperationInSuperTypes(nodeType, interfaceName, operationName, topologyContext);
}
if (interfaceType.getOperations() == null) {
return getOperationInSuperTypes(nodeType, interfaceName, operationName, topologyContext);
}
Operation operation = interfaceType.getOperations().get(operationName);
if (interfaceType.getOperations() == null) {
return getOperationInSuperTypes(nodeType, interfaceName, operationName, topologyContext);
}
return operation;
}
private static Operation getOperationInSuperTypes(NodeType nodeType, String interfaceName, String operationName, TopologyContext topologyContext) {
if (nodeType.getDerivedFrom() == null) {
return null;
}
for (String superType : nodeType.getDerivedFrom()) {
Operation operation = getOperation(superType, interfaceName, operationName, topologyContext);
if (operation != null) {
return operation;
}
}
return null;
}
public static boolean isOfType(AbstractInheritableToscaType indexedNodeType, String type) {
if (indexedNodeType == null) {
return false;
}
return indexedNodeType.getElementId().equals(type) || indexedNodeType.getDerivedFrom() != null && indexedNodeType.getDerivedFrom().contains(type);
}
public static Interface getInterface(String interfaceName, Map<String, Interface> interfaces) {
return interfaces == null ? null : interfaces.get(interfaceName);
}
public static boolean isCompute(String nodeId, TopologyContext topologyContext) {
NodeTemplate nodeTemplate = topologyContext.getTopology().getNodeTemplates().get(nodeId);
if (nodeTemplate == null) {
return false;
}
NodeType nodeType = (NodeType) topologyContext.findElement(NodeType.class, nodeTemplate.getType());
return isOfType(nodeType, NormativeComputeConstants.COMPUTE_TYPE);
}
public static boolean isComputeOrNetwork(String nodeId, TopologyContext topologyContext) {
NodeTemplate nodeTemplate = topologyContext.getTopology().getNodeTemplates().get(nodeId);
if (nodeTemplate == null) {
return false;
}
NodeType nodeType = (NodeType) topologyContext.findElement(NodeType.class, nodeTemplate.getType());
if (isOfType(nodeType, NormativeComputeConstants.COMPUTE_TYPE)) {
return true;
} else {
return isOfType(nodeType, NETWORK_TYPE);
}
}
public static boolean isComputeOrVolume(String nodeId, TopologyContext topologyContext) {
NodeTemplate nodeTemplate = topologyContext.getTopology().getNodeTemplates().get(nodeId);
if (nodeTemplate == null) {
return false;
}
NodeType nodeType = (NodeType) topologyContext.findElement(NodeType.class, nodeTemplate.getType());
if (isOfType(nodeType, NormativeComputeConstants.COMPUTE_TYPE)) {
return true;
} else {
return isOfType(nodeType, "tosca.nodes.BlockStorage");
}
}
public static boolean isNativeOrSubstitutionNode(String nodeId, TopologyContext topologyContext) {
NodeTemplate nodeTemplate = topologyContext.getTopology().getNodeTemplates().get(nodeId);
if (nodeTemplate == null) {
return false;
}
NodeType nodeType = topologyContext.findElement(NodeType.class, nodeTemplate.getType());
if (nodeType.isAbstract() || nodeType.getSubstitutionTopologyId() != null) {
return true;
}
// TODO: the following should be removed after merge with orchestrator refactoring branch
// (since these types will be abstract)
if (isOfType(nodeType, NormativeComputeConstants.COMPUTE_TYPE) || isOfType(nodeType, NETWORK_TYPE)) {
return true;
} else {
return isOfType(nodeType, "tosca.nodes.BlockStorage");
}
}
public static void linkSteps(AbstractStep from, AbstractStep to) {
if (from != null && to != null) {
from.addFollowing(to.getName());
to.addPreceding(from.getName());
}
}
public static String buildStepName(Workflow wf, AbstractStep step, int increment) {
StringBuilder nameBuilder = new StringBuilder(step.getStepAsString());
if (increment > 0) {
nameBuilder.append("_").append(increment);
}
String name = nameBuilder.toString();
if (wf.getSteps().containsKey(name)) {
return buildStepName(wf, step, ++increment);
} else {
return name;
}
}
public static boolean isStateStep(AbstractStep step) {
return (step instanceof NodeActivityStep) && ((NodeActivityStep) step).getActivity() instanceof SetStateActivity;
}
public static String debugWorkflow(Workflow wf) {
StringBuilder stringBuilder = new StringBuilder("\n ======> Paste the folowing graph in http://www.webgraphviz.com/ !!\n");
int subgraphCount = 0;
stringBuilder.append("\ndigraph ").append(wf.getName()).append(" {");
stringBuilder.append("\n node [shape=box];");
for (String host : wf.getHosts()) {
stringBuilder.append("\n subgraph cluster_").append(++subgraphCount).append(" {");
stringBuilder.append("\n label = \"").append(host).append("\";\n color=blue;");
for (AbstractStep step : wf.getSteps().values()) {
if (step instanceof NodeActivityStep && host.equals(((NodeActivityStep) step).getHostId())) {
stringBuilder.append("\n \"").append(step.getName()).append("\";");
}
}
stringBuilder.append("\n }\n");
}
for (AbstractStep step : wf.getSteps().values()) {
if (step.getFollowingSteps() != null) {
for (String following : step.getFollowingSteps()) {
stringBuilder.append("\n \"").append(step.getName()).append("\" -> \"").append(following).append("\";");
}
}
if (step.getFollowingSteps() == null || step.getFollowingSteps().isEmpty()) {
stringBuilder.append("\n \"").append(step.getName()).append("\" -> end;");
}
if (step.getPrecedingSteps() == null || step.getPrecedingSteps().isEmpty()) {
stringBuilder.append("\n start -> \"").append(step.getName()).append("\";");
}
}
stringBuilder.append("\n start [shape=doublecircle];\n");
stringBuilder.append(" end [shape=circle];\n");
stringBuilder.append("}\n");
stringBuilder.append("======================\n");
return stringBuilder.toString();
}
public static NodeActivityStep addOperationStep(Workflow wf, String nodeId, String interfaceName, String operationName) {
OperationCallActivity task = new OperationCallActivity();
task.setInterfaceName(interfaceName);
task.setOperationName(operationName);
task.setNodeId(nodeId);
NodeActivityStep step = new NodeActivityStep();
step.setNodeId(nodeId);
step.setActivity(task);
step.setName(buildStepName(wf, step, 0));
wf.addStep(step);
return step;
}
public static NodeActivityStep addStateStep(Workflow wf, String nodeId, String stateName) {
SetStateActivity task = new SetStateActivity();
task.setStateName(stateName);
task.setNodeId(nodeId);
NodeActivityStep step = new NodeActivityStep();
step.setNodeId(nodeId);
step.setActivity(task);
step.setName(buildStepName(wf, step, 0));
wf.addStep(step);
return step;
}
public static NodeActivityStep addDelegateWorkflowStep(Workflow wf, String nodeId) {
DelegateWorkflowActivity activity = new DelegateWorkflowActivity();
activity.setNodeId(nodeId);
activity.setWorkflowName(wf.getName());
NodeActivityStep step = new NodeActivityStep();
step.setNodeId(nodeId);
step.setActivity(activity);
step.setName(buildStepName(wf, step, 0));
wf.addStep(step);
return step;
}
public static AbstractStep getDelegateWorkflowStepByNode(Workflow wf, String nodeName) {
for (AbstractStep step : wf.getSteps().values()) {
if (step instanceof NodeActivityStep) {
NodeActivityStep defaultStep = (NodeActivityStep) step;
if (defaultStep.getNodeId().equals(nodeName) && (defaultStep.getActivity() instanceof DelegateWorkflowActivity)) {
return defaultStep;
}
}
}
return null;
}
public static NodeActivityStep getStateStepByNode(Workflow wf, String nodeName, String stateName) {
for (AbstractStep step : wf.getSteps().values()) {
if (step instanceof NodeActivityStep) {
NodeActivityStep defaultStep = (NodeActivityStep) step;
if (defaultStep.getActivity().getNodeId().equals(nodeName) && isStateStep(defaultStep, stateName)) {
return defaultStep;
}
}
}
return null;
}
public static boolean isStateStep(NodeActivityStep defaultStep, String stateName) {
if (defaultStep.getActivity() instanceof SetStateActivity && ((SetStateActivity) defaultStep.getActivity()).getStateName().equals(stateName)) {
return true;
}
return false;
}
}