Skip to content

Commit

Permalink
Added null checks for case instance migration
Browse files Browse the repository at this point in the history
  • Loading branch information
tijsrademakers committed Apr 10, 2024
1 parent 32d9433 commit 540746f
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public static Map<String, List<PlanItemInstanceEntity>> findChildPlanItemInstanc

for (PlanItemInstanceEntity childPlanItemInstance : childPlanItemInstances) {
PlanItem childPlanItem = childPlanItemInstance.getPlanItem();
if (planItemIds.contains(childPlanItem.getId())) {
if (childPlanItem != null && planItemIds.contains(childPlanItem.getId())) {
if (!result.containsKey(childPlanItem.getId())) {
result.put(childPlanItem.getId(), new ArrayList<>());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ public static List<PlanItemInstance> searchNonFinishedEqualPlanItemInstances(Pla
if (planItemInstanceContainer != null && planItemInstanceContainer.getChildPlanItemInstances() != null) {
return planItemInstanceContainer.getChildPlanItemInstances()
.stream()
.filter(pi -> planItemInstanceEntity.getPlanItem() != null)
.filter(pi -> pi.getPlanItem() != null)
.filter(pi -> planItemInstanceEntity.getPlanItem().getId().equals(pi.getPlanItem().getId()))
.filter(pi -> !PlanItemInstanceState.isInTerminalState(pi))
.filter(pi -> !pi.getId().equals(planItemInstanceEntity.getId()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.flowable.cmmn.api.runtime.MilestoneInstance;
import org.flowable.cmmn.api.runtime.PlanItemInstance;
import org.flowable.cmmn.api.runtime.PlanItemInstanceState;
import org.flowable.cmmn.api.runtime.UserEventListenerInstance;
import org.flowable.cmmn.engine.impl.persistence.entity.SentryPartInstanceEntity;
import org.flowable.cmmn.engine.test.impl.CmmnHistoryTestHelper;
import org.flowable.common.engine.api.FlowableException;
Expand Down Expand Up @@ -1881,6 +1882,60 @@ void listenerAndTaskInStagesWithSentryAndIfPart() {
assertThat(cmmnRuntimeService.createPlanItemInstanceQuery().caseInstanceId(caseInstance.getId()).planItemDefinitionId("expandedStage2").singleResult().getState()).isEqualTo(PlanItemInstanceState.ACTIVE);
}

@Test
void repetitionListenerAndChangedTask() {
// Arrange
CaseDefinition originalDefinition = deployCaseDefinition("test1", "org/flowable/cmmn/test/migration/repetition-with-listener-and-task.cmmn.xml");
CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder()
.caseDefinitionKey("repetitionTaskCase")
.variable("exitVar", "test")
.start();

List<PlanItemInstance> planItemInstances = cmmnRuntimeService.createPlanItemInstanceQuery().caseInstanceId(caseInstance.getId()).list();
assertThat(planItemInstances).hasSize(4);
assertThat(planItemInstances)
.extracting(PlanItemInstance::getCaseDefinitionId)
.containsOnly(originalDefinition.getId());
assertThat(planItemInstances)
.extracting(PlanItemInstance::getPlanItemDefinitionId)
.containsExactlyInAnyOrder("userEventListener1", "repeatableTask", "cmmnStage1", "stageTask");

UserEventListenerInstance userEventListenerInstance = cmmnRuntimeService.createUserEventListenerInstanceQuery().caseInstanceId(caseInstance.getId()).singleResult();
cmmnRuntimeService.completeUserEventListenerInstance(userEventListenerInstance.getId());

planItemInstances = cmmnRuntimeService.createPlanItemInstanceQuery().caseInstanceId(caseInstance.getId()).list();
assertThat(planItemInstances).hasSize(4);
PlanItemInstance planItemInstance = cmmnRuntimeService.createPlanItemInstanceQuery().caseInstanceId(caseInstance.getId()).planItemDefinitionId("repeatableTask").singleResult();
assertThat(planItemInstance.getState()).isEqualTo(PlanItemInstanceState.WAITING_FOR_REPETITION);

CaseDefinition destinationDefinition = deployCaseDefinition("test1", "org/flowable/cmmn/test/migration/repetition-with-listener-and-changed-task.cmmn.xml");

// Act
cmmnMigrationService.createCaseInstanceMigrationBuilder()
.migrateToCaseDefinition(destinationDefinition.getId())
.removeWaitingForRepetitionPlanItemDefinitionMapping(PlanItemDefinitionMappingBuilder.createRemoveWaitingForRepetitionPlanItemDefinitionMappingFor("repeatableTask"))
.addMoveToAvailablePlanItemDefinitionMapping(PlanItemDefinitionMappingBuilder.createMoveToAvailablePlanItemDefinitionMappingFor("changedTask"))
.addTerminatePlanItemDefinitionMapping(PlanItemDefinitionMappingBuilder.createTerminatePlanItemDefinitionMappingFor("stageTask"))
.migrate(caseInstance.getId());

// Assert
CaseInstance caseInstanceAfterMigration = cmmnRuntimeService.createCaseInstanceQuery()
.caseInstanceId(caseInstance.getId())
.singleResult();
assertThat(caseInstanceAfterMigration.getCaseDefinitionId()).isEqualTo(destinationDefinition.getId());
planItemInstances = cmmnRuntimeService.createPlanItemInstanceQuery().caseInstanceId(caseInstance.getId()).list();
assertThat(planItemInstances).hasSize(2);
assertThat(planItemInstances)
.extracting(PlanItemInstance::getCaseDefinitionId)
.containsOnly(destinationDefinition.getId());
assertThat(planItemInstances)
.extracting(PlanItemInstance::getPlanItemDefinitionId)
.containsExactlyInAnyOrder("userEventListener1", "changedTask");

userEventListenerInstance = cmmnRuntimeService.createUserEventListenerInstanceQuery().caseInstanceId(caseInstance.getId()).singleResult();
cmmnRuntimeService.completeUserEventListenerInstance(userEventListenerInstance.getId());
}

@Test
void activateNewStageWithSentry() {
// Arrange
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/cmmn" xmlns:cmmndi="http://www.omg.org/spec/CMMN/20151109/CMMNDI" xmlns:dc="http://www.omg.org/spec/CMMN/20151109/DC" xmlns:di="http://www.omg.org/spec/CMMN/20151109/DI" xmlns:design="http://flowable.org/design" targetNamespace="http://flowable.org/cmmn">
<case id="repetitionTaskCase" name="RepetitionTaskCase">
<casePlanModel id="onecaseplanmodel1" name="Case plan model">
<planItem id="planItemEventListener" name="eventListener1" definitionRef="userEventListener1">
<itemControl>
<repetitionRule flowable:counterVariable="repetitionCounter" />
</itemControl>
</planItem>
<planItem id="planItemchangedTask" name="changedTask" definitionRef="changedTask">
<itemControl>
<repetitionRule flowable:counterVariable="repetitionCounter" />
</itemControl>
<entryCriterion id="entryCriterion1" sentryRef="sentryentryCriterion1" />
</planItem>
<planItem id="planItemcmmnStage_1" name="Stage 1" definitionRef="cmmnStage1">
<entryCriterion id="entryCriterion2" sentryRef="entryStageSentry1" />
<exitCriterion id="entryCriterion3" sentryRef="exitStageSentry1" />
</planItem>
<sentry id="sentryentryCriterion1">
<planItemOnPart id="sentryOnPartentryCriterion1" sourceRef="planItemEventListener">
<standardEvent>occur</standardEvent>
</planItemOnPart>
</sentry>
<sentry id="entryStageSentry1">
<ifPart>
<condition><![CDATA[${false}]]></condition>
</ifPart>
</sentry>
<sentry id="exitStageSentry1">
<ifPart>
<condition><![CDATA[${exitVar == 'test'}]]></condition>
</ifPart>
</sentry>
<userEventListener id="userEventListener1" name="eventListener1" />
<task id="changedTask" flowable:type="java" flowable:expression="${true}" />
<stage id="cmmnStage1" name="Stage 1">
<planItem id="stagePlanItemChanged" name="Stage changed task" definitionRef="stageChangedTask"/>
<task id="stageChangedTask" name="Stage changed task" flowable:expression="${true}" />
</stage>
</casePlanModel>
</case>
</definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/cmmn" xmlns:cmmndi="http://www.omg.org/spec/CMMN/20151109/CMMNDI" xmlns:dc="http://www.omg.org/spec/CMMN/20151109/DC" xmlns:di="http://www.omg.org/spec/CMMN/20151109/DI" xmlns:design="http://flowable.org/design" targetNamespace="http://flowable.org/cmmn">
<case id="repetitionTaskCase" name="RepetitionTaskCase">
<casePlanModel id="onecaseplanmodel1" name="Case plan model">
<planItem id="planItemEventListener" name="eventListener1" definitionRef="userEventListener1">
<itemControl>
<repetitionRule flowable:counterVariable="repetitionCounter" />
</itemControl>
</planItem>
<planItem id="planItemrepeatableTask" name="repeatableTask" definitionRef="repeatableTask">
<itemControl>
<repetitionRule flowable:counterVariable="repetitionCounter" />
</itemControl>
<entryCriterion id="entryCriterion1" sentryRef="sentryentryCriterion1" />
</planItem>
<planItem id="planItemcmmnStage_1" name="Stage 1" definitionRef="cmmnStage1">
<entryCriterion id="entryCriterion2" sentryRef="entryStageSentry1" />
</planItem>
<sentry id="sentryentryCriterion1">
<planItemOnPart id="sentryOnPartentryCriterion1" sourceRef="planItemEventListener">
<standardEvent>occur</standardEvent>
</planItemOnPart>
</sentry>
<sentry id="entryStageSentry1">
<ifPart>
<condition><![CDATA[${true}]]></condition>
</ifPart>
</sentry>
<userEventListener id="userEventListener1" name="eventListener1" />
<task id="repeatableTask" flowable:type="java" flowable:expression="${true}" />
<stage id="cmmnStage1" name="Stage 1">
<planItem id="stagePlanItem1" name="Stage task" definitionRef="stageTask"/>
<task id="stageTask" name="Stage task" flowable:expression="${true}" flowable:async="true" />
</stage>
</casePlanModel>
</case>
</definitions>

0 comments on commit 540746f

Please sign in to comment.