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;
}
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;
}
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);
}
}
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();
}
}
}
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();
}
Aggregations