use of io.automatiko.engine.workflow.process.core.node.BoundaryEventNode in project automatiko-engine by automatiko-io.
the class CompensationScopeInstance method handleException.
public void handleException(io.automatiko.engine.api.runtime.process.NodeInstance nodeInstance, ExceptionHandler handler, String compensationActivityRef, Object dunno) {
WorkflowProcessInstanceImpl processInstance = (WorkflowProcessInstanceImpl) getProcessInstance();
NodeInstanceContainer nodeInstanceContainer = (NodeInstanceContainer) getContextInstanceContainer();
if (handler instanceof CompensationHandler) {
CompensationHandler compensationHandler = (CompensationHandler) handler;
try {
Node handlerNode = compensationHandler.getnode();
if (handlerNode instanceof BoundaryEventNode) {
NodeInstance compensationHandlerNodeInstance = nodeInstanceContainer.getNodeInstance(handlerNode);
compensationInstances.add(compensationHandlerNodeInstance);
// The BoundaryEventNodeInstance.signalEvent() contains the necessary logic
// to check whether or not compensation may proceed (? : (not-active +
// completed))
EventNodeInstance eventNodeInstance = (EventNodeInstance) compensationHandlerNodeInstance;
eventNodeInstance.signalEvent("Compensation", compensationActivityRef);
} else if (handlerNode instanceof EventSubProcessNode) {
// Check that subprocess parent has completed.
List<String> completedIds = processInstance.getCompletedNodeIds();
if (completedIds.contains(((NodeImpl) handlerNode.getParentContainer()).getMetaData("UniqueId"))) {
NodeInstance subProcessNodeInstance = ((NodeInstanceContainer) nodeInstanceContainer).getNodeInstance((Node) handlerNode.getParentContainer());
compensationInstances.add(subProcessNodeInstance);
NodeInstance compensationHandlerNodeInstance = ((NodeInstanceContainer) subProcessNodeInstance).getNodeInstance(handlerNode);
compensationInstances.add(compensationHandlerNodeInstance);
EventSubProcessNodeInstance eventNodeInstance = (EventSubProcessNodeInstance) compensationHandlerNodeInstance;
eventNodeInstance.signalEvent("Compensation", compensationActivityRef);
}
}
assert handlerNode instanceof BoundaryEventNode || handlerNode instanceof EventSubProcessNode : "Unexpected compensation handler node type : " + handlerNode.getClass().getSimpleName();
} catch (Exception e) {
throwWorkflowRuntimeException(nodeInstanceContainer, processInstance, "Unable to execute compensation.", e);
}
} else {
Exception e = new IllegalArgumentException("Unsupported compensation handler: " + handler);
throwWorkflowRuntimeException(nodeInstanceContainer, processInstance, e.getMessage(), e);
}
}
use of io.automatiko.engine.workflow.process.core.node.BoundaryEventNode in project automatiko-engine by automatiko-io.
the class BoundaryEventHandler method handleEscalationNode.
@SuppressWarnings("unchecked")
protected void handleEscalationNode(final Node node, final Element element, final String uri, final String localName, final ExtensibleXmlParser parser, final String attachedTo, final boolean cancelActivity) throws SAXException {
super.handleNode(node, element, uri, localName, parser);
BoundaryEventNode eventNode = (BoundaryEventNode) node;
eventNode.setMetaData("AttachedTo", attachedTo);
/**
* TODO: because of how we process bpmn2/xml files, we can't tell if the
* cancelActivity attribute is set to false or not (because we override with the
* xsd settings) BPMN2 spec, p. 255, Escalation row: "In contrast to an Error,
* an Escalation by default is assumed to not abort the Activity to which the
* boundary Event is attached."
*/
eventNode.setMetaData("CancelActivity", cancelActivity);
eventNode.setAttachedToNodeId(attachedTo);
org.w3c.dom.Node xmlNode = element.getFirstChild();
while (xmlNode != null) {
String nodeName = xmlNode.getNodeName();
if ("dataOutput".equals(nodeName)) {
String id = ((Element) xmlNode).getAttribute("id");
String outputName = ((Element) xmlNode).getAttribute("name");
dataOutputs.put(id, outputName);
populateDataOutputs(xmlNode, outputName, parser);
} else if ("dataOutputAssociation".equals(nodeName)) {
readDataOutputAssociation(xmlNode, eventNode, parser);
} else if ("escalationEventDefinition".equals(nodeName)) {
String escalationRef = ((Element) xmlNode).getAttribute("escalationRef");
if (escalationRef != null && escalationRef.trim().length() > 0) {
Map<String, Escalation> escalations = (Map<String, Escalation>) ((ProcessBuildData) parser.getData()).getMetaData(ProcessHandler.ESCALATIONS);
if (escalations == null) {
throw new IllegalArgumentException("No escalations found");
}
Escalation escalation = escalations.get(escalationRef);
if (escalation == null) {
throw new IllegalArgumentException("Could not find escalation " + escalationRef);
}
List<EventFilter> eventFilters = new ArrayList<EventFilter>();
EventTypeFilter eventFilter = new EventTypeFilter();
String type = escalation.getEscalationCode();
eventFilter.setType("Escalation-" + attachedTo + "-" + type);
eventFilters.add(eventFilter);
eventNode.setEventFilters(eventFilters);
eventNode.setMetaData("EscalationEvent", type);
} else {
throw new UnsupportedOperationException("General escalation is not yet supported.");
}
}
xmlNode = xmlNode.getNextSibling();
}
}
use of io.automatiko.engine.workflow.process.core.node.BoundaryEventNode in project automatiko-engine by automatiko-io.
the class BoundaryEventHandler method handleSignalNode.
protected void handleSignalNode(final Node node, final Element element, final String uri, final String localName, final ExtensibleXmlParser parser, final String attachedTo, final boolean cancelActivity) throws SAXException {
super.handleNode(node, element, uri, localName, parser);
BoundaryEventNode eventNode = (BoundaryEventNode) node;
eventNode.setMetaData("AttachedTo", attachedTo);
eventNode.setMetaData("CancelActivity", cancelActivity);
eventNode.setAttachedToNodeId(attachedTo);
org.w3c.dom.Node xmlNode = element.getFirstChild();
while (xmlNode != null) {
String nodeName = xmlNode.getNodeName();
if ("dataOutput".equals(nodeName)) {
String id = ((Element) xmlNode).getAttribute("id");
String outputName = ((Element) xmlNode).getAttribute("name");
dataOutputs.put(id, outputName);
populateDataOutputs(xmlNode, outputName, parser);
}
if ("dataOutputAssociation".equals(nodeName)) {
readDataOutputAssociation(xmlNode, eventNode, parser);
} else if ("signalEventDefinition".equals(nodeName)) {
String type = ((Element) xmlNode).getAttribute("signalRef");
if (type != null && type.trim().length() > 0) {
type = checkSignalAndConvertToRealSignalNam(parser, type);
List<EventFilter> eventFilters = new ArrayList<EventFilter>();
EventTypeFilter eventFilter = new EventTypeFilter();
eventFilter.setType(type);
eventFilters.add(eventFilter);
eventNode.setEventFilters(eventFilters);
eventNode.setScope("external");
eventNode.setMetaData("SignalName", type);
}
}
xmlNode = xmlNode.getNextSibling();
}
}
use of io.automatiko.engine.workflow.process.core.node.BoundaryEventNode in project automatiko-engine by automatiko-io.
the class ServerlessWorkflowParser method addErrorHandlingToState.
protected void addErrorHandlingToState(Workflow workflow, State state, ServerlessWorkflowFactory factory, AtomicLong ids, WorkflowProcess process, CompositeContextNode subprocess) {
if (state.getOnErrors() != null) {
for (io.serverlessworkflow.api.error.Error error : state.getOnErrors()) {
List<ErrorDefinition> defs = new ArrayList<>();
if (error.getErrorRef() != null) {
workflow.getErrors().getErrorDefs().stream().filter(err -> err.getName().equals(error.getErrorRef())).forEach(err -> defs.add(err));
} else {
workflow.getErrors().getErrorDefs().stream().filter(err -> error.getErrorRefs().contains(err.getName())).forEach(err -> defs.add(err));
}
BoundaryEventNode errorNode = factory.errorBoundaryEventNode(ids.getAndIncrement(), defs, null, process, subprocess, workflow);
if (error.getEnd() != null) {
EndNode onErrorEnd = factory.endNode(ids.getAndIncrement(), state.getName() + "onErrorEnd", error.getEnd().isTerminate(), process);
if (error.getEnd().getProduceEvents() != null && !error.getEnd().getProduceEvents().isEmpty()) {
produceEvents(error.getEnd().getProduceEvents(), factory, workflow, ids, process, errorNode.getId(), onErrorEnd.getId());
} else {
factory.connect(errorNode.getId(), onErrorEnd.getId(), "connect_" + errorNode.getId() + "_" + onErrorEnd.getId(), process, false);
}
} else {
if (error.getTransition().getNextState() != null) {
for (io.automatiko.engine.api.definition.process.Node node : process.getNodes()) {
if (node.getName().equals(error.getTransition().getNextState())) {
if (error.getTransition().getProduceEvents() != null && !error.getTransition().getProduceEvents().isEmpty()) {
produceEvents(error.getTransition().getProduceEvents(), factory, workflow, ids, process, errorNode.getId(), node.getId());
} else {
factory.connect(errorNode.getId(), node.getId(), "connect_" + errorNode.getId() + "_" + node.getId(), process, false);
}
break;
}
}
}
}
}
}
}
use of io.automatiko.engine.workflow.process.core.node.BoundaryEventNode in project automatiko-engine by automatiko-io.
the class ServerlessWorkflowParser method buildActionsForState.
protected void buildActionsForState(Workflow workflow, List<Action> actions, NodeContainer embeddedSubProcess, ServerlessWorkflowFactory factory, AtomicLong ids, BiConsumer<Node, Node> firstLastNodeConsumer, BiConsumer<Node, Node> actionConsumer, boolean isParallel) {
Node firstNode = null;
Node lastNode = null;
Node prevNode = null;
for (Action action : actions) {
if (action.getFunctionRef() != null) {
// handle function based action
Optional<FunctionDefinition> functionDefinition = workflow.getFunctions().getFunctionDefs().stream().filter(functionDef -> functionDef.getName().equals(action.getFunctionRef().getRefName())).distinct().findFirst();
if (functionDefinition.get().getType() == FunctionDefinition.Type.EXPRESSION) {
ActionNode actionNode = factory.expressionActionStateNode(ids.getAndIncrement(), action.getName(), embeddedSubProcess, functionDefinition.get().getOperation(), action);
if (firstNode == null) {
firstNode = actionNode;
}
lastNode = actionNode;
} else if (functionDefinition.get().getType() == null || functionDefinition.get().getType() == FunctionDefinition.Type.REST) {
WorkItemNode serviceNode = factory.serviceNode(ids.getAndIncrement(), action, functionDefinition.get(), embeddedSubProcess);
if (firstNode == null) {
firstNode = serviceNode;
}
lastNode = serviceNode;
if (workflow.getTimeouts() != null && workflow.getTimeouts().getActionExecTimeout() != null) {
serviceNode.setMetaData("timeout", String.valueOf(DateTimeUtils.parseDuration(workflow.getTimeouts().getActionExecTimeout())));
}
if (action.getRetryableErrors() != null && !action.getRetryableErrors().isEmpty()) {
List<ErrorDefinition> defs = new ArrayList<>();
for (String errorRef : action.getRetryableErrors()) {
ErrorDefinition errorDef = workflow.getErrors().getErrorDefs().stream().filter(error -> error.getName().equals(errorRef)).findFirst().orElseThrow(() -> new IllegalStateException("Missing error definition for " + errorRef));
defs.add(errorDef);
}
RetryDefinition retry = null;
BoundaryEventNode errorNode = factory.errorBoundaryEventNode(ids.getAndIncrement(), defs, retry, embeddedSubProcess, serviceNode, workflow);
EndNode onErrorEnd = factory.endNode(ids.getAndIncrement(), action.getName() + "onErrorEnd", false, embeddedSubProcess);
factory.connect(errorNode.getId(), onErrorEnd.getId(), "connect_" + errorNode.getId() + "_" + onErrorEnd.getId(), embeddedSubProcess, false);
}
} else {
throw new UnsupportedOperationException(functionDefinition.get().getType() + " is not yet supported");
}
} else if (action.getSubFlowRef() != null) {
// handler sub workflow action definition
String workflowId = Objects.requireNonNull(action.getSubFlowRef().getWorkflowId(), "Workflow id for subworkflow is mandatory");
boolean independent = false;
if (action.getSubFlowRef().getOnParentComplete() != null && action.getSubFlowRef().getOnParentComplete().equals(OnParentComplete.CONTINUE)) {
independent = true;
}
boolean waitForCompletion = true;
if (action.getSubFlowRef().getInvoke().equals(Invoke.ASYNC)) {
waitForCompletion = false;
}
SubProcessNode callactivity = factory.callActivity(ids.getAndIncrement(), action.getName(), workflowId, waitForCompletion, embeddedSubProcess);
callactivity.setIndependent(independent);
callactivity.setProcessVersion(action.getSubFlowRef().getVersion());
if (firstNode == null) {
firstNode = callactivity;
}
lastNode = callactivity;
}
if (action.getSleep() != null && action.getSleep().getBefore() != null) {
TimerNode sleep = factory.timerNode(ids.getAndIncrement(), "sleep-before-" + action.getName(), action.getSleep().getBefore(), embeddedSubProcess);
factory.connect(sleep.getId(), firstNode.getId(), "connection_" + sleep.getId() + "_" + firstNode.getId(), embeddedSubProcess, false);
firstNode = sleep;
}
if (action.getSleep() != null && action.getSleep().getAfter() != null) {
TimerNode sleep = factory.timerNode(ids.getAndIncrement(), "sleep-after-" + action.getName(), action.getSleep().getAfter(), embeddedSubProcess);
factory.connect(lastNode.getId(), sleep.getId(), "connection_" + lastNode.getId() + "_" + sleep.getId(), embeddedSubProcess, false);
lastNode = sleep;
}
actionConsumer.accept(firstNode, lastNode);
if (isParallel && actions.size() > 1) {
// reset first node as all of action nodes will be first nodes
firstNode = null;
} else {
if (prevNode != null) {
factory.connect(prevNode.getId(), lastNode.getId(), "connect_" + prevNode.getId() + "_" + lastNode.getId(), embeddedSubProcess, false);
}
}
prevNode = lastNode;
}
firstLastNodeConsumer.accept(firstNode, lastNode);
}
Aggregations