diff --git a/README.md b/README.md
index af15589..abacf50 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ First, add the dependency:
info.novatec
camunda-process-instance-migrator
- 1.0.4
+ 1.1.0
```
Secondly, initialise the migrator by injecting Camundas ProcessEngine. As long as you're only migrating on patch level and don't need to do minor migrations, there is no need for further configuration:
@@ -47,7 +47,9 @@ public class MigratorConfiguration {
@Bean
public ProcessInstanceMigrator processInstanceMigrator() {
- return new ProcessInstanceMigrator(processEngine);
+ return ProcessInstanceMigrator.builder()
+ .ofProcessEngine(processEngine())
+ .build();
}
}
@@ -79,16 +81,16 @@ public class MigratorConfiguration {
@Bean
public ProcessInstanceMigrator processInstanceMigrator() {
- ProcessInstanceMigrator processInstanceMigrator = new ProcessInstanceMigrator(processEngine);
-
- //MigrationInstructions are required for minor migrations
- processInstanceMigrator.setMigrationInstructions(generateMigrationInstructions());
- return processInstanceMigrator;
+ ProcessInstanceMigrator processInstanceMigrator = ProcessInstanceMigrator.builder()
+ .ofProcessEngine(processEngine())
+ .withGetMigrationInstructions(generateMigrationInstructions())
+ .build();
}
private MigrationInstructions generateMigrationInstructions(){
- return MigrationInstructions.builder()
- .putInstructions("Some_process_definition_key", Arrays.asList(
+ //use the prepared way of specifying instructions or implement your own
+ return new MigrationInstructionsMap()
+ .putInstructions("Some_process_definition_key", Arrays.asList(
MinorMigrationInstructions.builder()
.sourceMinorVersion(0)
.targetMinorVersion(2)
@@ -96,14 +98,38 @@ public class MigratorConfiguration {
.migrationInstructions(Arrays.asList(
new MigrationInstructionImpl("UserTask1", "UserTask3"),
new MigrationInstructionImpl("UserTask2", "UserTask3")))
- .build()))
- .build();
+ .build()));
}
}
```
Note that every call of "putInstructions" corresponds to one specific migration (in this case going from 1.0.x to 1.2.x). This could, however, also be achieved by specifying instructions for migration from 1.0.x to 1.1.x and from 1.1.x to 1.2.x.
Note that there is no necessity of actually having all versions deployed on a target environment. If you jump from 1.5.x to 1.8.x in, say, a productive environment, because intermediate versions were only deployed to earlier stages, it will still be sufficient to provide instructions that go from 1.5.x to 1.6.x, from 1.6.x to 1.7.x and from 1.7.x to 1.8.x. The migrator will interpret these instructions accordingly and skip the non-existent versions.
+## I need adjustments! What can I do?
+Of course you can always submit issues or create a pull request. But if you are looking for a quick change in functionality, it is recommended that you create your implementation of the interfaces that provide the migrators functionality. If, for example, you want to provide minor migration instructions via json file or you wish to modify logging, just provide your own implementation. For example:
+
+```java
+@Configuration
+public class MigratorConfiguration {
+
+ @Autowired
+ private ProcessEngine processEngine;
+
+ @Bean
+ public ProcessInstanceMigrator processInstanceMigrator() {
+ ProcessInstanceMigrator processInstanceMigrator = ProcessInstanceMigrator.builder()
+ .ofProcessEngine(processEngine())
+ //CustomJsonMigrationInstructionReader implements GetMigrationInstructions
+ .withGetMigrationInstructions(new CustomJsonMigrationInstructionReader())
+ //CustomMigratorLogger implements MigratorLogger
+ .withMigratorLogger(new CustomMigratorLogger())
+ .build();
+ }
+
+}
+```
+You may also provide custom implementations for how a patch migration plan is created, and for how the process instances, that are subject of migration, are determined.
+
## What limitations are there?
The tool was developed and tested using Camunda 7.14 and subsequently updated to Camunda 7.15 and 7.16. It may not work with older versions but there will be releases compatible with newer versions of Camunda Platform.
diff --git a/pom.xml b/pom.xml
index 30231b7..3ee38d1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
info.novatec
camunda-process-instance-migrator
- 1.0.5-SNAPSHOT
+ 1.1.1-SNAPSHOT
Camunda Process Instance Migrator
Process Instance Migrator for Camunda BPM
@@ -90,6 +90,13 @@
8.0.0
test
+
+
+ org.camunda.bpm.extension.mockito
+ camunda-bpm-mockito
+ test
+ 4.13.0
+
diff --git a/src/main/java/info/novatec/camunda/migrator/MigrationInstructions.java b/src/main/java/info/novatec/camunda/migrator/MigrationInstructions.java
deleted file mode 100644
index a5be63a..0000000
--- a/src/main/java/info/novatec/camunda/migrator/MigrationInstructions.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package info.novatec.camunda.migrator;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import lombok.Getter;
-
-/**
- * Class containing all minor migration instructions for all process
- * definitions. A Bean of this class should be provided for the
- * {@link ProcessInstanceMigrator}, even if no instructions are specified.
- */
-@Getter
-public class MigrationInstructions {
-
- private Map> migrationInstructionMap;
-
- private MigrationInstructions(Map> migrationInstructionMap) {
- this.migrationInstructionMap = migrationInstructionMap;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private Map> migrationInstructionMap;
-
- public Builder() {
- this.migrationInstructionMap = new HashMap<>();
- }
-
- public Builder putInstructions(String processDefinitionKey, List instructions) {
- if (migrationInstructionMap.containsKey(processDefinitionKey)) {
- migrationInstructionMap.get(processDefinitionKey).addAll(instructions);
- } else {
- //generate new ArrayList to guarantee support for structural modification (i.e. add)
- migrationInstructionMap.put(processDefinitionKey, new ArrayList<>(instructions));
- }
- return this;
- }
-
- public MigrationInstructions build() {
- return new MigrationInstructions(migrationInstructionMap);
- }
- }
-}
diff --git a/src/main/java/info/novatec/camunda/migrator/ProcessInstanceMigrator.java b/src/main/java/info/novatec/camunda/migrator/ProcessInstanceMigrator.java
index 4b9120c..1c7ba3b 100644
--- a/src/main/java/info/novatec/camunda/migrator/ProcessInstanceMigrator.java
+++ b/src/main/java/info/novatec/camunda/migrator/ProcessInstanceMigrator.java
@@ -1,43 +1,49 @@
package info.novatec.camunda.migrator;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.camunda.bpm.engine.ProcessEngine;
-import org.camunda.bpm.engine.impl.migration.MigrationInstructionImpl;
import org.camunda.bpm.engine.migration.MigrationInstruction;
import org.camunda.bpm.engine.migration.MigrationPlan;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.runtime.ProcessInstance;
-import lombok.Getter;
+import info.novatec.camunda.migrator.instances.GetOlderProcessInstances;
+import info.novatec.camunda.migrator.instances.VersionedProcessInstance;
+import info.novatec.camunda.migrator.instructions.GetMigrationInstructions;
+import info.novatec.camunda.migrator.instructions.MigrationInstructionCombiner;
+import info.novatec.camunda.migrator.instructions.MigrationInstructionsMap;
+import info.novatec.camunda.migrator.instructions.MigrationInstructionsAdder;
+import info.novatec.camunda.migrator.instructions.MinorMigrationInstructions;
+import info.novatec.camunda.migrator.logging.MigratorLogger;
+import info.novatec.camunda.migrator.plan.CreatePatchMigrationplan;
+import info.novatec.camunda.migrator.plan.VersionedDefinitionId;
import lombok.RequiredArgsConstructor;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
+import lombok.AccessLevel;
/**
* This migrator will, when called, attempt to migrate all existing process instances that come from a process
* definition with an older version tag. To enable this, all process models need to be properly versioned:
*
* - Increase patch version for simple changes which can be migrated by mapping equal task IDs. Migration of those changes should work out of the box.
- *
- Increase minor version for changes that need a mapping of some kind for migration to work. Provide these mappings via a {@link MigrationInstructions}-Bean.
+ *
- Increase minor version for changes that need a mapping of some kind for migration to work. Provide these mappings via a {@link MigrationInstructionsMap}-Bean.
*
- Increase major version for changes where no migration is possible or wanted.
*
*/
-@RequiredArgsConstructor
-@Setter
-@Slf4j
+@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public class ProcessInstanceMigrator {
private final ProcessEngine processEngine;
+ private final GetOlderProcessInstances getOlderProcessInstances;
+ private final CreatePatchMigrationplan createPatchMigrationplan;
+ private final MigratorLogger migratorLogger;
+ private final GetMigrationInstructions getMigrationInstructions;
- private MigrationInstructions migrationInstructions;
-
- private static final ProcessVersion OLDEST_RELEASED_VERSION = ProcessVersion.fromString("1.0.0").get();
+ public static ProcessInstanceMigratorBuilder builder() {
+ return new ProcessInstanceMigratorBuilder();
+ }
public void migrateInstancesOfAllProcesses() {
processEngine.getRepositoryService().createProcessDefinitionQuery()
@@ -47,37 +53,40 @@ public void migrateInstancesOfAllProcesses() {
.forEach(processDefinition -> migrateProcessInstances(processDefinition.getKey()));
}
- protected void migrateProcessInstances(String processDefinitionKey) {
- log.info("Starting migration for instances with process definition key {}", processDefinitionKey);
- log.info("Process instances BEFORE migration with process definition key {}", processDefinitionKey);
+ //TODO: make private
+ public void migrateProcessInstances(String processDefinitionKey) {
+ migratorLogger.logMigrationStart(processDefinitionKey);
+ migratorLogger.logMessageForInstancesBeforeMigration(processDefinitionKey);
logExistingProcessInstanceInfos(processDefinitionKey);
Optional newestProcessDefinition = getNewestDeployedVersion(processDefinitionKey);
if (!newestProcessDefinition.isPresent()) {
- log.info("No process definition with key {} deployed. No instances will be migrated", processDefinitionKey);
+ migratorLogger.logNoProcessInstancesDeployedWithKey(processDefinitionKey);
} else if (!newestProcessDefinition.get().getProcessVersion().isPresent()) {
- log.info("No process definitions with a Version Tag deployed deployed. No instances will be migrated");
+ migratorLogger.logNewestDefinitionDoesNotHaveVersionTag(processDefinitionKey);
} else {
ProcessVersion newestProcessVersion = newestProcessDefinition.get().getProcessVersion().get();
- log.info("Newest version for process definition key {} is {}. Attempting migration.", processDefinitionKey, newestProcessVersion.toVersionTag());
+ migratorLogger.logNewestVersionInfo(processDefinitionKey, newestProcessVersion.toVersionTag());
- List olderProcessInstances = getOlderProcessInstances(processDefinitionKey, newestProcessVersion);
+ List olderProcessInstances = getOlderProcessInstances
+ .getOlderProcessInstances(processDefinitionKey, newestProcessVersion);
for (VersionedProcessInstance processInstance : olderProcessInstances) {
MigrationPlan migrationPlan = null;
if (processInstance.getProcessVersion().isOlderPatchThan(newestProcessVersion)) {
- migrationPlan = migrationPlanByMappingEqualActivityIDs(newestProcessDefinition.get(), processInstance);
+ migrationPlan = createPatchMigrationplan.migrationPlanByMappingEqualActivityIDs(newestProcessDefinition.get(), processInstance);
} else if (processInstance.getProcessVersion().isOlderMinorThan(newestProcessVersion)) {
- migrationPlan = migrationPlanByMappingEqualActivityIDs(newestProcessDefinition.get(), processInstance);
+ migrationPlan = createPatchMigrationplan.migrationPlanByMappingEqualActivityIDs(newestProcessDefinition.get(), processInstance);
- List applicableMinorMigrationInstructions = getApplicableMinorMigrationInstructions(
- processDefinitionKey, processInstance.getProcessVersion().getMinorVersion(),
- newestProcessVersion.getMinorVersion(), newestProcessVersion.getMajorVersion());
+ List applicableMinorMigrationInstructions = getMigrationInstructions
+ .getApplicableMinorMigrationInstructions(processDefinitionKey,
+ processInstance.getProcessVersion().getMinorVersion(),
+ newestProcessVersion.getMinorVersion(), newestProcessVersion.getMajorVersion());
- List executableMigrationInstructions = combineMigrationInstructions(
+ List executableMigrationInstructions = MigrationInstructionCombiner.combineMigrationInstructions(
applicableMinorMigrationInstructions);
- addInstructions(migrationPlan, executableMigrationInstructions);
+ MigrationInstructionsAdder.addInstructions(migrationPlan, executableMigrationInstructions);
}
if (migrationPlan != null) {
try {
@@ -85,72 +94,28 @@ protected void migrateProcessInstances(String processDefinitionKey) {
.newMigration(migrationPlan)
.processInstanceIds(processInstance.getProcessInstanceId())
.execute();
- log.info("Successfully migrated process instance with id {} and businessKey {} from version {} to version {}",
+ migratorLogger.logMigrationSuccessful(
processInstance.getProcessInstanceId(), processInstance.getBusinessKey(),
processInstance.getProcessVersion().toVersionTag(), newestProcessVersion.toVersionTag());
} catch(Exception e) {
- log.warn("The process instance with the id {} and businessKey {} could not be migrated from version {} to version {}.\n"
- + "Source process definition id: {}\n"
- + "Target process definition id: {}\n",
- processInstance.getProcessInstanceId(), processInstance.getBusinessKey(),
+ migratorLogger.logMigrationError(
+ processInstance.getProcessInstanceId(), processInstance.getBusinessKey(),
processInstance.getProcessVersion().toVersionTag(), newestProcessVersion.toVersionTag(),
- processInstance.getProcessDefinitionId(), newestProcessDefinition.get().getProcessDefinitionId(),
- e);
+ processInstance.getProcessDefinitionId(), newestProcessDefinition.get().getProcessDefinitionId(), e);
}
} else {
- log.warn("No Migration plan could be generated to migrate the process instance with the id {} and businessKey {} from version {} to version {}",
- processInstance.getProcessInstanceId(), processInstance.getBusinessKey(),
+ migratorLogger.logMigrationPlanGenerationError(
+ processInstance.getProcessInstanceId(), processInstance.getBusinessKey(),
processInstance.getProcessVersion().toVersionTag(), newestProcessVersion.toVersionTag());
}
}
}
- log.info("Process instances AFTER migration with process definition key {}", processDefinitionKey);
+ migratorLogger.logMessageForInstancesAfterMigration(processDefinitionKey);
logExistingProcessInstanceInfos(processDefinitionKey);
}
- private void addInstructions(MigrationPlan migrationPlan,
- List executableMigrationInstructions) {
- List migrationPlanList = migrationPlan.getInstructions();
- List instructionsToBeAddedInTheEnd = new ArrayList<>();
- //first overwrite default instructions with specified instructions
- for(MigrationInstruction instruction : migrationPlanList) {
- boolean specifiedMigrationWasAdded = false;
- for (MigrationInstruction specifiedInstruction : executableMigrationInstructions) {
- if (instruction.getSourceActivityId().equals(specifiedInstruction.getSourceActivityId())) {
- instructionsToBeAddedInTheEnd.add(specifiedInstruction);
- specifiedMigrationWasAdded = true;
- }
- }
- if (!specifiedMigrationWasAdded) {
- instructionsToBeAddedInTheEnd.add(instruction);
- }
- }
- //then add all instructions for activities that are not handled in the default plan
- for (MigrationInstruction specifiedInstruction : executableMigrationInstructions) {
- boolean specifiedInstructionSourceWasHandledInDefaultPlan = false;
- for(MigrationInstruction instruction : migrationPlanList) {
- if (instruction.getSourceActivityId().equals(specifiedInstruction.getSourceActivityId())) {
- specifiedInstructionSourceWasHandledInDefaultPlan = true;
- }
- }
- if (!specifiedInstructionSourceWasHandledInDefaultPlan && !instructionsToBeAddedInTheEnd.contains(specifiedInstruction)) {
- instructionsToBeAddedInTheEnd.add(specifiedInstruction);
- }
- }
- migrationPlanList.clear();
- migrationPlanList.addAll(instructionsToBeAddedInTheEnd);
- }
-
- private MigrationPlan migrationPlanByMappingEqualActivityIDs(VersionedDefinitionId newestProcessDefinition, VersionedProcessInstance processInstance) {
- return processEngine.getRuntimeService()
- .createMigrationPlan(processInstance.getProcessDefinitionId(), newestProcessDefinition.getProcessDefinitionId())
- .mapEqualActivities()
- .updateEventTriggers()
- .build();
- }
-
private void logExistingProcessInstanceInfos(String processDefinitionKey) {
processEngine.getRuntimeService().createProcessInstanceQuery()
.processDefinitionKey(processDefinitionKey)
@@ -162,36 +127,10 @@ private void logExistingProcessInstanceInfos(String processDefinitionKey) {
.forEach((processDefinitionId, instances) -> {
ProcessDefinition processDefinition = processEngine.getRepositoryService().createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
String businessKeys = instances.stream().map(instance -> instance.getBusinessKey()).collect(Collectors.joining(","));
- log.info("processDefinitionId: {}, versionTag: {}, count {}, businessKeys: {}", processDefinitionId, processDefinition.getVersionTag(), instances.size(), businessKeys);
+ migratorLogger.logProcessInstancesInfo(processDefinitionId, processDefinition.getVersionTag(), instances.size(), businessKeys);
});
}
- private List getOlderProcessInstances(String processDefinitionKey, ProcessVersion newestVersion){
- return processEngine.getRepositoryService().createProcessDefinitionQuery()
- .processDefinitionKey(processDefinitionKey)
- .orderByProcessDefinitionVersion()
- .asc()
- .list()
- .stream()
- .filter(processDefinition -> processDefinition.getVersionTag() != null)
- .filter(processDefinition -> ProcessVersion.fromString(processDefinition.getVersionTag()).isPresent())
- .filter(processDefinition -> !ProcessVersion.fromString(processDefinition.getVersionTag()).get().isOlderVersionThan(OLDEST_RELEASED_VERSION))
- .filter(processDefinition -> ProcessVersion.fromString(processDefinition.getVersionTag()).get().isOlderVersionThan(newestVersion))
- .flatMap(processDefinition -> processEngine.getRuntimeService().createProcessInstanceQuery()
- .processDefinitionId(processDefinition.getId())
- .orderByBusinessKey()
- .asc()
- .list()
- .stream()
- .map(processInstance -> new VersionedProcessInstance(
- processInstance.getId(),
- processInstance.getBusinessKey(),
- ProcessVersion.fromString(processDefinition.getVersionTag()).get(),
- processDefinition.getId()
- ))
- ).collect(Collectors.toList());
- }
-
private Optional getNewestDeployedVersion(String processDefinitionKey) {
ProcessDefinition latestProcessDefinition = processEngine.getRepositoryService().createProcessDefinitionQuery()
.processDefinitionKey(processDefinitionKey)
@@ -203,73 +142,4 @@ private Optional getNewestDeployedVersion(String processD
new VersionedDefinitionId(ProcessVersion.fromString(processDefinition.getVersionTag()), processDefinition.getId()));
}
- private List getApplicableMinorMigrationInstructions(String processDefinitionKey,
- int sourceMinorVersion, int targetMinorVersion, int majorVersion) {
- if (migrationInstructions != null && migrationInstructions.getMigrationInstructionMap().containsKey(processDefinitionKey))
- return migrationInstructions.getMigrationInstructionMap().get(processDefinitionKey).stream()
- .filter(minorMigrationInstructions -> minorMigrationInstructions
- .getTargetMinorVersion() <= targetMinorVersion
- && minorMigrationInstructions.getSourceMinorVersion() >= sourceMinorVersion
- && minorMigrationInstructions.getMajorVersion() == majorVersion)
- .collect(Collectors.toList());
- else {
- return Collections.emptyList();
- }
- }
-
- private List combineMigrationInstructions(
- List applicableMinorMigrationInstructions) {
- List instructionList = new ArrayList<>();
- applicableMinorMigrationInstructions.stream()
- .sorted(Comparator.comparingInt(MinorMigrationInstructions::getSourceMinorVersion))
- // check every applicable minor-migration
- .forEach(minorMigrationInstructions ->
- minorMigrationInstructions.getMigrationInstructions().stream()
- // go through all instructions for every migration
- .forEach(migrationInstruction -> {
- // check if a migration instruction exists, that has that migrationInstructions
- // source as a target, i.e. instruction 1 goes from activity1 to activity2 and
- // instruction 2 goes from activity2 to activity3
- boolean migrationInstructionWasAlreadySet = false;
- MigrationInstruction instructionToReplace = null;
- for (MigrationInstruction alreadySetInstruction : instructionList) {
- if (alreadySetInstruction.getTargetActivityId() == migrationInstruction
- .getSourceActivityId()) {
- migrationInstructionWasAlreadySet = true;
- instructionToReplace = alreadySetInstruction;
- }
- }
- // if such a migration instruction exists, remove it and replace it with a
- // combined instruction
- if (migrationInstructionWasAlreadySet && instructionToReplace != null) {
- instructionList.remove(instructionToReplace);
- instructionList.add(new MigrationInstructionImpl(
- instructionToReplace.getSourceActivityId(),
- migrationInstruction.getTargetActivityId(), true));
- }
- // if the instruction does not need to be combined, just add it to the list
- else {
- instructionList.add(new MigrationInstructionImpl(
- migrationInstruction.getSourceActivityId(),
- migrationInstruction.getTargetActivityId(), true));
- }
- }));
- return instructionList;
- }
-
- @Getter
- @RequiredArgsConstructor
- private static class VersionedDefinitionId {
- private final Optional processVersion;
- private final String processDefinitionId;
- }
-
- @Getter
- @RequiredArgsConstructor
- private static class VersionedProcessInstance {
- private final String processInstanceId;
- private final String businessKey;
- private final ProcessVersion processVersion;
- private final String processDefinitionId;
- }
}
diff --git a/src/main/java/info/novatec/camunda/migrator/ProcessInstanceMigratorBuilder.java b/src/main/java/info/novatec/camunda/migrator/ProcessInstanceMigratorBuilder.java
new file mode 100644
index 0000000..43d22b5
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/ProcessInstanceMigratorBuilder.java
@@ -0,0 +1,77 @@
+package info.novatec.camunda.migrator;
+
+import org.camunda.bpm.engine.ProcessEngine;
+
+import info.novatec.camunda.migrator.instances.GetOlderProcessInstances;
+import info.novatec.camunda.migrator.instances.GetOlderProcessInstancesDefaultImpl;
+import info.novatec.camunda.migrator.instructions.GetMigrationInstructions;
+import info.novatec.camunda.migrator.instructions.MigrationInstructionsMap;
+import info.novatec.camunda.migrator.logging.MigratorLogger;
+import info.novatec.camunda.migrator.logging.MigratorLoggerDefaultImpl;
+import info.novatec.camunda.migrator.plan.CreatePatchMigrationplan;
+import info.novatec.camunda.migrator.plan.CreatePatchMigrationplanDefaultImpl;
+import lombok.NoArgsConstructor;
+
+/**
+ * Builder for an instance of ProcessInstanceMigrator. Requires at least one call of
+ * {@link #ofProcessEngine(ProcessEngine processEngine) ofProcessEngine}.
+ * Will create a set of basic configuration object if no further configuration is specified.
+ */
+@NoArgsConstructor
+public class ProcessInstanceMigratorBuilder {
+
+ private ProcessEngine processEngineToSet;
+ private GetOlderProcessInstances getOlderProcessInstancesToSet;
+ private CreatePatchMigrationplan createPatchMigrationplanToSet;
+ private MigratorLogger migratorLoggerToSet;
+ private GetMigrationInstructions getMigrationInstructionsToSet;
+
+ public ProcessInstanceMigratorBuilder ofProcessEngine(ProcessEngine processEngine) {
+ processEngineToSet = processEngine;
+ if (getOlderProcessInstancesToSet == null) {
+ this.getOlderProcessInstancesToSet = new GetOlderProcessInstancesDefaultImpl(processEngine);
+ }
+ if (createPatchMigrationplanToSet == null) {
+ this.createPatchMigrationplanToSet = new CreatePatchMigrationplanDefaultImpl(processEngine);
+ }
+ if (migratorLoggerToSet == null) {
+ this.migratorLoggerToSet = new MigratorLoggerDefaultImpl();
+ }
+ if (getMigrationInstructionsToSet == null) {
+ this.getMigrationInstructionsToSet = new MigrationInstructionsMap();
+ }
+ return this;
+ }
+
+ public ProcessInstanceMigratorBuilder withGetOlderProcessInstances(
+ GetOlderProcessInstances getOlderProcessInstances) {
+ this.getOlderProcessInstancesToSet = getOlderProcessInstances;
+ return this;
+ }
+
+ public ProcessInstanceMigratorBuilder withCreatePatchMigrationplanToSet(
+ CreatePatchMigrationplan createPatchMigrationplan) {
+ this.createPatchMigrationplanToSet = createPatchMigrationplan;
+ return this;
+ }
+
+ public ProcessInstanceMigratorBuilder withMigratorLogger(MigratorLogger migratorLogger) {
+ this.migratorLoggerToSet = migratorLogger;
+ return this;
+ }
+
+ public ProcessInstanceMigratorBuilder withGetMigrationInstructions(
+ GetMigrationInstructions getMigrationInstructions) {
+ this.getMigrationInstructionsToSet = getMigrationInstructions;
+ return this;
+ }
+
+ public ProcessInstanceMigrator build() {
+ if (processEngineToSet == null) {
+ throw new ProcessInstanceMigratorConfigurationException();
+ }
+ return new ProcessInstanceMigrator(processEngineToSet, getOlderProcessInstancesToSet,
+ createPatchMigrationplanToSet,
+ migratorLoggerToSet, getMigrationInstructionsToSet);
+ }
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/ProcessInstanceMigratorConfigurationException.java b/src/main/java/info/novatec/camunda/migrator/ProcessInstanceMigratorConfigurationException.java
new file mode 100644
index 0000000..260c5ca
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/ProcessInstanceMigratorConfigurationException.java
@@ -0,0 +1,18 @@
+package info.novatec.camunda.migrator;
+
+/**
+ * Exception to be thrown when an instance of {@link ProcessInstanceMigratorBuilder} attempts to build an instance of
+ * {@link ProcessInstanceMigrator} without sufficient configuration.
+ *
+ * @author Ben Fuernrohr
+ */
+public class ProcessInstanceMigratorConfigurationException extends RuntimeException {
+
+ private static final long serialVersionUID = 3010064810292611192L;
+ private static final String message = "Process Engine needs to be configured for ProcessInstanceMigrator";
+
+ public ProcessInstanceMigratorConfigurationException() {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/ProcessVersion.java b/src/main/java/info/novatec/camunda/migrator/ProcessVersion.java
index e5593da..5f6d32b 100644
--- a/src/main/java/info/novatec/camunda/migrator/ProcessVersion.java
+++ b/src/main/java/info/novatec/camunda/migrator/ProcessVersion.java
@@ -52,4 +52,10 @@ public boolean isOlderMajorThan(ProcessVersion processVersionToCompare) {
public String toVersionTag() {
return majorVersion + "." + minorVersion + "." + patchVersion;
}
+
+ public boolean equals(ProcessVersion other) {
+ return this.majorVersion == other.majorVersion &&
+ this.minorVersion == other.minorVersion &&
+ this.patchVersion == other.patchVersion;
+ }
}
diff --git a/src/main/java/info/novatec/camunda/migrator/instances/GetOlderProcessInstances.java b/src/main/java/info/novatec/camunda/migrator/instances/GetOlderProcessInstances.java
new file mode 100644
index 0000000..7df2a36
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/instances/GetOlderProcessInstances.java
@@ -0,0 +1,21 @@
+package info.novatec.camunda.migrator.instances;
+
+import java.util.List;
+
+import info.novatec.camunda.migrator.ProcessVersion;
+
+public interface GetOlderProcessInstances {
+
+ /**
+ * Retrieves all process instances of a given processDefinitionKey that are considered 'older' than the specified
+ * newest version so they can be subject of migration.
+ *
+ * @param processDefinitionKey
+ * the process definition key of the process for which process instances are to be looked up.
+ * @param newestVersion
+ * the version of the newest deployed process model.
+ * @return a list of {@link VersionedProcessInstance} that are considered to run on an 'older' process definition
+ * than the specified newest one.
+ */
+ public List getOlderProcessInstances(String processDefinitionKey, ProcessVersion newestVersion);
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/instances/GetOlderProcessInstancesDefaultImpl.java b/src/main/java/info/novatec/camunda/migrator/instances/GetOlderProcessInstancesDefaultImpl.java
new file mode 100644
index 0000000..b31392f
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/instances/GetOlderProcessInstancesDefaultImpl.java
@@ -0,0 +1,47 @@
+package info.novatec.camunda.migrator.instances;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.camunda.bpm.engine.ProcessEngine;
+
+import info.novatec.camunda.migrator.ProcessVersion;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Default implementation of {@link GetOlderProcessInstances} *
+ */
+@RequiredArgsConstructor
+public class GetOlderProcessInstancesDefaultImpl implements GetOlderProcessInstances {
+
+ private static final ProcessVersion OLDEST_RELEASED_VERSION = ProcessVersion.fromString("1.0.0").get();
+
+ private final ProcessEngine processEngine;
+
+ @Override
+ public List getOlderProcessInstances(String processDefinitionKey, ProcessVersion newestVersion){
+ return processEngine.getRepositoryService().createProcessDefinitionQuery()
+ .processDefinitionKey(processDefinitionKey)
+ .orderByProcessDefinitionVersion()
+ .asc()
+ .list()
+ .stream()
+ .filter(processDefinition -> processDefinition.getVersionTag() != null)
+ .filter(processDefinition -> ProcessVersion.fromString(processDefinition.getVersionTag()).isPresent())
+ .filter(processDefinition -> !ProcessVersion.fromString(processDefinition.getVersionTag()).get().isOlderVersionThan(OLDEST_RELEASED_VERSION))
+ .filter(processDefinition -> ProcessVersion.fromString(processDefinition.getVersionTag()).get().isOlderVersionThan(newestVersion))
+ .flatMap(processDefinition -> processEngine.getRuntimeService().createProcessInstanceQuery()
+ .processDefinitionId(processDefinition.getId())
+ .orderByBusinessKey()
+ .asc()
+ .list()
+ .stream()
+ .map(processInstance -> new VersionedProcessInstance(
+ processInstance.getId(),
+ processInstance.getBusinessKey(),
+ ProcessVersion.fromString(processDefinition.getVersionTag()).get(),
+ processDefinition.getId()
+ ))
+ ).collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/instances/VersionedProcessInstance.java b/src/main/java/info/novatec/camunda/migrator/instances/VersionedProcessInstance.java
new file mode 100644
index 0000000..66e877f
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/instances/VersionedProcessInstance.java
@@ -0,0 +1,14 @@
+package info.novatec.camunda.migrator.instances;
+
+import info.novatec.camunda.migrator.ProcessVersion;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public class VersionedProcessInstance {
+ private final String processInstanceId;
+ private final String businessKey;
+ private final ProcessVersion processVersion;
+ private final String processDefinitionId;
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/instructions/GetMigrationInstructions.java b/src/main/java/info/novatec/camunda/migrator/instructions/GetMigrationInstructions.java
new file mode 100644
index 0000000..4b42a11
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/instructions/GetMigrationInstructions.java
@@ -0,0 +1,24 @@
+package info.novatec.camunda.migrator.instructions;
+
+import java.util.List;
+
+public interface GetMigrationInstructions {
+
+ /**
+ * Retrieves a list of {@link MinorMigrationInstructions} that are applicable for the migration between two minor
+ * versions of a given process definition.
+ *
+ * @param processDefinitionKey
+ * the process definition key of the affectes process model
+ * @param sourceMinorVersion
+ * the minor version of the source process definition
+ * @param targetMinorVersion
+ * the minor version of the target process definition
+ * @param majorVersion
+ * the major version in which this migration occurs
+ * @return a list of {@link MinorMigrationInstructions} that need to be applied when migration from the given source
+ * to the given target minor version.
+ */
+ public List getApplicableMinorMigrationInstructions(String processDefinitionKey,
+ int sourceMinorVersion, int targetMinorVersion, int majorVersion);
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/instructions/MigrationInstructionCombiner.java b/src/main/java/info/novatec/camunda/migrator/instructions/MigrationInstructionCombiner.java
new file mode 100644
index 0000000..ded9987
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/instructions/MigrationInstructionCombiner.java
@@ -0,0 +1,59 @@
+package info.novatec.camunda.migrator.instructions;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import org.camunda.bpm.engine.impl.migration.MigrationInstructionImpl;
+import org.camunda.bpm.engine.migration.MigrationInstruction;
+
+public class MigrationInstructionCombiner {
+
+ /**
+ * Combines a list of {@link MinorMigrationInstructions} into a list of migration-ready
+ * {@link MigrationInstruction}, thereby taking into account possible 'adding' of instructions that span multiple
+ * minor versions.
+ *
+ * @param applicableMinorMigrationInstructions the migration instructions that are to be combined.
+ * @return a list of {@link MigrationInstruction} containing all combined instructions from the input.
+ */
+ public static List combineMigrationInstructions(
+ List applicableMinorMigrationInstructions) {
+ List instructionList = new ArrayList<>();
+ applicableMinorMigrationInstructions.stream()
+ .sorted(Comparator.comparingInt(MinorMigrationInstructions::getSourceMinorVersion))
+ // check every applicable minor-migration
+ .forEach(minorMigrationInstructions ->
+ minorMigrationInstructions.getMigrationInstructions().stream()
+ // go through all instructions for every migration
+ .forEach(migrationInstruction -> {
+ // check if a migration instruction exists, that has that migrationInstructions
+ // source as a target, i.e. instruction 1 goes from activity1 to activity2 and
+ // instruction 2 goes from activity2 to activity3
+ boolean migrationInstructionWasAlreadySet = false;
+ MigrationInstruction instructionToReplace = null;
+ for (MigrationInstruction alreadySetInstruction : instructionList) {
+ if (alreadySetInstruction.getTargetActivityId() == migrationInstruction
+ .getSourceActivityId()) {
+ migrationInstructionWasAlreadySet = true;
+ instructionToReplace = alreadySetInstruction;
+ }
+ }
+ // if such a migration instruction exists, remove it and replace it with a
+ // combined instruction
+ if (migrationInstructionWasAlreadySet && instructionToReplace != null) {
+ instructionList.remove(instructionToReplace);
+ instructionList.add(new MigrationInstructionImpl(
+ instructionToReplace.getSourceActivityId(),
+ migrationInstruction.getTargetActivityId(), true));
+ }
+ // if the instruction does not need to be combined, just add it to the list
+ else {
+ instructionList.add(new MigrationInstructionImpl(
+ migrationInstruction.getSourceActivityId(),
+ migrationInstruction.getTargetActivityId(), true));
+ }
+ }));
+ return instructionList;
+ }
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/instructions/MigrationInstructionsAdder.java b/src/main/java/info/novatec/camunda/migrator/instructions/MigrationInstructionsAdder.java
new file mode 100644
index 0000000..a52785e
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/instructions/MigrationInstructionsAdder.java
@@ -0,0 +1,52 @@
+package info.novatec.camunda.migrator.instructions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.camunda.bpm.engine.migration.MigrationInstruction;
+import org.camunda.bpm.engine.migration.MigrationPlan;
+
+public class MigrationInstructionsAdder {
+
+ /**
+ * Modifies a given instance of {@link MigrationPlan} by adding a list of {@link MigrationInstruction}. Instructions
+ * that clash with the original plan will displace the originals, others will just be added.
+ *
+ * @param migrationPlan
+ * the plan to be modified
+ * @param executableMigrationInstructions
+ * the migration instructions to be added to the original plan
+ */
+ public static void addInstructions(MigrationPlan migrationPlan,
+ List executableMigrationInstructions) {
+ List migrationPlanList = migrationPlan.getInstructions();
+ List instructionsToBeAddedInTheEnd = new ArrayList<>();
+ //first overwrite default instructions with specified instructions
+ for(MigrationInstruction instruction : migrationPlanList) {
+ boolean specifiedMigrationWasAdded = false;
+ for (MigrationInstruction specifiedInstruction : executableMigrationInstructions) {
+ if (instruction.getSourceActivityId().equals(specifiedInstruction.getSourceActivityId())) {
+ instructionsToBeAddedInTheEnd.add(specifiedInstruction);
+ specifiedMigrationWasAdded = true;
+ }
+ }
+ if (!specifiedMigrationWasAdded) {
+ instructionsToBeAddedInTheEnd.add(instruction);
+ }
+ }
+ //then add all instructions for activities that are not handled in the default plan
+ for (MigrationInstruction specifiedInstruction : executableMigrationInstructions) {
+ boolean specifiedInstructionSourceWasHandledInDefaultPlan = false;
+ for(MigrationInstruction instruction : migrationPlanList) {
+ if (instruction.getSourceActivityId().equals(specifiedInstruction.getSourceActivityId())) {
+ specifiedInstructionSourceWasHandledInDefaultPlan = true;
+ }
+ }
+ if (!specifiedInstructionSourceWasHandledInDefaultPlan && !instructionsToBeAddedInTheEnd.contains(specifiedInstruction)) {
+ instructionsToBeAddedInTheEnd.add(specifiedInstruction);
+ }
+ }
+ migrationPlanList.clear();
+ migrationPlanList.addAll(instructionsToBeAddedInTheEnd);
+ }
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/instructions/MigrationInstructionsMap.java b/src/main/java/info/novatec/camunda/migrator/instructions/MigrationInstructionsMap.java
new file mode 100644
index 0000000..391ea30
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/instructions/MigrationInstructionsMap.java
@@ -0,0 +1,52 @@
+package info.novatec.camunda.migrator.instructions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import lombok.Getter;
+
+/**
+ * Default implementation for {@link GetMigrationInstructions}.
+ */
+@Getter
+public class MigrationInstructionsMap implements GetMigrationInstructions {
+
+ private Map> migrationInstructionMap;
+
+ public MigrationInstructionsMap() {
+ this.migrationInstructionMap = new HashMap<>();
+ }
+
+ public void clearInstructions() {
+ this.migrationInstructionMap = new HashMap<>();
+ }
+
+ public MigrationInstructionsMap putInstructions(String processDefinitionKey, List instructions) {
+ if (migrationInstructionMap.containsKey(processDefinitionKey)) {
+ migrationInstructionMap.get(processDefinitionKey).addAll(instructions);
+ } else {
+ //generate new ArrayList to guarantee support for structural modification (i.e. add)
+ migrationInstructionMap.put(processDefinitionKey, new ArrayList<>(instructions));
+ }
+ return this;
+ }
+
+ @Override
+ public List getApplicableMinorMigrationInstructions(String processDefinitionKey,
+ int sourceMinorVersion, int targetMinorVersion, int majorVersion) {
+ if (migrationInstructionMap.containsKey(processDefinitionKey))
+ return migrationInstructionMap.get(processDefinitionKey).stream()
+ .filter(minorMigrationInstructions -> minorMigrationInstructions
+ .getTargetMinorVersion() <= targetMinorVersion
+ && minorMigrationInstructions.getSourceMinorVersion() >= sourceMinorVersion
+ && minorMigrationInstructions.getMajorVersion() == majorVersion)
+ .collect(Collectors.toList());
+ else {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/MinorMigrationInstructions.java b/src/main/java/info/novatec/camunda/migrator/instructions/MinorMigrationInstructions.java
similarity index 93%
rename from src/main/java/info/novatec/camunda/migrator/MinorMigrationInstructions.java
rename to src/main/java/info/novatec/camunda/migrator/instructions/MinorMigrationInstructions.java
index 8acd84f..e69e345 100644
--- a/src/main/java/info/novatec/camunda/migrator/MinorMigrationInstructions.java
+++ b/src/main/java/info/novatec/camunda/migrator/instructions/MinorMigrationInstructions.java
@@ -1,4 +1,4 @@
-package info.novatec.camunda.migrator;
+package info.novatec.camunda.migrator.instructions;
import java.util.List;
diff --git a/src/main/java/info/novatec/camunda/migrator/logging/MigratorLogger.java b/src/main/java/info/novatec/camunda/migrator/logging/MigratorLogger.java
new file mode 100644
index 0000000..1f3271c
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/logging/MigratorLogger.java
@@ -0,0 +1,122 @@
+package info.novatec.camunda.migrator.logging;
+
+public interface MigratorLogger {
+
+ /**
+ * Creates a log message indicating that migration is starting.
+ *
+ * @param processDefinitionKey
+ * the process definition key for which migration is starting.
+ */
+ public void logMigrationStart(String processDefinitionKey);
+
+ /**
+ * Creates a log message indicating that what follows will be a list of process instances that will be migrated.
+ *
+ * @param processDefinitionKey
+ * the process definition key for which migration is about to occur.
+ */
+ public void logMessageForInstancesBeforeMigration(String processDefinitionKey);
+
+ /**
+ * Creates a log message indicating that what follows will be a list of process instances that have been migrated.
+ *
+ * @param processDefinitionKey
+ * the process definition key for which migration occurred.
+ */
+ public void logMessageForInstancesAfterMigration(String processDefinitionKey);
+
+ /**
+ * Creates a log message containing the information of process instances that are subject of migration.
+ *
+ * @param processDefinitionId
+ * the process definition id of the process instances
+ * @param versionTag
+ * the version tag of the process instances
+ * @param numberOfInstances
+ * the number of process instances
+ * @param businessKeys
+ * a string containing the combined business keys of the process instances
+ */
+ public void logProcessInstancesInfo(String processDefinitionId, String versionTag, int numberOfInstances,
+ String businessKeys);
+
+ /**
+ * Creates a log message indicating that no process instances with a given key were deployed.
+ *
+ * @param processDefinitionKey
+ * the process definition key for which no process instances were deployed.
+ */
+ public void logNoProcessInstancesDeployedWithKey(String processDefinitionKey);
+
+ /**
+ * Creates a log message indicating that the newest process version of a given process definition key does not have
+ * a version tag.
+ *
+ * @param processDefinitionKey
+ * the process definition key for which the newest version has no version tag.
+ */
+ public void logNewestDefinitionDoesNotHaveVersionTag(String processDefinitionKey);
+
+ /**
+ * Creates a log message containing the information of the newest version for a given process definition.
+ *
+ * @param processDefinitionKey
+ * the process definition key of the newest process definition
+ * @param versionTag
+ * the version tag of the newest process definition
+ */
+ public void logNewestVersionInfo(String processDefinitionKey, String versionTag);
+
+ /**
+ * Creates a log message indicating that migration was successful for a process instance.
+ *
+ * @param processInstanceId
+ * the ID of the migrated process instance.
+ * @param businessKey
+ * the business key of the migrated process instances.
+ * @param versionTagOld
+ * the version tag of the process instance before migration.
+ * @param versionTagNew
+ * that version tag of the process instance after migration.
+ */
+ public void logMigrationSuccessful(String processInstanceId, String businessKey, String versionTagOld,
+ String versionTagNew);
+
+ /**
+ * Creates a log message indicating that migration failed for a process instance.
+ *
+ * @param processInstanceId
+ * the ID of the process instance for which migration failed.
+ * @param businessKey
+ * the business key of the process instance for which migration failed.
+ * @param versionTagOld
+ * the version tag of the process instance before migration.
+ * @param versionTagNew
+ * the version tag that the process instance should have been migrated to.
+ * @param processDefinitionIdOld
+ * the process definition ID of the process instance before migration.
+ * @param processDefinitionIdNew
+ * the process definition ID that the process instance should have been migrated to.
+ * @param e
+ * the exception that occured during migration.
+ */
+ public void logMigrationError(String processInstanceId, String businessKey, String versionTagOld,
+ String versionTagNew, String processDefinitionIdOld, String processDefinitionIdNew, Exception e);
+
+ /**
+ * Creates a log message indicating that creating a migration plan has failed.
+ *
+ * @param processInstanceId
+ * the ID of the process instance for which no plan could be generated.
+ * @param businessKey
+ * the business key of the process instance for which no plan could be generated.
+ * @param versionTagOld
+ * the version tag of the process instance before migration.
+ * @param versionTagNew
+ * the version tag that the process instance should have been migrated to.
+ */
+ public void logMigrationPlanGenerationError(String processInstanceId, String businessKey, String versionTagOld,
+ String versionTagNew);
+
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/logging/MigratorLoggerDefaultImpl.java b/src/main/java/info/novatec/camunda/migrator/logging/MigratorLoggerDefaultImpl.java
new file mode 100644
index 0000000..b2ca57a
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/logging/MigratorLoggerDefaultImpl.java
@@ -0,0 +1,79 @@
+package info.novatec.camunda.migrator.logging;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class MigratorLoggerDefaultImpl implements MigratorLogger {
+
+ @Override
+ public void logMigrationStart(String processDefinitionKey) {
+ log.info("Starting migration for instances with process definition key {}", processDefinitionKey);
+
+ }
+
+ @Override
+ public void logMessageForInstancesBeforeMigration(String processDefinitionKey) {
+ log.info("Process instances BEFORE migration with process definition key {}", processDefinitionKey);
+
+ }
+
+ @Override
+ public void logMessageForInstancesAfterMigration(String processDefinitionKey) {
+ log.info("Process instances AFTER migration with process definition key {}", processDefinitionKey);
+
+ }
+
+ @Override
+ public void logProcessInstancesInfo(String processDefinitionId, String versionTag, int numberOfInstances,
+ String businessKeys) {
+ log.info("processDefinitionId: {}, versionTag: {}, count {}, businessKeys: {}", processDefinitionId, versionTag,
+ numberOfInstances, businessKeys);
+
+ }
+
+ @Override
+ public void logNoProcessInstancesDeployedWithKey(String processDefinitionKey) {
+ log.info("No process definition with key {} deployed. No instances will be migrated", processDefinitionKey);
+
+ }
+
+ @Override
+ public void logNewestDefinitionDoesNotHaveVersionTag(String processDefinitionKey) {
+ log.info("Newest process definition for process with key {} has no version tag. No instances will be migrated");
+
+ }
+
+ @Override
+ public void logNewestVersionInfo(String processDefinitionKey, String versionTag) {
+ log.info("Newest version for process definition key {} is {}. Attempting migration.", processDefinitionKey, versionTag);
+
+ }
+
+ @Override
+ public void logMigrationSuccessful(String processInstanceId, String businessKey, String versionTagOld,
+ String versionTagNew) {
+ log.info("Successfully migrated process instance with id {} and businessKey {} from version {} to version {}",
+ processInstanceId, businessKey, versionTagOld, versionTagNew);
+
+ }
+
+ @Override
+ public void logMigrationError(String processInstanceId, String businessKey, String versionTagOld,
+ String versionTagNew, String processDefinitionIdOld, String processDefinitionIdNew, Exception e) {
+ log.warn("The process instance with the id {} and businessKey {} could not be migrated from version {} to version {}.\n"
+ + "Source process definition id: {}\n"
+ + "Target process definition id: {}\n",
+ processInstanceId, businessKey, versionTagOld, versionTagNew, processDefinitionIdOld,
+ processDefinitionIdNew, e);
+
+ }
+
+ @Override
+ public void logMigrationPlanGenerationError(String processInstanceId, String businessKey, String versionTagOld,
+ String versionTagNew) {
+ log.warn("No Migration plan could be generated to migrate the process instance with the id {} and businessKey {} from version {} to version {}",
+ processInstanceId, businessKey, versionTagOld, versionTagNew);
+
+ }
+
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/plan/CreatePatchMigrationplan.java b/src/main/java/info/novatec/camunda/migrator/plan/CreatePatchMigrationplan.java
new file mode 100644
index 0000000..b7d13b5
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/plan/CreatePatchMigrationplan.java
@@ -0,0 +1,20 @@
+package info.novatec.camunda.migrator.plan;
+
+import org.camunda.bpm.engine.migration.MigrationPlan;
+
+import info.novatec.camunda.migrator.instances.VersionedProcessInstance;
+
+public interface CreatePatchMigrationplan {
+
+ /**
+ * Creates a basic migration plan for patch migration.
+ *
+ * @param newestProcessDefinition
+ * the {@link VersionedDefinitionId} containing information about the newest deployed process definition.
+ * @param processInstance
+ * the process instance for which the migration plan is to be generated.
+ * @return a {@link MigrationPlan} for migration the process instance to the newest version.
+ */
+ public MigrationPlan migrationPlanByMappingEqualActivityIDs(VersionedDefinitionId newestProcessDefinition,
+ VersionedProcessInstance processInstance);
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/plan/CreatePatchMigrationplanDefaultImpl.java b/src/main/java/info/novatec/camunda/migrator/plan/CreatePatchMigrationplanDefaultImpl.java
new file mode 100644
index 0000000..8a30be1
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/plan/CreatePatchMigrationplanDefaultImpl.java
@@ -0,0 +1,22 @@
+package info.novatec.camunda.migrator.plan;
+
+import org.camunda.bpm.engine.ProcessEngine;
+import org.camunda.bpm.engine.migration.MigrationPlan;
+
+import info.novatec.camunda.migrator.instances.VersionedProcessInstance;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public class CreatePatchMigrationplanDefaultImpl implements CreatePatchMigrationplan {
+
+ private final ProcessEngine processEngine;
+
+ @Override
+ public MigrationPlan migrationPlanByMappingEqualActivityIDs(VersionedDefinitionId newestProcessDefinition, VersionedProcessInstance processInstance) {
+ return processEngine.getRuntimeService()
+ .createMigrationPlan(processInstance.getProcessDefinitionId(), newestProcessDefinition.getProcessDefinitionId())
+ .mapEqualActivities()
+ .updateEventTriggers()
+ .build();
+ }
+}
diff --git a/src/main/java/info/novatec/camunda/migrator/plan/VersionedDefinitionId.java b/src/main/java/info/novatec/camunda/migrator/plan/VersionedDefinitionId.java
new file mode 100644
index 0000000..74c3dcd
--- /dev/null
+++ b/src/main/java/info/novatec/camunda/migrator/plan/VersionedDefinitionId.java
@@ -0,0 +1,14 @@
+package info.novatec.camunda.migrator.plan;
+
+import java.util.Optional;
+
+import info.novatec.camunda.migrator.ProcessVersion;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public class VersionedDefinitionId {
+ private final Optional processVersion;
+ private final String processDefinitionId;
+}
diff --git a/src/test/java/info/novatec/camunda/migrator/instances/GetOlderProcessInstancesDefaultImplTest.java b/src/test/java/info/novatec/camunda/migrator/instances/GetOlderProcessInstancesDefaultImplTest.java
new file mode 100644
index 0000000..e9bb119
--- /dev/null
+++ b/src/test/java/info/novatec/camunda/migrator/instances/GetOlderProcessInstancesDefaultImplTest.java
@@ -0,0 +1,112 @@
+package info.novatec.camunda.migrator.instances;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.camunda.bpm.extension.mockito.QueryMocks.mockProcessDefinitionQuery;
+import static org.camunda.bpm.extension.mockito.QueryMocks.mockProcessInstanceQuery;
+import static org.mockito.Mockito.*;
+
+import java.util.List;
+
+import org.camunda.bpm.engine.ProcessEngine;
+import org.camunda.bpm.engine.RepositoryService;
+import org.camunda.bpm.engine.RuntimeService;
+import org.camunda.bpm.engine.repository.ProcessDefinition;
+import org.camunda.bpm.engine.runtime.ProcessInstance;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+
+import info.novatec.camunda.migrator.ProcessVersion;
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+public class GetOlderProcessInstancesDefaultImplTest {
+
+ private static final String PROCESS_DEFINITION_KEY = "myKey";
+ private static final String OLDER_VERSION_PROCESS_DEFINITION_ID = "12345";
+ private static final ProcessVersion NEWEST_VERSION = ProcessVersion.fromString("1.5.9").get();
+ private static final ProcessVersion OLDER_VERSION = ProcessVersion.fromString("1.3.4").get();
+ private static final ProcessVersion TOO_OLD_VERSION = ProcessVersion.fromString("0.2.3").get();
+ private static final ProcessVersion TOO_NEW_VERSION = ProcessVersion.fromString("2.5.10").get();
+ private static final String PROCESS_INSTANCE_1_BUSINESS_KEY = "0815";
+ private static final String PROCESS_INSTANCE_2_BUSINESS_KEY = "0816";
+ private static final String PROCESS_INSTANCE_1_ID = "4711";
+ private static final String PROCESS_INSTANCE_2_ID = "4712";
+
+ @Mock
+ ProcessEngine processEngine;
+ @InjectMocks
+ GetOlderProcessInstancesDefaultImpl getOlderProcessInstancesDefaultImpl;
+
+ @Mock
+ RepositoryService repositoryService;
+ @Mock
+ RuntimeService runtimeService;
+
+ @Mock
+ ProcessDefinition processDefinitionResult1;
+ @Mock
+ ProcessDefinition processDefinitionResult2;
+ @Mock
+ ProcessDefinition processDefinitionResult3;
+ @Mock
+ ProcessInstance processInstanceResult1;
+ @Mock
+ ProcessInstance processInstanceResult2;
+
+ @BeforeEach
+ void setup() {
+ when(processEngine.getRepositoryService()).thenReturn(repositoryService);
+ when(processEngine.getRuntimeService()).thenReturn(runtimeService);
+
+ mockProcessDefinitionQuery(repositoryService)
+ .list(asList(new ProcessDefinition[] {processDefinitionResult1, processDefinitionResult2,
+ processDefinitionResult3}));
+ mockProcessInstanceQuery(runtimeService)
+ .list(asList(new ProcessInstance[] {processInstanceResult1, processInstanceResult2}));
+
+ when(processInstanceResult1.getBusinessKey()).thenReturn(PROCESS_INSTANCE_1_BUSINESS_KEY);
+ when(processInstanceResult2.getBusinessKey()).thenReturn(PROCESS_INSTANCE_2_BUSINESS_KEY);
+ when(processInstanceResult1.getId()).thenReturn(PROCESS_INSTANCE_1_ID);
+ when(processInstanceResult2.getId()).thenReturn(PROCESS_INSTANCE_2_ID);
+
+ }
+
+ @Test
+ void getOlderProcessInstances_should_get_older_process_instances() {
+ when(processDefinitionResult1.getVersionTag()).thenReturn(OLDER_VERSION.toVersionTag());
+ when(processDefinitionResult1.getId()).thenReturn(OLDER_VERSION_PROCESS_DEFINITION_ID);
+
+ List result = getOlderProcessInstancesDefaultImpl
+ .getOlderProcessInstances(PROCESS_DEFINITION_KEY, NEWEST_VERSION);
+
+ assertThat(result).hasSize(2);
+ assertThat(result).allMatch(instance ->
+ instance.getProcessDefinitionId().equals(OLDER_VERSION_PROCESS_DEFINITION_ID) &&
+ instance.getProcessVersion().equals(OLDER_VERSION));
+ assertThat(result).anyMatch(instance ->
+ instance.getBusinessKey().equals(PROCESS_INSTANCE_1_BUSINESS_KEY) &&
+ instance.getProcessInstanceId().equals(PROCESS_INSTANCE_1_ID));
+ assertThat(result).anyMatch(instance ->
+ instance.getBusinessKey().equals(PROCESS_INSTANCE_2_BUSINESS_KEY) &&
+ instance.getProcessInstanceId().equals(PROCESS_INSTANCE_2_ID));
+ }
+
+ @Test
+ void getOlderProcessInstances_should_filter_older_newer_and_null_version_tags() {
+ when(processDefinitionResult1.getVersionTag()).thenReturn(TOO_OLD_VERSION.toVersionTag());
+ when(processDefinitionResult2.getVersionTag()).thenReturn(null);
+ when(processDefinitionResult3.getVersionTag()).thenReturn(TOO_NEW_VERSION.toVersionTag());
+
+ List result = getOlderProcessInstancesDefaultImpl
+ .getOlderProcessInstances(PROCESS_DEFINITION_KEY, NEWEST_VERSION);
+
+ assertThat(result).isEmpty();
+ }
+}
diff --git a/src/test/java/info/novatec/camunda/migrator/instructions/MigrationInstructionCombinerTest.java b/src/test/java/info/novatec/camunda/migrator/instructions/MigrationInstructionCombinerTest.java
new file mode 100644
index 0000000..0edf65a
--- /dev/null
+++ b/src/test/java/info/novatec/camunda/migrator/instructions/MigrationInstructionCombinerTest.java
@@ -0,0 +1,117 @@
+package info.novatec.camunda.migrator.instructions;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.camunda.bpm.engine.migration.MigrationInstruction;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+public class MigrationInstructionCombinerTest {
+
+ private static final int MAJOR_VERSION = 1;
+
+ private static final String ACTIVITY_1 = "ServiceTask1";
+ private static final String ACTIVITY_2 = "ServiceTask2";
+ private static final String ACTIVITY_3 = "UserTask1";
+ private static final String ACTIVITY_4 = "UserTask2";
+ private static final String ACTIVITY_5 = "ReceiveTask1";
+ private static final String ACTIVITY_6 = "ReceiveTask2";
+ private static final String ACTIVITY_7 = "CallActivity1";
+ private static final String ACTIVITY_8 = "CallActivity2";
+
+ @Mock
+ MigrationInstruction migrationInstruction1;
+ @Mock
+ MigrationInstruction migrationInstruction2;
+ @Mock
+ MigrationInstruction migrationInstruction3;
+ @Mock
+ MigrationInstruction migrationInstruction4;
+
+ MinorMigrationInstructions migrationInstructions1To2;
+
+ MinorMigrationInstructions migrationInstructions2To3;
+
+ @BeforeEach()
+ void setUp() {
+ migrationInstructions1To2 = MinorMigrationInstructions.builder()
+ .majorVersion(MAJOR_VERSION)
+ .sourceMinorVersion(1)
+ .targetMinorVersion(2)
+ .migrationInstructions(Arrays.asList(migrationInstruction1, migrationInstruction2))
+ .build();
+
+ migrationInstructions2To3 = MinorMigrationInstructions.builder()
+ .majorVersion(MAJOR_VERSION)
+ .sourceMinorVersion(2)
+ .targetMinorVersion(3)
+ .migrationInstructions(Arrays.asList(migrationInstruction3, migrationInstruction4))
+ .build();
+ }
+
+ @Test
+ void combineMigrationInstruction_should_combine_instructions_where_source_matches_target() {
+ when(migrationInstruction1.getSourceActivityId()).thenReturn(ACTIVITY_1);
+ when(migrationInstruction1.getTargetActivityId()).thenReturn(ACTIVITY_2);
+
+ when(migrationInstruction2.getSourceActivityId()).thenReturn(ACTIVITY_3);
+ when(migrationInstruction2.getTargetActivityId()).thenReturn(ACTIVITY_4);
+
+ when(migrationInstruction3.getSourceActivityId()).thenReturn(ACTIVITY_2);
+ when(migrationInstruction3.getTargetActivityId()).thenReturn(ACTIVITY_5);
+
+ when(migrationInstruction4.getSourceActivityId()).thenReturn(ACTIVITY_4);
+ when(migrationInstruction4.getTargetActivityId()).thenReturn(ACTIVITY_6);
+
+ List result = MigrationInstructionCombiner.combineMigrationInstructions(
+ Arrays.asList(new MinorMigrationInstructions[] {migrationInstructions1To2, migrationInstructions2To3}));
+
+ assertThat(result).hasSize(2);
+ assertThat(result)
+ .anyMatch(migrationInstruction -> migrationInstruction.getSourceActivityId() == ACTIVITY_1
+ && migrationInstruction.getTargetActivityId() == ACTIVITY_5);
+ assertThat(result)
+ .anyMatch(migrationInstruction -> migrationInstruction.getSourceActivityId() == ACTIVITY_3
+ && migrationInstruction.getTargetActivityId() == ACTIVITY_6);
+ }
+
+ @Test
+ void combineMigrationInstruction_should_not_combine_instructions_where_source_does_not_match_target() {
+ when(migrationInstruction1.getSourceActivityId()).thenReturn(ACTIVITY_1);
+ when(migrationInstruction1.getTargetActivityId()).thenReturn(ACTIVITY_2);
+
+ when(migrationInstruction2.getSourceActivityId()).thenReturn(ACTIVITY_3);
+ when(migrationInstruction2.getTargetActivityId()).thenReturn(ACTIVITY_4);
+
+ when(migrationInstruction3.getSourceActivityId()).thenReturn(ACTIVITY_5);
+ when(migrationInstruction3.getTargetActivityId()).thenReturn(ACTIVITY_6);
+
+ when(migrationInstruction4.getSourceActivityId()).thenReturn(ACTIVITY_7);
+ when(migrationInstruction4.getTargetActivityId()).thenReturn(ACTIVITY_8);
+
+ List result = MigrationInstructionCombiner.combineMigrationInstructions(
+ Arrays.asList(new MinorMigrationInstructions[] {migrationInstructions1To2, migrationInstructions2To3}));
+
+ assertThat(result).hasSize(4);
+ assertThat(result)
+ .anyMatch(migrationInstruction -> migrationInstruction.getSourceActivityId() == ACTIVITY_1
+ && migrationInstruction.getTargetActivityId() == ACTIVITY_2);
+ assertThat(result)
+ .anyMatch(migrationInstruction -> migrationInstruction.getSourceActivityId() == ACTIVITY_3
+ && migrationInstruction.getTargetActivityId() == ACTIVITY_4);
+ assertThat(result)
+ .anyMatch(migrationInstruction -> migrationInstruction.getSourceActivityId() == ACTIVITY_5
+ && migrationInstruction.getTargetActivityId() == ACTIVITY_6);
+ assertThat(result)
+ .anyMatch(migrationInstruction -> migrationInstruction.getSourceActivityId() == ACTIVITY_7
+ && migrationInstruction.getTargetActivityId() == ACTIVITY_8);
+ }
+}
diff --git a/src/test/java/info/novatec/camunda/migrator/instructions/MigrationInstructionsAdderTest.java b/src/test/java/info/novatec/camunda/migrator/instructions/MigrationInstructionsAdderTest.java
new file mode 100644
index 0000000..9ae838d
--- /dev/null
+++ b/src/test/java/info/novatec/camunda/migrator/instructions/MigrationInstructionsAdderTest.java
@@ -0,0 +1,124 @@
+package info.novatec.camunda.migrator.instructions;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.camunda.bpm.engine.migration.MigrationInstruction;
+import org.camunda.bpm.engine.migration.MigrationPlan;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+public class MigrationInstructionsAdderTest {
+
+ private static final String ACTIVITY_1 = "ServiceTask1";
+ private static final String ACTIVITY_2 = "ServiceTask2";
+ private static final String ACTIVITY_3 = "UserTask1";
+ private static final String ACTIVITY_4 = "UserTask2";
+ private static final String ACTIVITY_5 = "ReceiveTask1";
+ private static final String ACTIVITY_6 = "ReceiveTask2";
+
+ @Mock
+ MigrationPlan migrationPlan;
+
+ @Spy
+ List migrationPlanInstructionList = new ArrayList<>();
+
+ List instructionList;
+
+ @Mock
+ MigrationInstruction migrationInstruction1;
+ @Mock
+ MigrationInstruction migrationInstruction2;
+ @Mock
+ MigrationInstruction migrationInstruction3;
+ @Mock
+ MigrationInstruction migrationInstruction4;
+
+ @Captor
+ private ArgumentCaptor> migrationInstructionCaptor;
+
+ @BeforeEach()
+ void setUp() {
+ migrationPlanInstructionList.add(migrationInstruction1);
+ migrationPlanInstructionList.add(migrationInstruction2);
+
+ instructionList = new ArrayList<>();
+ instructionList.add(migrationInstruction3);
+ instructionList.add(migrationInstruction4);
+
+ when(migrationPlan.getInstructions()).thenReturn(migrationPlanInstructionList);
+ }
+
+ @Test
+ void addInstructions_should_overwrite_instructions_with_existing_source() {
+ when(migrationInstruction1.getSourceActivityId()).thenReturn(ACTIVITY_1);
+ when(migrationInstruction1.getTargetActivityId()).thenReturn(ACTIVITY_1);
+
+ when(migrationInstruction2.getSourceActivityId()).thenReturn(ACTIVITY_2);
+ when(migrationInstruction2.getTargetActivityId()).thenReturn(ACTIVITY_2);
+
+ when(migrationInstruction3.getSourceActivityId()).thenReturn(ACTIVITY_1);
+ when(migrationInstruction3.getTargetActivityId()).thenReturn(ACTIVITY_3);
+
+ when(migrationInstruction4.getSourceActivityId()).thenReturn(ACTIVITY_2);
+ when(migrationInstruction4.getTargetActivityId()).thenReturn(ACTIVITY_4);
+
+ MigrationInstructionsAdder.addInstructions(migrationPlan, instructionList);
+
+ verify(migrationPlanInstructionList).clear();
+ verify(migrationPlanInstructionList).addAll(migrationInstructionCaptor.capture());
+ List newInstructions = migrationInstructionCaptor.getValue();
+
+ assertThat(newInstructions).hasSize(2);
+ assertThat(newInstructions).anyMatch(instruction -> instruction.getSourceActivityId() == ACTIVITY_1
+ && instruction.getTargetActivityId() == ACTIVITY_3);
+ assertThat(newInstructions).anyMatch(instruction -> instruction.getSourceActivityId() == ACTIVITY_2
+ && instruction.getTargetActivityId() == ACTIVITY_4);
+ }
+
+ @Test
+ void addInstructions_should_add_instructions_with_not_yet_existing_source() {
+ when(migrationInstruction1.getSourceActivityId()).thenReturn(ACTIVITY_1);
+ when(migrationInstruction1.getTargetActivityId()).thenReturn(ACTIVITY_1);
+
+ when(migrationInstruction2.getSourceActivityId()).thenReturn(ACTIVITY_2);
+ when(migrationInstruction2.getTargetActivityId()).thenReturn(ACTIVITY_2);
+
+ when(migrationInstruction3.getSourceActivityId()).thenReturn(ACTIVITY_3);
+ when(migrationInstruction3.getTargetActivityId()).thenReturn(ACTIVITY_4);
+
+ when(migrationInstruction4.getSourceActivityId()).thenReturn(ACTIVITY_5);
+ when(migrationInstruction4.getTargetActivityId()).thenReturn(ACTIVITY_6);
+
+ MigrationInstructionsAdder.addInstructions(migrationPlan, instructionList);
+
+ verify(migrationPlanInstructionList).clear();
+ verify(migrationPlanInstructionList).addAll(migrationInstructionCaptor.capture());
+ List newInstructions = migrationInstructionCaptor.getValue();
+
+ assertThat(newInstructions).hasSize(4);
+ assertThat(newInstructions).anyMatch(instruction -> instruction.getSourceActivityId() == ACTIVITY_1
+ && instruction.getTargetActivityId() == ACTIVITY_1);
+ assertThat(newInstructions).anyMatch(instruction -> instruction.getSourceActivityId() == ACTIVITY_2
+ && instruction.getTargetActivityId() == ACTIVITY_2);
+ assertThat(newInstructions).anyMatch(instruction -> instruction.getSourceActivityId() == ACTIVITY_3
+ && instruction.getTargetActivityId() == ACTIVITY_4);
+ assertThat(newInstructions).anyMatch(instruction -> instruction.getSourceActivityId() == ACTIVITY_5
+ && instruction.getTargetActivityId() == ACTIVITY_6);
+ }
+
+}
diff --git a/src/test/java/info/novatec/camunda/migrator/ProcessInstanceMigratorTest.java b/src/test/java/info/novatec/camunda/migrator/integration/ProcessInstanceMigratorTest.java
similarity index 96%
rename from src/test/java/info/novatec/camunda/migrator/ProcessInstanceMigratorTest.java
rename to src/test/java/info/novatec/camunda/migrator/integration/ProcessInstanceMigratorTest.java
index 167f963..1ff5fd8 100644
--- a/src/test/java/info/novatec/camunda/migrator/ProcessInstanceMigratorTest.java
+++ b/src/test/java/info/novatec/camunda/migrator/integration/ProcessInstanceMigratorTest.java
@@ -1,4 +1,4 @@
-package info.novatec.camunda.migrator;
+package info.novatec.camunda.migrator.integration;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.runtime.ProcessInstance;
@@ -7,9 +7,11 @@
import org.junit.ClassRule;
import org.junit.Test;
-import static info.novatec.camunda.migrator.TestHelper.*;
-import static info.novatec.camunda.migrator.assertions.TaskListAsserter.assertThat;
-import static info.novatec.camunda.migrator.assertions.ProcessInstanceListAsserter.assertThat;
+import info.novatec.camunda.migrator.ProcessInstanceMigrator;
+
+import static info.novatec.camunda.migrator.integration.TestHelper.*;
+import static info.novatec.camunda.migrator.integration.assertions.ProcessInstanceListAsserter.assertThat;
+import static info.novatec.camunda.migrator.integration.assertions.TaskListAsserter.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.*;
import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.assertThat;
@@ -29,7 +31,7 @@ public class ProcessInstanceMigratorTest {
private static final String PROCESS_DEFINITION_KEY = "MigrateableProcess";
- private ProcessInstanceMigrator processInstanceMigrator = new ProcessInstanceMigrator(processEngine());
+ private ProcessInstanceMigrator processInstanceMigrator = ProcessInstanceMigrator.builder().ofProcessEngine(processEngine()).build();
private ProcessDefinition initialProcessDefinition;
private ProcessDefinition newestProcessDefinitionAfterRedeployment;
@@ -335,7 +337,7 @@ public void processInstanceMigrator_should_not_migrate_instances_from_process_mo
.numberOfProcessInstancesIs(2)
.allProcessInstancesHaveDefinitionId(initialProcessDefinition.getId());
- assertThat(getCurrentTasks(PROCESS_DEFINITION_KEY, taskService()))
+ assertThat(getCurrentTasks(PROCESS_DEFINITION_KEY, taskService()))
.numberOfTasksIs(2)
.allTasksHaveDefinitionId(initialProcessDefinition.getId())
.allTasksHaveFormkey(null);
@@ -346,7 +348,7 @@ public void processInstanceMigrator_should_not_migrate_instances_from_process_mo
.numberOfProcessInstancesIs(2)
.allProcessInstancesHaveDefinitionId(initialProcessDefinition.getId());
- assertThat(getCurrentTasks(PROCESS_DEFINITION_KEY, taskService()))
+ assertThat(getCurrentTasks(PROCESS_DEFINITION_KEY, taskService()))
.numberOfTasksIs(2)
.allTasksHaveDefinitionId(initialProcessDefinition.getId())
.allTasksHaveFormkey(null);
diff --git a/src/test/java/info/novatec/camunda/migrator/ProcessInstanceMigratorTest_Minor.java b/src/test/java/info/novatec/camunda/migrator/integration/ProcessInstanceMigratorTest_Minor.java
similarity index 85%
rename from src/test/java/info/novatec/camunda/migrator/ProcessInstanceMigratorTest_Minor.java
rename to src/test/java/info/novatec/camunda/migrator/integration/ProcessInstanceMigratorTest_Minor.java
index b4b7a4a..ac533d3 100644
--- a/src/test/java/info/novatec/camunda/migrator/ProcessInstanceMigratorTest_Minor.java
+++ b/src/test/java/info/novatec/camunda/migrator/integration/ProcessInstanceMigratorTest_Minor.java
@@ -1,9 +1,10 @@
-package info.novatec.camunda.migrator;
+package info.novatec.camunda.migrator.integration;
-import static info.novatec.camunda.migrator.TestHelper.*;
-import static info.novatec.camunda.migrator.assertions.ProcessInstanceListAsserter.assertThat;
-import static info.novatec.camunda.migrator.assertions.TaskListAsserter.assertThat;
+import static info.novatec.camunda.migrator.integration.TestHelper.*;
+import static info.novatec.camunda.migrator.integration.assertions.ProcessInstanceListAsserter.assertThat;
+import static info.novatec.camunda.migrator.integration.assertions.TaskListAsserter.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.camunda.bpm.engine.test.assertions.bpmn.AbstractAssertions.processEngine;
import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.*;
import java.util.Arrays;
@@ -18,6 +19,10 @@
import org.junit.ClassRule;
import org.junit.Test;
+import info.novatec.camunda.migrator.ProcessInstanceMigrator;
+import info.novatec.camunda.migrator.instructions.MigrationInstructionsMap;
+import info.novatec.camunda.migrator.instructions.MinorMigrationInstructions;
+
public class ProcessInstanceMigratorTest_Minor {
@ClassRule
@@ -30,7 +35,11 @@ public class ProcessInstanceMigratorTest_Minor {
private static final String PROCESS_DEFINITION_KEY = "MigrateableProcess";
- private ProcessInstanceMigrator processInstanceMigrator = new ProcessInstanceMigrator(processEngine());
+ private MigrationInstructionsMap migrationInstructionsMap = new MigrationInstructionsMap();
+ private ProcessInstanceMigrator processInstanceMigrator = ProcessInstanceMigrator.builder()
+ .ofProcessEngine(processEngine())
+ .withGetMigrationInstructions(migrationInstructionsMap)
+ .build();
private ProcessDefinition initialProcessDefinition;
private ProcessDefinition newestProcessDefinitionAfterRedeployment;
@@ -58,6 +67,8 @@ public void cleanUp() {
.list()
.forEach(
deployment -> repositoryService().deleteDeployment(deployment.getId()));
+
+ this.migrationInstructionsMap.clearInstructions();
}
@Test
@@ -103,9 +114,7 @@ public void processInstanceMigrator_should_migrate_to_higher_minor_version_if_mi
.allTasksHaveKey("UserTask1")
.allTasksHaveFormkey(null);
- processInstanceMigrator.setMigrationInstructions(MigrationInstructions.builder()
- .putInstructions(PROCESS_DEFINITION_KEY, generateMigrationInstructionsFor100To150())
- .build());
+ migrationInstructionsMap.putInstructions(PROCESS_DEFINITION_KEY, generateMigrationInstructionsFor100To150());
processInstanceMigrator.migrateInstancesOfAllProcesses();
assertThat(getRunningProcessInstances(PROCESS_DEFINITION_KEY, runtimeService()))
@@ -135,9 +144,7 @@ public void processInstanceMigrator_should_not_migrate_if_migration_to_higher_mi
.allTasksHaveKey("UserTask1")
.allTasksHaveFormkey(null);
- processInstanceMigrator.setMigrationInstructions(MigrationInstructions.builder()
- .putInstructions(PROCESS_DEFINITION_KEY, generateFaultyMigrationInstructionsFor100To150())
- .build());
+ migrationInstructionsMap.putInstructions(PROCESS_DEFINITION_KEY, generateFaultyMigrationInstructionsFor100To150());
processInstanceMigrator.migrateInstancesOfAllProcesses();
assertThat(getRunningProcessInstances(PROCESS_DEFINITION_KEY, runtimeService()))
@@ -167,10 +174,8 @@ public void processInstanceMigrator_should_migrate_to_higher_minor_by_adding_up_
.allTasksHaveKey("UserTask1")
.allTasksHaveFormkey(null);
- processInstanceMigrator.setMigrationInstructions(MigrationInstructions.builder()
- .putInstructions(PROCESS_DEFINITION_KEY, generateMigrationInstructionFor100To130())
- .putInstructions(PROCESS_DEFINITION_KEY, generateMigrationInstructionFor130To150())
- .build());
+ migrationInstructionsMap.putInstructions(PROCESS_DEFINITION_KEY, generateMigrationInstructionFor100To130());
+ migrationInstructionsMap.putInstructions(PROCESS_DEFINITION_KEY, generateMigrationInstructionFor130To150());
processInstanceMigrator.migrateInstancesOfAllProcesses();
assertThat(getRunningProcessInstances(PROCESS_DEFINITION_KEY, runtimeService()))
@@ -203,9 +208,7 @@ public void processInstanceMigrator_should_migrate_to_higher_minor_and_patch_ver
.oneTaskHasKey("UserTask2")
.allTasksHaveFormkey(null);
- processInstanceMigrator.setMigrationInstructions(MigrationInstructions.builder()
- .putInstructions(PROCESS_DEFINITION_KEY, generateMigrationInstructionsFor100To150())
- .build());
+ migrationInstructionsMap.putInstructions(PROCESS_DEFINITION_KEY, generateMigrationInstructionsFor100To150());
processInstanceMigrator.migrateInstancesOfAllProcesses();
assertThat(getRunningProcessInstances(PROCESS_DEFINITION_KEY, runtimeService()))
@@ -238,17 +241,15 @@ public void processInstanceMigrator_should_migrate_to_mapped_id_even_if_same_id_
.oneTaskHasKey("UserTask2")
.allTasksHaveFormkey(null);
- processInstanceMigrator.setMigrationInstructions(MigrationInstructions.builder()
- .putInstructions(PROCESS_DEFINITION_KEY, Arrays.asList(
- MinorMigrationInstructions.builder()
- .sourceMinorVersion(0)
- .targetMinorVersion(7)
- .migrationInstructions(Arrays.asList(
- new MigrationInstructionImpl("UserTask1", "UserTask7"),
- new MigrationInstructionImpl("UserTask2", "UserTask7")))
- .majorVersion(1)
- .build()))
- .build());
+ migrationInstructionsMap.putInstructions(PROCESS_DEFINITION_KEY, Arrays.asList(
+ MinorMigrationInstructions.builder()
+ .sourceMinorVersion(0)
+ .targetMinorVersion(7)
+ .migrationInstructions(Arrays.asList(
+ new MigrationInstructionImpl("UserTask1", "UserTask7"),
+ new MigrationInstructionImpl("UserTask2", "UserTask7")))
+ .majorVersion(1)
+ .build()));
processInstanceMigrator.migrateInstancesOfAllProcesses();
diff --git a/src/test/java/info/novatec/camunda/migrator/TestHelper.java b/src/test/java/info/novatec/camunda/migrator/integration/TestHelper.java
similarity index 97%
rename from src/test/java/info/novatec/camunda/migrator/TestHelper.java
rename to src/test/java/info/novatec/camunda/migrator/integration/TestHelper.java
index cc24f85..c57d806 100644
--- a/src/test/java/info/novatec/camunda/migrator/TestHelper.java
+++ b/src/test/java/info/novatec/camunda/migrator/integration/TestHelper.java
@@ -1,4 +1,4 @@
-package info.novatec.camunda.migrator;
+package info.novatec.camunda.migrator.integration;
import java.util.List;
diff --git a/src/test/java/info/novatec/camunda/migrator/assertions/ProcessInstanceListAsserter.java b/src/test/java/info/novatec/camunda/migrator/integration/assertions/ProcessInstanceListAsserter.java
similarity index 95%
rename from src/test/java/info/novatec/camunda/migrator/assertions/ProcessInstanceListAsserter.java
rename to src/test/java/info/novatec/camunda/migrator/integration/assertions/ProcessInstanceListAsserter.java
index 8a23a45..0af99f6 100644
--- a/src/test/java/info/novatec/camunda/migrator/assertions/ProcessInstanceListAsserter.java
+++ b/src/test/java/info/novatec/camunda/migrator/integration/assertions/ProcessInstanceListAsserter.java
@@ -1,4 +1,4 @@
-package info.novatec.camunda.migrator.assertions;
+package info.novatec.camunda.migrator.integration.assertions;
import lombok.RequiredArgsConstructor;
import org.assertj.core.api.Assertions;
diff --git a/src/test/java/info/novatec/camunda/migrator/assertions/TaskListAsserter.java b/src/test/java/info/novatec/camunda/migrator/integration/assertions/TaskListAsserter.java
similarity index 96%
rename from src/test/java/info/novatec/camunda/migrator/assertions/TaskListAsserter.java
rename to src/test/java/info/novatec/camunda/migrator/integration/assertions/TaskListAsserter.java
index 81436ed..6806670 100644
--- a/src/test/java/info/novatec/camunda/migrator/assertions/TaskListAsserter.java
+++ b/src/test/java/info/novatec/camunda/migrator/integration/assertions/TaskListAsserter.java
@@ -1,4 +1,4 @@
-package info.novatec.camunda.migrator.assertions;
+package info.novatec.camunda.migrator.integration.assertions;
import java.util.List;