Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public void deleteChildEntity(CommandContext commandContext, DelegatePlanItemIns
CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
cmmnEngineConfiguration.getCmmnHistoryManager().recordCaseInstanceEnd(
caseInstance, CaseInstanceState.TERMINATED, cmmnEngineConfiguration.getClock().getCurrentTime());
caseInstanceEntityManager.delete(caseInstance.getId(), cascade, null);
caseInstanceEntityManager.delete(caseInstance.getId(), cascade, "cmmn-state-transition-delete-case");
}

// This is not the regular termination through the agenda, but the historic plan item state still needs to be correct.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,69 @@ public void testTerminateCaseInstanceWithNestedCaseTasks() {
}
}

@Test
@CmmnDeployment(resources = {
"org/flowable/cmmn/test/runtime/CaseTaskTest.caseTaskWithChildHumanTask.cmmn",
"org/flowable/cmmn/test/runtime/oneHumanTaskCase.cmmn"
})
public void testTerminateCaseInstanceSetsDeleteReasonOnChildCaseTask() {
CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("caseTaskWithChildHumanTask").start();
Task childTask = cmmnTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance.getId()).singleResult();
assertThat(childTask.getScopeId()).isNotEqualTo(caseInstance.getId());

cmmnRuntimeService.terminateCaseInstance(caseInstance.getId());

assertThat(cmmnTaskService.createTaskQuery().count()).isZero();
if (CmmnHistoryTestHelper.isHistoryLevelAtLeast(HistoryLevel.AUDIT, cmmnEngineConfiguration)) {
HistoricTaskInstance historicChildTask = cmmnHistoryService.createHistoricTaskInstanceQuery().taskId(childTask.getId()).singleResult();
assertThat(historicChildTask.getEndTime()).isNotNull();
assertThat(historicChildTask.getDeleteReason()).isEqualTo("cmmn-state-transition-delete-case");
}
}

@Test
@CmmnDeployment(resources = {
"org/flowable/cmmn/test/runtime/CaseTaskTest.caseTaskWithChildHumanTask.cmmn",
"org/flowable/cmmn/test/runtime/oneHumanTaskCase.cmmn"
})
public void testDeleteCaseInstanceSetsDeleteReasonOnChildCaseTask() {
CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("caseTaskWithChildHumanTask").start();
Task childTask = cmmnTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance.getId()).singleResult();
assertThat(childTask.getScopeId()).isNotEqualTo(caseInstance.getId());

cmmnRuntimeService.deleteCaseInstance(caseInstance.getId());

assertThat(cmmnTaskService.createTaskQuery().count()).isZero();
if (CmmnHistoryTestHelper.isHistoryLevelAtLeast(HistoryLevel.AUDIT, cmmnEngineConfiguration)) {
HistoricTaskInstance historicChildTask = cmmnHistoryService.createHistoricTaskInstanceQuery().taskId(childTask.getId()).singleResult();
assertThat(historicChildTask.getEndTime()).isNotNull();
assertThat(historicChildTask.getDeleteReason()).isEqualTo("cmmn-state-transition-delete-case");
}
}

@Test
@CmmnDeployment(resources = {
"org/flowable/cmmn/test/runtime/CaseTaskTest.testThreeLevelRootCase.cmmn",
"org/flowable/cmmn/test/runtime/CaseTaskTest.testThreeLevelLevel1Case.cmmn",
"org/flowable/cmmn/test/runtime/oneHumanTaskCase.cmmn"
})
public void testTerminateCaseInstanceSetsDeleteReasonOnGrandchildCaseTask() {
CaseInstance rootCase = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("rootCase").start();
String level1CaseId = (String) rootCase.getCaseVariables().get("caseIdVariable");
String oneHumanTaskCaseId = (String) cmmnRuntimeService.getVariable(level1CaseId, "caseIdVariable");
Task grandchildTask = cmmnTaskService.createTaskQuery().caseInstanceIdWithChildren(rootCase.getId()).singleResult();
assertThat(grandchildTask.getScopeId()).isEqualTo(oneHumanTaskCaseId);

cmmnRuntimeService.terminateCaseInstance(rootCase.getId());

assertThat(cmmnTaskService.createTaskQuery().count()).isZero();
if (CmmnHistoryTestHelper.isHistoryLevelAtLeast(HistoryLevel.AUDIT, cmmnEngineConfiguration)) {
HistoricTaskInstance historicGrandchildTask = cmmnHistoryService.createHistoricTaskInstanceQuery().taskId(grandchildTask.getId()).singleResult();
assertThat(historicGrandchildTask.getEndTime()).isNotNull();
assertThat(historicGrandchildTask.getDeleteReason()).isEqualTo("cmmn-state-transition-delete-case");
}
}

@Test
@CmmnDeployment
public void testFallbackToDefaultTenant() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL"
xmlns:dc="http://www.omg.org/spec/CMMN/20151109/DC"
xmlns:di="http://www.omg.org/spec/CMMN/20151109/DI"
xmlns:cmmndi="http://www.omg.org/spec/CMMN/20151109/CMMNDI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
targetNamespace="http://flowable.org/cmmn">

<case id="caseTaskWithChildHumanTask">
<casePlanModel id="myPlanModel" name="My CasePlanModel">

<planItem id="planItem1" name="The Case" definitionRef="theCase" />

<caseTask id="theCase" caseRef="oneHumanTaskCase" />

</casePlanModel>
</case>

</definitions>
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ public interface DeleteReason {

String TRANSACTION_CANCELED = "transaction canceled";

String ADHOC_SUBPROCESS_COMPLETED = "adhoc subprocess completed";

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.flowable.bpmn.model.SubProcess;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.debug.ExecutionTreeUtil;
import org.flowable.engine.history.DeleteReason;
import org.flowable.engine.impl.delegate.ActivityBehavior;
import org.flowable.engine.impl.delegate.TriggerableActivityBehavior;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
Expand Down Expand Up @@ -99,7 +100,8 @@ protected void evaluateEventSubProcesses(List<EventSubProcess> eventSubProcesses
if (conditionIsTrue) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);
if (startEvent.isInterrupting()) {
executionEntityManager.deleteChildExecutions(parentExecution, null, true);
executionEntityManager.deleteChildExecutions(parentExecution, null, null,
DeleteReason.EVENT_SUBPROCESS_INTERRUPTING + "(" + startEvent.getId() + ")", true, startEvent);
}

ExecutionEntity eventSubProcessExecution = executionEntityManager.createChildExecution(parentExecution);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.flowable.bpmn.model.Activity;
Expand All @@ -36,6 +37,7 @@
import org.flowable.common.engine.api.delegate.BusinessError;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.delegate.event.impl.FlowableEventBuilder;
import org.flowable.engine.history.DeleteReason;
import org.flowable.engine.impl.Condition;
import org.flowable.engine.impl.bpmn.helper.ErrorPropagation;
import org.flowable.engine.impl.bpmn.helper.SkipExpressionUtil;
Expand Down Expand Up @@ -301,6 +303,13 @@ protected void handleAdhocSubProcess(FlowNode flowNode) {
}
}

if (completeAdhocSubProcess && adhocSubProcess.isCancelRemainingInstances()) {
// The remaining activities are cancelled; otherwise EndExecutionOperation deletes them with a null delete reason.
// Done before leaving, so the executions of the outgoing sequence flows are kept.
CommandContextUtil.getExecutionEntityManager(commandContext).deleteChildExecutions(execution.getParent(),
Collections.singletonList(execution.getId()), null, DeleteReason.ADHOC_SUBPROCESS_COMPLETED, true, flowNode);
}

if (flowNode.getOutgoingFlows().size() > 0) {
leaveFlowNode(flowNode);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
import java.util.Collections;

import org.flowable.common.engine.impl.history.HistoryLevel;
import org.flowable.engine.history.DeleteReason;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.impl.test.HistoryTestHelper;
import org.flowable.engine.impl.test.PluggableFlowableTestCase;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.test.Deployment;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.junit.jupiter.api.Test;

/**
Expand Down Expand Up @@ -142,12 +144,18 @@ public void testNonInterruptingNestedSubProcess() {
public void testInterruptingNestedSubProcess() {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("process");
assertThat(runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).count()).isEqualTo(3);
Task interruptedTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();

runtimeService.evaluateConditionalEvents(processInstance.getId(), Collections.singletonMap("myVar", "test"));
assertThat(runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).count()).isEqualTo(5);

assertThat(taskService.createTaskQuery().count()).isEqualTo(1);

if (HistoryTestHelper.isHistoryLevelAtLeast(HistoryLevel.AUDIT, processEngineConfiguration)) {
assertThat(historyService.createHistoricTaskInstanceQuery().taskId(interruptedTask.getId()).singleResult().getDeleteReason())
.isEqualTo(DeleteReason.EVENT_SUBPROCESS_INTERRUPTING + "(eventProcessStart)");
}

// now let's complete the task in the event subprocess
Task task = taskService.createTaskQuery().taskDefinitionKey("eventSubProcessTask").singleResult();
taskService.complete(task.getId());
Expand Down Expand Up @@ -208,6 +216,30 @@ public void testSimpleInterruptingEventSubProcess() {
assertProcessEnded(processInstance.getId());
}

@Test
@Deployment(resources = "org/flowable/engine/test/bpmn/event/conditional/ConditionalEventSubprocessTest.testSimpleInterruptingEventSubProcess.bpmn20.xml")
public void testInterruptingEventSubProcessSetsDeleteReason() {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("simpleConditionalEventSubProcess");
Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskDefinitionKey("task").singleResult();

runtimeService.evaluateConditionalEvents(processInstance.getId(), Collections.singletonMap("testVar", true));

assertThat(taskService.createTaskQuery().processInstanceId(processInstance.getId()).list())
.extracting(Task::getTaskDefinitionKey)
.containsExactly("eventSubProcessTask1");

if (HistoryTestHelper.isHistoryLevelAtLeast(HistoryLevel.ACTIVITY, processEngineConfiguration)) {
assertThat(historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstance.getId()).activityId("task").singleResult()
.getDeleteReason()).isEqualTo(DeleteReason.EVENT_SUBPROCESS_INTERRUPTING + "(eventSubProcessConditionalStart)");
}

if (HistoryTestHelper.isHistoryLevelAtLeast(HistoryLevel.AUDIT, processEngineConfiguration)) {
HistoricTaskInstance historicTask = historyService.createHistoricTaskInstanceQuery().taskId(task.getId()).singleResult();
assertThat(historicTask.getEndTime()).isNotNull();
assertThat(historicTask.getDeleteReason()).isEqualTo(DeleteReason.EVENT_SUBPROCESS_INTERRUPTING + "(eventSubProcessConditionalStart)");
}
}

@Test
@Deployment
public void testGroovyCondition() {
Expand Down
Loading
Loading