diff options
2 files changed, 235 insertions, 0 deletions
diff --git a/bpmn/mso-infrastructure-bpmn/src/main/java/org/onap/so/bpmn/common/workflow/service/AutoProcessInstanceMigrationService.java b/bpmn/mso-infrastructure-bpmn/src/main/java/org/onap/so/bpmn/common/workflow/service/AutoProcessInstanceMigrationService.java new file mode 100644 index 0000000000..58d0c6d374 --- /dev/null +++ b/bpmn/mso-infrastructure-bpmn/src/main/java/org/onap/so/bpmn/common/workflow/service/AutoProcessInstanceMigrationService.java @@ -0,0 +1,111 @@ +package org.onap.so.bpmn.common.workflow.service; + +import java.util.ArrayList; +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.migration.MigrationInstruction; +import org.camunda.bpm.engine.migration.MigrationPlan; +import org.camunda.bpm.engine.migration.MigrationPlanExecutionBuilder; +import org.camunda.bpm.engine.repository.ProcessDefinition; +import org.camunda.bpm.engine.runtime.ProcessInstance; +import org.camunda.bpm.engine.runtime.ProcessInstanceQuery; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; + +@Service +public class AutoProcessInstanceMigrationService { + + private static Logger logger = LoggerFactory.getLogger(AutoProcessInstanceMigrationService.class); + + @Autowired + private Environment env; + @Autowired + protected ProcessEngine processEngine; + + @Value("${migration.autoMigrationEnabled:false}") + private boolean autoMigrationEnabled; + + private RuntimeService runtimeService; + private RepositoryService repositoryService; + private List<String> processDefinitionKeys; + + @EventListener(ApplicationReadyEvent.class) + protected void executeAutoProcessInstanceMigrations() { + if (autoMigrationEnabled) { + runtimeService = processEngine.getRuntimeService(); + repositoryService = processEngine.getRepositoryService(); + for (ProcessDefinition definition : getProcessDefinitions()) { + for (ProcessDefinition procDefOld : getOldProcessDefinitions(definition.getKey(), + definition.getVersion())) { + migrate(procDefOld.getId(), definition.getId()); + } + } + } + } + + protected List<ProcessDefinition> getProcessDefinitions() { + + List<ProcessDefinition> processDefinitions = new ArrayList<ProcessDefinition>(); + processDefinitionKeys = env.getProperty("migration.processDefinitionKeys", List.class, new ArrayList<String>()); + for (String key : processDefinitionKeys) { + processDefinitions.add(repositoryService.createProcessDefinitionQuery().processDefinitionKey(key) + .latestVersion().singleResult()); + } + return processDefinitions; + } + + private void migrate(String sourceProcessDefinitionId, String targetProcessDefinitionId) { + MigrationPlan migrationPlan = + runtimeService.createMigrationPlan(sourceProcessDefinitionId, targetProcessDefinitionId) + .mapEqualActivities().updateEventTriggers().build(); + List<String> activityIds = new ArrayList<>(); + + for (MigrationInstruction instruction : migrationPlan.getInstructions()) { + activityIds.add(instruction.getSourceActivityId()); + } + for (String activityId : activityIds) { + ProcessInstanceQuery activeProcessInstancesQuery = runtimeService.createProcessInstanceQuery() + .processDefinitionId(sourceProcessDefinitionId).activityIdIn(activityId).active(); + if (!activeProcessInstancesQuery.list().isEmpty()) { + logger.info("Migrating {} process instance(s) from {} to {}", + Long.valueOf(activeProcessInstancesQuery.count()), sourceProcessDefinitionId, + targetProcessDefinitionId); + MigrationPlanExecutionBuilder migration = + runtimeService.newMigration(migrationPlan).processInstanceQuery(activeProcessInstancesQuery); + migration.executeAsync(); + } + } + suspendEmptyProcessDefinition(sourceProcessDefinitionId); + } + + private void suspendEmptyProcessDefinition(String sourceProcessDefinitionId) { + List<ProcessInstance> activeProcessInstances = runtimeService.createProcessInstanceQuery() + .processDefinitionId(sourceProcessDefinitionId).active().list(); + if (activeProcessInstances.isEmpty()) { + repositoryService.suspendProcessDefinitionById(sourceProcessDefinitionId); + } else { + logger.info("Unable to migrate {} process instance(s) from {}", + Integer.valueOf(activeProcessInstances.size()), sourceProcessDefinitionId); + } + } + + protected List<ProcessDefinition> getOldProcessDefinitions(String key, int version) { + List<ProcessDefinition> processDefinitions = + repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).list(); + List<ProcessDefinition> oldProcessDefinitions = new ArrayList<>(); + for (ProcessDefinition processDef : processDefinitions) { + if (!processDef.isSuspended() && (processDef.getVersion() != version)) { + oldProcessDefinitions.add(processDef); + } + } + return oldProcessDefinitions; + } +} diff --git a/bpmn/mso-infrastructure-bpmn/src/test/java/org/onap/so/bpmn/common/workflow/service/AutoProcessInstanceMigrationServiceTest.java b/bpmn/mso-infrastructure-bpmn/src/test/java/org/onap/so/bpmn/common/workflow/service/AutoProcessInstanceMigrationServiceTest.java new file mode 100644 index 0000000000..36e828448d --- /dev/null +++ b/bpmn/mso-infrastructure-bpmn/src/test/java/org/onap/so/bpmn/common/workflow/service/AutoProcessInstanceMigrationServiceTest.java @@ -0,0 +1,124 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.so.bpmn.common.workflow.service; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doReturn; +import java.util.ArrayList; +import java.util.List; +import org.camunda.bpm.engine.ProcessEngine; +import org.camunda.bpm.engine.RepositoryService; +import org.camunda.bpm.engine.repository.ProcessDefinition; +import org.camunda.bpm.engine.repository.ProcessDefinitionQuery; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.core.env.Environment; + +@RunWith(MockitoJUnitRunner.class) +public class AutoProcessInstanceMigrationServiceTest { + + @Mock + private ProcessEngine processEngine; + + @Mock + private ProcessDefinition outdated; + + @Mock + private ProcessDefinition newDef; + + @Mock + private ProcessDefinition key; + + @Mock + private ProcessDefinition testKey; + + @Mock + private ProcessDefinition suspendedDef; + + @Mock + private RepositoryService repositoryService; + + @Mock + private ProcessDefinitionQuery query; + + @Mock + private ProcessDefinitionQuery keyQuery; + + @Mock + private Environment env; + + @Spy + @InjectMocks + private AutoProcessInstanceMigrationService migrationService; + + + @Test + public void getOldProcessDefinitionsTest() { + List<ProcessDefinition> expectedList = new ArrayList<>(); + expectedList.add(outdated); + + List<ProcessDefinition> defList = new ArrayList<>(); + defList.add(outdated); + defList.add(newDef); + defList.add(suspendedDef); + + + doReturn(query).when(repositoryService).createProcessDefinitionQuery(); + doReturn(query).when(query).processDefinitionKey("test"); + doReturn(defList).when(query).list(); + doReturn(3).when(outdated).getVersion(); + doReturn(4).when(newDef).getVersion(); + doReturn(true).when(suspendedDef).isSuspended(); + List<ProcessDefinition> outdatedList = migrationService.getOldProcessDefinitions("test", 4); + + assertEquals(expectedList, outdatedList); + } + + @Test + public void getProcessDefinitionsTest() { + List<ProcessDefinition> expected = new ArrayList<ProcessDefinition>(); + expected.add(testKey); + expected.add(key); + + List<String> processDefinitionKeys = new ArrayList<String>(); + processDefinitionKeys.add("testKey"); + processDefinitionKeys.add("key"); + + doReturn(processDefinitionKeys).when(env).getProperty("migration.processDefinitionKeys", List.class, + new ArrayList<String>()); + + doReturn(query).when(repositoryService).createProcessDefinitionQuery(); + doReturn(query).when(query).processDefinitionKey("testKey"); + doReturn(query).when(query).latestVersion(); + doReturn(testKey).when(query).singleResult(); + + doReturn(keyQuery).when(query).processDefinitionKey("key"); + doReturn(keyQuery).when(keyQuery).latestVersion(); + doReturn(key).when(keyQuery).singleResult(); + + List<ProcessDefinition> actualProcessDefinitions = migrationService.getProcessDefinitions(); + + assertEquals(expected, actualProcessDefinitions); + } +} |