/// <summary>
        ///
        /// </summary>
        /// <param name="executionEntityManager"></param>
        /// <param name="parentExecution"></param>
        /// <param name="subProcess"></param>
        /// <returns></returns>
        protected internal virtual IExecutionEntity HandleSubProcessEnd(IExecutionEntityManager executionEntityManager, IExecutionEntity parentExecution, SubProcess subProcess)
        {
            // create a new execution to take the outgoing sequence flows
            IExecutionEntity executionToContinue = executionEntityManager.CreateChildExecution(parentExecution.Parent);

            executionToContinue.CurrentFlowElement = subProcess;

            bool hasCompensation = false;

            if (subProcess is Transaction)
            {
                hasCompensation = true;
            }
            else
            {
                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;
                                }
                            }
                        }
                    }
                }
            }

            // All executions will be cleaned up afterwards. However, for compensation we need
            // a copy of these executions so we can use them later on when the compensation is thrown.
            // The following method does exactly that, and moves the executions beneath the process instance.
            if (hasCompensation)
            {
                ScopeUtil.CreateCopyOfSubProcessExecutionForCompensation(parentExecution);
            }

            executionEntityManager.DeleteChildExecutions(parentExecution, null, false);
            executionEntityManager.DeleteExecutionAndRelatedData(parentExecution, null, false);

            Context.ProcessEngineConfiguration.EventDispatcher.DispatchEvent(ActivitiEventBuilder.CreateActivityEvent(ActivitiEventType.ACTIVITY_COMPLETED, subProcess.Id, subProcess.Name, parentExecution.Id, parentExecution.ProcessInstanceId, parentExecution.ProcessDefinitionId, subProcess));
            return(executionToContinue);
        }
Beispiel #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="flowNode"></param>
        protected internal virtual void ExecuteSynchronous(FlowNode flowNode)
        {
            // Execution listener
            if (CollectionUtil.IsNotEmpty(flowNode.ExecutionListeners))
            {
                ExecuteExecutionListeners(flowNode, BaseExecutionListenerFields.EVENTNAME_START);
            }

            commandContext.HistoryManager.RecordActivityStart(execution);

            // Execute actual behavior
            IActivityBehavior activityBehavior = (IActivityBehavior)flowNode.Behavior;

            if (activityBehavior != null)
            {
                logger.LogDebug($"Executing activityBehavior {activityBehavior.GetType()} on activity '{flowNode.Id}' with execution {execution.Id}");

                ProcessEngineConfigurationImpl processEngineConfiguration = Context.ProcessEngineConfiguration;
                if (processEngineConfiguration != null && processEngineConfiguration.EventDispatcher.Enabled)
                {
                    processEngineConfiguration.EventDispatcher.DispatchEvent(ActivitiEventBuilder.CreateActivityEvent(ActivitiEventType.ACTIVITY_STARTED, flowNode.Id, flowNode.Name, execution.Id, execution.ProcessInstanceId, execution.ProcessDefinitionId, flowNode));
                }

                try
                {
                    activityBehavior.Execute(execution);
                }
                catch (BpmnError error)
                {
                    // re-throw business fault so that it can be caught by an Error Intermediate Event or Error Event Sub-Process in the process
                    ErrorPropagation.PropagateError(error, execution);
                }
                catch (Exception e)
                {
                    if (LogMDC.MDCEnabled)
                    {
                        LogMDC.PutMDCExecution(execution);
                    }
                    throw e;
                }
            }
            else
            {
                logger.LogDebug($"No activityBehavior on activity '{flowNode.Id}' with execution {execution.Id}");
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="flowNode"></param>
        protected internal virtual void HandleActivityEnd(FlowNode flowNode)
        {
            // a process instance execution can never leave a flow node, but it can pass here whilst cleaning up
            // hence the check for NOT being a process instance
            if (!execution.ProcessInstanceType)
            {
                if (CollectionUtil.IsNotEmpty(flowNode.ExecutionListeners))
                {
                    ExecuteExecutionListeners(flowNode, BaseExecutionListenerFields.EVENTNAME_END);
                }

                commandContext.HistoryManager.RecordActivityEnd(execution, null);

                if (!(execution.CurrentFlowElement is SubProcess))
                {
                    Context.ProcessEngineConfiguration.EventDispatcher.DispatchEvent(ActivitiEventBuilder.CreateActivityEvent(ActivitiEventType.ACTIVITY_COMPLETED, flowNode.Id, flowNode.Name, execution.Id, execution.ProcessInstanceId, execution.ProcessDefinitionId, flowNode));
                }
            }
        }
Beispiel #4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="activityBehavior"></param>
        /// <param name="flowNode"></param>
        protected internal virtual void ExecuteActivityBehavior(IActivityBehavior activityBehavior, FlowNode flowNode)
        {
            log.LogDebug($"Executing activityBehavior {activityBehavior.GetType()} on activity '{flowNode.Id}' with execution {execution.Id}");

            ProcessEngineConfigurationImpl processEngineConfiguration = Context.ProcessEngineConfiguration;

            if (processEngineConfiguration != null && processEngineConfiguration.EventDispatcher.Enabled)
            {
                processEngineConfiguration.EventDispatcher.DispatchEvent(ActivitiEventBuilder.CreateActivityEvent(ActivitiEventType.ACTIVITY_STARTED, flowNode.Id, flowNode.Name, execution.Id, execution.ProcessInstanceId, execution.ProcessDefinitionId, flowNode));
            }

            try
            {
                activityBehavior.Execute(execution);
            }
            catch (Exception e)
            {
                throw new Exception($"{e.Message}", e);
            }
        }
        public virtual void HandleEvent(IEventSubscriptionEntity eventSubscription, object payload, ICommandContext commandContext)
        {
            string configuration = eventSubscription.Configuration;

            if (configuration is null)
            {
                throw new ActivitiException("Compensating execution not set for compensate event subscription with id " + eventSubscription.Id);
            }

            IExecutionEntity compensatingExecution = commandContext.ExecutionEntityManager.FindById <IExecutionEntity>(configuration);

            string  processDefinitionId = compensatingExecution.ProcessDefinitionId;
            Process process             = ProcessDefinitionUtil.GetProcess(processDefinitionId);

            if (process == null)
            {
                throw new ActivitiException("Cannot start process instance. Process model (id = " + processDefinitionId + ") could not be found");
            }

            FlowElement flowElement = process.GetFlowElement(eventSubscription.ActivityId, true);

            if (flowElement is SubProcess && !((SubProcess)flowElement).ForCompensation)
            {
                // descend into scope:
                compensatingExecution.IsScope = true;
                IList <ICompensateEventSubscriptionEntity> eventsForThisScope = commandContext.EventSubscriptionEntityManager.FindCompensateEventSubscriptionsByExecutionId(compensatingExecution.Id);
                ScopeUtil.ThrowCompensationEvent(eventsForThisScope, compensatingExecution, false);
            }
            else
            {
                try
                {
                    if (commandContext.ProcessEngineConfiguration.EventDispatcher.Enabled)
                    {
                        commandContext.ProcessEngineConfiguration.EventDispatcher.DispatchEvent(ActivitiEventBuilder.CreateActivityEvent(ActivitiEventType.ACTIVITY_COMPENSATE, flowElement.Id, flowElement.Name, compensatingExecution.Id, compensatingExecution.ProcessInstanceId, compensatingExecution.ProcessDefinitionId, flowElement));
                    }
                    compensatingExecution.CurrentFlowElement = flowElement;
                    Context.Agenda.PlanContinueProcessInCompensation(compensatingExecution);
                }
                catch (Exception e)
                {
                    throw new ActivitiException("Error while handling compensation event " + eventSubscription, e);
                }
            }
        }
        // private static Logger log = LoggerFactory.getLogger(typeof(ExclusiveGatewayActivityBehavior));

        /// <summary>
        /// The default behaviour of BPMN, taking every outgoing sequence flow (where the condition evaluates to true), is not valid for an exclusive gateway.
        ///
        /// Hence, this behaviour is overridden and replaced by the correct behavior: selecting the first sequence flow which condition evaluates to true (or which hasn't got a condition) and leaving the
        /// activity through that sequence flow.
        ///
        /// If no sequence flow is selected (ie all conditions evaluate to false), then the default sequence flow is taken (if defined).
        /// </summary>
        public override void Leave(IExecutionEntity execution)
        {
            if (log.IsEnabled(LogLevel.Debug))
            {
                log.LogDebug($"Leaving exclusive gateway '{execution.CurrentActivityId}'");
            }

            ExclusiveGateway exclusiveGateway = (ExclusiveGateway)execution.CurrentFlowElement;

            ProcessEngineConfigurationImpl processEngineConfiguration = Context.ProcessEngineConfiguration;

            if (processEngineConfiguration is object && processEngineConfiguration.EventDispatcher.Enabled)
            {
                processEngineConfiguration.EventDispatcher.DispatchEvent(ActivitiEventBuilder.CreateActivityEvent(ActivitiEventType.ACTIVITY_COMPLETED, exclusiveGateway.Id, exclusiveGateway.Name, execution.Id, execution.ProcessInstanceId, execution.ProcessDefinitionId, exclusiveGateway));
            }

            SequenceFlow outgoingSequenceFlow  = null;
            SequenceFlow defaultSequenceFlow   = null;
            string       defaultSequenceFlowId = exclusiveGateway.DefaultFlow;

            // Determine sequence flow to take
            foreach (SequenceFlow sequenceFlow in exclusiveGateway.OutgoingFlows)
            {
                string skipExpressionString = sequenceFlow.SkipExpression;
                if (!SkipExpressionUtil.IsSkipExpressionEnabled(execution, skipExpressionString))
                {
                    bool conditionEvaluatesToTrue = ConditionUtil.HasTrueCondition(sequenceFlow, execution);
                    if (conditionEvaluatesToTrue && (defaultSequenceFlowId is null || !defaultSequenceFlowId.Equals(sequenceFlow.Id)))
                    {
                        if (log.IsEnabled(LogLevel.Debug))
                        {
                            log.LogDebug($"Sequence flow '{sequenceFlow.Id}'selected as outgoing sequence flow.");
                        }
                        outgoingSequenceFlow = sequenceFlow;
                        break;
                    }
                }
                else if (SkipExpressionUtil.ShouldSkipFlowElement(Context.CommandContext, execution, skipExpressionString))
                {
                    outgoingSequenceFlow = sequenceFlow;
                    break;
                }

                // Already store it, if we would need it later. Saves one for loop.
                if (defaultSequenceFlowId is object && defaultSequenceFlowId.Equals(sequenceFlow.Id))
                {
                    defaultSequenceFlow = sequenceFlow;
                }
            }

            // We have to record the end here, or else we're already past it
            Context.CommandContext.HistoryManager.RecordActivityEnd(execution, null);

            // Leave the gateway
            if (outgoingSequenceFlow != null)
            {
                execution.CurrentFlowElement = outgoingSequenceFlow;

                log.LogInformation($"条件表达式:id={outgoingSequenceFlow.Id} expression={outgoingSequenceFlow.ConditionExpression}");
            }
            else
            {
                if (defaultSequenceFlow != null)
                {
                    execution.CurrentFlowElement = defaultSequenceFlow;

                    log.LogInformation($"条件表达式:id={defaultSequenceFlow.Id} expression={defaultSequenceFlow.ConditionExpression}");
                }
                else
                {
                    // No sequence flow could be found, not even a default one
                    throw new ActivitiException("No outgoing sequence flow of the exclusive gateway '" + exclusiveGateway.Id + "' could be selected for continuing the process");
                }
            }

            base.Leave(execution);
        }