Search in sources :

Example 1 with CompensationScope

use of io.automatiko.engine.workflow.base.core.context.exception.CompensationScope in project automatiko-engine by automatiko-io.

the class CompensationScopeInstance method handleException.

public void handleException(io.automatiko.engine.api.runtime.process.NodeInstance nodeInstance, String activityRef, Object dunno) {
    assert activityRef != null : "It should not be possible for the compensation activity reference to be null here.";
    CompensationScope compensationScope = (CompensationScope) getExceptionScope();
    // broadcast/general compensation in reverse order
    if (activityRef.startsWith(IMPLICIT_COMPENSATION_PREFIX)) {
        activityRef = activityRef.substring(IMPLICIT_COMPENSATION_PREFIX.length());
        assert activityRef.equals(compensationScope.getContextContainerId()) : "Compensation activity ref [" + activityRef + "] does not match" + " Compensation Scope container id [" + compensationScope.getContextContainerId() + "]";
        Map<String, ExceptionHandler> handlers = compensationScope.getExceptionHandlers();
        List<String> completedNodeIds = ((WorkflowProcessInstanceImpl) getProcessInstance()).getCompletedNodeIds();
        ListIterator<String> iter = completedNodeIds.listIterator(completedNodeIds.size());
        while (iter.hasPrevious()) {
            String completedId = iter.previous();
            ExceptionHandler handler = handlers.get(completedId);
            if (handler != null) {
                handleException(nodeInstance, handler, completedId, null);
            }
        }
    } else {
        // Specific compensation
        ExceptionHandler handler = compensationScope.getExceptionHandler(activityRef);
        if (handler == null) {
            throw new IllegalArgumentException("Could not find CompensationHandler for " + activityRef);
        }
        handleException(nodeInstance, handler, activityRef, null);
    }
    // Cancel all node instances created for compensation
    while (!compensationInstances.isEmpty()) {
        NodeInstance generatedInstance = compensationInstances.pop();
        ((NodeInstanceContainer) generatedInstance.getNodeInstanceContainer()).removeNodeInstance(generatedInstance);
    }
}
Also used : ExceptionHandler(io.automatiko.engine.workflow.base.core.context.exception.ExceptionHandler) NodeInstanceContainer(io.automatiko.engine.workflow.process.instance.NodeInstanceContainer) WorkflowProcessInstanceImpl(io.automatiko.engine.workflow.process.instance.impl.WorkflowProcessInstanceImpl) CompensationScope(io.automatiko.engine.workflow.base.core.context.exception.CompensationScope) EventNodeInstance(io.automatiko.engine.workflow.process.instance.node.EventNodeInstance) NodeInstance(io.automatiko.engine.workflow.process.instance.NodeInstance) EventSubProcessNodeInstance(io.automatiko.engine.workflow.process.instance.node.EventSubProcessNodeInstance)

Example 2 with CompensationScope

use of io.automatiko.engine.workflow.base.core.context.exception.CompensationScope in project automatiko-engine by automatiko-io.

the class ExecutableProcessValidator method validateCompensationIntermediateOrEndEvent.

protected void validateCompensationIntermediateOrEndEvent(Node node, ExecutableProcess process, List<ProcessValidationError> errors) {
    if (node.getMetaData().containsKey("Compensation")) {
        // Validate that activityRef in throw/end compensation event refers to "visible"
        // compensation
        String activityRef = (String) node.getMetaData().get("Compensation");
        Node refNode = null;
        if (activityRef != null) {
            Queue<Node> nodeQueue = new LinkedList<>();
            nodeQueue.addAll(Arrays.asList(process.getNodes()));
            while (!nodeQueue.isEmpty()) {
                Node polledNode = nodeQueue.poll();
                if (activityRef.equals(polledNode.getMetaData().get("UniqueId"))) {
                    refNode = polledNode;
                    break;
                }
                if (node instanceof NodeContainer) {
                    nodeQueue.addAll(Arrays.asList(((NodeContainer) node).getNodes()));
                }
            }
        }
        if (refNode == null) {
            addErrorMessage(process, node, errors, "Does not reference an activity that exists (" + activityRef + ") in its compensation event definition.");
        }
        CompensationScope compensationScope = (CompensationScope) ((NodeImpl) node).resolveContext(CompensationScope.COMPENSATION_SCOPE, activityRef);
        if (compensationScope == null) {
            addErrorMessage(process, node, errors, "References an activity (" + activityRef + ") in its compensation event definition that is not visible to it.");
        }
    }
}
Also used : TimerNode(io.automatiko.engine.workflow.process.core.node.TimerNode) MilestoneNode(io.automatiko.engine.workflow.process.core.node.MilestoneNode) ActionNode(io.automatiko.engine.workflow.process.core.node.ActionNode) FaultNode(io.automatiko.engine.workflow.process.core.node.FaultNode) ForEachSplitNode(io.automatiko.engine.workflow.process.core.node.ForEachNode.ForEachSplitNode) EventSubProcessNode(io.automatiko.engine.workflow.process.core.node.EventSubProcessNode) StateNode(io.automatiko.engine.workflow.process.core.node.StateNode) WorkItemNode(io.automatiko.engine.workflow.process.core.node.WorkItemNode) ForEachJoinNode(io.automatiko.engine.workflow.process.core.node.ForEachNode.ForEachJoinNode) SubProcessNode(io.automatiko.engine.workflow.process.core.node.SubProcessNode) ThrowLinkNode(io.automatiko.engine.workflow.process.core.node.ThrowLinkNode) RuleSetNode(io.automatiko.engine.workflow.process.core.node.RuleSetNode) CompositeNode(io.automatiko.engine.workflow.process.core.node.CompositeNode) CatchLinkNode(io.automatiko.engine.workflow.process.core.node.CatchLinkNode) Node(io.automatiko.engine.api.definition.process.Node) BoundaryEventNode(io.automatiko.engine.workflow.process.core.node.BoundaryEventNode) DynamicNode(io.automatiko.engine.workflow.process.core.node.DynamicNode) ForEachNode(io.automatiko.engine.workflow.process.core.node.ForEachNode) StartNode(io.automatiko.engine.workflow.process.core.node.StartNode) EndNode(io.automatiko.engine.workflow.process.core.node.EndNode) EventNode(io.automatiko.engine.workflow.process.core.node.EventNode) NodeContainer(io.automatiko.engine.api.definition.process.NodeContainer) CompensationScope(io.automatiko.engine.workflow.base.core.context.exception.CompensationScope) LinkedList(java.util.LinkedList)

Example 3 with CompensationScope

use of io.automatiko.engine.workflow.base.core.context.exception.CompensationScope in project automatiko-engine by automatiko-io.

the class CompensationTest method addCompensationScope.

/*
	 * General HELPER methods
	 */
private void addCompensationScope(final Node node, final io.automatiko.engine.api.definition.process.NodeContainer parentContainer, final String compensationHandlerId) {
    ContextContainer contextContainer = (ContextContainer) parentContainer;
    CompensationScope scope = null;
    boolean addScope = false;
    if (contextContainer.getContexts(CompensationScope.COMPENSATION_SCOPE) == null) {
        addScope = true;
    } else {
        scope = (CompensationScope) contextContainer.getContexts(CompensationScope.COMPENSATION_SCOPE).get(0);
        if (scope == null) {
            addScope = true;
        }
    }
    if (addScope) {
        scope = new CompensationScope();
        contextContainer.addContext(scope);
        contextContainer.setDefaultContext(scope);
        scope.setContextContainer(contextContainer);
    }
    CompensationHandler handler = new CompensationHandler();
    handler.setNode(node);
    scope.setExceptionHandler(compensationHandlerId, handler);
    node.setMetaData("isForCompensation", Boolean.TRUE);
}
Also used : ContextContainer(io.automatiko.engine.workflow.base.core.ContextContainer) CompensationHandler(io.automatiko.engine.workflow.base.core.context.exception.CompensationHandler) CompensationScope(io.automatiko.engine.workflow.base.core.context.exception.CompensationScope)

Example 4 with CompensationScope

use of io.automatiko.engine.workflow.base.core.context.exception.CompensationScope in project automatiko-engine by automatiko-io.

the class ProcessHandler method addCompensationScope.

protected static void addCompensationScope(final ExecutableProcess process, final Node node, final io.automatiko.engine.api.definition.process.NodeContainer parentContainer, final String compensationHandlerId) {
    process.getMetaData().put("Compensation", true);
    assert parentContainer instanceof ContextContainer : "Expected parent node to be a CompositeContextNode, not a " + parentContainer.getClass().getSimpleName();
    ContextContainer contextContainer = (ContextContainer) parentContainer;
    CompensationScope scope = null;
    boolean addScope = false;
    if (contextContainer.getContexts(CompensationScope.COMPENSATION_SCOPE) == null) {
        addScope = true;
    } else {
        scope = (CompensationScope) contextContainer.getContexts(CompensationScope.COMPENSATION_SCOPE).get(0);
        if (scope == null) {
            addScope = true;
        }
    }
    if (addScope) {
        scope = new CompensationScope();
        contextContainer.addContext(scope);
        contextContainer.setDefaultContext(scope);
        scope.setContextContainer(contextContainer);
    }
    CompensationHandler handler = new CompensationHandler();
    handler.setNode(node);
    if (scope.getExceptionHandler(compensationHandlerId) != null) {
        throw new IllegalArgumentException("More than one compensation handler per node (" + compensationHandlerId + ")" + " is not supported!");
    }
    scope.setExceptionHandler(compensationHandlerId, handler);
}
Also used : ContextContainer(io.automatiko.engine.workflow.base.core.ContextContainer) CompensationHandler(io.automatiko.engine.workflow.base.core.context.exception.CompensationHandler) CompensationScope(io.automatiko.engine.workflow.base.core.context.exception.CompensationScope)

Example 5 with CompensationScope

use of io.automatiko.engine.workflow.base.core.context.exception.CompensationScope in project automatiko-engine by automatiko-io.

the class CompensationEventListener method signalEvent.

/**
 * When signaling compensation, you can do that in 1 of 2 ways: 1.
 * signalEvent("Compensation", <node-with-compensation-handler-id>) This is
 * specific compensation, that only possibly triggers the compensation handler
 * attached to the node referred to by the <node-with-compensation-handler-id>.
 * 2. signalEvent("Compensation", "implicit:" +
 * <node-container-containing-compensation-scope-id> ) This is implicit or
 * general compensation, in which you trigger all visible compensation handlers
 * (in the proper order, etc.) in the (sub-)process referred to by the
 * <node-container-containing-compensation-scope-id>.
 */
public void signalEvent(String compensationType, Object activityRefStr) {
    if (!(activityRefStr instanceof String)) {
        throw new WorkflowRuntimeException(null, getProcessInstance(), "Compensation can only be triggered with String events, not an event of type " + (activityRefStr == null ? "null" : activityRefStr.getClass().getSimpleName()));
    }
    // 1. parse the activity ref (is it general or specific compensation?)
    String activityRef = (String) activityRefStr;
    String toCompensateNodeId = activityRef;
    boolean generalCompensation = false;
    if (activityRef.startsWith(IMPLICIT_COMPENSATION_PREFIX)) {
        toCompensateNodeId = activityRef.substring(IMPLICIT_COMPENSATION_PREFIX.length());
        generalCompensation = true;
    }
    io.automatiko.engine.workflow.base.core.Process process = (io.automatiko.engine.workflow.base.core.Process) instance.getProcess();
    // 2. for specific compensation: find the node that will be compensated
    // for general compensation: find the compensation scope container that contains
    // all the visible compensation handlers
    Node toCompensateNode = null;
    ContextContainer compensationScopeContainer = null;
    if (generalCompensation) {
        if (toCompensateNodeId.equals(instance.getProcessId())) {
            compensationScopeContainer = process;
        } else {
            compensationScopeContainer = (ContextContainer) findNode(toCompensateNodeId);
        }
    } else {
        toCompensateNode = findNode(toCompensateNodeId);
    }
    // c. handle the exception (which also cleans up the generated node instances)
    if (toCompensateNode != null || compensationScopeContainer != null) {
        CompensationScope compensationScope = null;
        if (compensationScopeContainer != null) {
            compensationScope = (CompensationScope) compensationScopeContainer.getDefaultContext(COMPENSATION_SCOPE);
        } else {
            compensationScope = (CompensationScope) ((NodeImpl) toCompensateNode).resolveContext(COMPENSATION_SCOPE, toCompensateNodeId);
        }
        assert compensationScope != null : "Compensation scope for node [" + toCompensateNodeId + "] could not be found!";
        CompensationScopeInstance scopeInstance;
        if (compensationScope.getContextContainerId().equals(process.getId())) {
            // process level compensation
            scopeInstance = (CompensationScopeInstance) instance.getContextInstance(compensationScope);
        } else {
            // nested compensation
            Stack<NodeInstance> generatedInstances;
            if (toCompensateNode == null) {
                // logic is the same if it's specific or general
                generatedInstances = createNodeInstanceContainers((Node) compensationScopeContainer, true);
            } else {
                generatedInstances = createNodeInstanceContainers(toCompensateNode, false);
            }
            NodeInstance nodeInstanceContainer = generatedInstances.peek();
            scopeInstance = ((CompensationScopeInstance) ((ContextInstanceContainer) nodeInstanceContainer).getContextInstance(compensationScope));
            scopeInstance.addCompensationInstances(generatedInstances);
        }
        scopeInstance.handleException(null, activityRef, null);
    }
}
Also used : NodeImpl(io.automatiko.engine.workflow.process.core.impl.NodeImpl) CompensationScopeInstance(io.automatiko.engine.workflow.base.instance.context.exception.CompensationScopeInstance) Node(io.automatiko.engine.api.definition.process.Node) ExecutableProcess(io.automatiko.engine.workflow.process.executable.core.ExecutableProcess) WorkflowRuntimeException(io.automatiko.engine.workflow.process.instance.WorkflowRuntimeException) ContextContainer(io.automatiko.engine.workflow.base.core.ContextContainer) CompensationScope(io.automatiko.engine.workflow.base.core.context.exception.CompensationScope) NodeInstance(io.automatiko.engine.workflow.process.instance.NodeInstance) CompositeNodeInstance(io.automatiko.engine.workflow.process.instance.node.CompositeNodeInstance)

Aggregations

CompensationScope (io.automatiko.engine.workflow.base.core.context.exception.CompensationScope)6 ContextContainer (io.automatiko.engine.workflow.base.core.ContextContainer)4 CompensationHandler (io.automatiko.engine.workflow.base.core.context.exception.CompensationHandler)3 Node (io.automatiko.engine.api.definition.process.Node)2 NodeInstance (io.automatiko.engine.workflow.process.instance.NodeInstance)2 NodeContainer (io.automatiko.engine.api.definition.process.NodeContainer)1 ExceptionHandler (io.automatiko.engine.workflow.base.core.context.exception.ExceptionHandler)1 CompensationScopeInstance (io.automatiko.engine.workflow.base.instance.context.exception.CompensationScopeInstance)1 NodeImpl (io.automatiko.engine.workflow.process.core.impl.NodeImpl)1 ActionNode (io.automatiko.engine.workflow.process.core.node.ActionNode)1 BoundaryEventNode (io.automatiko.engine.workflow.process.core.node.BoundaryEventNode)1 CatchLinkNode (io.automatiko.engine.workflow.process.core.node.CatchLinkNode)1 CompositeNode (io.automatiko.engine.workflow.process.core.node.CompositeNode)1 DynamicNode (io.automatiko.engine.workflow.process.core.node.DynamicNode)1 EndNode (io.automatiko.engine.workflow.process.core.node.EndNode)1 EventNode (io.automatiko.engine.workflow.process.core.node.EventNode)1 EventSubProcessNode (io.automatiko.engine.workflow.process.core.node.EventSubProcessNode)1 FaultNode (io.automatiko.engine.workflow.process.core.node.FaultNode)1 ForEachNode (io.automatiko.engine.workflow.process.core.node.ForEachNode)1 ForEachJoinNode (io.automatiko.engine.workflow.process.core.node.ForEachNode.ForEachJoinNode)1