Search in sources :

Example 1 with NodeInstanceContainer

use of io.automatiko.engine.workflow.process.instance.NodeInstanceContainer 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 NodeInstanceContainer

use of io.automatiko.engine.workflow.process.instance.NodeInstanceContainer 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);
    }
}
Also used : NodeInstanceContainer(io.automatiko.engine.workflow.process.instance.NodeInstanceContainer) NodeImpl(io.automatiko.engine.workflow.process.core.impl.NodeImpl) EventSubProcessNode(io.automatiko.engine.workflow.process.core.node.EventSubProcessNode) Node(io.automatiko.engine.api.definition.process.Node) EventSubProcessNode(io.automatiko.engine.workflow.process.core.node.EventSubProcessNode) BoundaryEventNode(io.automatiko.engine.workflow.process.core.node.BoundaryEventNode) WorkflowProcessInstanceImpl(io.automatiko.engine.workflow.process.instance.impl.WorkflowProcessInstanceImpl) CompensationHandler(io.automatiko.engine.workflow.base.core.context.exception.CompensationHandler) BoundaryEventNode(io.automatiko.engine.workflow.process.core.node.BoundaryEventNode) WorkflowRuntimeException(io.automatiko.engine.workflow.process.instance.WorkflowRuntimeException) EventSubProcessNodeInstance(io.automatiko.engine.workflow.process.instance.node.EventSubProcessNodeInstance) List(java.util.List) 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) EventNodeInstance(io.automatiko.engine.workflow.process.instance.node.EventNodeInstance)

Example 3 with NodeInstanceContainer

use of io.automatiko.engine.workflow.process.instance.NodeInstanceContainer in project automatiko-engine by automatiko-io.

the class BoundaryEventNodeInstance method signalEvent.

@Override
public void signalEvent(String type, Object event) {
    BoundaryEventNode boundaryNode = (BoundaryEventNode) getEventNode();
    String attachedTo = boundaryNode.getAttachedToNodeId();
    Collection<NodeInstance> nodeInstances = ((NodeInstanceContainer) getProcessInstance()).getNodeInstances(true);
    if (type != null && type.startsWith("Compensation")) {
        // if not active && completed, signal
        if (!isAttachedToNodeActive(nodeInstances, attachedTo, type, event) && isAttachedToNodeCompleted(attachedTo)) {
            super.signalEvent(type, event);
        } else {
            cancel();
        }
    } else {
        if (isAttachedToNodeActive(nodeInstances, attachedTo, type, event)) {
            super.signalEvent(type, event);
        } else {
            cancel();
        }
    }
}
Also used : NodeInstanceContainer(io.automatiko.engine.workflow.process.instance.NodeInstanceContainer) BoundaryEventNode(io.automatiko.engine.workflow.process.core.node.BoundaryEventNode) NodeInstance(io.automatiko.engine.workflow.process.instance.NodeInstance)

Example 4 with NodeInstanceContainer

use of io.automatiko.engine.workflow.process.instance.NodeInstanceContainer 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);
}
Also used : NodeInstanceContainer(io.automatiko.engine.workflow.process.instance.NodeInstanceContainer) WorkflowProcessInstanceImpl(io.automatiko.engine.workflow.process.instance.impl.WorkflowProcessInstanceImpl) Process(io.automatiko.engine.api.definition.process.Process) Date(java.util.Date) ProcessInstance(io.automatiko.engine.workflow.base.instance.ProcessInstance) ArrayList(java.util.ArrayList) List(java.util.List) InternalProcessRuntime(io.automatiko.engine.workflow.base.instance.InternalProcessRuntime) NodeInstance(io.automatiko.engine.api.runtime.process.NodeInstance)

Example 5 with NodeInstanceContainer

use of io.automatiko.engine.workflow.process.instance.NodeInstanceContainer in project automatiko-engine by automatiko-io.

the class SplitInstance method executeStrategy.

protected void executeStrategy(Split split, String type) {
    // TODO make different strategies for each type
    String uniqueId = (String) getNode().getMetaData().get(UNIQUE_ID);
    if (uniqueId == null) {
        uniqueId = ((NodeImpl) getNode()).getUniqueId();
    }
    switch(split.getType()) {
        case Split.TYPE_AND:
            triggerCompleted(io.automatiko.engine.workflow.process.core.Node.CONNECTION_DEFAULT_TYPE, true);
            break;
        case Split.TYPE_XOR:
            List<Connection> outgoing = split.getDefaultOutgoingConnections();
            int priority = Integer.MAX_VALUE;
            Connection selected = null;
            for (final Iterator<Connection> iterator = outgoing.iterator(); iterator.hasNext(); ) {
                final Connection connection = (Connection) iterator.next();
                ConstraintEvaluator constraint = (ConstraintEvaluator) split.getConstraint(connection);
                if (constraint != null && constraint.getPriority() < priority && !constraint.isDefault()) {
                    try {
                        if (constraint.evaluate(this, connection, constraint)) {
                            selected = connection;
                            priority = constraint.getPriority();
                        }
                    } catch (RuntimeException e) {
                        throw new RuntimeException("Exception when trying to evaluate constraint " + constraint.getName() + " in split " + split.getName(), e);
                    }
                }
            }
            ((NodeInstanceContainer) getNodeInstanceContainer()).removeNodeInstance(this);
            if (selected == null) {
                for (final Iterator<Connection> iterator = outgoing.iterator(); iterator.hasNext(); ) {
                    final Connection connection = (Connection) iterator.next();
                    if (split.isDefault(connection)) {
                        selected = connection;
                        break;
                    }
                }
            }
            if (selected == null) {
                throw new IllegalArgumentException("XOR split could not find at least one valid outgoing connection for split " + getSplit().getName());
            }
            if (!hasLoop(selected.getTo(), split)) {
                setLevel(1);
                ((NodeInstanceContainer) getNodeInstanceContainer()).setCurrentLevel(1);
            }
            triggerConnection(selected);
            ((WorkflowProcessInstanceImpl) getProcessInstance()).addCompletedNodeId(uniqueId);
            break;
        case Split.TYPE_OR:
            ((NodeInstanceContainer) getNodeInstanceContainer()).removeNodeInstance(this);
            outgoing = split.getDefaultOutgoingConnections();
            boolean found = false;
            List<NodeInstanceTrigger> nodeInstances = new ArrayList<NodeInstanceTrigger>();
            List<Connection> outgoingCopy = new ArrayList<Connection>(outgoing);
            while (!outgoingCopy.isEmpty()) {
                priority = Integer.MAX_VALUE;
                Connection selectedConnection = null;
                ConstraintEvaluator selectedConstraint = null;
                for (final Iterator<Connection> iterator = outgoingCopy.iterator(); iterator.hasNext(); ) {
                    final Connection connection = (Connection) iterator.next();
                    ConstraintEvaluator constraint = (ConstraintEvaluator) split.getConstraint(connection);
                    if (constraint != null && constraint.getPriority() < priority && !constraint.isDefault()) {
                        priority = constraint.getPriority();
                        selectedConnection = connection;
                        selectedConstraint = constraint;
                    }
                }
                if (selectedConstraint == null) {
                    break;
                }
                if (selectedConstraint.evaluate(this, selectedConnection, selectedConstraint)) {
                    nodeInstances.add(new NodeInstanceTrigger(followConnection(selectedConnection), selectedConnection.getToType()));
                    found = true;
                }
                outgoingCopy.remove(selectedConnection);
            }
            for (NodeInstanceTrigger nodeInstance : nodeInstances) {
                // stop if this process instance has been aborted / completed
                if (getProcessInstance().getState() == STATE_COMPLETED || getProcessInstance().getState() == STATE_ABORTED) {
                    return;
                }
                triggerNodeInstance(nodeInstance.getNodeInstance(), nodeInstance.getToType());
            }
            if (!found) {
                for (final Iterator<Connection> iterator = outgoing.iterator(); iterator.hasNext(); ) {
                    final Connection connection = (Connection) iterator.next();
                    ConstraintEvaluator constraint = (ConstraintEvaluator) split.getConstraint(connection);
                    if (constraint != null && constraint.isDefault() || split.isDefault(connection)) {
                        triggerConnection(connection);
                        found = true;
                        break;
                    }
                }
            }
            if (!found) {
                throw new IllegalArgumentException("OR split could not find at least one valid outgoing connection for split " + getSplit().getName());
            }
            ((WorkflowProcessInstanceImpl) getProcessInstance()).addCompletedNodeId(uniqueId);
            break;
        case Split.TYPE_XAND:
            ((io.automatiko.engine.workflow.process.instance.NodeInstanceContainer) getNodeInstanceContainer()).removeNodeInstance(this);
            Node node = getNode();
            List<Connection> connections = null;
            if (node != null) {
                connections = node.getOutgoingConnections(type);
            }
            if (connections == null || connections.isEmpty()) {
                ((io.automatiko.engine.workflow.process.instance.NodeInstanceContainer) getNodeInstanceContainer()).nodeInstanceCompleted(this, type);
            } else {
                ExclusiveGroupInstance groupInstance = new ExclusiveGroupInstance();
                io.automatiko.engine.api.runtime.process.NodeInstanceContainer parent = getNodeInstanceContainer();
                if (parent instanceof ContextInstanceContainer) {
                    ((ContextInstanceContainer) parent).addContextInstance(ExclusiveGroup.EXCLUSIVE_GROUP, groupInstance);
                } else {
                    throw new IllegalArgumentException("An Exclusive AND is only possible if the parent is a context instance container");
                }
                Map<io.automatiko.engine.workflow.process.instance.NodeInstance, String> nodeInstancesMap = new HashMap<io.automatiko.engine.workflow.process.instance.NodeInstance, String>();
                for (Connection connection : connections) {
                    nodeInstancesMap.put(followConnection(connection), connection.getToType());
                }
                for (NodeInstance nodeInstance : nodeInstancesMap.keySet()) {
                    groupInstance.addNodeInstance(nodeInstance);
                }
                for (Map.Entry<io.automatiko.engine.workflow.process.instance.NodeInstance, String> entry : nodeInstancesMap.entrySet()) {
                    // stop if this process instance has been aborted / completed
                    if (getProcessInstance().getState() != ProcessInstance.STATE_ACTIVE) {
                        return;
                    }
                    boolean hidden = false;
                    if (getNode().getMetaData().get("hidden") != null) {
                        hidden = true;
                    }
                    InternalProcessRuntime runtime = getProcessInstance().getProcessRuntime();
                    if (!hidden) {
                        runtime.getProcessEventSupport().fireBeforeNodeLeft(this, runtime);
                    }
                    ((io.automatiko.engine.workflow.process.instance.NodeInstance) entry.getKey()).trigger(this, entry.getValue());
                    if (!hidden) {
                        runtime.getProcessEventSupport().fireAfterNodeLeft(this, runtime);
                    }
                }
            }
            ((WorkflowProcessInstanceImpl) getProcessInstance()).addCompletedNodeId(uniqueId);
            break;
        default:
            throw new IllegalArgumentException("Illegal split type " + split.getType());
    }
}
Also used : NodeInstanceContainer(io.automatiko.engine.workflow.process.instance.NodeInstanceContainer) HashMap(java.util.HashMap) Node(io.automatiko.engine.api.definition.process.Node) WorkflowProcessInstanceImpl(io.automatiko.engine.workflow.process.instance.impl.WorkflowProcessInstanceImpl) ArrayList(java.util.ArrayList) ConstraintEvaluator(io.automatiko.engine.workflow.base.instance.impl.ConstraintEvaluator) WorkflowRuntimeException(io.automatiko.engine.workflow.process.instance.WorkflowRuntimeException) ContextInstanceContainer(io.automatiko.engine.workflow.base.instance.ContextInstanceContainer) ExclusiveGroupInstance(io.automatiko.engine.workflow.base.instance.context.exclusive.ExclusiveGroupInstance) Connection(io.automatiko.engine.api.definition.process.Connection) InternalProcessRuntime(io.automatiko.engine.workflow.base.instance.InternalProcessRuntime) NodeInstance(io.automatiko.engine.api.runtime.process.NodeInstance) HashMap(java.util.HashMap) Map(java.util.Map)

Aggregations

NodeInstanceContainer (io.automatiko.engine.workflow.process.instance.NodeInstanceContainer)10 WorkflowProcessInstanceImpl (io.automatiko.engine.workflow.process.instance.impl.WorkflowProcessInstanceImpl)6 NodeInstance (io.automatiko.engine.workflow.process.instance.NodeInstance)4 Node (io.automatiko.engine.api.definition.process.Node)3 NodeInstance (io.automatiko.engine.api.runtime.process.NodeInstance)3 InternalProcessRuntime (io.automatiko.engine.workflow.base.instance.InternalProcessRuntime)3 ProcessInstance (io.automatiko.engine.workflow.base.instance.ProcessInstance)3 ArrayList (java.util.ArrayList)3 List (java.util.List)3 Process (io.automatiko.engine.api.definition.process.Process)2 ContextInstanceContainer (io.automatiko.engine.workflow.base.instance.ContextInstanceContainer)2 BoundaryEventNode (io.automatiko.engine.workflow.process.core.node.BoundaryEventNode)2 EventSubProcessNode (io.automatiko.engine.workflow.process.core.node.EventSubProcessNode)2 ExecutableProcess (io.automatiko.engine.workflow.process.executable.core.ExecutableProcess)2 WorkflowRuntimeException (io.automatiko.engine.workflow.process.instance.WorkflowRuntimeException)2 EventNodeInstance (io.automatiko.engine.workflow.process.instance.node.EventNodeInstance)2 EventSubProcessNodeInstance (io.automatiko.engine.workflow.process.instance.node.EventSubProcessNodeInstance)2 Date (java.util.Date)2 Connection (io.automatiko.engine.api.definition.process.Connection)1 NodeContainer (io.automatiko.engine.api.definition.process.NodeContainer)1