use of io.automatiko.engine.api.definition.process.Process in project automatiko-engine by automatiko-io.
the class ServerlessWorkflowParser method parse.
public Process parse(Reader workflowFile) {
AtomicLong ids = new AtomicLong(0);
Workflow workflow = Workflow.fromSource(toString(workflowFile));
ServerlessWorkflowFactory factory = new ServerlessWorkflowFactory();
if (!"jq".equalsIgnoreCase(workflow.getExpressionLang())) {
throw new IllegalArgumentException("Not supported expression language, only 'jq' is supported");
}
WorkflowProcess process = factory.createProcess(workflow);
State start = WorkflowUtils.getStartingState(workflow);
Node startNode;
if (start.getType().equals(DefaultState.Type.EVENT)) {
List<Node> nodes = new ArrayList<>();
EventState eventState = (EventState) start;
for (OnEvents onEvent : eventState.getOnEvents()) {
if (eventState.isExclusive()) {
// use event based gateway
Join join = factory.joinNode(ids.getAndIncrement(), "join_" + eventState.getName(), Join.TYPE_XOR, process);
for (String eventRef : onEvent.getEventRefs()) {
EventDefinition event = WorkflowUtils.getDefinedConsumedEvents(workflow).stream().filter(e -> e.getName().equals(eventRef)).findFirst().get();
StartNode startMessageNode = factory.messageStartNode(ids.getAndIncrement(), event, onEvent, process);
factory.connect(startMessageNode.getId(), join.getId(), "connection_" + startMessageNode.getId() + "_" + join.getId(), process, false);
}
buildActionsForState(workflow, onEvent.getActions(), process, factory, ids, (first, last) -> {
factory.connect(join.getId(), first.getId(), join.getId() + "_" + first.getId(), process, false);
nodes.add(last);
}, (first, last) -> {
}, false);
} else {
// use parallel gateway
Join parallelJoin = factory.joinNode(ids.getAndIncrement(), "join_" + eventState.getName(), Join.TYPE_AND, process);
for (String eventRef : onEvent.getEventRefs()) {
EventDefinition event = WorkflowUtils.getDefinedConsumedEvents(workflow).stream().filter(e -> e.getName().equals(eventRef)).findFirst().get();
StartNode startMessageNode = factory.messageStartNode(ids.getAndIncrement(), event, onEvent, process);
factory.connect(startMessageNode.getId(), parallelJoin.getId(), "connection_" + startMessageNode.getId() + "_" + parallelJoin.getId(), process, false);
}
buildActionsForState(workflow, onEvent.getActions(), process, factory, ids, (first, last) -> {
factory.connect(parallelJoin.getId(), first.getId(), parallelJoin.getId() + "_" + first.getId(), process, false);
nodes.add(last);
}, (first, last) -> {
}, false);
}
}
// start node becomes the last node after message event handling so other parts are connected to it
startNode = nodes.get(0);
if (eventState.getStateDataFilter() != null && eventState.getStateDataFilter().getOutput() != null) {
ActionNode stateDataFilterActionNode = factory.stateDataFilterActionNode(ids.getAndIncrement(), "", process, eventState.getStateDataFilter().getOutput());
factory.connect(startNode.getId(), stateDataFilterActionNode.getId(), "connection_" + startNode.getId() + "_" + stateDataFilterActionNode.getId(), process, false);
startNode = stateDataFilterActionNode;
}
if (eventState.getEnd() != null) {
EndNode endNode = factory.endNode(ids.getAndIncrement(), eventState.getName() + "-end", eventState.getEnd().isTerminate(), process);
if (eventState.getEnd().getProduceEvents() != null && !eventState.getEnd().getProduceEvents().isEmpty()) {
produceEvents(eventState.getEnd().getProduceEvents(), factory, workflow, ids, process, startNode.getId(), endNode.getId());
} else {
factory.connect(startNode.getId(), endNode.getId(), "connection_" + startNode.getId() + "_" + endNode.getId(), process, false);
}
}
} else {
startNode = factory.startNode(ids.getAndIncrement(), start.getName() + "-start", process);
}
// map of state names to node ids for connecting purpose
Map<String, Long> mappedNodes = new LinkedHashMap<>();
Node currentNode = null;
// process all states and create proper node representation for each state
for (State state : workflow.getStates()) {
if (state.getType().equals(Type.INJECT)) {
ActionNode actionNode = factory.injectStateNode(ids.getAndIncrement(), state.getName(), process, ((InjectState) state).getData().toString());
mappedNodes.put(state.getName(), actionNode.getId());
if (state.getEnd() != null) {
EndNode endNode = factory.endNode(ids.getAndIncrement(), state.getName() + "-end", state.getEnd().isTerminate(), process);
if (state.getEnd().getProduceEvents() != null && !state.getEnd().getProduceEvents().isEmpty()) {
produceEvents(state.getEnd().getProduceEvents(), factory, workflow, ids, process, actionNode.getId(), endNode.getId());
} else {
factory.connect(actionNode.getId(), endNode.getId(), "connection_" + actionNode.getId() + "_" + endNode.getId(), process, false);
}
}
setUniqueId(actionNode, state);
currentNode = actionNode;
} else if (state.getType().equals(DefaultState.Type.OPERATION)) {
OperationState operationState = (OperationState) state;
CompositeContextNode embeddedSubProcess = factory.subProcessNode(ids.getAndIncrement(), state.getName(), process);
currentNode = embeddedSubProcess;
setUniqueId(embeddedSubProcess, state);
// handle state data inputs
Assignment inputAssignment = new Assignment("jq", "", "");
inputAssignment.setMetaData("Action", new InputJqAssignmentAction(state.getStateDataFilter() == null ? null : factory.unwrapExpression(state.getStateDataFilter().getInput())));
embeddedSubProcess.addInAssociation(new DataAssociation(Collections.emptyList(), "", Arrays.asList(inputAssignment), null));
// handle state data outputs
Assignment outputAssignment = new Assignment("jq", "", "");
outputAssignment.setMetaData("Action", new OutputJqAssignmentAction(state.getStateDataFilter() == null ? null : factory.unwrapExpression(state.getStateDataFilter().getOutput())));
embeddedSubProcess.addOutAssociation(new DataAssociation(Collections.emptyList(), "", Arrays.asList(outputAssignment), null));
mappedNodes.put(state.getName(), embeddedSubProcess.getId());
StartNode embeddedStartNode = factory.startNode(ids.getAndIncrement(), "EmbeddedStart", embeddedSubProcess);
EndNode embeddedEndNode = factory.endNode(ids.getAndIncrement(), "EmbeddedEnd", false, embeddedSubProcess);
if (operationState.getActions() == null || operationState.getActions().isEmpty()) {
factory.connect(embeddedStartNode.getId(), embeddedEndNode.getId(), embeddedStartNode.getId() + "_" + embeddedEndNode.getId(), embeddedSubProcess, false);
if (state.getEnd() != null) {
EndNode endNode = factory.endNode(ids.getAndIncrement(), state.getName() + "-end", state.getEnd().isTerminate(), process);
if (state.getEnd().getProduceEvents() != null && !state.getEnd().getProduceEvents().isEmpty()) {
produceEvents(state.getEnd().getProduceEvents(), factory, workflow, ids, process, embeddedSubProcess.getId(), endNode.getId());
} else {
factory.connect(embeddedSubProcess.getId(), endNode.getId(), "connection_" + embeddedSubProcess.getId() + "_" + endNode.getId(), process, false);
}
}
// ensure that start node is connected
if (state.equals(start) && currentNode != null) {
factory.connect(startNode.getId(), currentNode.getId(), "connection_" + startNode.getId() + "_" + currentNode.getId(), process, false);
}
continue;
}
if (operationState.getActionMode() == null || operationState.getActionMode() == ActionMode.SEQUENTIAL) {
buildActionsForState(workflow, operationState.getActions(), embeddedSubProcess, factory, ids, (first, last) -> {
factory.connect(embeddedStartNode.getId(), first.getId(), embeddedStartNode.getId() + "_" + first.getId(), embeddedSubProcess, false);
factory.connect(last.getId(), embeddedEndNode.getId(), last.getId() + "_" + embeddedEndNode.getId(), embeddedSubProcess, false);
}, (first, last) -> {
}, false);
} else {
Split split = factory.splitNode(ids.getAndIncrement(), "parallel-split-" + state.getName(), Split.TYPE_AND, embeddedSubProcess);
Join join = factory.joinNode(ids.getAndIncrement(), "parallel-join-" + state.getName(), Join.TYPE_AND, embeddedSubProcess);
factory.connect(embeddedStartNode.getId(), split.getId(), embeddedStartNode.getId() + "_" + split.getId(), embeddedSubProcess, false);
factory.connect(join.getId(), embeddedEndNode.getId(), join.getId() + "_" + embeddedEndNode.getId(), embeddedSubProcess, false);
buildActionsForState(workflow, operationState.getActions(), embeddedSubProcess, factory, ids, (first, last) -> {
}, (first, last) -> {
factory.connect(split.getId(), first.getId(), split.getId() + "_" + first.getId(), embeddedSubProcess, false);
factory.connect(last.getId(), join.getId(), last.getId() + "_" + join.getId(), embeddedSubProcess, false);
}, true);
}
if (state.getEnd() != null) {
EndNode endNode = factory.endNode(ids.getAndIncrement(), state.getName() + "-end", state.getEnd().isTerminate(), process);
if (state.getEnd().getProduceEvents() != null && !state.getEnd().getProduceEvents().isEmpty()) {
produceEvents(state.getEnd().getProduceEvents(), factory, workflow, ids, process, embeddedSubProcess.getId(), endNode.getId());
} else {
factory.connect(embeddedSubProcess.getId(), endNode.getId(), "connection_" + embeddedSubProcess.getId() + "_" + endNode.getId(), process, false);
}
}
} else if (state.getType().equals(DefaultState.Type.EVENT)) {
EventState eventState = (EventState) state;
if (eventState.equals(start)) {
// event state that is start node is already handled
continue;
}
for (OnEvents onEvent : eventState.getOnEvents()) {
CompositeContextNode embeddedSubProcess = factory.subProcessNode(ids.getAndIncrement(), state.getName(), process);
setUniqueId(embeddedSubProcess, state);
currentNode = embeddedSubProcess;
// handle state data inputs
Assignment inputAssignment = new Assignment("jq", "", "");
inputAssignment.setMetaData("Action", new InputJqAssignmentAction(state.getStateDataFilter() == null ? null : factory.unwrapExpression(state.getStateDataFilter().getInput())));
embeddedSubProcess.addInAssociation(new DataAssociation(Collections.emptyList(), "", Arrays.asList(inputAssignment), null));
// handle state data outputs
Assignment outputAssignment = new Assignment("jq", "", "");
outputAssignment.setMetaData("Action", new OutputJqAssignmentAction(state.getStateDataFilter() == null ? null : factory.unwrapExpression(state.getStateDataFilter().getOutput())));
embeddedSubProcess.addOutAssociation(new DataAssociation(Collections.emptyList(), "", Arrays.asList(outputAssignment), null));
mappedNodes.put(state.getName(), embeddedSubProcess.getId());
StartNode embeddedStartNode = factory.startNode(ids.getAndIncrement(), "EmbeddedStart", embeddedSubProcess);
EndNode embeddedEndNode = factory.endNode(ids.getAndIncrement(), "EmbeddedEnd", false, embeddedSubProcess);
if (eventState.isExclusive()) {
// use event based gateway
Split eventSplit = factory.eventBasedSplit(ids.getAndIncrement(), "split_" + state.getName(), embeddedSubProcess);
Join join = factory.joinNode(ids.getAndIncrement(), "join_" + state.getName(), Join.TYPE_XOR, embeddedSubProcess);
factory.connect(embeddedStartNode.getId(), eventSplit.getId(), "connection_" + embeddedStartNode.getId() + "_" + eventSplit.getId(), embeddedSubProcess, false);
for (String eventRef : onEvent.getEventRefs()) {
EventDefinition event = WorkflowUtils.getDefinedConsumedEvents(workflow).stream().filter(e -> e.getName().equals(eventRef)).findFirst().get();
EventNode eventNode = factory.consumeEventNode(ids.getAndIncrement(), event, onEvent.getEventDataFilter(), embeddedSubProcess);
factory.connect(eventSplit.getId(), eventNode.getId(), "connection_" + eventSplit.getId() + "_" + eventNode.getId(), embeddedSubProcess, false);
factory.connect(eventNode.getId(), join.getId(), "connection_" + eventNode.getId() + "_" + join.getId(), embeddedSubProcess, false);
}
buildActionsForState(workflow, onEvent.getActions(), embeddedSubProcess, factory, ids, (first, last) -> {
factory.connect(join.getId(), first.getId(), join.getId() + "_" + first.getId(), embeddedSubProcess, false);
factory.connect(last.getId(), embeddedEndNode.getId(), last.getId() + "_" + embeddedEndNode.getId(), embeddedSubProcess, false);
}, (first, last) -> {
}, false);
} else {
// use parallel gateway
Split parallelSplit = factory.splitNode(ids.getAndIncrement(), "split_" + state.getName(), Split.TYPE_AND, embeddedSubProcess);
Join parallelJoin = factory.joinNode(ids.getAndIncrement(), "join_" + state.getName(), Join.TYPE_AND, embeddedSubProcess);
factory.connect(embeddedStartNode.getId(), parallelSplit.getId(), "connection_" + embeddedStartNode.getId() + "_" + parallelSplit.getId(), embeddedSubProcess, false);
for (String eventRef : onEvent.getEventRefs()) {
EventDefinition event = WorkflowUtils.getDefinedConsumedEvents(workflow).stream().filter(e -> e.getName().equals(eventRef)).findFirst().get();
EventNode eventNode = factory.consumeEventNode(ids.getAndIncrement(), event, onEvent.getEventDataFilter(), embeddedSubProcess);
factory.connect(parallelSplit.getId(), eventNode.getId(), "connection_" + parallelSplit.getId() + "_" + eventNode.getId(), embeddedSubProcess, false);
factory.connect(eventNode.getId(), parallelJoin.getId(), "connection_" + eventNode.getId() + "_" + parallelJoin.getId(), embeddedSubProcess, false);
}
buildActionsForState(workflow, onEvent.getActions(), embeddedSubProcess, factory, ids, (first, last) -> {
factory.connect(parallelJoin.getId(), first.getId(), parallelJoin.getId() + "_" + first.getId(), embeddedSubProcess, false);
factory.connect(last.getId(), embeddedEndNode.getId(), last.getId() + "_" + embeddedEndNode.getId(), embeddedSubProcess, false);
}, (first, last) -> {
}, false);
}
if (state.getEnd() != null) {
EndNode endNode = factory.endNode(ids.getAndIncrement(), state.getName() + "-end", state.getEnd().isTerminate(), process);
if (state.getEnd().getProduceEvents() != null && !state.getEnd().getProduceEvents().isEmpty()) {
produceEvents(state.getEnd().getProduceEvents(), factory, workflow, ids, process, embeddedSubProcess.getId(), endNode.getId());
} else {
factory.connect(embeddedSubProcess.getId(), endNode.getId(), "connection_" + embeddedSubProcess.getId() + "_" + endNode.getId(), process, false);
}
}
}
} else if (state.getType().equals(DefaultState.Type.CALLBACK)) {
CallbackState callcackState = (CallbackState) state;
CompositeContextNode embeddedSubProcess = factory.subProcessNode(ids.getAndIncrement(), state.getName(), process);
currentNode = embeddedSubProcess;
setUniqueId(embeddedSubProcess, state);
// handle state data inputs
Assignment inputAssignment = new Assignment("jq", "", "");
inputAssignment.setMetaData("Action", new InputJqAssignmentAction(state.getStateDataFilter() == null ? null : factory.unwrapExpression(state.getStateDataFilter().getInput())));
embeddedSubProcess.addInAssociation(new DataAssociation(Collections.emptyList(), "", Arrays.asList(inputAssignment), null));
// handle state data outputs
Assignment outputAssignment = new Assignment("jq", "", "");
outputAssignment.setMetaData("Action", new OutputJqAssignmentAction(state.getStateDataFilter() == null ? null : factory.unwrapExpression(state.getStateDataFilter().getOutput())));
embeddedSubProcess.addOutAssociation(new DataAssociation(Collections.emptyList(), "", Arrays.asList(outputAssignment), null));
mappedNodes.put(state.getName(), embeddedSubProcess.getId());
StartNode embeddedStartNode = factory.startNode(ids.getAndIncrement(), "EmbeddedStart", embeddedSubProcess);
EndNode embeddedEndNode = factory.endNode(ids.getAndIncrement(), "EmbeddedEnd", false, embeddedSubProcess);
EventDefinition event = WorkflowUtils.getDefinedConsumedEvents(workflow).stream().filter(e -> e.getName().equals(callcackState.getEventRef())).findFirst().get();
EventNode eventNode = factory.consumeEventNode(ids.getAndIncrement(), event, callcackState.getEventDataFilter(), embeddedSubProcess);
buildActionsForState(workflow, Collections.singletonList(callcackState.getAction()), embeddedSubProcess, factory, ids, (first, last) -> {
factory.connect(embeddedStartNode.getId(), first.getId(), embeddedStartNode.getId() + "_" + first.getId(), embeddedSubProcess, false);
factory.connect(last.getId(), eventNode.getId(), last.getId() + "_" + eventNode.getId(), embeddedSubProcess, false);
}, (first, last) -> {
}, false);
factory.connect(eventNode.getId(), embeddedEndNode.getId(), "connection_" + eventNode.getId() + "_" + embeddedEndNode.getId(), embeddedSubProcess, false);
if (state.getEnd() != null) {
EndNode endNode = factory.endNode(ids.getAndIncrement(), state.getName() + "-end", state.getEnd().isTerminate(), process);
if (state.getEnd().getProduceEvents() != null && !state.getEnd().getProduceEvents().isEmpty()) {
produceEvents(state.getEnd().getProduceEvents(), factory, workflow, ids, process, embeddedSubProcess.getId(), endNode.getId());
} else {
factory.connect(embeddedSubProcess.getId(), endNode.getId(), "connection_" + embeddedSubProcess.getId() + "_" + endNode.getId(), process, false);
}
}
} else if (state.getType().equals(Type.SLEEP)) {
TimerNode sleep = factory.timerNode(ids.getAndIncrement(), "sleep-" + state.getName(), ((SleepState) state).getDuration(), process);
mappedNodes.put(state.getName(), sleep.getId());
setUniqueId(sleep, state);
if (state.getEnd() != null) {
EndNode endNode = factory.endNode(ids.getAndIncrement(), state.getName() + "-end", state.getEnd().isTerminate(), process);
if (state.getEnd().getProduceEvents() != null && !state.getEnd().getProduceEvents().isEmpty()) {
produceEvents(state.getEnd().getProduceEvents(), factory, workflow, ids, process, sleep.getId(), endNode.getId());
} else {
factory.connect(sleep.getId(), endNode.getId(), "connection_" + sleep.getId() + "_" + endNode.getId(), process, false);
}
}
currentNode = sleep;
} else if (state.getType().equals(DefaultState.Type.PARALLEL)) {
ParallelState parallelState = (ParallelState) state;
CompositeContextNode embeddedSubProcess = factory.subProcessNode(ids.getAndIncrement(), state.getName(), process);
setUniqueId(embeddedSubProcess, state);
currentNode = embeddedSubProcess;
// handle state data inputs
Assignment inputAssignment = new Assignment("jq", "", "");
inputAssignment.setMetaData("Action", new InputJqAssignmentAction(state.getStateDataFilter() == null ? null : factory.unwrapExpression(state.getStateDataFilter().getInput())));
embeddedSubProcess.addInAssociation(new DataAssociation(Collections.emptyList(), "", Arrays.asList(inputAssignment), null));
// handle state data outputs
Assignment outputAssignment = new Assignment("jq", "", "");
outputAssignment.setMetaData("Action", new OutputJqAssignmentAction(state.getStateDataFilter() == null ? null : factory.unwrapExpression(state.getStateDataFilter().getOutput())));
embeddedSubProcess.addOutAssociation(new DataAssociation(Collections.emptyList(), "", Arrays.asList(outputAssignment), null));
mappedNodes.put(state.getName(), embeddedSubProcess.getId());
StartNode embeddedStartNode = factory.startNode(ids.getAndIncrement(), "EmbeddedStart", embeddedSubProcess);
EndNode embeddedEndNode = factory.endNode(ids.getAndIncrement(), "EmbeddedEnd", false, embeddedSubProcess);
Split parallelSplit = factory.splitNode(ids.getAndIncrement(), "split_" + state.getName(), Split.TYPE_AND, embeddedSubProcess);
Join parallelJoin;
if (parallelState.getCompletionType().equals(CompletionType.AT_LEAST)) {
parallelJoin = factory.joinNode(ids.getAndIncrement(), "join_" + state.getName(), Join.TYPE_N_OF_M, embeddedSubProcess);
parallelJoin.setN(parallelState.getNumCompleted());
} else {
parallelJoin = factory.joinNode(ids.getAndIncrement(), "join_" + state.getName(), Join.TYPE_AND, embeddedSubProcess);
}
factory.connect(embeddedStartNode.getId(), parallelSplit.getId(), "connection_" + embeddedStartNode.getId() + "_" + parallelSplit.getId(), embeddedSubProcess, false);
for (Branch branch : parallelState.getBranches()) {
buildActionsForState(workflow, branch.getActions(), embeddedSubProcess, factory, ids, (first, last) -> {
factory.connect(parallelSplit.getId(), first.getId(), parallelSplit.getId() + "_" + first.getId(), embeddedSubProcess, false);
factory.connect(last.getId(), parallelJoin.getId(), last.getId() + "_" + parallelJoin.getId(), embeddedSubProcess, false);
}, (first, last) -> {
}, true);
}
factory.connect(parallelJoin.getId(), embeddedEndNode.getId(), "connection_" + parallelJoin.getId() + "_" + embeddedEndNode.getId(), embeddedSubProcess, false);
if (state.getEnd() != null) {
EndNode endNode = factory.endNode(ids.getAndIncrement(), state.getName() + "-end", state.getEnd().isTerminate(), process);
if (state.getEnd().getProduceEvents() != null && !state.getEnd().getProduceEvents().isEmpty()) {
produceEvents(state.getEnd().getProduceEvents(), factory, workflow, ids, process, embeddedSubProcess.getId(), endNode.getId());
} else {
factory.connect(embeddedSubProcess.getId(), endNode.getId(), "connection_" + embeddedSubProcess.getId() + "_" + endNode.getId(), process, false);
}
}
} else if (state.getType().equals(DefaultState.Type.FOREACH)) {
}
// ensure that start node is connected
if (state.equals(start) && currentNode != null) {
factory.connect(startNode.getId(), currentNode.getId(), "connection_" + startNode.getId() + "_" + currentNode.getId(), process, false);
}
}
for (State state : workflow.getStates()) {
if (state.getType().equals(Type.SWITCH)) {
// switch state must be processed at the end as it needs to reference other nodes by id
SwitchState switchState = (SwitchState) state;
if (switchState.getDataConditions() != null && !switchState.getDataConditions().isEmpty()) {
Split splitNode = factory.splitNode(ids.getAndIncrement(), "split_" + state.getName(), Split.TYPE_XOR, process);
currentNode = splitNode;
setUniqueId(splitNode, state);
mappedNodes.put(state.getName(), splitNode.getId());
int priority = 1;
for (DataCondition condition : switchState.getDataConditions()) {
boolean isDefaultConstraint = false;
if (switchState.getDefaultCondition() != null && switchState.getDefaultCondition().getTransition() != null && condition.getTransition() != null && condition.getTransition().getNextState().equals(switchState.getDefaultCondition().getTransition().getNextState())) {
isDefaultConstraint = true;
}
if (switchState.getDefaultCondition() != null && switchState.getDefaultCondition().getEnd() != null && condition.getEnd() != null) {
isDefaultConstraint = true;
}
Connection outgoingConnection = null;
long target = 0;
if (condition.getEnd() != null) {
EndNode endNode = factory.endNode(ids.getAndIncrement(), "end_" + switchState.getName(), false, process);
target = endNode.getId();
outgoingConnection = factory.connect(splitNode.getId(), endNode.getId(), "connection_" + splitNode.getId() + "_" + endNode.getId(), process, false);
} else if (condition.getTransition() != null && condition.getTransition().getNextState() != null) {
long source = splitNode.getId();
target = mappedNodes.get(condition.getTransition().getNextState());
outgoingConnection = factory.connect(source, target, "connection_" + source + "_" + target, process, false);
}
ReturnValueConstraintEvaluator returnValueConstraint = new ReturnValueConstraintEvaluator();
returnValueConstraint.setDialect("jq");
returnValueConstraint.setName(splitNode.getId() + "_" + target);
returnValueConstraint.setPriority(priority);
returnValueConstraint.setDefault(isDefaultConstraint);
returnValueConstraint.setType("DROOLS_DEFAULT");
returnValueConstraint.setConstraint(factory.unwrapExpression(condition.getCondition()));
returnValueConstraint.setEvaluator(new JqReturnValueEvaluator(factory.unwrapExpression(condition.getCondition())));
splitNode.setConstraint(outgoingConnection, returnValueConstraint);
}
} else if (switchState.getEventConditions() != null && !switchState.getEventConditions().isEmpty()) {
Split splitNode = factory.eventBasedSplit(ids.getAndIncrement(), "split_" + state.getName(), process);
currentNode = splitNode;
setUniqueId(splitNode, state);
mappedNodes.put(state.getName(), splitNode.getId());
for (EventCondition eventCondition : switchState.getEventConditions()) {
EventDefinition event = WorkflowUtils.getDefinedConsumedEvents(workflow).stream().filter(e -> e.getName().equals(eventCondition.getEventRef())).findFirst().get();
EventNode eventNode = factory.consumeEventNode(ids.getAndIncrement(), event, eventCondition.getEventDataFilter(), process);
factory.connect(splitNode.getId(), eventNode.getId(), "connection_" + splitNode.getId() + "_" + eventNode.getId(), process, false);
long target = 0;
if (eventCondition.getEnd() != null) {
EndNode endNode = factory.endNode(ids.getAndIncrement(), "end_" + switchState.getName(), false, process);
target = endNode.getId();
factory.connect(splitNode.getId(), endNode.getId(), "connection_" + splitNode.getId() + "_" + endNode.getId(), process, false);
} else if (eventCondition.getTransition() != null && eventCondition.getTransition().getNextState() != null) {
target = mappedNodes.get(eventCondition.getTransition().getNextState());
factory.connect(eventNode.getId(), target, "connection_" + eventNode.getId() + "_" + target, process, false);
}
}
if (switchState.getTimeouts() != null && switchState.getTimeouts().getEventTimeout() != null) {
TimerNode timer = factory.timerNode(ids.getAndIncrement(), "event-switch-timeout", switchState.getTimeouts().getEventTimeout(), process);
factory.connect(splitNode.getId(), timer.getId(), "connection_" + splitNode.getId() + "_" + timer.getId(), process, false);
EndNode endNode = factory.endNode(ids.getAndIncrement(), "end_" + switchState.getName(), false, process);
factory.connect(timer.getId(), endNode.getId(), "connection_" + timer.getId() + "_" + endNode.getId(), process, false);
}
}
// ensure that start node is connected
if (state.equals(start) && currentNode != null) {
factory.connect(startNode.getId(), currentNode.getId(), "connection_" + startNode.getId() + "_" + currentNode.getId(), process, false);
}
}
}
// next connect all nodes
for (State state : workflow.getStates()) {
if (!mappedNodes.containsKey(state.getName())) {
continue;
}
long source = mappedNodes.get(state.getName());
if (state.getTransition() != null && state.getTransition().getNextState() != null) {
long target = mappedNodes.get(state.getTransition().getNextState());
if (state.getTransition().getProduceEvents() != null && !state.getTransition().getProduceEvents().isEmpty()) {
produceEvents(state.getTransition().getProduceEvents(), factory, workflow, ids, process, source, target);
} else {
factory.connect(source, target, "connection_" + source + "_" + target, process, false);
}
}
}
// attach error handling
for (State state : workflow.getStates()) {
if (!mappedNodes.containsKey(state.getName())) {
continue;
}
long source = mappedNodes.get(state.getName());
if (process.getNode(source) instanceof CompositeContextNode) {
addErrorHandlingToState(workflow, state, factory, ids, process, (CompositeContextNode) process.getNode(source));
}
}
factory.validate((ExecutableProcess) process);
if (workflow.getTimeouts() != null && workflow.getTimeouts().getWorkflowExecTimeout() != null) {
factory.addExecutionTimeout(ids.getAndIncrement(), workflow.getTimeouts().getWorkflowExecTimeout(), (ExecutableProcess) process);
}
process.setMetaData("SW-Workflow", workflow);
return process;
}
use of io.automatiko.engine.api.definition.process.Process in project automatiko-engine by automatiko-io.
the class EndNodeInstance method internalTrigger.
public void internalTrigger(final NodeInstance from, String type) {
super.internalTrigger(from, type);
if (!io.automatiko.engine.workflow.process.core.Node.CONNECTION_DEFAULT_TYPE.equals(type)) {
throw new IllegalArgumentException("An EndNode only accepts default incoming connections!");
}
leaveTime = new Date();
boolean hidden = false;
if (getNode().getMetaData().get(HIDDEN) != null) {
hidden = true;
}
if (getProcessInstance().isFunctionFlow(this) && getNodeInstanceContainer() instanceof ProcessInstance) {
// only when running as function flow and node is in the top level node container meaning process instance
// and not subprocesses
getProcessInstance().getMetaData().compute("ATK_FUNC_FLOW_NEXT", (k, v) -> {
if (v == null) {
v = new ArrayList<String>();
}
Process process = getProcessInstance().getProcess();
String version = "";
if (process.getVersion() != null && !process.getVersion().trim().isEmpty()) {
version = ".v" + process.getVersion().replaceAll("\\.", "_");
}
String defaultNextNode = process.getPackageName() + "." + process.getId() + version + "." + getNodeName().toLowerCase();
((List<String>) v).add((String) getNode().getMetaData().getOrDefault("functionType", defaultNextNode));
return v;
});
}
InternalProcessRuntime runtime = getProcessInstance().getProcessRuntime();
if (!hidden) {
runtime.getProcessEventSupport().fireBeforeNodeLeft(this, runtime);
}
((NodeInstanceContainer) getNodeInstanceContainer()).removeNodeInstance(this);
if (getEndNode().isTerminate()) {
if (getNodeInstanceContainer() instanceof CompositeNodeInstance) {
if (getEndNode().getScope() == PROCESS_SCOPE) {
getProcessInstance().setState(STATE_COMPLETED);
} else {
while (!getNodeInstanceContainer().getNodeInstances().isEmpty()) {
((io.automatiko.engine.workflow.process.instance.NodeInstance) getNodeInstanceContainer().getNodeInstances().iterator().next()).cancel();
}
((NodeInstanceContainer) getNodeInstanceContainer()).nodeInstanceCompleted(this, null);
}
} else {
((NodeInstanceContainer) getNodeInstanceContainer()).setState(STATE_COMPLETED);
}
} else {
((NodeInstanceContainer) getNodeInstanceContainer()).nodeInstanceCompleted(this, null);
}
if (!hidden) {
runtime.getProcessEventSupport().fireAfterNodeLeft(this, runtime);
}
String uniqueId = (String) getNode().getMetaData().get(UNIQUE_ID);
if (uniqueId == null) {
uniqueId = ((NodeImpl) getNode()).getUniqueId();
}
((WorkflowProcessInstanceImpl) getProcessInstance()).addCompletedNodeId(uniqueId);
}
use of io.automatiko.engine.api.definition.process.Process in project automatiko-engine by automatiko-io.
the class NodeInstanceImpl method trigger.
public final void trigger(NodeInstance from, String type) {
io.automatiko.engine.workflow.process.core.Node currentNode = (io.automatiko.engine.workflow.process.core.Node) getNode();
// function flow check
if (getProcessInstance().isFunctionFlow(this) && getProcessInstance().isExecutionNode(currentNode)) {
Integer functionFlowCounter = (Integer) getProcessInstance().getMetaData("ATK_FUNC_FLOW_COUNTER");
if (functionFlowCounter == null) {
functionFlowCounter = 1;
getProcessInstance().getMetaData().put("ATK_FUNC_FLOW_COUNTER", functionFlowCounter);
} else {
// function flow already called function
getProcessInstance().getMetaData().compute("ATK_FUNC_FLOW_NEXT", (k, v) -> {
if (v == null) {
v = new ArrayList<String>();
}
Process process = getProcessInstance().getProcess();
String version = "";
if (process.getVersion() != null && !process.getVersion().trim().isEmpty()) {
version = ".v" + process.getVersion().replaceAll("\\.", "_");
}
String defaultNextNode = process.getPackageName() + "." + process.getId() + version + "." + getNodeName().toLowerCase();
((List<String>) v).add((String) getNode().getMetaData().getOrDefault("functionType", defaultNextNode));
return v;
});
nodeInstanceContainer.removeNodeInstance(this);
return;
}
}
// check activation condition if this can be invoked
if (currentNode.getActivationCheck().isPresent()) {
if (!currentNode.getActivationCheck().get().isValid(getProcessInstance().getVariables())) {
nodeInstanceContainer.removeNodeInstance(this);
return;
}
}
internalChangeState(NodeInstanceState.Active);
boolean hidden = false;
if (getNode().getMetaData().get(HIDDEN) != null) {
hidden = true;
}
if (from != null) {
int level = ((io.automatiko.engine.workflow.process.instance.NodeInstance) from).getLevel();
((io.automatiko.engine.workflow.process.instance.NodeInstanceContainer) getNodeInstanceContainer()).setCurrentLevel(level);
Collection<Connection> incoming = getNode().getIncomingConnections(type);
for (Connection conn : incoming) {
if (conn.getFrom().getId() == from.getNodeId()) {
this.metaData.put(INCOMING_CONNECTION, conn.getMetaData().get(UNIQUE_ID));
break;
}
}
}
if (dynamicParameters != null) {
for (Entry<String, Object> entry : dynamicParameters.entrySet()) {
setVariable(entry.getKey(), entry.getValue());
}
}
configureSla();
InternalProcessRuntime runtime = getProcessInstance().getProcessRuntime();
if (!hidden) {
runtime.getProcessEventSupport().fireBeforeNodeTriggered(this, runtime);
}
try {
internalTrigger(from, type);
} catch (Exception e) {
String errorId = captureError(e);
internalChangeState(NodeInstanceState.Failed);
runtime.getProcessEventSupport().fireAfterNodeInstanceFailed(getProcessInstance(), this, errorId, getRootException(e).getMessage(), e, runtime);
// stop after capturing error
return;
}
if (!hidden) {
runtime.getProcessEventSupport().fireAfterNodeTriggered(this, runtime);
}
}
use of io.automatiko.engine.api.definition.process.Process in project automatiko-engine by automatiko-io.
the class ProcessToExecModelGeneratorTest method testScriptAndWorkItemModelGeneration.
@Test
public void testScriptAndWorkItemModelGeneration() {
ExecutableProcessFactory factory = ExecutableProcessFactory.createProcess("demo.orders");
factory.variable("order", new ObjectDataType(Integer.class)).variable("order", new ObjectDataType(List.class, "java.util.List<String>")).variable("approver", new ObjectDataType(String.class)).name("orders").packageName("com.myspace.demo").dynamic(false).version("1.0").workItemNode(1).name("Log").workName("Log").done().actionNode(2).name("Dump order").action("java", "System.out.println(\"Order has been created \" + order);").done().endNode(3).name("end").terminate(false).done().startNode(4).name("start").done().connection(2, 1).connection(4, 2).connection(1, 3);
Process process = factory.validate().getProcess();
ModelMetaData modelMetadata = ProcessToExecModelGenerator.INSTANCE.generateModel((WorkflowProcess) process);
assertNotNull(modelMetadata, "Dumper should return non null class for process");
logger.debug(modelMetadata.generate());
assertEquals("com.myspace.demo.Orders_1_0Model", modelMetadata.getModelClassName());
}
use of io.automatiko.engine.api.definition.process.Process in project automatiko-engine by automatiko-io.
the class ProcessCodegen method ofPath.
public static ProcessCodegen ofPath(List<String> dependencies, Path... paths) throws IOException {
List<Process> allProcesses = new ArrayList<>();
for (String dependency : dependencies) {
File file = new File(dependency);
if (file.isDirectory()) {
try (Stream<Path> filesStream = Files.walk(file.toPath())) {
List<File> files = filesStream.filter(p -> SUPPORTED_BPMN_EXTENSIONS.stream().anyMatch(p.toString()::endsWith) || SUPPORTED_SW_EXTENSIONS.keySet().stream().anyMatch(p.toString()::endsWith)).map(Path::toFile).collect(Collectors.toList());
allProcesses.addAll(parseProcesses(files, true));
}
} else {
try (ZipFile zipFile = new ZipFile(dependency)) {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
ResourceType resourceType = determineResourceType(entry.getName());
if (SUPPORTED_BPMN_EXTENSIONS.stream().anyMatch(entry.getName()::endsWith)) {
InternalResource resource = new ByteArrayResource(readBytesFromInputStream(zipFile.getInputStream(entry)));
resource.setResourceType(resourceType);
resource.setSourcePath(entry.getName());
allProcesses.addAll(parseProcessFile(resource));
}
}
} catch (IOException e) {
}
}
}
for (Path path : paths) {
Path srcPath = Paths.get(path.toString());
try (Stream<Path> filesStream = Files.walk(srcPath)) {
List<File> files = filesStream.filter(p -> SUPPORTED_BPMN_EXTENSIONS.stream().anyMatch(p.toString()::endsWith) || SUPPORTED_SW_EXTENSIONS.keySet().stream().anyMatch(p.toString()::endsWith)).map(Path::toFile).collect(Collectors.toList());
allProcesses.addAll(parseProcesses(files, false));
}
}
return ofProcesses(allProcesses);
}
Aggregations