public override void Execute(IExecutionEntity execution)
        {
            // The join in the inclusive gateway works as follows:
            // When an execution enters it, it is inactivated.
            // All the inactivated executions stay in the inclusive gateway
            // until ALL executions that CAN reach the inclusive gateway have reached it.
            //
            // This check is repeated on execution changes until the inactivated
            // executions leave the gateway.

            execution.Inactivate();
            ExecuteInclusiveGatewayLogic(execution);
        }
Exemplo n.º 2
0
        public override void Leave(IExecutionEntity execution, object signalData)
        {
            lock (syncRoot)
            {
                ICommandContext commandContext = Context.CommandContext;
                if (commandContext == null)
                {
                    throw new ActivitiException("lazy loading outside command context");
                }

                completedPolicy.LeaveExection = execution;

                bool zeroNrOfInstances = false;
                if (ResolveNrOfInstances(execution) == 0)
                {
                    // Empty collection, just leave.
                    zeroNrOfInstances = true;
                    RemoveLocalLoopVariable(execution, CollectionElementIndexVariable);
                    base.Leave(execution, signalData); // Plan the default leave
                    execution.IsMultiInstanceRoot = false;
                }

                int loopCounter            = GetLoopVariable(execution, CollectionElementIndexVariable).GetValueOrDefault(0);
                int nrOfInstances          = GetLoopVariable(execution, NUMBER_OF_INSTANCES).GetValueOrDefault(0);
                int nrOfCompletedInstances = GetLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES).GetValueOrDefault(0) + 1;
                int nrOfActiveInstances    = GetLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES).GetValueOrDefault(0) - 1;

                Context.CommandContext.HistoryManager.RecordActivityEnd(execution, null);
                CallActivityEndListeners(execution);

                if (zeroNrOfInstances)
                {
                    return;
                }

                IExecutionEntity miRootExecution = GetMultiInstanceRootExecution(execution);
                if (miRootExecution != null)
                { // will be null in case of empty collection
                    SetLoopVariable(miRootExecution, NUMBER_OF_COMPLETED_INSTANCES, nrOfCompletedInstances);
                    SetLoopVariable(miRootExecution, NUMBER_OF_ACTIVE_INSTANCES, nrOfActiveInstances < 0 ? 0 : nrOfActiveInstances);
                }

                //ExecuteCompensationBoundaryEvents(execution.CurrentFlowElement, execution);

                LogLoopDetails(execution, "instance completed", loopCounter, nrOfCompletedInstances, nrOfActiveInstances, nrOfActiveInstances < 0 ? 0 : nrOfActiveInstances);

                if (execution.Parent != null)
                {
                    execution.Inactivate();
                    LockFirstParentScope(execution);

                    if (CompletionConditionSatisfied(execution.Parent, signalData) || nrOfCompletedInstances >= nrOfInstances)
                    {
                        IExecutionEntity executionToUse;
                        if (nrOfInstances > 0)
                        {
                            executionToUse = execution.Parent;
                        }
                        else
                        {
                            executionToUse = execution;
                        }

                        bool     hasCompensation = false;
                        Activity activity        = (Activity)execution.CurrentFlowElement;
                        if (activity is Transaction)
                        {
                            hasCompensation = true;
                        }
                        else if (activity is SubProcess subProcess)
                        {
                            foreach (FlowElement subElement in subProcess.FlowElements)
                            {
                                if (subElement is Activity subActivity)
                                {
                                    if (CollectionUtil.IsNotEmpty(subActivity.BoundaryEvents))
                                    {
                                        foreach (BoundaryEvent boundaryEvent in subActivity.BoundaryEvents)
                                        {
                                            if (CollectionUtil.IsNotEmpty(boundaryEvent.EventDefinitions) && boundaryEvent.EventDefinitions[0] is CompensateEventDefinition)
                                            {
                                                hasCompensation = true;
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        if (hasCompensation)
                        {
                            ScopeUtil.CreateCopyOfSubProcessExecutionForCompensation(executionToUse);
                        }

                        if (activity is CallActivity)
                        {
                            IExecutionEntityManager executionEntityManager = Context.CommandContext.ExecutionEntityManager;
                            if (executionToUse != null)
                            {
                                IList <string> callActivityExecutionIds = new List <string>();

                                // Find all execution entities that are at the call activity
                                IList <IExecutionEntity> childExecutions = executionEntityManager.CollectChildren(executionToUse);
                                if (childExecutions != null)
                                {
                                    foreach (IExecutionEntity childExecution in childExecutions)
                                    {
                                        if (activity.Id.Equals(childExecution.CurrentActivityId))
                                        {
                                            callActivityExecutionIds.Add(childExecution.Id);
                                        }
                                    }

                                    // Now all call activity executions have been collected, loop again and check which should be removed
                                    for (int i = childExecutions.Count - 1; i >= 0; i--)
                                    {
                                        IExecutionEntity childExecution = childExecutions[i];
                                        if (!string.IsNullOrWhiteSpace(childExecution.SuperExecutionId) && callActivityExecutionIds.Contains(childExecution.SuperExecutionId))
                                        {
                                            executionEntityManager.DeleteProcessInstanceExecutionEntity(childExecution.Id, activity.Id, "call activity completion condition met", true, false);
                                        }
                                    }
                                }
                            }
                        }

                        DeleteChildExecutions(executionToUse, false, Context.CommandContext);
                        RemoveLocalLoopVariable(executionToUse, CollectionElementIndexVariable);
                        executionToUse.IsScope             = false;
                        executionToUse.IsMultiInstanceRoot = false;
                        Context.Agenda.PlanTakeOutgoingSequenceFlowsOperation(executionToUse, true);
                    }
                }
                else
                {
                    RemoveLocalLoopVariable(execution, CollectionElementIndexVariable);
                    execution.IsMultiInstanceRoot = false;
                    base.Leave(execution, signalData);
                }
            }
        }
        public override void Execute(IExecutionEntity execution)
        {
            // First off all, deactivate the execution
            execution.Inactivate();

            // Join
            FlowElement     flowElement = execution.CurrentFlowElement;
            ParallelGateway parallelGateway;

            if (flowElement is ParallelGateway)
            {
                parallelGateway = (ParallelGateway)flowElement;
            }
            else
            {
                throw new ActivitiException("Programmatic error: parallel gateway behaviour can only be applied" + " to a ParallelGateway instance, but got an instance of " + flowElement);
            }

            LockFirstParentScope(execution);

            IExecutionEntity multiInstanceExecution = null;

            if (HasMultiInstanceParent(parallelGateway))
            {
                multiInstanceExecution = FindMultiInstanceParentExecution(execution);
            }

            IExecutionEntityManager        executionEntityManager = Context.CommandContext.ExecutionEntityManager;
            ICollection <IExecutionEntity> joinedExecutions       = executionEntityManager.FindInactiveExecutionsByActivityIdAndProcessInstanceId(execution.CurrentActivityId, execution.ProcessInstanceId);

            if (multiInstanceExecution != null)
            {
                joinedExecutions = CleanJoinedExecutions(joinedExecutions, multiInstanceExecution);
            }

            int nbrOfExecutionsToJoin          = parallelGateway.IncomingFlows.Count;
            int nbrOfExecutionsCurrentlyJoined = joinedExecutions.Count;

            // Fork

            // Is needed to set the endTime for all historic activity joins
            Context.CommandContext.HistoryManager.RecordActivityEnd(execution, null);

            if (nbrOfExecutionsCurrentlyJoined == nbrOfExecutionsToJoin)
            {
                // Fork
                if (log.IsEnabled(LogLevel.Debug))
                {
                    log.LogDebug($"parallel gateway '{execution.CurrentActivityId}' activates: {nbrOfExecutionsCurrentlyJoined} of {nbrOfExecutionsToJoin} joined");
                }

                if (parallelGateway.IncomingFlows.Count > 1)
                {
                    // All (now inactive) children are deleted.
                    foreach (IExecutionEntity joinedExecution in joinedExecutions)
                    {
                        // The current execution will be reused and not deleted
                        if (!joinedExecution.Id.Equals(execution.Id))
                        {
                            executionEntityManager.DeleteExecutionAndRelatedData(joinedExecution, null, false);
                        }
                    }
                }

                // TODO: potential optimization here: reuse more then 1 execution, only 1 currently
                Context.Agenda.PlanTakeOutgoingSequenceFlowsOperation(execution, false); // false -> ignoring conditions on parallel gw
            }
            else if (log.IsEnabled(LogLevel.Debug))
            {
                log.LogDebug($"parallel gateway '{execution.CurrentActivityId}' does not activate: {nbrOfExecutionsCurrentlyJoined} of {nbrOfExecutionsToJoin} joined");
            }
        }