Search in sources :

Example 1 with ScopeImpl

use of org.camunda.bpm.engine.impl.pvm.process.ScopeImpl in project camunda-bpm-platform by camunda.

the class GetActivityInstanceCmd method execute.

public ActivityInstance execute(CommandContext commandContext) {
    ensureNotNull("processInstanceId", processInstanceId);
    List<ExecutionEntity> executionList = loadProcessInstance(processInstanceId, commandContext);
    if (executionList.isEmpty()) {
        return null;
    }
    checkGetActivityInstance(processInstanceId, commandContext);
    List<ExecutionEntity> nonEventScopeExecutions = filterNonEventScopeExecutions(executionList);
    List<ExecutionEntity> leaves = filterLeaves(nonEventScopeExecutions);
    // Leaves must be ordered in a predictable way (e.g. by ID)
    // in order to return a stable execution tree with every repeated invocation of this command.
    // For legacy process instances, there may miss scope executions for activities that are now a scope.
    // In this situation, there may be multiple scope candidates for the same instance id; which one
    // can depend on the order the leaves are iterated.
    orderById(leaves);
    ExecutionEntity processInstance = filterProcessInstance(executionList);
    if (processInstance.isEnded()) {
        return null;
    }
    // create act instance for process instance
    ActivityInstanceImpl processActInst = createActivityInstance(processInstance, processInstance.getProcessDefinition(), processInstanceId, null);
    Map<String, ActivityInstanceImpl> activityInstances = new HashMap<String, ActivityInstanceImpl>();
    activityInstances.put(processInstanceId, processActInst);
    Map<String, TransitionInstanceImpl> transitionInstances = new HashMap<String, TransitionInstanceImpl>();
    for (ExecutionEntity leaf : leaves) {
        // it will not have an activity set
        if (leaf.getActivity() == null) {
            continue;
        }
        Map<ScopeImpl, PvmExecutionImpl> activityExecutionMapping = leaf.createActivityExecutionMapping();
        Map<ScopeImpl, PvmExecutionImpl> scopeInstancesToCreate = new HashMap<ScopeImpl, PvmExecutionImpl>(activityExecutionMapping);
        // and does not throw compensation
        if (leaf.getActivityInstanceId() != null) {
            if (!CompensationBehavior.isCompensationThrowing(leaf) || LegacyBehavior.isCompensationThrowing(leaf, activityExecutionMapping)) {
                String parentActivityInstanceId = null;
                parentActivityInstanceId = activityExecutionMapping.get(leaf.getActivity().getFlowScope()).getParentActivityInstanceId();
                ActivityInstanceImpl leafInstance = createActivityInstance(leaf, leaf.getActivity(), leaf.getActivityInstanceId(), parentActivityInstanceId);
                activityInstances.put(leafInstance.getId(), leafInstance);
                scopeInstancesToCreate.remove(leaf.getActivity());
            }
        } else {
            TransitionInstanceImpl transitionInstance = createTransitionInstance(leaf);
            transitionInstances.put(transitionInstance.getId(), transitionInstance);
            scopeInstancesToCreate.remove(leaf.getActivity());
        }
        LegacyBehavior.removeLegacyNonScopesFromMapping(scopeInstancesToCreate);
        scopeInstancesToCreate.remove(leaf.getProcessDefinition());
        // create an activity instance for each scope (including compensation throwing executions)
        for (Map.Entry<ScopeImpl, PvmExecutionImpl> scopeExecutionEntry : scopeInstancesToCreate.entrySet()) {
            ScopeImpl scope = scopeExecutionEntry.getKey();
            PvmExecutionImpl scopeExecution = scopeExecutionEntry.getValue();
            String activityInstanceId = null;
            String parentActivityInstanceId = null;
            activityInstanceId = scopeExecution.getParentActivityInstanceId();
            parentActivityInstanceId = activityExecutionMapping.get(scope.getFlowScope()).getParentActivityInstanceId();
            if (activityInstances.containsKey(activityInstanceId)) {
                continue;
            } else {
                // regardless of the tree structure (compacted or not), the scope's activity instance id
                // is the activity instance id of the parent execution and the parent activity instance id
                // of that is the actual parent activity instance id
                ActivityInstanceImpl scopeInstance = createActivityInstance(scopeExecution, scope, activityInstanceId, parentActivityInstanceId);
                activityInstances.put(activityInstanceId, scopeInstance);
            }
        }
    }
    LegacyBehavior.repairParentRelationships(activityInstances.values(), processInstanceId);
    populateChildInstances(activityInstances, transitionInstances);
    return processActInst;
}
Also used : HashMap(java.util.HashMap) PvmExecutionImpl(org.camunda.bpm.engine.impl.pvm.runtime.PvmExecutionImpl) TransitionInstanceImpl(org.camunda.bpm.engine.impl.persistence.entity.TransitionInstanceImpl) ExecutionEntity(org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity) ActivityInstanceImpl(org.camunda.bpm.engine.impl.persistence.entity.ActivityInstanceImpl) ScopeImpl(org.camunda.bpm.engine.impl.pvm.process.ScopeImpl) HashMap(java.util.HashMap) Map(java.util.Map)

Example 2 with ScopeImpl

use of org.camunda.bpm.engine.impl.pvm.process.ScopeImpl in project camunda-bpm-platform by camunda.

the class AbstractInstantiationCmd method execute.

public Void execute(final CommandContext commandContext) {
    ExecutionEntity processInstance = commandContext.getExecutionManager().findExecutionById(processInstanceId);
    final ProcessDefinitionImpl processDefinition = processInstance.getProcessDefinition();
    CoreModelElement elementToInstantiate = getTargetElement(processDefinition);
    EnsureUtil.ensureNotNull(NotValidException.class, describeFailure("Element '" + getTargetElementId() + "' does not exist in process '" + processDefinition.getId() + "'"), "element", elementToInstantiate);
    // rebuild the mapping because the execution tree changes with every iteration
    final ActivityExecutionTreeMapping mapping = new ActivityExecutionTreeMapping(commandContext, processInstanceId);
    // before instantiating an activity, two things have to be determined:
    // 
    // activityStack:
    // For the activity to instantiate, we build a stack of parent flow scopes
    // for which no executions exist yet and that have to be instantiated
    // 
    // scopeExecution:
    // This is typically the execution under which a new sub tree has to be created.
    // if an explicit ancestor activity instance is set:
    // - this is the scope execution for that ancestor activity instance
    // - throws exception if that scope execution is not in the parent hierarchy
    // of the activity to be started
    // if no explicit ancestor activity instance is set:
    // - this is the execution of the first parent/ancestor flow scope that has an execution
    // - throws an exception if there is more than one such execution
    ScopeImpl targetFlowScope = getTargetFlowScope(processDefinition);
    // prepare to walk up the flow scope hierarchy and collect the flow scope activities
    ActivityStackCollector stackCollector = new ActivityStackCollector();
    FlowScopeWalker walker = new FlowScopeWalker(targetFlowScope);
    walker.addPreVisitor(stackCollector);
    ExecutionEntity scopeExecution = null;
    // if no explicit ancestor activity instance is set
    if (ancestorActivityInstanceId == null) {
        // walk until a scope is reached for which executions exist
        walker.walkWhile(new ReferenceWalker.WalkCondition<ScopeImpl>() {

            public boolean isFulfilled(ScopeImpl element) {
                return !mapping.getExecutions(element).isEmpty() || element == processDefinition;
            }
        });
        Set<ExecutionEntity> flowScopeExecutions = mapping.getExecutions(walker.getCurrentElement());
        if (flowScopeExecutions.size() > 1) {
            throw new ProcessEngineException("Ancestor activity execution is ambiguous for activity " + targetFlowScope);
        }
        scopeExecution = flowScopeExecutions.iterator().next();
    } else {
        ActivityInstance tree = commandContext.runWithoutAuthorization(new Callable<ActivityInstance>() {

            public ActivityInstance call() throws Exception {
                return new GetActivityInstanceCmd(processInstanceId).execute(commandContext);
            }
        });
        ActivityInstance ancestorInstance = findActivityInstance(tree, ancestorActivityInstanceId);
        EnsureUtil.ensureNotNull(NotValidException.class, describeFailure("Ancestor activity instance '" + ancestorActivityInstanceId + "' does not exist"), "ancestorInstance", ancestorInstance);
        // determine ancestor activity scope execution and activity
        final ExecutionEntity ancestorScopeExecution = getScopeExecutionForActivityInstance(processInstance, mapping, ancestorInstance);
        final PvmScope ancestorScope = getScopeForActivityInstance(processDefinition, ancestorInstance);
        // walk until the scope of the ancestor scope execution is reached
        walker.walkWhile(new ReferenceWalker.WalkCondition<ScopeImpl>() {

            public boolean isFulfilled(ScopeImpl element) {
                return (mapping.getExecutions(element).contains(ancestorScopeExecution) && element == ancestorScope) || element == processDefinition;
            }
        });
        Set<ExecutionEntity> flowScopeExecutions = mapping.getExecutions(walker.getCurrentElement());
        if (!flowScopeExecutions.contains(ancestorScopeExecution)) {
            throw new NotValidException(describeFailure("Scope execution for '" + ancestorActivityInstanceId + "' cannot be found in parent hierarchy of flow element '" + elementToInstantiate.getId() + "'"));
        }
        scopeExecution = ancestorScopeExecution;
    }
    List<PvmActivity> activitiesToInstantiate = stackCollector.getActivityStack();
    Collections.reverse(activitiesToInstantiate);
    // We have to make a distinction between
    // - "regular" activities for which the activity stack can be instantiated and started
    // right away
    // - interrupting or cancelling activities for which we have to ensure that
    // the interruption and cancellation takes place before we instantiate the activity stack
    ActivityImpl topMostActivity = null;
    ScopeImpl flowScope = null;
    if (!activitiesToInstantiate.isEmpty()) {
        topMostActivity = (ActivityImpl) activitiesToInstantiate.get(0);
        flowScope = topMostActivity.getFlowScope();
    } else if (ActivityImpl.class.isAssignableFrom(elementToInstantiate.getClass())) {
        topMostActivity = (ActivityImpl) elementToInstantiate;
        flowScope = topMostActivity.getFlowScope();
    } else if (TransitionImpl.class.isAssignableFrom(elementToInstantiate.getClass())) {
        TransitionImpl transitionToInstantiate = (TransitionImpl) elementToInstantiate;
        flowScope = transitionToInstantiate.getSource().getFlowScope();
    }
    if (!supportsConcurrentChildInstantiation(flowScope)) {
        throw new ProcessEngineException("Concurrent instantiation not possible for " + "activities in scope " + flowScope.getId());
    }
    ActivityStartBehavior startBehavior = ActivityStartBehavior.CONCURRENT_IN_FLOW_SCOPE;
    if (topMostActivity != null) {
        startBehavior = topMostActivity.getActivityStartBehavior();
        if (!activitiesToInstantiate.isEmpty()) {
            // this is in BPMN relevant if there is an interrupting event sub process.
            // we have to distinguish between instantiation of the start event and any other activity.
            // instantiation of the start event means interrupting behavior; instantiation
            // of any other task means no interruption.
            PvmActivity initialActivity = topMostActivity.getProperties().get(BpmnProperties.INITIAL_ACTIVITY);
            PvmActivity secondTopMostActivity = null;
            if (activitiesToInstantiate.size() > 1) {
                secondTopMostActivity = activitiesToInstantiate.get(1);
            } else if (ActivityImpl.class.isAssignableFrom(elementToInstantiate.getClass())) {
                secondTopMostActivity = (PvmActivity) elementToInstantiate;
            }
            if (initialActivity != secondTopMostActivity) {
                startBehavior = ActivityStartBehavior.CONCURRENT_IN_FLOW_SCOPE;
            }
        }
    }
    switch(startBehavior) {
        case CANCEL_EVENT_SCOPE:
            {
                ScopeImpl scopeToCancel = topMostActivity.getEventScope();
                ExecutionEntity executionToCancel = getSingleExecutionForScope(mapping, scopeToCancel);
                if (executionToCancel != null) {
                    executionToCancel.deleteCascade("Cancelling activity " + topMostActivity + " executed.", skipCustomListeners, skipIoMappings);
                    instantiate(executionToCancel.getParent(), activitiesToInstantiate, elementToInstantiate);
                } else {
                    ExecutionEntity flowScopeExecution = getSingleExecutionForScope(mapping, topMostActivity.getFlowScope());
                    instantiateConcurrent(flowScopeExecution, activitiesToInstantiate, elementToInstantiate);
                }
                break;
            }
        case INTERRUPT_EVENT_SCOPE:
            {
                ScopeImpl scopeToCancel = topMostActivity.getEventScope();
                ExecutionEntity executionToCancel = getSingleExecutionForScope(mapping, scopeToCancel);
                executionToCancel.interrupt("Interrupting activity " + topMostActivity + " executed.", skipCustomListeners, skipIoMappings);
                executionToCancel.setActivity(null);
                executionToCancel.leaveActivityInstance();
                instantiate(executionToCancel, activitiesToInstantiate, elementToInstantiate);
                break;
            }
        case INTERRUPT_FLOW_SCOPE:
            {
                ScopeImpl scopeToCancel = topMostActivity.getFlowScope();
                ExecutionEntity executionToCancel = getSingleExecutionForScope(mapping, scopeToCancel);
                executionToCancel.interrupt("Interrupting activity " + topMostActivity + " executed.", skipCustomListeners, skipIoMappings);
                executionToCancel.setActivity(null);
                executionToCancel.leaveActivityInstance();
                instantiate(executionToCancel, activitiesToInstantiate, elementToInstantiate);
                break;
            }
        default:
            {
                // or this execution has ended executing its scope, it can be reused
                if (!scopeExecution.hasChildren() && (scopeExecution.getActivity() == null || scopeExecution.isEnded())) {
                    // reuse the scope execution
                    instantiate(scopeExecution, activitiesToInstantiate, elementToInstantiate);
                } else {
                    // if the activity is not cancelling/interrupting, it can simply be instantiated as
                    // a concurrent child of the scopeExecution
                    instantiateConcurrent(scopeExecution, activitiesToInstantiate, elementToInstantiate);
                }
                break;
            }
    }
    return null;
}
Also used : TransitionImpl(org.camunda.bpm.engine.impl.pvm.process.TransitionImpl) NotValidException(org.camunda.bpm.engine.exception.NotValidException) ProcessDefinitionImpl(org.camunda.bpm.engine.impl.pvm.process.ProcessDefinitionImpl) ActivityInstance(org.camunda.bpm.engine.runtime.ActivityInstance) PvmActivity(org.camunda.bpm.engine.impl.pvm.PvmActivity) ActivityStackCollector(org.camunda.bpm.engine.impl.tree.ActivityStackCollector) ProcessEngineException(org.camunda.bpm.engine.ProcessEngineException) NotValidException(org.camunda.bpm.engine.exception.NotValidException) PvmScope(org.camunda.bpm.engine.impl.pvm.PvmScope) ExecutionEntity(org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity) ReferenceWalker(org.camunda.bpm.engine.impl.tree.ReferenceWalker) ActivityImpl(org.camunda.bpm.engine.impl.pvm.process.ActivityImpl) ActivityExecutionTreeMapping(org.camunda.bpm.engine.impl.ActivityExecutionTreeMapping) FlowScopeWalker(org.camunda.bpm.engine.impl.tree.FlowScopeWalker) CoreModelElement(org.camunda.bpm.engine.impl.core.model.CoreModelElement) ScopeImpl(org.camunda.bpm.engine.impl.pvm.process.ScopeImpl) ActivityStartBehavior(org.camunda.bpm.engine.impl.pvm.process.ActivityStartBehavior) ProcessEngineException(org.camunda.bpm.engine.ProcessEngineException)

Example 3 with ScopeImpl

use of org.camunda.bpm.engine.impl.pvm.process.ScopeImpl in project camunda-bpm-platform by camunda.

the class ActivityExecutionTreeMapping method mergeScopeExecutions.

protected void mergeScopeExecutions(ExecutionEntity leaf) {
    Map<ScopeImpl, PvmExecutionImpl> mapping = leaf.createActivityExecutionMapping();
    for (Map.Entry<ScopeImpl, PvmExecutionImpl> mappingEntry : mapping.entrySet()) {
        ScopeImpl scope = mappingEntry.getKey();
        ExecutionEntity scopeExecution = (ExecutionEntity) mappingEntry.getValue();
        submitExecution(scopeExecution, scope);
    }
}
Also used : ExecutionEntity(org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity) PvmExecutionImpl(org.camunda.bpm.engine.impl.pvm.runtime.PvmExecutionImpl) ScopeImpl(org.camunda.bpm.engine.impl.pvm.process.ScopeImpl) HashMap(java.util.HashMap) Map(java.util.Map)

Example 4 with ScopeImpl

use of org.camunda.bpm.engine.impl.pvm.process.ScopeImpl in project camunda-bpm-platform by camunda.

the class AbstractInstanceCancellationCmd method handleChildRemovalInScope.

protected void handleChildRemovalInScope(ExecutionEntity removedExecution) {
    // TODO: the following should be closer to PvmAtomicOperationDeleteCascadeFireActivityEnd
    // (note though that e.g. boundary events expect concurrent executions to be preserved)
    // 
    // Idea: attempting to prune and synchronize on the parent is the default behavior when
    // a concurrent child is removed, but scope activities implementing ModificationObserverBehavior
    // override this default (and therefore *must* take care of reorganization themselves)
    // notify the behavior that a concurrent execution has been removed
    // must be set due to deleteCascade behavior
    ActivityImpl activity = removedExecution.getActivity();
    if (activity == null) {
        return;
    }
    ScopeImpl flowScope = activity.getFlowScope();
    PvmExecutionImpl scopeExecution = removedExecution.getParentScopeExecution(false);
    PvmExecutionImpl executionInParentScope = removedExecution.isConcurrent() ? removedExecution : removedExecution.getParent();
    if (flowScope.getActivityBehavior() != null && flowScope.getActivityBehavior() instanceof ModificationObserverBehavior) {
        // let child removal be handled by the scope itself
        ModificationObserverBehavior behavior = (ModificationObserverBehavior) flowScope.getActivityBehavior();
        behavior.destroyInnerInstance(executionInParentScope);
    } else {
        if (executionInParentScope.isConcurrent()) {
            executionInParentScope.remove();
            scopeExecution.tryPruneLastConcurrentChild();
            scopeExecution.forceUpdate();
        }
    }
}
Also used : ActivityImpl(org.camunda.bpm.engine.impl.pvm.process.ActivityImpl) PvmExecutionImpl(org.camunda.bpm.engine.impl.pvm.runtime.PvmExecutionImpl) ScopeImpl(org.camunda.bpm.engine.impl.pvm.process.ScopeImpl) ModificationObserverBehavior(org.camunda.bpm.engine.impl.pvm.delegate.ModificationObserverBehavior)

Example 5 with ScopeImpl

use of org.camunda.bpm.engine.impl.pvm.process.ScopeImpl in project camunda-bpm-platform by camunda.

the class AbstractProcessInstanceModificationCommand method getScopeExecutionForActivityInstance.

protected ExecutionEntity getScopeExecutionForActivityInstance(ExecutionEntity processInstance, ActivityExecutionTreeMapping mapping, ActivityInstance activityInstance) {
    ensureNotNull("activityInstance", activityInstance);
    ProcessDefinitionImpl processDefinition = processInstance.getProcessDefinition();
    ScopeImpl scope = getScopeForActivityInstance(processDefinition, activityInstance);
    Set<ExecutionEntity> executions = mapping.getExecutions(scope);
    Set<String> activityInstanceExecutions = new HashSet<String>(Arrays.asList(activityInstance.getExecutionIds()));
    // remove with fix of CAM-3574
    for (String activityInstanceExecutionId : activityInstance.getExecutionIds()) {
        ExecutionEntity execution = Context.getCommandContext().getExecutionManager().findExecutionById(activityInstanceExecutionId);
        if (execution.isConcurrent() && execution.hasChildren()) {
            // concurrent executions have at most one child
            ExecutionEntity child = execution.getExecutions().get(0);
            activityInstanceExecutions.add(child.getId());
        }
    }
    // find the scope execution for the given activity instance
    Set<ExecutionEntity> retainedExecutionsForInstance = new HashSet<ExecutionEntity>();
    for (ExecutionEntity execution : executions) {
        if (activityInstanceExecutions.contains(execution.getId())) {
            retainedExecutionsForInstance.add(execution);
        }
    }
    if (retainedExecutionsForInstance.size() != 1) {
        throw new ProcessEngineException("There are " + retainedExecutionsForInstance.size() + " (!= 1) executions for activity instance " + activityInstance.getId());
    }
    return retainedExecutionsForInstance.iterator().next();
}
Also used : ProcessDefinitionImpl(org.camunda.bpm.engine.impl.pvm.process.ProcessDefinitionImpl) ExecutionEntity(org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity) ScopeImpl(org.camunda.bpm.engine.impl.pvm.process.ScopeImpl) ProcessEngineException(org.camunda.bpm.engine.ProcessEngineException) HashSet(java.util.HashSet)

Aggregations

ScopeImpl (org.camunda.bpm.engine.impl.pvm.process.ScopeImpl)37 ExecutionEntity (org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity)10 ActivityImpl (org.camunda.bpm.engine.impl.pvm.process.ActivityImpl)10 PvmActivity (org.camunda.bpm.engine.impl.pvm.PvmActivity)6 PvmExecutionImpl (org.camunda.bpm.engine.impl.pvm.runtime.PvmExecutionImpl)6 FlowScopeWalker (org.camunda.bpm.engine.impl.tree.FlowScopeWalker)5 HashMap (java.util.HashMap)4 List (java.util.List)4 ProcessEngineException (org.camunda.bpm.engine.ProcessEngineException)4 ReferenceWalker (org.camunda.bpm.engine.impl.tree.ReferenceWalker)4 ArrayList (java.util.ArrayList)3 HashSet (java.util.HashSet)3 Map (java.util.Map)3 PvmScope (org.camunda.bpm.engine.impl.pvm.PvmScope)3 Deployment (org.camunda.bpm.engine.test.Deployment)3 MigratingActivityInstance (org.camunda.bpm.engine.impl.migration.instance.MigratingActivityInstance)2 EventSubscriptionEntity (org.camunda.bpm.engine.impl.persistence.entity.EventSubscriptionEntity)2 JobEntity (org.camunda.bpm.engine.impl.persistence.entity.JobEntity)2 ActivityBehavior (org.camunda.bpm.engine.impl.pvm.delegate.ActivityBehavior)2 CompositeActivityBehavior (org.camunda.bpm.engine.impl.pvm.delegate.CompositeActivityBehavior)2