示例#1
0
        public virtual void execute(PvmExecutionImpl execution)
        {
            // reset activity instance id before creating the scope
            execution.ActivityInstanceId = execution.ParentActivityInstanceId;

            PvmExecutionImpl propagatingExecution = null;
            PvmActivity      activity             = execution.getActivity();

            if (activity.Scope)
            {
                propagatingExecution = execution.createExecution();
                propagatingExecution.setActivity(activity);
                propagatingExecution.setTransition(execution.getTransition());
                execution.setTransition(null);
                execution.Active = false;
                execution.setActivity(null);
                LOG.createScope(execution, propagatingExecution);
                propagatingExecution.initialize();
            }
            else
            {
                propagatingExecution = execution;
            }


            scopeCreated(propagatingExecution);
        }
示例#2
0
        public virtual void execute(PvmExecutionImpl execution)
        {
            // Assumption: execution is scope
            PvmActivity cancellingActivity = execution.NextActivity;

            execution.NextActivity = null;

            // first, cancel and destroy the current scope
            execution.Active = true;

            PvmExecutionImpl propagatingExecution = null;

            if (LegacyBehavior.isConcurrentScope(execution))
            {
                // this is legacy behavior
                LegacyBehavior.cancelConcurrentScope(execution, (PvmActivity)cancellingActivity.EventScope);
                propagatingExecution = execution;
            }
            else
            {
                // Unlike PvmAtomicOperationTransitionDestroyScope this needs to use delete() (instead of destroy() and remove()).
                // The reason is that PvmAtomicOperationTransitionDestroyScope is executed when a scope (or non scope) is left using
                // a sequence flow. In that case the execution will have completed all the work inside the current activity
                // and will have no more child executions. In PvmAtomicOperationCancelScope the scope is cancelled due to
                // a boundary event firing. In that case the execution has not completed all the work in the current scope / activity
                // and it is necessary to delete the complete hierarchy of executions below and including the execution itself.
                execution.deleteCascade("Cancel scope activity " + cancellingActivity + " executed.");
                propagatingExecution = execution.Parent;
            }

            propagatingExecution.setActivity(cancellingActivity);
            propagatingExecution.Active = true;
            propagatingExecution.Ended  = false;
            activityCancelled(propagatingExecution);
        }
示例#3
0
        public virtual void execute(PvmExecutionImpl execution)
        {
            ExecutionStartContext executionStartContext = execution.ExecutionStartContext;

            InstantiationStack  instantiationStack = executionStartContext.InstantiationStack;
            IList <PvmActivity> activityStack      = instantiationStack.Activities;
            PvmActivity         currentActivity    = activityStack.RemoveAt(0);

            PvmExecutionImpl propagatingExecution = execution;

            if (currentActivity.Scope)
            {
                propagatingExecution = execution.createExecution();
                execution.Active     = false;
                propagatingExecution.setActivity(currentActivity);
                propagatingExecution.initialize();
            }
            else
            {
                propagatingExecution.setActivity(currentActivity);
            }

            // notify listeners for the instantiated activity
            propagatingExecution.performOperation(operationOnScopeInitialization);
        }
示例#4
0
        protected internal virtual void validateAndSwitchVersionOfExecution(CommandContext commandContext, ExecutionEntity execution, ProcessDefinitionEntity newProcessDefinition)
        {
            // check that the new process definition version contains the current activity
            if (execution.getActivity() != null)
            {
                string      activityId  = execution.getActivity().Id;
                PvmActivity newActivity = newProcessDefinition.findActivity(activityId);

                if (newActivity == null)
                {
                    throw new ProcessEngineException("The new process definition " + "(key = '" + newProcessDefinition.Key + "') " + "does not contain the current activity " + "(id = '" + activityId + "') " + "of the process instance " + "(id = '" + processInstanceId + "').");
                }

                // clear cached activity so that outgoing transitions are refreshed
                execution.setActivity(newActivity);
            }

            // switch the process instance to the new process definition version
            execution.setProcessDefinition(newProcessDefinition);

            // and change possible existing tasks (as the process definition id is stored there too)
            IList <TaskEntity> tasks = commandContext.TaskManager.findTasksByExecutionId(execution.Id);

            foreach (TaskEntity taskEntity in tasks)
            {
                taskEntity.ProcessDefinitionId = newProcessDefinition.Id;
            }
        }
示例#5
0
        protected internal override PvmActivity getInterruptingActivity(PvmExecutionImpl execution)
        {
            PvmActivity nextActivity = execution.NextActivity;

            execution.NextActivity = null;
            return(nextActivity);
        }
示例#6
0
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: @Override public void execute(org.camunda.bpm.engine.impl.pvm.delegate.ActivityExecution execution) throws Exception
        public virtual void execute(ActivityExecution execution)
        {
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final org.camunda.bpm.engine.impl.pvm.PvmActivity currentActivity = execution.getActivity();
            PvmActivity currentActivity = execution.Activity;

//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final EscalationEventDefinitionFinder escalationEventDefinitionFinder = new EscalationEventDefinitionFinder(escalation.getEscalationCode(), currentActivity);
            EscalationEventDefinitionFinder   escalationEventDefinitionFinder   = new EscalationEventDefinitionFinder(this, escalation.EscalationCode, currentActivity);
            ActivityExecutionMappingCollector activityExecutionMappingCollector = new ActivityExecutionMappingCollector(execution);

            ActivityExecutionHierarchyWalker walker = new ActivityExecutionHierarchyWalker(execution);

            walker.addScopePreVisitor(escalationEventDefinitionFinder);
            walker.addExecutionPreVisitor(activityExecutionMappingCollector);
            walker.addExecutionPreVisitor(new OutputVariablesPropagator());

            walker.walkUntil(new WalkConditionAnonymousInnerClass(this, escalationEventDefinitionFinder));

            EscalationEventDefinition escalationEventDefinition = escalationEventDefinitionFinder.EscalationEventDefinition;

            if (escalationEventDefinition != null)
            {
                executeEscalationHandler(escalationEventDefinition, activityExecutionMappingCollector);
            }

            if (escalationEventDefinition == null || !escalationEventDefinition.CancelActivity)
            {
                leaveExecution(execution, currentActivity, escalationEventDefinition);
            }
        }
示例#7
0
        protected internal virtual void createCompensateEventSubscription(ActivityExecution execution, ActivityImpl compensationHandler)
        {
            // the compensate event subscription is created at subprocess or miBody of the the current activity
            PvmActivity       currentActivity = execution.Activity;
            ActivityExecution scopeExecution  = execution.findExecutionForFlowScope(currentActivity.FlowScope);

            EventSubscriptionEntity.createAndInsert((ExecutionEntity)scopeExecution, EventType.COMPENSATE, compensationHandler);
        }
示例#8
0
 protected internal virtual void performInstance(ActivityExecution execution, PvmActivity activity, int loopCounter)
 {
     setLoopVariable(execution, LOOP_COUNTER, loopCounter);
     evaluateCollectionVariable(execution, loopCounter);
     execution.Ended  = false;
     execution.Active = true;
     execution.executeActivity(activity);
 }
示例#9
0
 public InstantiationStack(IList <PvmActivity> activities, PvmActivity targetActivity, PvmTransition targetTransition)
 {
     EnsureUtil.ensureOnlyOneNotNull("target must be either a transition or an activity", targetActivity, targetTransition);
     this.activities = activities;
     // TODO: make this a subclass that contains targetActivity and targetTransition?!
     this.targetActivity   = targetActivity;
     this.targetTransition = targetTransition;
 }
示例#10
0
//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
//ORIGINAL LINE: protected void leaveExecution(org.camunda.bpm.engine.impl.pvm.delegate.ActivityExecution execution, final org.camunda.bpm.engine.impl.pvm.PvmActivity currentActivity, org.camunda.bpm.engine.impl.bpmn.parser.EscalationEventDefinition escalationEventDefinition)
        protected internal virtual void leaveExecution(ActivityExecution execution, PvmActivity currentActivity, EscalationEventDefinition escalationEventDefinition)
        {
            // execution tree could have been expanded by triggering a non-interrupting event
            ExecutionEntity replacingExecution = ((ExecutionEntity)execution).ReplacedBy;

            ExecutionEntity leavingExecution = (ExecutionEntity)(replacingExecution != null ? replacingExecution : execution);

            leave(leavingExecution);
        }
示例#11
0
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public void execute(org.camunda.bpm.engine.impl.pvm.delegate.ActivityExecution execution) throws Exception
        public virtual void execute(ActivityExecution execution)
        {
            execution.inactivate();
            lockConcurrentRoot(execution);

            PvmActivity activity = execution.Activity;

            if (activatesGateway(execution, activity))
            {
                LOG.activityActivation(activity.Id);

                IList <ActivityExecution> joinedExecutions = execution.findInactiveConcurrentExecutions(activity);
                string defaultSequenceFlow = (string)execution.Activity.getProperty("default");
                IList <PvmTransition> transitionsToTake = new List <PvmTransition>();

                // find matching non-default sequence flows
                foreach (PvmTransition outgoingTransition in execution.Activity.OutgoingTransitions)
                {
                    if (string.ReferenceEquals(defaultSequenceFlow, null) || !outgoingTransition.Id.Equals(defaultSequenceFlow))
                    {
                        Condition condition = (Condition)outgoingTransition.getProperty(BpmnParse.PROPERTYNAME_CONDITION);
                        if (condition == null || condition.evaluate(execution))
                        {
                            transitionsToTake.Add(outgoingTransition);
                        }
                    }
                }

                // if none found, add default flow
                if (transitionsToTake.Count == 0)
                {
                    if (!string.ReferenceEquals(defaultSequenceFlow, null))
                    {
                        PvmTransition defaultTransition = execution.Activity.findOutgoingTransition(defaultSequenceFlow);
                        if (defaultTransition == null)
                        {
                            throw LOG.missingDefaultFlowException(execution.Activity.Id, defaultSequenceFlow);
                        }

                        transitionsToTake.Add(defaultTransition);
                    }
                    else
                    {
                        // No sequence flow could be found, not even a default one
                        throw LOG.stuckExecutionException(execution.Activity.Id);
                    }
                }

                // take the flows found
                execution.leaveActivityViaTransitions(transitionsToTake, joinedExecutions);
            }
            else
            {
                LOG.noActivityActivation(activity.Id);
            }
        }
示例#12
0
        protected internal virtual ActivityImpl getFlowScopeActivity(PvmActivity activity)
        {
            ScopeImpl    flowScope         = activity.FlowScope;
            ActivityImpl flowScopeActivity = null;

            if (flowScope.ProcessDefinition != flowScope)
            {
                flowScopeActivity = (ActivityImpl)flowScope;
            }
            return(flowScopeActivity);
        }
示例#13
0
        /// <summary>
        /// Subclasses that call leave() will first pass through this method, before
        /// the regular <seealso cref="FlowNodeActivityBehavior.leave(ActivityExecution)"/> is
        /// called.
        /// </summary>
        public override void doLeave(ActivityExecution execution)
        {
            PvmActivity  currentActivity     = execution.Activity;
            ActivityImpl compensationHandler = ((ActivityImpl)currentActivity).findCompensationHandler();

            // subscription for compensation event subprocess is already created
            if (compensationHandler != null && !isCompensationEventSubprocess(compensationHandler))
            {
                createCompensateEventSubscription(execution, compensationHandler);
            }
            base.doLeave(execution);
        }
示例#14
0
        protected internal virtual void eventNotificationsCompleted(PvmExecutionImpl execution)
        {
            // hack around execution tree structure not being in sync with activity instance concept:
            // if we start a scope activity, remember current activity instance in parent
            PvmExecutionImpl parent   = execution.Parent;
            PvmActivity      activity = execution.getActivity();

            if (parent != null && execution.Scope && activity.Scope && canHaveChildScopes(execution))
            {
                parent.ActivityInstanceId = execution.ActivityInstanceId;
            }
        }
示例#15
0
        /// <summary>
        /// Cancels an execution which is both concurrent and scope. This can only happen if
        /// (a) the process instance has been migrated from a previous version to a new version of the process engine
        ///
        /// See: javadoc of this class for note about concurrent scopes.
        /// </summary>
        /// <param name="execution"> the concurrent scope execution to destroy </param>
        /// <param name="cancelledScopeActivity"> the activity that cancels the execution; it must hold that
        ///   cancellingActivity's event scope is the scope the execution is responsible for </param>
        public static void cancelConcurrentScope(PvmExecutionImpl execution, PvmActivity cancelledScopeActivity)
        {
            ensureConcurrentScope(execution);
            LOG.debugCancelConcurrentScopeExecution(execution);

            execution.interrupt("Scope " + cancelledScopeActivity + " cancelled.");
            // <!> HACK set to event scope activity and leave activity instance
            execution.setActivity(cancelledScopeActivity);
            execution.leaveActivityInstance();
            execution.interrupt("Scope " + cancelledScopeActivity + " cancelled.");
            execution.destroy();
        }
示例#16
0
        protected internal virtual PvmScope getScopeForEscalation(EscalationEventDefinition escalationEventDefinition)
        {
            PvmActivity escalationHandler = escalationEventDefinition.EscalationHandler;

            if (escalationEventDefinition.CancelActivity)
            {
                return(escalationHandler.EventScope);
            }
            else
            {
                return(escalationHandler.FlowScope);
            }
        }
示例#17
0
 /// <summary>
 /// Get the inner activity of the multi instance execution.
 /// </summary>
 /// <param name="execution">
 ///          of multi instance activity </param>
 /// <returns> inner activity </returns>
 public virtual ActivityImpl getInnerActivity(PvmActivity miBodyActivity)
 {
     foreach (PvmActivity activity in miBodyActivity.Activities)
     {
         ActivityImpl innerActivity = (ActivityImpl)activity;
         // note that miBody can contains also a compensation handler
         if (!innerActivity.CompensationHandler)
         {
             return(innerActivity);
         }
     }
     throw new ProcessEngineException("inner activity of multi instance body activity '" + miBodyActivity.Id + "' not found");
 }
示例#18
0
        protected internal virtual void executeEscalationHandler(EscalationEventDefinition escalationEventDefinition, ActivityExecutionMappingCollector activityExecutionMappingCollector)
        {
            PvmActivity       escalationHandler   = escalationEventDefinition.EscalationHandler;
            PvmScope          escalationScope     = getScopeForEscalation(escalationEventDefinition);
            ActivityExecution escalationExecution = activityExecutionMappingCollector.getExecutionForScope(escalationScope);

            if (!string.ReferenceEquals(escalationEventDefinition.EscalationCodeVariable, null))
            {
                escalationExecution.setVariable(escalationEventDefinition.EscalationCodeVariable, escalation.EscalationCode);
            }

            escalationExecution.executeActivity(escalationHandler);
        }
示例#19
0
        public virtual void execute(PvmExecutionImpl execution)
        {
            // Invariant: execution is the Scope Execution for the activity's flow scope.

            PvmActivity activityToStart = execution.NextActivity;

            execution.NextActivity = null;

            PvmExecutionImpl propagatingExecution = execution.createConcurrentExecution();

            // set next activity on propagating execution
            propagatingExecution.setActivity(activityToStart);
            concurrentExecutionCreated(propagatingExecution);
        }
示例#20
0
        protected internal override void eventNotificationsCompleted(PvmExecutionImpl execution)
        {
            PvmActivity activity = execution.getActivity();

            if (execution.Scope && (executesNonScopeActivity(execution) || isAsyncBeforeActivity(execution)) && !CompensationBehavior.executesNonScopeCompensationHandler(execution))
            {
                execution.removeAllTasks();
                // case this is a scope execution and the activity is not a scope
                execution.leaveActivityInstance();
                execution.setActivity(getFlowScopeActivity(activity));
                execution.performOperation(PvmAtomicOperation_Fields.DELETE_CASCADE_FIRE_ACTIVITY_END);
            }
            else
            {
                if (execution.Scope)
                {
                    execution.destroy();
                }

                // remove this execution and its concurrent parent (if exists)
                execution.remove();

                bool continueRemoval = !execution.DeleteRoot;

                if (continueRemoval)
                {
                    PvmExecutionImpl propagatingExecution = execution.Parent;
                    if (propagatingExecution != null && !propagatingExecution.Scope && !propagatingExecution.hasChildren())
                    {
                        propagatingExecution.remove();
                        continueRemoval      = !propagatingExecution.DeleteRoot;
                        propagatingExecution = propagatingExecution.Parent;
                    }

                    if (continueRemoval)
                    {
                        if (propagatingExecution != null)
                        {
                            // continue deletion with the next scope execution
                            // set activity on parent in case the parent is an inactive scope execution and activity has been set to 'null'.
                            if (propagatingExecution.getActivity() == null && activity != null && activity.FlowScope != null)
                            {
                                propagatingExecution.setActivity(getFlowScopeActivity(activity));
                            }
                        }
                    }
                }
            }
        }
示例#21
0
        public override Void execute(CommandContext commandContext)
        {
            ExecutionEntity       processInstance   = commandContext.ExecutionManager.findExecutionById(processInstanceId);
            ProcessDefinitionImpl processDefinition = processInstance.getProcessDefinition();

            PvmActivity activity = processDefinition.findActivity(activityId);

            // forbid instantiation of compensation boundary events
            if (activity != null && "compensationBoundaryCatch".Equals(activity.getProperty("type")))
            {
                throw new ProcessEngineException("Cannot start before activity " + activityId + "; activity " + "is a compensation boundary event.");
            }

            return(base.execute(commandContext));
        }
示例#22
0
        public virtual void visit(PvmScope scope)
        {
            IList <ErrorEventDefinition> errorEventDefinitions = scope.Properties.get(BpmnProperties.ERROR_EVENT_DEFINITIONS);

            foreach (ErrorEventDefinition errorEventDefinition in errorEventDefinitions)
            {
                PvmActivity activityHandler = scope.ProcessDefinition.findActivity(errorEventDefinition.HandlerActivityId);
                if ((!isReThrowingErrorEventSubprocess(activityHandler)) && ((exception != null && errorEventDefinition.catchesException(exception)) || (exception == null && errorEventDefinition.catchesError(errorCode))))
                {
                    errorHandlerActivity      = activityHandler;
                    this.errorEventDefinition = errorEventDefinition;
                    break;
                }
            }
        }
示例#23
0
        protected internal virtual TransitionImpl findTransition(ProcessDefinitionImpl processDefinition)
        {
            PvmActivity activity = processDefinition.findActivity(activityId);

            EnsureUtil.ensureNotNull(typeof(NotValidException), describeFailure("Activity '" + activityId + "' does not exist"), "activity", activity);

            if (activity.OutgoingTransitions.Count == 0)
            {
                throw new ProcessEngineException("Cannot start after activity " + activityId + "; activity " + "has no outgoing sequence flow to take");
            }
            else if (activity.OutgoingTransitions.Count > 1)
            {
                throw new ProcessEngineException("Cannot start after activity " + activityId + "; " + "activity has more than one outgoing sequence flow");
            }

            return((TransitionImpl)activity.OutgoingTransitions[0]);
        }
示例#24
0
        public override void complete(ActivityExecution scopeExecution)
        {
            int loopCounter            = getLoopVariable(scopeExecution, LOOP_COUNTER) + 1;
            int nrOfInstances          = getLoopVariable(scopeExecution, NUMBER_OF_INSTANCES).Value;
            int nrOfCompletedInstances = getLoopVariable(scopeExecution, NUMBER_OF_COMPLETED_INSTANCES) + 1;

            setLoopVariable(scopeExecution, NUMBER_OF_COMPLETED_INSTANCES, nrOfCompletedInstances);

            if (loopCounter == nrOfInstances || completionConditionSatisfied(scopeExecution))
            {
                leave(scopeExecution);
            }
            else
            {
                PvmActivity innerActivity = getInnerActivity(scopeExecution.Activity);
                performInstance(scopeExecution, innerActivity, loopCounter);
            }
        }
示例#25
0
        protected internal override void eventNotificationsCompleted(PvmExecutionImpl execution)
        {
            PvmActivity activity = execution.getActivity();

            if ((execution.Scope) && (activity != null) && (!activity.Scope))
            {
                execution.setActivity((PvmActivity)activity.FlowScope);
                execution.performOperation(this);
            }
            else
            {
                if (execution.Scope)
                {
                    execution.destroy();
                }

                execution.remove();
            }
        }
示例#26
0
        public virtual void execute(AsyncContinuationConfiguration configuration, ExecutionEntity execution, CommandContext commandContext, string tenantId)
        {
            LegacyBehavior.repairMultiInstanceAsyncJob(execution);

            PvmAtomicOperation atomicOperation = findMatchingAtomicOperation(configuration.AtomicOperation);

            ensureNotNull("Cannot process job with configuration " + configuration, "atomicOperation", atomicOperation);

            // reset transition id.
            string transitionId = configuration.TransitionId;

            if (!string.ReferenceEquals(transitionId, null))
            {
                PvmActivity    activity   = execution.getActivity();
                TransitionImpl transition = (TransitionImpl)activity.findOutgoingTransition(transitionId);
                execution.Transition = transition;
            }

            Context.CommandInvocationContext.performOperation(atomicOperation, execution);
        }
示例#27
0
        protected internal virtual void eventNotificationsCompleted(PvmExecutionImpl execution)
        {
            PvmActivity destination = execution.getTransition().getDestination();

            // check start behavior of next activity
            switch (destination.ActivityStartBehavior)
            {
            case DEFAULT:
                execution.setActivity(destination);
                execution.dispatchDelayedEventsAndPerformOperation(PvmAtomicOperation_Fields.TRANSITION_CREATE_SCOPE);
                break;

            case INTERRUPT_FLOW_SCOPE:
                execution.setActivity(null);
                execution.performOperation(PvmAtomicOperation_Fields.TRANSITION_INTERRUPT_FLOW_SCOPE);
                break;

            default:
                throw new ProcessEngineException("Unsupported start behavior for activity '" + destination + "' started from a sequence flow: " + destination.ActivityStartBehavior);
            }
        }
示例#28
0
        public virtual void execute(PvmExecutionImpl execution)
        {
            PvmActivity interruptingActivity = getInterruptingActivity(execution);

            PvmExecutionImpl scopeExecution = !execution.Scope ? execution.Parent : execution;

            if (scopeExecution != execution)
            {
                // remove the current execution before interrupting and continuing executing the interrupted activity
                // reason:
                //   * interrupting should not attempt to fire end events for this execution
                //   * the interruptingActivity is executed with the scope execution
                execution.remove();
            }

            scopeExecution.interrupt("Interrupting activity " + interruptingActivity + " executed.");

            scopeExecution.setActivity(interruptingActivity);
            scopeExecution.Active = true;
            scopeExecution.setTransition(execution.getTransition());
            scopeInterrupted(scopeExecution);
        }
示例#29
0
        protected internal override JobHandlerConfiguration resolveJobHandlerConfiguration(AtomicOperationInvocation context)
        {
            AsyncContinuationConfiguration configuration = new AsyncContinuationConfiguration();

            configuration.AtomicOperation = context.Operation.CanonicalName;

            ExecutionEntity execution = context.Execution;
            PvmActivity     activity  = execution.getActivity();

            if (activity != null && activity.AsyncAfter)
            {
                if (execution.Transition != null)
                {
                    // store id of selected transition in case this is async after.
                    // id is not serialized with the execution -> we need to remember it as
                    // job handler configuration.
                    configuration.TransitionId = execution.Transition.Id;
                }
            }

            return(configuration);
        }
示例#30
0
        public virtual void execute(ActivityExecution execution)
        {
            PvmActivity activity = execution.Activity;

            IList <PvmTransition> outgoingTransitions = execution.Activity.OutgoingTransitions;

            execution.inactivate();

            IList <ActivityExecution> joinedExecutions = execution.findInactiveConcurrentExecutions(activity);

            int nbrOfExecutionsToJoin = execution.Activity.IncomingTransitions.Count;
            int nbrOfExecutionsJoined = joinedExecutions.Count;

            if (nbrOfExecutionsJoined == nbrOfExecutionsToJoin)
            {
                LOG.debug("parallel gateway '" + activity.Id + "' activates: " + nbrOfExecutionsJoined + " of " + nbrOfExecutionsToJoin + " joined");
                execution.leaveActivityViaTransitions(outgoingTransitions, joinedExecutions);
            }
            else
            {
                LOG.debug("parallel gateway '" + activity.Id + "' does not activate: " + nbrOfExecutionsJoined + " of " + nbrOfExecutionsToJoin + " joined");
            }
        }