com.fivefaces.cloud.workflow.awsonprem.impl.StateMachineExecutorImpl Maven / Gradle / Ivy
package com.fivefaces.cloud.workflow.awsonprem.impl;
import com.amazonaws.services.stepfunctions.builder.StateMachine;
import com.amazonaws.services.stepfunctions.builder.states.*;
import com.fivefaces.cloud.workflow.awsonprem.ChoiceStateExecutor;
import com.fivefaces.cloud.workflow.awsonprem.PassStateInvoker;
import com.fivefaces.cloud.workflow.awsonprem.StateMachineExecutor;
import com.fivefaces.cloud.workflow.awsonprem.TaskStateInvoker;
import com.fivefaces.cloud.workflow.awsonprem.exception.StateMachineFailedException;
import com.fivefaces.cloud.workflow.awsonprem.model.Execution;
import com.fivefaces.cloud.workflow.awsonprem.model.ExecutionResult;
import com.fivefaces.cloud.workflow.awsonprem.model.ExecutionResultStatus;
import com.fivefaces.cloud.workflow.awsonprem.utils.JsonPathUtils;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.fivefaces.cloud.workflow.awsonprem.StateMachineConstants.CAUSE;
import static com.fivefaces.cloud.workflow.awsonprem.StateMachineConstants.ERROR;
import static com.jayway.jsonpath.Option.SUPPRESS_EXCEPTIONS;
/*
Limitations:
1. Most Choice computations are not implemented until they are needed.
2. Parallel, and Wait state types are not implemented.
3. InputPath and OutputPath are not implemented.
4. Retry, Catch are not implemented.
Spec: https://states-language.net/
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class StateMachineExecutorImpl implements StateMachineExecutor {
private final TaskStateInvoker taskStateInvoker;
private final PassStateInvoker passStateInvoker;
private final ChoiceStateExecutor choiceStateExecutor;
@Override
public ExecutionResult execute(StateMachine stateMachine, Execution execution) {
try {
executeState(stateMachine.getStartAt(), stateMachine.getStates(), execution);
ExecutionResult result = new ExecutionResult();
result.setStatus(ExecutionResultStatus.SUCCEEDED);
result.setOutput(execution.getInput().jsonString());
if (execution.debug()) {
execution.finishLog();
result.setDebug(execution.getLogs());
}
return result;
} catch (StateMachineFailedException ex) {
ExecutionResult result = new ExecutionResult();
result.setStatus(ExecutionResultStatus.FAILED);
result.setOutput(execution.getInput().jsonString());
if (execution.debug()) {
execution.finishLog();
result.setDebug(execution.getLogs());
result.setErrorMessage(ex.getMessage());
result.setFailingState(execution.getCurrentStateLog() != null ? execution.getCurrentStateLog().getName() : "INIT");
}
return result;
}
}
private void executeState(String stateName, Map states, Execution execution) {
State state = states.get(stateName);
if (execution.debug()) {
execution.addLog(stateName);
}
switch (state.getType()) {
case State.TASK:
executeState((TaskState) state, states, execution);
break;
case State.CHOICE:
executeState((ChoiceState) state, states, execution);
break;
case State.PASS:
executeState((PassState) state, states, execution);
break;
case State.MAP:
executeState((MapState) state, states, execution);
break;
case State.FAIL:
executeState((FailState) state, execution);
case State.SUCCEED:
break;
default:
throw new IllegalStateException("Could not understand state with type " + state.getType());
}
}
private void executeState(TaskState state, Map states, Execution execution) {
Object result = taskStateInvoker.execute(state, execution);
putResult(result, state.getResultPath(), execution);
transitionState(state.getTransition(), states, execution);
}
private void executeState(ChoiceState state, Map states, Execution execution) {
transitionState(choiceStateExecutor.execute(state, execution), states, execution);
}
private void executeState(PassState state, Map states, Execution execution) {
Object result = passStateInvoker.execute(state, execution);
putResult(result, state.getResultPath(), execution);
transitionState(state.getTransition(), states, execution);
}
private void executeState(MapState state, Map states, Execution execution) {
Object itemsObj = execution.getInput().read(JsonPath.compile(state.getItemsPath()));
if (!(itemsObj instanceof Collection)) {
throw new StateMachineFailedException("ItemsPath does not result in an array");
}
Collection
© 2015 - 2024 Weber Informatics LLC | Privacy Policy