public TransactionScope(TransactionMode mode) : base(SessionScopeType.Transactional) { this.mode = mode; ISessionScope previousScope = ScopeUtil.FindPreviousScope(this, mode == TransactionMode.Inherits ? true : false ); if (previousScope != null) { if (previousScope.ScopeType == SessionScopeType.Transactional) { parentTransactionScope = previousScope as TransactionScope; } else { // This is not a safe cast. Reconsider it parentSimpleScope = (AbstractScope) previousScope; foreach(ISession session in parentSimpleScope.GetSessions()) { EnsureHasTransaction(session); } } } }
public void Visit(ClassAst ast) { if (Global == null) { Global = Current; } var classSymbol = ScopeUtil.DefineClassSymbol(ast); Current.Define(classSymbol); SetScopeType(ScopeType.Class); SetScopeSource(classSymbol); ScopeTree.CreateScope(); ast.Body.Visit(this); classSymbol.Symbols = ast.Body.CurrentScope.Symbols; //redefine the class symbol now with actual symbols Current.Define(classSymbol); ast.Body.CurrentScope.AllowAllForwardReferences = true; ScopeTree.PopScope(); if (ast.Global == null) { ast.Global = Global; } SetScopeType(ScopeType.Global); }
/// <summary> /// /// </summary> /// <param name="executionEntityManager"></param> /// <param name="parentExecution"></param> protected internal virtual void HandleMultiInstanceSubProcess(IExecutionEntityManager executionEntityManager, IExecutionEntity parentExecution) { IList <IExecutionEntity> activeChildExecutions = GetActiveChildExecutionsForExecution(executionEntityManager, parentExecution.Id); bool containsOtherChildExecutions = false; foreach (IExecutionEntity activeExecution in activeChildExecutions) { if (!activeExecution.Id.Equals(execution.Id)) { containsOtherChildExecutions = true; } } if (!containsOtherChildExecutions) { // Destroy the current scope (subprocess) and leave via the subprocess ScopeUtil.CreateCopyOfSubProcessExecutionForCompensation(parentExecution); Context.Agenda.PlanDestroyScopeOperation(parentExecution); SubProcess subProcess = execution.CurrentFlowElement.SubProcess; MultiInstanceActivityBehavior multiInstanceBehavior = (MultiInstanceActivityBehavior)subProcess.Behavior; parentExecution.CurrentFlowElement = subProcess; multiInstanceBehavior.Leave(parentExecution); } }
private void ValidateReturnStatementType(MethodDeclr ast, Symbol symbol) { if (!ResolvingTypes) { return; } IType returnStatementType; // no return found if (ast.ReturnAst == null) { returnStatementType = new BuiltInType(ExpressionTypes.Void); } else { returnStatementType = ast.ReturnAst.AstSymbolType; } var delcaredSymbol = ScopeUtil.CreateSymbolType(ast.MethodReturnType); // if its inferred, just use whatever the return statement i if (delcaredSymbol.ExpressionType == ExpressionTypes.Inferred) { return; } if (!TokenUtil.EqualOrPromotable(returnStatementType.ExpressionType, delcaredSymbol.ExpressionType)) { throw new InvalidSyntax(String.Format("Return type {0} for function {1} is not of the same type of declared method (type {2})", returnStatementType.ExpressionType, symbol.Name, delcaredSymbol.ExpressionType)); } }
public void Visit(FuncInvoke ast) { if (ast.CallingScope != null) { ast.Arguments.ForEach(arg => arg.CallingScope = ast.CallingScope); } ast.Arguments.ForEach(arg => arg.Visit(this)); SetScope(ast); var functionType = Resolve(ast.FunctionName) as MethodSymbol; if (functionType != null && ast.Arguments.Count < functionType.MethodDeclr.Arguments.Count) { var curriedMethod = CreateCurriedMethod(ast, functionType); curriedMethod.Visit(this); var methodSymbol = ScopeUtil.DefineMethod(curriedMethod); Current.Define(methodSymbol); ast.ConvertedExpression = curriedMethod; } else if (ResolvingTypes) { ast.AstSymbolType = ResolveType(ast.FunctionName, ast.CurrentScope); } }
public object get(string str, Class c) { try { return(ScopeUtil.get(ReferenceObject, str ?? "", c ?? null)); } catch { } return(null); }
/// <summary> /// Initializes a new instance of the <see cref="TransactionScope"/> class. /// </summary> /// <param name="mode">Whatever to create a new transaction or inherits an existing one</param> /// <param name="isolationLevel">The transaction isolation level.</param> /// <param name="onDisposeBehavior">The on dispose behavior.</param> public TransactionScope(TransactionMode mode, IsolationLevel isolationLevel, OnDispose onDisposeBehavior) : base(FlushAction.Config, SessionScopeType.Transactional) { this.mode = mode; this.isolationLevel = isolationLevel; this.onDisposeBehavior = onDisposeBehavior; bool preferenceForTransactionScope = mode == TransactionMode.Inherits ? true : false; ISessionScope previousScope = ScopeUtil.FindPreviousScope(this, preferenceForTransactionScope); if (previousScope != null) { if (previousScope.ScopeType == SessionScopeType.Transactional) { parentTransactionScope = previousScope as TransactionScope; } else { // This is not a safe cast. Reconsider it parentSimpleScope = (AbstractScope)previousScope; foreach (ISession session in parentSimpleScope.GetSessions()) { EnsureHasTransaction(session); } } } }
public override void Execute(IExecutionEntity execution) { ThrowEvent throwEvent = (ThrowEvent)execution.CurrentFlowElement; /* * From the BPMN 2.0 spec: * * The Activity to be compensated MAY be supplied. * * If an Activity is not supplied, then the compensation is broadcast to all completed Activities in * the current Sub- Process (if present), or the entire Process instance (if at the global level). This "throws" the compensation. */ string activityRef = compensateEventDefinition.ActivityRef; ICommandContext commandContext = Context.CommandContext; IEventSubscriptionEntityManager eventSubscriptionEntityManager = commandContext.EventSubscriptionEntityManager; IList <ICompensateEventSubscriptionEntity> eventSubscriptions = new List <ICompensateEventSubscriptionEntity>(); if (!string.IsNullOrWhiteSpace(activityRef)) { // If an activity ref is provided, only that activity is compensated ((List <ICompensateEventSubscriptionEntity>)eventSubscriptions).AddRange(eventSubscriptionEntityManager.FindCompensateEventSubscriptionsByProcessInstanceIdAndActivityId(execution.ProcessInstanceId, activityRef)); } else { // If no activity ref is provided, it is broadcast to the current sub process / process instance Process process = ProcessDefinitionUtil.GetProcess(execution.ProcessDefinitionId); IFlowElementsContainer flowElementsContainer; if (throwEvent.SubProcess == null) { flowElementsContainer = process; } else { flowElementsContainer = throwEvent.SubProcess; } foreach (FlowElement flowElement in flowElementsContainer.FlowElements) { if (flowElement is Activity) { ((List <ICompensateEventSubscriptionEntity>)eventSubscriptions).AddRange(eventSubscriptionEntityManager.FindCompensateEventSubscriptionsByProcessInstanceIdAndActivityId(execution.ProcessInstanceId, flowElement.Id)); } } } if (eventSubscriptions.Count == 0) { Leave(execution); } else { // TODO: implement async (waitForCompletion=false in bpmn) ScopeUtil.ThrowCompensationEvent(eventSubscriptions, execution, false); Leave(execution); } }
public override void Trigger(IExecutionEntity execution, string triggerName, object triggerData, bool throwError = true) { BoundaryEvent boundaryEvent = (BoundaryEvent)execution.CurrentFlowElement; ICommandContext commandContext = Context.CommandContext; IExecutionEntityManager executionEntityManager = commandContext.ExecutionEntityManager; IExecutionEntity subProcessExecution = null; // TODO: this can be optimized. A full search in the all executions shouldn't be needed IList <IExecutionEntity> processInstanceExecutions = executionEntityManager.FindChildExecutionsByProcessInstanceId(execution.ProcessInstanceId); foreach (IExecutionEntity childExecution in processInstanceExecutions) { if (childExecution.CurrentFlowElement != null && childExecution.CurrentFlowElement.Id.Equals(boundaryEvent.AttachedToRefId)) { subProcessExecution = childExecution; break; } } if (subProcessExecution == null) { throw new ActivitiException("No execution found for sub process of boundary cancel event " + boundaryEvent.Id); } IEventSubscriptionEntityManager eventSubscriptionEntityManager = commandContext.EventSubscriptionEntityManager; IList <ICompensateEventSubscriptionEntity> eventSubscriptions = eventSubscriptionEntityManager.FindCompensateEventSubscriptionsByExecutionId(subProcessExecution.ParentId); if (eventSubscriptions.Count == 0) { Leave(execution); } else { Leave(execution); string deleteReason = History.DeleteReasonFields.BOUNDARY_EVENT_INTERRUPTING + "(" + boundaryEvent.Id + ")"; // cancel boundary is always sync ScopeUtil.ThrowCompensationEvent(eventSubscriptions, execution, false); executionEntityManager.DeleteExecutionAndRelatedData(subProcessExecution, deleteReason, false); if (subProcessExecution.CurrentFlowElement is Activity activity) { if (activity.LoopCharacteristics != null) { IExecutionEntity miExecution = subProcessExecution.Parent; IList <IExecutionEntity> miChildExecutions = executionEntityManager.FindChildExecutionsByParentExecutionId(miExecution.Id); foreach (IExecutionEntity miChildExecution in miChildExecutions) { if (subProcessExecution.Id.Equals(miChildExecution.Id) == false && activity.Id.Equals(miChildExecution.CurrentActivityId)) { executionEntityManager.DeleteExecutionAndRelatedData(miChildExecution, deleteReason, false); } } } } } }
/// <summary> /// Creates a type for built in types or resolves user defined types /// </summary> /// <param name="ast"></param> /// <returns></returns> private IType ResolveOrDefine(Expr ast) { if (ast == null) { return(null); } switch (ast.Token.TokenType) { case TokenType.Word: return(ResolveType(ast)); } return(ScopeUtil.CreateSymbolType(ast)); }
/// <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); }
private LambdaDeclr CreateCurriedMethod(FuncInvoke ast, MethodSymbol functionType) { var srcMethod = functionType.MethodDeclr; var fixedAssignments = new List <VarDeclrAst>(); var count = 0; foreach (var argValue in ast.Arguments) { var srcArg = srcMethod.Arguments[count] as VarDeclrAst; var token = new Token(srcArg.DeclarationType.Token.TokenType, argValue.Token.TokenValue); var declr = new VarDeclrAst(token, srcArg.Token, new Expr(argValue.Token)); // if we're creating a curry using a variable then we need to resolve the variable type // otherwise we can make a symbol for the literal var newArgType = argValue.Token.TokenType == TokenType.Word ? ast.CurrentScope.Resolve(argValue).Type : ScopeUtil.CreateSymbolType(argValue); // create a symbol type for the target we're invoking on so we can do type checking var targetArgType = ScopeUtil.CreateSymbolType(srcArg.DeclarationType); if (!TokenUtil.EqualOrPromotable(newArgType, targetArgType)) { throw new InvalidSyntax(String.Format("Cannot pass argument {0} of type {1} to partial function {2} as argument {3} of type {4}", argValue.Token.TokenValue, newArgType.TypeName, srcMethod.MethodName.Token.TokenValue, srcArg.VariableName.Token.TokenValue, targetArgType.TypeName)); } fixedAssignments.Add(declr); count++; } var newBody = fixedAssignments.Concat(srcMethod.Body.ScopedStatements).ToList(); var curriedMethod = new LambdaDeclr(srcMethod.Arguments.Skip(ast.Arguments.Count).ToList(), new ScopeDeclr(newBody)); SetScope(curriedMethod); return(curriedMethod); }
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); } } }
public void Visit(MethodDeclr ast) { var previousMethod = CurrentMethod; CurrentMethod = ast; var symbol = ScopeUtil.DefineMethod(ast); Current.Define(symbol); ScopeTree.CreateScope(); ast.Arguments.ForEach(arg => arg.Visit(this)); ast.Body.Visit(this); SetScope(ast); if (symbol.Type.ExpressionType == ExpressionTypes.Inferred) { if (ast.ReturnAst == null) { ast.AstSymbolType = new BuiltInType(ExpressionTypes.Void); } else { ast.AstSymbolType = ast.ReturnAst.AstSymbolType; } } else { ast.AstSymbolType = symbol.Type; } ValidateReturnStatementType(ast, symbol); ScopeTree.PopScope(); CurrentMethod = previousMethod; }
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); } }
public void Visit(VarDeclrAst ast) { var isVar = ast.DeclarationType.Token.TokenType == TokenType.Infer; if (ast.DeclarationType != null && !isVar) { var symbol = ScopeUtil.DefineUserSymbol(ast.DeclarationType, ast.VariableName); symbol.IsArray = ast is ArrayDeclrAst; DefineToScope(ast, symbol); ast.AstSymbolType = symbol.Type; } if (ast.VariableValue == null && isVar) { var symbol = ScopeUtil.DefineUserSymbol(ast.DeclarationType, ast.VariableName); DefineToScope(ast, symbol); ast.AstSymbolType = symbol.Type; } else if (ast.VariableValue != null) { ast.VariableValue.Visit(this); // if its type inferred, determine the declaration by the value's type if (isVar) { // if the right hand side is a method declaration, make sure to track the source value // this way we can reference it later to determine not only that this is a method type, but what // is the expected return value for static type checking later var val = ast.VariableValue.ConvertedExpression ?? ast.VariableValue; ast.AstSymbolType = val is MethodDeclr ? new BuiltInType(ExpressionTypes.Method, val) : val.AstSymbolType; var symbol = ScopeUtil.DefineUserSymbol(ast.AstSymbolType, ast.VariableName); symbol.IsArray = ast is ArrayDeclrAst; DefineToScope(ast, symbol); } else if (ResolvingTypes) { var declaredType = ScopeUtil.CreateSymbolType(ast.DeclarationType); var value = ast.VariableValue.ConvertedExpression ?? ast.VariableValue; ReturnAst returnType = null; // when we're resolving types check if the rhs is a function invoke. if it is, see // what the return value of the src expression is so we can make sure that the // lhs and the rhs match. try { returnType = value is FuncInvoke ? ((value as FuncInvoke).AstSymbolType) != null ? ((value as FuncInvoke).AstSymbolType.Src as MethodDeclr).ReturnAst : null : null; } catch { } value = returnType != null ? returnType.ReturnExpression : value; if (!TokenUtil.EqualOrPromotable(value.AstSymbolType.ExpressionType, declaredType.ExpressionType)) { throw new InvalidSyntax(String.Format("Cannot assign {0} of type {1} to {2}", ast.VariableValue, value.AstSymbolType.ExpressionType, declaredType.ExpressionType)); } } } SetScope(ast); }
private dynamic Exec(Ast ast) { try { if (ast == null) { return(null); } if (ast.ConvertedExpression != null) { return(Exec(ast.ConvertedExpression)); } switch (ast.AstType) { case AstTypes.ScopeDeclr: ScopeDelcaration(ast as ScopeDeclr); break; case AstTypes.VarDeclr: VariableDeclaration(ast as VarDeclrAst); break; case AstTypes.Expression: var ret = Expression(ast as Expr); if (ret != null) { return(ret); } break; case AstTypes.Print: Print(ast as PrintAst); break; case AstTypes.FunctionInvoke: return(InvokeFunction(ast as FuncInvoke)); case AstTypes.Conditional: ConditionalDo(ast as Conditional); break; case AstTypes.MethodDeclr: var methodDeclr = ast as MethodDeclr; return(new MethodSymbol(methodDeclr.Token.TokenValue, ScopeUtil.CreateSymbolType(methodDeclr.ReturnAst), methodDeclr)); case AstTypes.While: WhileDo(ast as WhileLoop); break; case AstTypes.Return: ReturnDo(ast as ReturnAst); break; case AstTypes.For: ForDo(ast as ForLoop); break; case AstTypes.Class: ClassDo(ast as ClassAst); break; case AstTypes.ClassRef: return(ClassRefDo(ast as ClassReference)); break; case AstTypes.New: return(NewDo(ast as NewAst)); break; } } catch (ReturnException ex) { // let the return value bubble up through all the exectuions until we // get to the source syntax tree that invoked it. at that point safely return the value if (ast.AstType == AstTypes.FunctionInvoke) { return(ex.Value); } throw; } 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); } } }