/// <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); }
/// <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)); } } }
/// <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); }