diff --git a/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationBuilder.java b/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationBuilder.java index 94f5c4f19b3..0da16ae400b 100644 --- a/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationBuilder.java +++ b/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationBuilder.java @@ -134,6 +134,22 @@ public interface CaseInstanceMigrationBuilder { */ CaseInstanceMigrationBuilder addChangePlanItemIdWithDefinitionIdMapping(ChangePlanItemIdWithDefinitionIdMapping mapping); + /** + * Specifies an expression which is executed before the migration starts. + * + * @param preUpgradeExpression the expression e.g. ${mySpringBean.doSomething()} + * @return Returns the builder + */ + CaseInstanceMigrationBuilder withPreUpgradeExpression(String preUpgradeExpression); + + /** + * Specifies an expression which is executed after the migration is finished. + * + * @param postUpgradeExpression the expression e.g. ${mySpringBean.doSomething()} + * @return Returns the builder + */ + CaseInstanceMigrationBuilder withPostUpgradeExpression(String postUpgradeExpression); + /** * Specifies a case instance variable that will also be available during the case migration * diff --git a/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationDocument.java b/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationDocument.java index 8015b8511ab..b5f31e5c7da 100644 --- a/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationDocument.java +++ b/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationDocument.java @@ -43,6 +43,10 @@ public interface CaseInstanceMigrationDocument { List getChangePlanItemIdWithDefinitionIdMappings(); + String getPreUpgradeExpression(); + + String getPostUpgradeExpression(); + Map> getPlanItemLocalVariables(); Map getCaseInstanceVariables(); diff --git a/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationDocumentBuilder.java b/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationDocumentBuilder.java index a6aeb20a542..0f0bca815ab 100644 --- a/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationDocumentBuilder.java +++ b/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/migration/CaseInstanceMigrationDocumentBuilder.java @@ -55,6 +55,10 @@ public interface CaseInstanceMigrationDocumentBuilder { CaseInstanceMigrationDocumentBuilder addCaseInstanceVariables(Map caseInstanceVariables); + CaseInstanceMigrationDocumentBuilder preUpgradeExpression(String preUpgradeExpression); + + CaseInstanceMigrationDocumentBuilder postUpgradeExpression(String postUpgradeExpression); + CaseInstanceMigrationDocument build(); } diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationBuilderImpl.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationBuilderImpl.java index 8ee674cafe1..64356b4245b 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationBuilderImpl.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationBuilderImpl.java @@ -122,6 +122,18 @@ public CaseInstanceMigrationBuilder addChangePlanItemIdWithDefinitionIdMapping(C return this; } + @Override + public CaseInstanceMigrationBuilder withPreUpgradeExpression(String preUpgradeExpression) { + this.caseInstanceMigrationDocumentDocumentBuilder.preUpgradeExpression(preUpgradeExpression); + return this; + } + + @Override + public CaseInstanceMigrationBuilder withPostUpgradeExpression(String postUpgradeExpression) { + this.caseInstanceMigrationDocumentDocumentBuilder.postUpgradeExpression(postUpgradeExpression); + return this; + } + @Override public CaseInstanceMigrationBuilder withCaseInstanceVariable(String variableName, Object variableValue) { this.caseInstanceMigrationDocumentDocumentBuilder.addCaseInstanceVariable(variableName, variableValue); @@ -139,6 +151,8 @@ public CaseInstanceMigrationDocument getCaseInstanceMigrationDocument() { return this.caseInstanceMigrationDocumentDocumentBuilder.build(); } + + @Override public void migrate(String caseInstanceId) { getCmmnMigrationService().migrateCaseInstance(caseInstanceId, getCaseInstanceMigrationDocument()); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationDocumentBuilderImpl.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationDocumentBuilderImpl.java index 0a2982a7370..826b7c37c0e 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationDocumentBuilderImpl.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationDocumentBuilderImpl.java @@ -43,6 +43,8 @@ public class CaseInstanceMigrationDocumentBuilderImpl implements CaseInstanceMig protected List waitingForRepetitionPlanItemDefinitionMappings = new ArrayList<>(); protected List removeWaitingForRepetitionPlanItemDefinitionMappings = new ArrayList<>(); protected List changePlanItemIdMappings = new ArrayList<>(); + protected String preUpgradeExpression; + protected String postUpgradeExpression; protected List changePlanItemIdWithDefinitionIdMappings = new ArrayList<>(); protected Map caseInstanceVariables = new HashMap<>(); @@ -149,6 +151,18 @@ public CaseInstanceMigrationDocumentBuilder addCaseInstanceVariables(Map caseInstanceVariables = convertFromJsonNodeToObject(caseInstanceVariablesNode, objectMapper); documentBuilder.addCaseInstanceVariables(caseInstanceVariables); } + + String preUpgradeExpression = getJsonProperty(PRE_UPGRADE_EXPRESSION_KEY_JSON_PROPERTY, rootNode); + documentBuilder.preUpgradeExpression(preUpgradeExpression); + + String postUpgradeExpression = getJsonProperty(POST_UPGRADE_EXPRESSION_KEY_JSON_PROPERTY, rootNode); + documentBuilder.postUpgradeExpression(postUpgradeExpression); + return documentBuilder.build(); } catch (IOException e) { diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationDocumentImpl.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationDocumentImpl.java index 32d865cdbe7..f0a79ef7f73 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationDocumentImpl.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationDocumentImpl.java @@ -43,6 +43,8 @@ public class CaseInstanceMigrationDocumentImpl implements CaseInstanceMigrationD protected List removeWaitingForRepetitionPlanItemDefinitionMappings = new ArrayList<>(); protected List changePlanItemIdMappings = new ArrayList<>(); protected List changePlanItemIdWithDefinitionIdMappings = new ArrayList<>(); + protected String preUpgradeExpression; + protected String postUpgradeExpression; protected Map caseInstanceVariables = new HashMap<>(); protected Map> planItemLocalVariables = new HashMap<>(); @@ -97,6 +99,14 @@ public void setCaseInstanceVariables(Map caseInstanceVariables) this.caseInstanceVariables = caseInstanceVariables; } + public void setPreUpgradeExpression(String preUpgradeExpression) { + this.preUpgradeExpression = preUpgradeExpression; + } + + public void setPostUpgradeExpression(String postUpgradeExpression) { + this.postUpgradeExpression = postUpgradeExpression; + } + @Override public String getMigrateToCaseDefinitionId() { return this.migrateToCaseDefinitionId; @@ -152,6 +162,16 @@ public List getChangePlanItemIdWithDefi return changePlanItemIdWithDefinitionIdMappings; } + @Override + public String getPreUpgradeExpression() { + return preUpgradeExpression; + } + + @Override + public String getPostUpgradeExpression() { + return postUpgradeExpression; + } + @Override public Map> getPlanItemLocalVariables() { return this.planItemLocalVariables; diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationManagerImpl.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationManagerImpl.java index 93330694e68..2b1dde9173a 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationManagerImpl.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationManagerImpl.java @@ -256,6 +256,10 @@ public void migrateHistoricCaseInstancesOfCaseDefinition(String caseDefinitionId protected void doMigrateCaseInstance(CaseInstanceEntity caseInstance, CaseDefinition caseDefinitionToMigrateTo, CaseInstanceMigrationDocument document, CommandContext commandContext) { LOGGER.debug("Start migration of case instance with Id:'{}' to case definition identified by {}", caseInstance.getId(), printCaseDefinitionIdentifierMessage(document)); + if (document.getPreUpgradeExpression() != null && !document.getPreUpgradeExpression().isEmpty()) { + cmmnEngineConfiguration.getExpressionManager().createExpression(document.getPreUpgradeExpression()).getValue(caseInstance); + } + ChangePlanItemStateBuilderImpl changePlanItemStateBuilder = prepareChangeStateBuilder(caseInstance, caseDefinitionToMigrateTo, document, commandContext); LOGGER.debug("Updating case definition reference of case root execution with id:'{}' to '{}'", caseInstance.getId(), caseDefinitionToMigrateTo.getId()); @@ -293,6 +297,10 @@ protected void doMigrateCaseInstance(CaseInstanceEntity caseInstance, CaseDefini caseInstanceMigrationCallback.caseInstanceMigrated(caseInstance, caseDefinitionToMigrateTo, document); } } + + if (document.getPostUpgradeExpression() != null && !document.getPostUpgradeExpression().isEmpty()) { + cmmnEngineConfiguration.getExpressionManager().createExpression(document.getPostUpgradeExpression()).getValue(caseInstance); + } } protected void doMigrateHistoricCaseInstance(HistoricCaseInstanceEntity historicCaseInstance, CaseDefinition caseDefinitionToMigrateTo, HistoricCaseInstanceMigrationDocument document, CommandContext commandContext) { diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/migration/CaseInstanceMigrationTest.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/migration/CaseInstanceMigrationTest.java index cc03055bf8d..6691664955a 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/migration/CaseInstanceMigrationTest.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/migration/CaseInstanceMigrationTest.java @@ -4242,6 +4242,56 @@ void withSentryIfPartEventDeferred() { } } + @Test + void withPreUpgradeExpression() { + // Arrange + CaseDefinition definition1 = deployCaseDefinition("test1", "org/flowable/cmmn/test/migration/one-task.cmmn.xml"); + CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("testCase").start(); + CaseDefinition definition2 = deployCaseDefinition("test1", "org/flowable/cmmn/test/migration/one-task.cmmn.xml"); + + // Act + cmmnMigrationService.createCaseInstanceMigrationBuilder() + .migrateToCaseDefinition(definition2.getId()) + .withPreUpgradeExpression("${variableContainer.setVariable('preUpgradeExpressionExecuted', true)}") + .migrate(caseInstance.getId()); + + // Assert + CaseInstance caseInstanceAfterMigration = cmmnRuntimeService.createCaseInstanceQuery() + .caseInstanceId(caseInstance.getId()) + .includeCaseVariables() + .singleResult(); + assertThat(caseInstanceAfterMigration.getCaseDefinitionId()).isEqualTo(definition2.getId()); + assertThat(caseInstanceAfterMigration.getCaseDefinitionVersion()).isEqualTo(2); + assertThat(caseInstanceAfterMigration.getCaseDefinitionDeploymentId()).isEqualTo(definition2.getDeploymentId()); + + assertThat((Boolean) caseInstanceAfterMigration.getCaseVariables().getOrDefault("preUpgradeExpressionExecuted", false)).isTrue(); + } + + @Test + void withPostUpgradeExpression() { + // Arrange + CaseDefinition definition1 = deployCaseDefinition("test1", "org/flowable/cmmn/test/migration/one-task.cmmn.xml"); + CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("testCase").start(); + CaseDefinition definition2 = deployCaseDefinition("test1", "org/flowable/cmmn/test/migration/one-task.cmmn.xml"); + + // Act + cmmnMigrationService.createCaseInstanceMigrationBuilder() + .migrateToCaseDefinition(definition2.getId()) + .withPostUpgradeExpression("${variableContainer.setVariable('postUpgradeExpressionExecuted', true)}") + .migrate(caseInstance.getId()); + + // Assert + CaseInstance caseInstanceAfterMigration = cmmnRuntimeService.createCaseInstanceQuery() + .caseInstanceId(caseInstance.getId()) + .includeCaseVariables() + .singleResult(); + assertThat(caseInstanceAfterMigration.getCaseDefinitionId()).isEqualTo(definition2.getId()); + assertThat(caseInstanceAfterMigration.getCaseDefinitionVersion()).isEqualTo(2); + assertThat(caseInstanceAfterMigration.getCaseDefinitionDeploymentId()).isEqualTo(definition2.getDeploymentId()); + + assertThat((Boolean) caseInstanceAfterMigration.getCaseVariables().getOrDefault("postUpgradeExpressionExecuted", false)).isTrue(); + } + // with sentries // with stages // with new expected case variables