/// <summary> /// /// </summary> protected override void RunOperation() { try { // Find the actual scope that needs to be destroyed. // This could be the incoming execution, or the first parent execution where isScope = true // Find parent scope execution IExecutionEntity scopeExecution = execution.IsScope ? execution : FindFirstParentScopeExecution(execution); if (scopeExecution == null) { throw new ActivitiException("Programmatic error: no parent scope execution found for boundary event"); } IExecutionEntityManager executionEntityManager = commandContext.ExecutionEntityManager; DeleteAllChildExecutions(executionEntityManager, scopeExecution); // Delete all scope tasks ITaskEntityManager taskEntityManager = commandContext.TaskEntityManager; DeleteAllScopeTasks(scopeExecution, taskEntityManager); // Delete all scope jobs ITimerJobEntityManager timerJobEntityManager = commandContext.TimerJobEntityManager; DeleteAllScopeJobs(scopeExecution, timerJobEntityManager); // Remove variables associated with this scope IVariableInstanceEntityManager variableInstanceEntityManager = commandContext.VariableInstanceEntityManager; RemoveAllVariablesFromScope(scopeExecution, variableInstanceEntityManager); commandContext.HistoryManager.RecordActivityEnd(scopeExecution, scopeExecution.DeleteReason); executionEntityManager.Delete(scopeExecution); } catch (Exception ex) { logger.LogError(ex, ex.Message); throw; } }
public override void Trigger(IExecutionEntity execution, string triggerName, object triggerData, bool throwError = true) { ICommandContext commandContext = Context.CommandContext; IExecutionEntityManager executionEntityManager = commandContext.ExecutionEntityManager; StartEvent startEvent = (StartEvent)execution.CurrentFlowElement; if (startEvent.Interrupting) { IList <IExecutionEntity> childExecutions = executionEntityManager.FindChildExecutionsByParentExecutionId(execution.ParentId); foreach (IExecutionEntity childExecution in childExecutions) { if (!childExecution.Id.Equals(execution.Id)) { executionEntityManager.DeleteExecutionAndRelatedData(childExecution, History.DeleteReasonFields.EVENT_SUBPROCESS_INTERRUPTING + "(" + startEvent.Id + ")", false); } } } IEventSubscriptionEntityManager eventSubscriptionEntityManager = Context.CommandContext.EventSubscriptionEntityManager; IList <IEventSubscriptionEntity> eventSubscriptions = execution.EventSubscriptions; foreach (IEventSubscriptionEntity eventSubscription in eventSubscriptions) { if (eventSubscription.EventType == MessageEventSubscriptionEntityFields.EVENT_TYPE && eventSubscription.EventName.Equals(messageEventDefinition.MessageRef)) { eventSubscriptionEntityManager.Delete(eventSubscription); } } execution.CurrentFlowElement = (SubProcess)execution.CurrentFlowElement.ParentContainer; execution.IsScope = true; IExecutionEntity outgoingFlowExecution = executionEntityManager.CreateChildExecution(execution); outgoingFlowExecution.CurrentFlowElement = startEvent; Leave(outgoingFlowExecution); }
public virtual object Execute(ICommandContext commandContext) { // check that the new process definition is just another version of the same // process definition that the process instance is using IExecutionEntityManager executionManager = commandContext.ExecutionEntityManager; IExecutionEntity processInstance = executionManager.FindById <IExecutionEntity>(new KeyValuePair <string, object>("id", processInstanceId)); if (processInstance == null) { throw new ActivitiObjectNotFoundException("No process instance found for id = '" + processInstanceId + "'.", typeof(IProcessInstance)); } else if (!processInstance.ProcessInstanceType) { throw new ActivitiIllegalArgumentException("A process instance id is required, but the provided id " + "'" + processInstanceId + "' " + "points to a child execution of process instance " + "'" + processInstance.ProcessInstanceId + "'. " + "Please invoke the " + this.GetType().Name + " with a root execution id."); } DeploymentManager deploymentCache = commandContext.ProcessEngineConfiguration.DeploymentManager; IProcessDefinition currentProcessDefinition = deploymentCache.FindDeployedProcessDefinitionById(processInstance.ProcessDefinitionId); IProcessDefinition newProcessDefinition = deploymentCache.FindDeployedProcessDefinitionByKeyAndVersionAndTenantId(currentProcessDefinition.Key, processDefinitionVersion, currentProcessDefinition.TenantId); ValidateAndSwitchVersionOfExecution(commandContext, processInstance, newProcessDefinition); // switch the historic process instance to the new process definition version commandContext.HistoryManager.RecordProcessDefinitionChange(processInstanceId, newProcessDefinition.Id); // switch all sub-executions of the process instance to the new process definition version ICollection <IExecutionEntity> childExecutions = executionManager.FindChildExecutionsByProcessInstanceId(processInstanceId); foreach (IExecutionEntity executionEntity in childExecutions) { ValidateAndSwitchVersionOfExecution(commandContext, executionEntity, newProcessDefinition); } return(null); }
protected internal virtual void ExecuteInterruptingBehavior(IExecutionEntity executionEntity, ICommandContext commandContext) { // The destroy scope operation will look for the parent execution and // destroy the whole scope, and leave the boundary event using this parent execution. // // The take outgoing seq flows operation below (the non-interrupting else clause) on the other hand uses the // child execution to leave, which keeps the scope alive. // Which is what we need here. IExecutionEntityManager executionEntityManager = commandContext.ExecutionEntityManager; IExecutionEntity attachedRefScopeExecution = executionEntityManager.FindById <IExecutionEntity>(executionEntity.ParentId); IExecutionEntity scopeExecution = null; IExecutionEntity currentlyExaminedExecution = executionEntityManager.FindById <IExecutionEntity>(attachedRefScopeExecution.ParentId); GetScopeExecution(executionEntityManager, ref scopeExecution, ref currentlyExaminedExecution); DeleteChildExecutions(attachedRefScopeExecution, executionEntity, commandContext); // set new parent for boundary event execution executionEntity.Parent = scopeExecution ?? throw new ActivitiException("Programmatic error: no parent scope execution found for boundary event"); Context.Agenda.PlanTakeOutgoingSequenceFlowsOperation(executionEntity, true); }
/// <summary> /// /// </summary> /// <param name="executionEntityManager"></param> /// <param name="processInstanceId"></param> /// <returns></returns> protected internal virtual int GetNumberOfActiveChildExecutionsForProcessInstance(IExecutionEntityManager executionEntityManager, string processInstanceId, IExecutionEntity endingExecution) { ICollection <IExecutionEntity> executions = executionEntityManager.FindChildExecutionsByProcessInstanceId(processInstanceId); int activeExecutions = 0; foreach (IExecutionEntity execution in executions) { if (endingExecution is object && endingExecution.Id == execution.Id) { continue; } if (execution.IsActive && !processInstanceId.Equals(execution.Id)) { activeExecutions++; } } return(activeExecutions); }
/// <summary> /// /// </summary> protected internal virtual void HandleRegularExecution() { IExecutionEntityManager executionEntityManager = commandContext.ExecutionEntityManager; // There will be a parent execution (or else we would be in the process instance handling method) IExecutionEntity parentExecution = executionEntityManager.FindById <IExecutionEntity>(execution.ParentId); // If the execution is a scope, all the child executions must be deleted first. if (execution.IsScope) { executionEntityManager.DeleteChildExecutions(execution, null, false); } // Delete current execution logger.LogDebug($"Ending execution {execution.Id}"); executionEntityManager.DeleteExecutionAndRelatedData(execution, null, false); logger.LogDebug($"Parent execution found. Continuing process using execution {parentExecution.Id}"); // When ending an execution in a multi instance subprocess , special care is needed if (IsEndEventInMultiInstanceSubprocess(execution)) { HandleMultiInstanceSubProcess(executionEntityManager, parentExecution); return; } SubProcess subProcess = execution.CurrentFlowElement.SubProcess; // If there are no more active child executions, the process can be continued // If not (eg an embedded subprocess still has active elements, we cannot continue) if (GetNumberOfActiveChildExecutionsForExecution(executionEntityManager, parentExecution.Id) == 0 || IsAllEventScopeExecutions(executionEntityManager, parentExecution)) { IExecutionEntity executionToContinue = null; if (subProcess != null) { // In case of ending a subprocess: go up in the scopes and continue via the parent scope // unless its a compensation, then we don't need to do anything and can just end it if (subProcess.ForCompensation) { Context.Agenda.PlanEndExecutionOperation(parentExecution); } else { executionToContinue = HandleSubProcessEnd(executionEntityManager, parentExecution, subProcess); } } else { // In the 'regular' case (not being in a subprocess), we use the parent execution to // continue process instance execution executionToContinue = HandleRegularExecutionEnd(executionEntityManager, parentExecution); } if (executionToContinue != null) { // only continue with outgoing sequence flows if the execution is // not the process instance root execution (otherwise the process instance is finished) if (executionToContinue.ProcessInstanceType) { HandleProcessInstanceExecution(executionToContinue); } else { Context.Agenda.PlanTakeOutgoingSequenceFlowsOperation(executionToContinue, true); } } } }
protected internal virtual void DefaultTerminateEndEventBehaviour(IExecutionEntity execution, ICommandContext commandContext, IExecutionEntityManager executionEntityManager) { IExecutionEntity scopeExecutionEntity = executionEntityManager.FindFirstScope(execution); SendProcessInstanceCancelledEvent(scopeExecutionEntity, execution.CurrentFlowElement); // If the scope is the process instance, we can just terminate it all // Special treatment is needed when the terminated activity is a subprocess (embedded/callactivity/..) // The subprocess is destroyed, but the execution calling it, continues further on. // In case of a multi-instance subprocess, only one instance is terminated, the other instances continue to exist. string deleteReason = CreateDeleteReason(execution.CurrentActivityId); if (scopeExecutionEntity.ProcessInstanceType && scopeExecutionEntity.SuperExecutionId is null) { EndAllHistoricActivities(scopeExecutionEntity.Id, deleteReason); DeleteExecutionEntities(executionEntityManager, scopeExecutionEntity, deleteReason); commandContext.HistoryManager.RecordProcessInstanceEnd(scopeExecutionEntity.Id, deleteReason, execution.CurrentActivityId); } else if (scopeExecutionEntity.CurrentFlowElement != null && scopeExecutionEntity.CurrentFlowElement is SubProcess) { // SubProcess SubProcess subProcess = (SubProcess)scopeExecutionEntity.CurrentFlowElement; scopeExecutionEntity.DeleteReason = deleteReason; if (subProcess.HasMultiInstanceLoopCharacteristics()) { Context.Agenda.PlanDestroyScopeOperation(scopeExecutionEntity); MultiInstanceActivityBehavior multiInstanceBehavior = (MultiInstanceActivityBehavior)subProcess.Behavior; multiInstanceBehavior.Leave(scopeExecutionEntity); } else { Context.Agenda.PlanDestroyScopeOperation(scopeExecutionEntity); IExecutionEntity outgoingFlowExecution = executionEntityManager.CreateChildExecution(scopeExecutionEntity.Parent); outgoingFlowExecution.CurrentFlowElement = scopeExecutionEntity.CurrentFlowElement; Context.Agenda.PlanTakeOutgoingSequenceFlowsOperation(outgoingFlowExecution, true); } } else if (scopeExecutionEntity.ParentId is null && scopeExecutionEntity.SuperExecutionId is object) { // CallActivity IExecutionEntity callActivityExecution = scopeExecutionEntity.SuperExecution; CallActivity callActivity = (CallActivity)callActivityExecution.CurrentFlowElement; if (callActivity.HasMultiInstanceLoopCharacteristics()) { MultiInstanceActivityBehavior multiInstanceBehavior = (MultiInstanceActivityBehavior)callActivity.Behavior; multiInstanceBehavior.Leave(callActivityExecution); executionEntityManager.DeleteProcessInstanceExecutionEntity(scopeExecutionEntity.Id, execution.CurrentFlowElement.Id, "terminate end event", false, false); } else { executionEntityManager.DeleteProcessInstanceExecutionEntity(scopeExecutionEntity.Id, execution.CurrentFlowElement.Id, "terminate end event", false, false); IExecutionEntity superExecutionEntity = executionEntityManager.FindById <IExecutionEntity>(scopeExecutionEntity.SuperExecutionId); Context.Agenda.PlanTakeOutgoingSequenceFlowsOperation(superExecutionEntity, true); } } }
protected internal virtual void TerminateAllBehaviour(IExecutionEntity execution, ICommandContext commandContext, IExecutionEntityManager executionEntityManager) { IExecutionEntity rootExecutionEntity = executionEntityManager.FindByRootProcessInstanceId(execution.RootProcessInstanceId); string deleteReason = CreateDeleteReason(execution.CurrentActivityId); DeleteExecutionEntities(executionEntityManager, rootExecutionEntity, deleteReason); EndAllHistoricActivities(rootExecutionEntity.Id, deleteReason); commandContext.HistoryManager.RecordProcessInstanceEnd(rootExecutionEntity.Id, deleteReason, execution.CurrentActivityId); }
protected internal virtual void TerminateMultiInstanceRoot(IExecutionEntity execution, ICommandContext commandContext, IExecutionEntityManager executionEntityManager) { // When terminateMultiInstance is 'true', we look for the multi instance root and delete it from there. IExecutionEntity miRootExecutionEntity = executionEntityManager.FindFirstMultiInstanceRoot(execution); if (miRootExecutionEntity != null) { // Create sibling execution to continue process instance execution before deletion IExecutionEntity siblingExecution = executionEntityManager.CreateChildExecution(miRootExecutionEntity.Parent); siblingExecution.CurrentFlowElement = miRootExecutionEntity.CurrentFlowElement; DeleteExecutionEntities(executionEntityManager, miRootExecutionEntity, CreateDeleteReason(miRootExecutionEntity.ActivityId)); Context.Agenda.PlanTakeOutgoingSequenceFlowsOperation(siblingExecution, true); } else { DefaultTerminateEndEventBehaviour(execution, commandContext, executionEntityManager); } }
public override void Execute(IExecutionEntity execution) { IExecutionEntity executionEntity = execution; ICommandContext commandContext = Context.CommandContext; IExecutionEntityManager executionEntityManager = commandContext.ExecutionEntityManager; // find cancel boundary event: IExecutionEntity parentScopeExecution = null; IExecutionEntity currentlyExaminedExecution = executionEntityManager.FindById <IExecutionEntity>(executionEntity.ParentId); while (currentlyExaminedExecution != null && parentScopeExecution == null) { if (currentlyExaminedExecution.CurrentFlowElement is SubProcess) { parentScopeExecution = currentlyExaminedExecution; SubProcess subProcess = (SubProcess)currentlyExaminedExecution.CurrentFlowElement; if (subProcess.LoopCharacteristics != null) { IExecutionEntity miExecution = parentScopeExecution.Parent; FlowElement miElement = miExecution.CurrentFlowElement; if (miElement != null && miElement.Id.Equals(subProcess.Id)) { parentScopeExecution = miExecution; } } } else { currentlyExaminedExecution = executionEntityManager.FindById <IExecutionEntity>(currentlyExaminedExecution.ParentId); } } if (parentScopeExecution == null) { throw new ActivitiException("No sub process execution found for cancel end event " + executionEntity.CurrentActivityId); } { SubProcess subProcess = (SubProcess)parentScopeExecution.CurrentFlowElement; BoundaryEvent cancelBoundaryEvent = null; if (CollectionUtil.IsNotEmpty(subProcess.BoundaryEvents)) { foreach (BoundaryEvent boundaryEvent in subProcess.BoundaryEvents) { if (CollectionUtil.IsNotEmpty(boundaryEvent.EventDefinitions) && boundaryEvent.EventDefinitions[0] is CancelEventDefinition) { cancelBoundaryEvent = boundaryEvent; break; } } } if (cancelBoundaryEvent == null) { throw new ActivitiException("Could not find cancel boundary event for cancel end event " + executionEntity.CurrentActivityId); } IExecutionEntity newParentScopeExecution = null; currentlyExaminedExecution = executionEntityManager.FindById <IExecutionEntity>(parentScopeExecution.ParentId); while (currentlyExaminedExecution != null && newParentScopeExecution == null) { if (currentlyExaminedExecution.IsScope) { newParentScopeExecution = currentlyExaminedExecution; } else { currentlyExaminedExecution = executionEntityManager.FindById <IExecutionEntity>(currentlyExaminedExecution.ParentId); } } ScopeUtil.CreateCopyOfSubProcessExecutionForCompensation(parentScopeExecution); if (subProcess.LoopCharacteristics != null) { IList <IExecutionEntity> multiInstanceExecutions = parentScopeExecution.Executions; IList <IExecutionEntity> executionsToDelete = new List <IExecutionEntity>(); foreach (IExecutionEntity multiInstanceExecution in multiInstanceExecutions) { if (!multiInstanceExecution.Id.Equals(parentScopeExecution.Id)) { ScopeUtil.CreateCopyOfSubProcessExecutionForCompensation(multiInstanceExecution); // end all executions in the scope of the transaction executionsToDelete.Add(multiInstanceExecution); DeleteChildExecutions(multiInstanceExecution, executionEntity, commandContext, History.DeleteReasonFields.TRANSACTION_CANCELED); } } foreach (IExecutionEntity executionEntityToDelete in executionsToDelete) { DeleteChildExecutions(executionEntityToDelete, executionEntity, commandContext, History.DeleteReasonFields.TRANSACTION_CANCELED); } } // The current activity is finished (and will not be ended in the deleteChildExecutions) commandContext.HistoryManager.RecordActivityEnd(executionEntity, null); // set new parent for boundary event execution executionEntity.Parent = newParentScopeExecution ?? throw new ActivitiException("Programmatic error: no parent scope execution found for boundary event " + cancelBoundaryEvent.Id); executionEntity.CurrentFlowElement = cancelBoundaryEvent; // end all executions in the scope of the transaction DeleteChildExecutions(parentScopeExecution, executionEntity, commandContext, History.DeleteReasonFields.TRANSACTION_CANCELED); commandContext.HistoryManager.RecordActivityEnd(parentScopeExecution, History.DeleteReasonFields.TRANSACTION_CANCELED); Context.Agenda.PlanTriggerExecutionOperation(executionEntity); } }
private void DeleteTasks(ICommandContext commandContext, Interceptor.ICommandExecutor commandExecutor, IExecutionEntity execution, IExecutionEntityManager executionEntityManager, List <ITask> tasks) { foreach (ITaskEntity delTask in tasks) { commandExecutor.Execute(new AddCommentCmd(delTask.Id, delTask.ProcessInstanceId, returnToReason)); commandContext.TaskEntityManager.DeleteTask(delTask, returnToReason, false, false); } DeleteExecutions(execution, true, returnToReason, commandContext); }
private void ReturnToTasks(ICommandContext commandContext, Interceptor.ICommandExecutor commandExecutor, IExecutionEntity execution, IExecutionEntityManager executionEntityManager, List <ITask> tasks) { foreach (ITaskEntity delTask in tasks) { IActivitiEventDispatcher eventDispatcher = commandContext.ProcessEngineConfiguration.EventDispatcher; if (eventDispatcher.Enabled) { eventDispatcher.DispatchEvent(ActivitiEventBuilder.CreateTaskReturnEntityEvent(delTask, returnToActivityId)); } commandExecutor.Execute(new AddCommentCmd(delTask.Id, delTask.ProcessInstanceId, returnToReason)); commandContext.TaskEntityManager.DeleteTask(delTask, returnToReason, false, false); } DeleteExecutions(execution, true, returnToReason, commandContext); }
public override void Execute(IExecutionEntity execution) { string finalProcessDefinitonKey; if (processDefinitionExpression != null) { finalProcessDefinitonKey = (string)processDefinitionExpression.GetValue(execution); } else { finalProcessDefinitonKey = processDefinitonKey; } IProcessDefinition processDefinition = FindProcessDefinition(finalProcessDefinitonKey, execution.TenantId); // Get model from cache Process subProcess = ProcessDefinitionUtil.GetProcess(processDefinition.Id); if (subProcess == null) { throw new ActivitiException("Cannot start a sub process instance. Process model " + processDefinition.Name + " (id = " + processDefinition.Id + ") could not be found"); } FlowElement initialFlowElement = subProcess.InitialFlowElement; if (initialFlowElement == null) { throw new ActivitiException("No start element found for process definition " + processDefinition.Id); } // Do not start a process instance if the process definition is suspended if (ProcessDefinitionUtil.IsProcessDefinitionSuspended(processDefinition.Id)) { throw new ActivitiException("Cannot start process instance. Process definition " + processDefinition.Name + " (id = " + processDefinition.Id + ") is suspended"); } ProcessEngineConfigurationImpl processEngineConfiguration = Context.ProcessEngineConfiguration; IExecutionEntityManager executionEntityManager = Context.CommandContext.ExecutionEntityManager; ExpressionManager expressionManager = processEngineConfiguration.ExpressionManager; CallActivity callActivity = (CallActivity)execution.CurrentFlowElement; string businessKey = null; if (!string.IsNullOrWhiteSpace(callActivity.BusinessKey)) { IExpression expression = expressionManager.CreateExpression(callActivity.BusinessKey); businessKey = expression.GetValue(execution).ToString(); } else if (callActivity.InheritBusinessKey) { IExecutionEntity processInstance = executionEntityManager.FindById <IExecutionEntity>(execution.ProcessInstanceId); businessKey = processInstance.BusinessKey; } IExecutionEntity subProcessInstance = Context.CommandContext.ExecutionEntityManager.CreateSubprocessInstance(processDefinition, execution, businessKey); Context.CommandContext.HistoryManager.RecordSubProcessInstanceStart(execution, subProcessInstance, initialFlowElement); // process template-defined data objects IDictionary <string, object> variables = ProcessDataObjects(subProcess.DataObjects); if (callActivity.InheritVariables) { IDictionary <string, object> executionVariables = execution.Variables; foreach (KeyValuePair <string, object> entry in executionVariables.SetOfKeyValuePairs()) { variables[entry.Key] = entry.Value; } } // copy process variables foreach (IOParameter ioParameter in callActivity.InParameters) { object value = null; if (!string.IsNullOrWhiteSpace(ioParameter.SourceExpression)) { IExpression expression = expressionManager.CreateExpression(ioParameter.SourceExpression.Trim()); value = expression.GetValue(execution); } else { value = execution.GetVariable(ioParameter.Source); } variables[ioParameter.Target] = value; } if (variables.Count > 0) { InitializeVariables(subProcessInstance, variables); } // Create the first execution that will visit all the process definition elements IExecutionEntity subProcessInitialExecution = executionEntityManager.CreateChildExecution(subProcessInstance); subProcessInitialExecution.CurrentFlowElement = initialFlowElement; Context.Agenda.PlanContinueProcessOperation(subProcessInitialExecution); Context.ProcessEngineConfiguration.EventDispatcher.DispatchEvent(ActivitiEventBuilder.CreateProcessStartedEvent(subProcessInitialExecution, variables, false)); }
/// <summary> /// /// </summary> /// <param name="flowNode"></param> protected internal virtual void LeaveFlowNode(FlowNode flowNode) { log.LogDebug($"Leaving flow node {flowNode.GetType()} with id '{flowNode.Id}' by following it's {flowNode.OutgoingFlows.Count} outgoing sequenceflow"); // Get default sequence flow (if set) string defaultSequenceFlowId = null; if (flowNode is Activity) { defaultSequenceFlowId = ((Activity)flowNode).DefaultFlow; } else if (flowNode is Gateway) { defaultSequenceFlowId = ((Gateway)flowNode).DefaultFlow; } // Determine which sequence flows can be used for leaving IList <SequenceFlow> outgoingSequenceFlows = new List <SequenceFlow>(); foreach (SequenceFlow sequenceFlow in flowNode.OutgoingFlows) { string skipExpressionString = sequenceFlow.SkipExpression; if (!SkipExpressionUtil.IsSkipExpressionEnabled(execution, skipExpressionString)) { if (!evaluateConditions || (evaluateConditions && ConditionUtil.HasTrueCondition(sequenceFlow, execution) && (defaultSequenceFlowId is null || !defaultSequenceFlowId.Equals(sequenceFlow.Id)))) { outgoingSequenceFlows.Add(sequenceFlow); } } else if (flowNode.OutgoingFlows.Count == 1 || SkipExpressionUtil.ShouldSkipFlowElement(commandContext, execution, skipExpressionString)) { // The 'skip' for a sequence flow means that we skip the condition, not the sequence flow. outgoingSequenceFlows.Add(sequenceFlow); } } // Check if there is a default sequence flow if (outgoingSequenceFlows.Count == 0 && evaluateConditions) { // The elements that set this to false also have no support for default sequence flow if (defaultSequenceFlowId is object) { foreach (SequenceFlow sequenceFlow in flowNode.OutgoingFlows) { if (defaultSequenceFlowId.Equals(sequenceFlow.Id)) { outgoingSequenceFlows.Add(sequenceFlow); break; } } } } // No outgoing found. Ending the execution if (outgoingSequenceFlows.Count == 0) { if (flowNode.OutgoingFlows == null || flowNode.OutgoingFlows.Count == 0) { log.LogDebug($"No outgoing sequence flow found for flow node '{flowNode.Id}'."); Context.Agenda.PlanEndExecutionOperation(execution); } else { throw new ActivitiException("No outgoing sequence flow of element '" + flowNode.Id + "' could be selected for continuing the process"); } } else { // Leave, and reuse the incoming sequence flow, make executions for all the others (if applicable) IExecutionEntityManager executionEntityManager = commandContext.ExecutionEntityManager; IList <IExecutionEntity> outgoingExecutions = new List <IExecutionEntity>(flowNode.OutgoingFlows.Count); SequenceFlow sequenceFlow = outgoingSequenceFlows[0]; // Reuse existing one execution.CurrentFlowElement = sequenceFlow; execution.IsActive = true; outgoingExecutions.Add(execution); // Executions for all the other one if (outgoingSequenceFlows.Count > 1) { for (int i = 1; i < outgoingSequenceFlows.Count; i++) { IExecutionEntity parent = execution.ParentId is object?execution.Parent : execution; IExecutionEntity outgoingExecutionEntity = commandContext.ExecutionEntityManager.CreateChildExecution(parent); SequenceFlow outgoingSequenceFlow = outgoingSequenceFlows[i]; outgoingExecutionEntity.CurrentFlowElement = outgoingSequenceFlow; executionEntityManager.Insert(outgoingExecutionEntity); outgoingExecutions.Add(outgoingExecutionEntity); } } // Leave (only done when all executions have been made, since some queries depend on this) foreach (IExecutionEntity outgoingExecution in outgoingExecutions) { Context.Agenda.PlanContinueProcessOperation(outgoingExecution); } } }
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"); } }
/// <summary> /// /// </summary> /// <param name="executionEntityManager"></param> /// <param name="executionId"></param> /// <returns></returns> protected internal virtual IList <IExecutionEntity> GetActiveChildExecutionsForExecution(IExecutionEntityManager executionEntityManager, string executionId) { IList <IExecutionEntity> activeChildExecutions = new List <IExecutionEntity>(); IList <IExecutionEntity> executions = executionEntityManager.FindChildExecutionsByParentExecutionId(executionId); foreach (IExecutionEntity activeExecution in executions) { if (!(activeExecution.CurrentFlowElement is BoundaryEvent)) { activeChildExecutions.Add(activeExecution); } } return(activeChildExecutions); }
/// <summary> /// /// </summary> /// <param name="processInstanceExecution"></param> protected internal virtual void HandleProcessInstanceExecution(IExecutionEntity processInstanceExecution) { IExecutionEntityManager executionEntityManager = commandContext.ExecutionEntityManager; string processInstanceId = processInstanceExecution.Id; // No parent execution == process instance id logger.LogDebug($"No parent execution found. Verifying if process instance {processInstanceId} can be stopped."); IExecutionEntity superExecution = processInstanceExecution.SuperExecution; ISubProcessActivityBehavior subProcessActivityBehavior = null; // copy variables before destroying the ended sub process instance (call activity) if (superExecution != null) { FlowNode superExecutionElement = (FlowNode)superExecution.CurrentFlowElement; subProcessActivityBehavior = (ISubProcessActivityBehavior)superExecutionElement.Behavior; try { subProcessActivityBehavior.Completing(superExecution, processInstanceExecution); } //catch (Exception e) //{ // //logger.error("Error while completing sub process of execution {}", processInstanceExecution, e); // throw e; //} catch (Exception e) { logger.LogError($"Error while completing sub process of execution {processInstanceExecution}.Exception Message: {e.Message}"); throw new ActivitiException("Error while completing sub process of execution " + processInstanceExecution, e); } } int activeExecutions = GetNumberOfActiveChildExecutionsForProcessInstance(executionEntityManager, processInstanceId, superExecution); if (activeExecutions == 0) { logger.LogDebug($"No active executions found. Ending process instance {processInstanceId} "); // note the use of execution here vs processinstance execution for getting the flowelement executionEntityManager.DeleteProcessInstanceExecutionEntity(processInstanceId, execution.CurrentFlowElement?.Id, null, false, false); } else { logger.LogDebug($"Active executions found. Process instance {processInstanceId} will not be ended."); } Process process = ProcessDefinitionUtil.GetProcess(processInstanceExecution.ProcessDefinitionId); // Execute execution listeners for process end. if (CollectionUtil.IsNotEmpty(process.ExecutionListeners)) { ExecuteExecutionListeners(process, processInstanceExecution, BaseExecutionListenerFields.EVENTNAME_END); } // and trigger execution afterwards if doing a call activity if (superExecution != null) { superExecution.SubProcessInstance = null; try { subProcessActivityBehavior.Completed(superExecution); } //catch (Exception e) //{ // logger.error("Error while completing sub process of execution {}", processInstanceExecution, e); // throw e; //} catch (Exception e) { logger.LogError($"Error while completing sub process of execution {processInstanceExecution}. Exception Messgae: {e.Message}."); throw new ActivitiException("Error while completing sub process of execution " + processInstanceExecution, e); } } }
public static void PropagateError(string errorCode, IExecutionEntity execution) { IDictionary <string, IList <Event> > eventMap = FindCatchingEventsForProcess(execution.ProcessDefinitionId, errorCode); if (eventMap.Count > 0) { ExecuteCatch(eventMap, execution, errorCode); } else if (!execution.ProcessInstanceId.Equals(execution.RootProcessInstanceId)) { // Call activity IExecutionEntityManager executionEntityManager = Context.CommandContext.ExecutionEntityManager; IExecutionEntity processInstanceExecution = executionEntityManager.FindById <IExecutionEntity>(execution.ProcessInstanceId); if (processInstanceExecution != null) { IExecutionEntity parentExecution = processInstanceExecution.SuperExecution; IList <string> toDeleteProcessInstanceIds = new List <string> { execution.ProcessInstanceId }; while (parentExecution != null && eventMap.Count == 0) { eventMap = FindCatchingEventsForProcess(parentExecution.ProcessDefinitionId, errorCode); if (eventMap.Count > 0) { foreach (string processInstanceId in toDeleteProcessInstanceIds) { IExecutionEntity processInstanceEntity = executionEntityManager.FindById <IExecutionEntity>(processInstanceId); // Delete executionEntityManager.DeleteProcessInstanceExecutionEntity(processInstanceEntity.Id, execution.CurrentFlowElement?.Id, "ERROR_EVENT " + errorCode, false, false); // Event ProcessEngineConfigurationImpl processEngineConfiguration = Context.ProcessEngineConfiguration; if (!(processEngineConfiguration is null) && Context.ProcessEngineConfiguration.EventDispatcher.Enabled) { processEngineConfiguration.EventDispatcher.DispatchEvent(ActivitiEventBuilder.CreateEntityEvent(ActivitiEventType.PROCESS_COMPLETED_WITH_ERROR_END_EVENT, processInstanceEntity)); } } ExecuteCatch(eventMap, parentExecution, errorCode); } else { toDeleteProcessInstanceIds.Add(parentExecution.ProcessInstanceId); IExecutionEntity superExecution = parentExecution.SuperExecution; if (superExecution != null) { parentExecution = superExecution; } else if (!parentExecution.Id.Equals(parentExecution.RootProcessInstanceId)) { // stop at the root parentExecution = parentExecution.ProcessInstance; } else { parentExecution = null; } } } } } if (eventMap.Count == 0) { throw new BpmnError(errorCode, "No catching boundary event found for error with errorCode '" + errorCode + "', neither in same process nor in parent process"); } }
public virtual object Execute(ICommandContext commandContext) { lock (syncRoot) { ProcessEngineConfigurationImpl processEngineConfiguration = commandContext.ProcessEngineConfiguration; Interceptor.ICommandExecutor commandExecutor = processEngineConfiguration.CommandExecutor; ITaskEntity task = commandExecutor.Execute(new GetTaskByIdCmd(currentTaskId)) as ITaskEntity; if (task is null) { throw new ActivitiObjectNotFoundException(string.Concat("No task found for id '", currentTaskId)); } string currentExecutionId = task.ExecutionId; IExecutionEntity execution = task.Execution; if (execution is null) { throw new ActivitiObjectNotFoundException(string.Concat("No execution found for id '", currentExecutionId)); } var flowElement = ProcessDefinitionUtil.GetFlowElement(execution.ProcessDefinitionId, returnToActivityId); if (flowElement is null) { throw new ActivitiObjectNotFoundException(string.Concat("No execution found for id '", currentExecutionId, "'")); } IHistoricActivityInstanceEntity hisInst = processEngineConfiguration.HistoryService.CreateHistoricActivityInstanceQuery() .SetProcessInstanceId(execution.ProcessInstanceId) .SetActivityId(returnToActivityId) .OrderByHistoricActivityInstanceStartTime() .Desc() .List() .FirstOrDefault() as IHistoricActivityInstanceEntity; IExecutionEntityManager executionEntityManager = commandContext.ExecutionEntityManager; IExecutionEntity returnToExec = executionEntityManager.CreateChildExecution(execution.ProcessInstance); returnToExec.CurrentFlowElement = flowElement; foreach (var key in variables.Keys) { returnToExec.SetVariable(key, variables[key]); } executionEntityManager.Insert(returnToExec); commandContext.Agenda.PlanContinueProcessOperation(returnToExec); IExecutionEntity miRoot = commandExecutor.Execute(new GetMultiInstanceRootExecutionCmd(execution)); List <ITask> tasks = new List <ITask>(); if (miRoot != null) { ITaskQuery query = commandContext.ProcessEngineConfiguration.TaskService.CreateTaskQuery(); IEnumerable <IExecutionEntity> childExecutions = commandExecutor.Execute(new GetChildExecutionsCmd(miRoot)); query.SetExecutionIdIn(childExecutions.Select(x => x.Id).ToArray()); tasks.AddRange(query.List()); } else { tasks.Add(task); } DeleteTasks(commandContext, commandExecutor, miRoot != null ? miRoot : execution, executionEntityManager, tasks); return(null); } }
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); } } }