Search in sources :

Example 1 with TransitionImpl

use of org.camunda.bpm.engine.impl.pvm.process.TransitionImpl 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 2 with TransitionImpl

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

the class StartProcessInstanceAtActivitiesCmd method determineFirstActivity.

/**
 * get the activity that is started by the first instruction, if exists;
 * return null if the first instruction is a start-transition instruction
 */
protected ActivityImpl determineFirstActivity(ProcessDefinitionImpl processDefinition, ProcessInstanceModificationBuilderImpl modificationBuilder) {
    AbstractProcessInstanceModificationCommand firstInstruction = modificationBuilder.getModificationOperations().get(0);
    if (firstInstruction instanceof AbstractInstantiationCmd) {
        AbstractInstantiationCmd instantiationInstruction = (AbstractInstantiationCmd) firstInstruction;
        CoreModelElement targetElement = instantiationInstruction.getTargetElement(processDefinition);
        ensureNotNull(NotValidException.class, "Element '" + instantiationInstruction.getTargetElementId() + "' does not exist in process " + processDefinition.getId(), "targetElement", targetElement);
        if (targetElement instanceof ActivityImpl) {
            return (ActivityImpl) targetElement;
        } else if (targetElement instanceof TransitionImpl) {
            return (ActivityImpl) ((TransitionImpl) targetElement).getDestination();
        }
    }
    return null;
}
Also used : TransitionImpl(org.camunda.bpm.engine.impl.pvm.process.TransitionImpl) ActivityImpl(org.camunda.bpm.engine.impl.pvm.process.ActivityImpl) CoreModelElement(org.camunda.bpm.engine.impl.core.model.CoreModelElement)

Example 3 with TransitionImpl

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

the class ProcessDefinitionBuilder method buildProcessDefinition.

public PvmProcessDefinition buildProcessDefinition() {
    for (Object[] unresolvedTransition : unresolvedTransitions) {
        TransitionImpl transition = (TransitionImpl) unresolvedTransition[0];
        String destinationActivityName = (String) unresolvedTransition[1];
        ActivityImpl destination = processDefinition.findActivity(destinationActivityName);
        if (destination == null) {
            throw new RuntimeException("destination '" + destinationActivityName + "' not found.  (referenced from transition in '" + transition.getSource().getId() + "')");
        }
        transition.setDestination(destination);
    }
    return processDefinition;
}
Also used : TransitionImpl(org.camunda.bpm.engine.impl.pvm.process.TransitionImpl) ActivityImpl(org.camunda.bpm.engine.impl.pvm.process.ActivityImpl)

Example 4 with TransitionImpl

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

the class AsyncAfterMigrationValidator method validate.

@Override
public void validate(MigratingTransitionInstance migratingInstance, MigratingProcessInstance migratingProcessInstance, MigratingTransitionInstanceValidationReportImpl instanceReport) {
    ActivityImpl targetActivity = (ActivityImpl) migratingInstance.getTargetScope();
    if (targetActivity != null && migratingInstance.isAsyncAfter()) {
        MigratingJobInstance jobInstance = migratingInstance.getJobInstance();
        AsyncContinuationConfiguration config = (AsyncContinuationConfiguration) jobInstance.getJobEntity().getJobHandlerConfiguration();
        String sourceTransitionId = config.getTransitionId();
        if (targetActivity.getOutgoingTransitions().size() > 1) {
            if (sourceTransitionId == null) {
                instanceReport.addFailure("Transition instance is assigned to no sequence flow" + " and target activity has more than one outgoing sequence flow");
            } else {
                TransitionImpl matchingOutgoingTransition = targetActivity.findOutgoingTransition(sourceTransitionId);
                if (matchingOutgoingTransition == null) {
                    instanceReport.addFailure("Transition instance is assigned to a sequence flow" + " that cannot be matched in the target activity");
                }
            }
        }
    }
}
Also used : TransitionImpl(org.camunda.bpm.engine.impl.pvm.process.TransitionImpl) ActivityImpl(org.camunda.bpm.engine.impl.pvm.process.ActivityImpl) MigratingJobInstance(org.camunda.bpm.engine.impl.migration.instance.MigratingJobInstance) AsyncContinuationConfiguration(org.camunda.bpm.engine.impl.jobexecutor.AsyncContinuationJobHandler.AsyncContinuationConfiguration)

Example 5 with TransitionImpl

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

the class MigratingAsyncJobInstance method updateAsyncAfterTargetConfiguration.

protected void updateAsyncAfterTargetConfiguration(AsyncContinuationConfiguration currentConfiguration) {
    ActivityImpl targetActivity = (ActivityImpl) targetScope;
    List<PvmTransition> outgoingTransitions = targetActivity.getOutgoingTransitions();
    AsyncContinuationConfiguration targetConfiguration = new AsyncContinuationConfiguration();
    if (outgoingTransitions.isEmpty()) {
        targetConfiguration.setAtomicOperation(PvmAtomicOperation.ACTIVITY_END.getCanonicalName());
    } else {
        targetConfiguration.setAtomicOperation(PvmAtomicOperation.TRANSITION_NOTIFY_LISTENER_TAKE.getCanonicalName());
        if (outgoingTransitions.size() == 1) {
            targetConfiguration.setTransitionId(outgoingTransitions.get(0).getId());
        } else {
            TransitionImpl matchingTargetTransition = null;
            String currentTransitionId = currentConfiguration.getTransitionId();
            if (currentTransitionId != null) {
                matchingTargetTransition = targetActivity.findOutgoingTransition(currentTransitionId);
            }
            if (matchingTargetTransition != null) {
                targetConfiguration.setTransitionId(matchingTargetTransition.getId());
            } else {
                // should not happen since it is avoided by validation
                throw new ProcessEngineException("Cannot determine matching outgoing sequence flow");
            }
        }
    }
    jobEntity.setJobHandlerConfiguration(targetConfiguration);
}
Also used : TransitionImpl(org.camunda.bpm.engine.impl.pvm.process.TransitionImpl) ActivityImpl(org.camunda.bpm.engine.impl.pvm.process.ActivityImpl) PvmTransition(org.camunda.bpm.engine.impl.pvm.PvmTransition) ProcessEngineException(org.camunda.bpm.engine.ProcessEngineException) AsyncContinuationConfiguration(org.camunda.bpm.engine.impl.jobexecutor.AsyncContinuationJobHandler.AsyncContinuationConfiguration)

Aggregations

TransitionImpl (org.camunda.bpm.engine.impl.pvm.process.TransitionImpl)11 ActivityImpl (org.camunda.bpm.engine.impl.pvm.process.ActivityImpl)8 PvmActivity (org.camunda.bpm.engine.impl.pvm.PvmActivity)4 ProcessEngineException (org.camunda.bpm.engine.ProcessEngineException)3 PvmTransition (org.camunda.bpm.engine.impl.pvm.PvmTransition)3 CoreModelElement (org.camunda.bpm.engine.impl.core.model.CoreModelElement)2 AsyncContinuationConfiguration (org.camunda.bpm.engine.impl.jobexecutor.AsyncContinuationJobHandler.AsyncContinuationConfiguration)2 ExecutionEntity (org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity)2 ProcessDefinitionImpl (org.camunda.bpm.engine.impl.pvm.process.ProcessDefinitionImpl)2 ExecutionStartContext (org.camunda.bpm.engine.impl.pvm.runtime.ExecutionStartContext)2 NotValidException (org.camunda.bpm.engine.exception.NotValidException)1 ActivityExecutionTreeMapping (org.camunda.bpm.engine.impl.ActivityExecutionTreeMapping)1 CommandContext (org.camunda.bpm.engine.impl.interceptor.CommandContext)1 CommandExecutor (org.camunda.bpm.engine.impl.interceptor.CommandExecutor)1 MigratingJobInstance (org.camunda.bpm.engine.impl.migration.instance.MigratingJobInstance)1 ProcessDefinitionEntity (org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity)1 PvmScope (org.camunda.bpm.engine.impl.pvm.PvmScope)1 ActivityExecution (org.camunda.bpm.engine.impl.pvm.delegate.ActivityExecution)1 ModificationObserverBehavior (org.camunda.bpm.engine.impl.pvm.delegate.ModificationObserverBehavior)1 ActivityStartBehavior (org.camunda.bpm.engine.impl.pvm.process.ActivityStartBehavior)1