All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.camunda.bpm.engine.impl.migration.MigrateProcessInstanceCmd Maven / Gradle / Ivy

There is a newer version: 7.23.0-alpha1
Show newest version
/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
 * under one or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership. Camunda licenses this file to you under the Apache License,
 * Version 2.0; 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.
 */
package org.camunda.bpm.engine.impl.migration;


import static org.camunda.bpm.engine.impl.util.EnsureUtil.ensureNotContainsNull;
import static org.camunda.bpm.engine.impl.util.EnsureUtil.ensureNotEmpty;
import static org.camunda.bpm.engine.impl.util.EnsureUtil.ensureNotNull;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;

import org.camunda.bpm.engine.BadUserRequestException;
import org.camunda.bpm.engine.impl.ProcessEngineImpl;
import org.camunda.bpm.engine.impl.ProcessEngineLogger;
import org.camunda.bpm.engine.impl.cfg.CommandChecker;
import org.camunda.bpm.engine.impl.cmd.SetExecutionVariablesCmd;
import org.camunda.bpm.engine.impl.context.ProcessApplicationContextUtil;
import org.camunda.bpm.engine.impl.interceptor.Command;
import org.camunda.bpm.engine.impl.interceptor.CommandContext;
import org.camunda.bpm.engine.impl.migration.instance.DeleteUnmappedInstanceVisitor;
import org.camunda.bpm.engine.impl.migration.instance.MigratingActivityInstance;
import org.camunda.bpm.engine.impl.migration.instance.MigratingActivityInstanceVisitor;
import org.camunda.bpm.engine.impl.migration.instance.MigratingCompensationEventSubscriptionInstance;
import org.camunda.bpm.engine.impl.migration.instance.MigratingEventScopeInstance;
import org.camunda.bpm.engine.impl.migration.instance.MigratingProcessElementInstanceTopDownWalker;
import org.camunda.bpm.engine.impl.migration.instance.MigratingProcessInstance;
import org.camunda.bpm.engine.impl.migration.instance.MigratingScopeInstance;
import org.camunda.bpm.engine.impl.migration.instance.MigratingScopeInstanceBottomUpWalker;
import org.camunda.bpm.engine.impl.migration.instance.MigratingTransitionInstance;
import org.camunda.bpm.engine.impl.migration.instance.MigrationCompensationInstanceVisitor;
import org.camunda.bpm.engine.impl.migration.instance.parser.MigratingInstanceParser;
import org.camunda.bpm.engine.impl.migration.validation.instance.MigratingActivityInstanceValidationReportImpl;
import org.camunda.bpm.engine.impl.migration.validation.instance.MigratingActivityInstanceValidator;
import org.camunda.bpm.engine.impl.migration.validation.instance.MigratingCompensationInstanceValidator;
import org.camunda.bpm.engine.impl.migration.validation.instance.MigratingProcessInstanceValidationReportImpl;
import org.camunda.bpm.engine.impl.migration.validation.instance.MigratingTransitionInstanceValidationReportImpl;
import org.camunda.bpm.engine.impl.migration.validation.instance.MigratingTransitionInstanceValidator;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;
import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.camunda.bpm.engine.migration.MigrationPlan;

/**
 * How migration works:
 *
 * 
    *
  1. Validate migration instructions. *
  2. Delete activity instances that are not going to be migrated, invoking execution listeners * and io mappings. This is performed in a bottom-up fashion in the activity instance tree and ensures * that the "upstream" tree is always consistent with respect to the old process definition. *
  3. Migrate and create activity instances. Creation invokes execution listeners * and io mappings. This is performed in a top-down fashion in the activity instance tree and * ensures that the "upstream" tree is always consistent with respect to the new process definition. *
* @author Thorben Lindhauer */ public class MigrateProcessInstanceCmd extends AbstractMigrationCmd implements Command { protected static final MigrationLogger LOGGER = ProcessEngineLogger.MIGRATION_LOGGER; protected boolean skipJavaSerializationFormatCheck; public MigrateProcessInstanceCmd(MigrationPlanExecutionBuilderImpl migrationPlanExecutionBuilder, boolean skipJavaSerializationFormatCheck) { super(migrationPlanExecutionBuilder); this.skipJavaSerializationFormatCheck = skipJavaSerializationFormatCheck; } @Override public Void execute(final CommandContext commandContext) { final MigrationPlan migrationPlan = executionBuilder.getMigrationPlan(); final Collection processInstanceIds = collectProcessInstanceIds(); ensureNotNull(BadUserRequestException.class, "Migration plan cannot be null", "migration plan", migrationPlan); ensureNotEmpty(BadUserRequestException.class, "Process instance ids cannot empty", "process instance ids", processInstanceIds); ensureNotContainsNull(BadUserRequestException.class, "Process instance ids cannot be null", "process instance ids", processInstanceIds); ProcessDefinitionEntity sourceDefinition = resolveSourceProcessDefinition(commandContext); final ProcessDefinitionEntity targetDefinition = resolveTargetProcessDefinition(commandContext); checkAuthorizations(commandContext, sourceDefinition, targetDefinition); writeUserOperationLog(commandContext, sourceDefinition, targetDefinition, processInstanceIds.size(), migrationPlan.getVariables(), false); commandContext.runWithoutAuthorization((Callable) () -> { for (String processInstanceId : processInstanceIds) { migrateProcessInstance(commandContext, processInstanceId, migrationPlan, targetDefinition, skipJavaSerializationFormatCheck); } return null; }); return null; } public Void migrateProcessInstance(CommandContext commandContext, String processInstanceId, MigrationPlan migrationPlan, ProcessDefinitionEntity targetProcessDefinition, boolean skipJavaSerializationFormatCheck) { ensureNotNull(BadUserRequestException.class, "Process instance id cannot be null", "process instance id", processInstanceId); final ExecutionEntity processInstance = commandContext.getExecutionManager() .findExecutionById(processInstanceId); ensureProcessInstanceExist(processInstanceId, processInstance); ensureOperationAllowed(commandContext, processInstance, targetProcessDefinition); ensureSameProcessDefinition(processInstance, migrationPlan.getSourceProcessDefinitionId()); MigratingProcessInstanceValidationReportImpl processInstanceReport = new MigratingProcessInstanceValidationReportImpl(); // Initialize migration: match migration instructions to activity instances and collect required entities ProcessEngineImpl processEngine = commandContext.getProcessEngineConfiguration() .getProcessEngine(); MigratingInstanceParser migratingInstanceParser = new MigratingInstanceParser(processEngine); final MigratingProcessInstance migratingProcessInstance = migratingInstanceParser.parse(processInstanceId, migrationPlan, processInstanceReport); validateInstructions(commandContext, migratingProcessInstance, processInstanceReport); if (processInstanceReport.hasFailures()) { throw LOGGER.failingMigratingProcessInstanceValidation(processInstanceReport); } executeInContext(() -> deleteUnmappedActivityInstances(migratingProcessInstance), migratingProcessInstance.getSourceDefinition()); executeInContext(() -> migrateProcessInstance(migratingProcessInstance), migratingProcessInstance.getTargetDefinition()); Map variables = migrationPlan.getVariables(); if (variables != null) { // we don't need a context switch here since when setting an execution triggering variable, // a context switch is performed at a later point via command invocation context commandContext.executeWithOperationLogPrevented( new SetExecutionVariablesCmd(processInstanceId, variables, false, skipJavaSerializationFormatCheck)); } return null; } protected void executeInContext(final Runnable runnable, ProcessDefinitionEntity contextDefinition) { ProcessApplicationContextUtil.doContextSwitch(runnable, contextDefinition); } /** * delete unmapped instances in a bottom-up fashion (similar to deleteCascade and regular BPMN execution) */ protected void deleteUnmappedActivityInstances(MigratingProcessInstance migratingProcessInstance) { boolean isSkipCustomListeners = executionBuilder.isSkipCustomListeners(); boolean isSkipIoMappings = executionBuilder.isSkipIoMappings(); final DeleteUnmappedInstanceVisitor visitor = new DeleteUnmappedInstanceVisitor(isSkipCustomListeners, isSkipIoMappings); Set leafInstances = collectLeafInstances(migratingProcessInstance); for (MigratingScopeInstance leafInstance : leafInstances) { MigratingScopeInstanceBottomUpWalker walker = new MigratingScopeInstanceBottomUpWalker(leafInstance); walker.addPreVisitor(visitor); walker.walkUntil(element -> { // walk until top of instance tree is reached or until // a node is reached for which we have not yet visited every child return element == null || !visitor.hasVisitedAll(element.getChildScopeInstances()); }); } } protected Set collectLeafInstances(MigratingProcessInstance migratingProcessInstance) { Set leafInstances = new HashSet<>(); Collection migratingScopeInstances = migratingProcessInstance.getMigratingScopeInstances(); for (MigratingScopeInstance migratingScopeInstance : migratingScopeInstances) { if (migratingScopeInstance.getChildScopeInstances().isEmpty()) { leafInstances.add(migratingScopeInstance); } } return leafInstances; } protected void validateInstructions(CommandContext commandContext, MigratingProcessInstance migratingProcessInstance, MigratingProcessInstanceValidationReportImpl processInstanceReport) { List migratingActivityInstanceValidators = commandContext.getProcessEngineConfiguration().getMigratingActivityInstanceValidators(); List migratingTransitionInstanceValidators = commandContext.getProcessEngineConfiguration().getMigratingTransitionInstanceValidators(); List migratingCompensationInstanceValidators = commandContext.getProcessEngineConfiguration().getMigratingCompensationInstanceValidators(); Map instanceReports = new HashMap<>(); Collection migratingActivityInstances = migratingProcessInstance.getMigratingActivityInstances(); for (MigratingActivityInstance migratingActivityInstance : migratingActivityInstances) { MigratingActivityInstanceValidationReportImpl instanceReport = validateActivityInstance(migratingActivityInstance, migratingProcessInstance, migratingActivityInstanceValidators); instanceReports.put(migratingActivityInstance, instanceReport); } Collection migratingEventScopeInstances = migratingProcessInstance.getMigratingEventScopeInstances(); for (MigratingEventScopeInstance migratingEventScopeInstance : migratingEventScopeInstances) { MigratingActivityInstance ancestorInstance = migratingEventScopeInstance.getClosestAncestorActivityInstance(); validateEventScopeInstance( migratingEventScopeInstance, migratingProcessInstance, migratingCompensationInstanceValidators, instanceReports.get(ancestorInstance)); } for (MigratingCompensationEventSubscriptionInstance migratingEventSubscriptionInstance : migratingProcessInstance.getMigratingCompensationSubscriptionInstances()) { MigratingActivityInstance ancestorInstance = migratingEventSubscriptionInstance.getClosestAncestorActivityInstance(); validateCompensateSubscriptionInstance( migratingEventSubscriptionInstance, migratingProcessInstance, migratingCompensationInstanceValidators, instanceReports.get(ancestorInstance)); } for (MigratingActivityInstanceValidationReportImpl instanceReport : instanceReports.values()) { if (instanceReport.hasFailures()) { processInstanceReport.addActivityInstanceReport(instanceReport); } } Collection migratingTransitionInstances = migratingProcessInstance.getMigratingTransitionInstances(); for (MigratingTransitionInstance migratingTransitionInstance : migratingTransitionInstances) { MigratingTransitionInstanceValidationReportImpl instanceReport = validateTransitionInstance(migratingTransitionInstance, migratingProcessInstance, migratingTransitionInstanceValidators); if (instanceReport.hasFailures()) { processInstanceReport.addTransitionInstanceReport(instanceReport); } } } protected MigratingActivityInstanceValidationReportImpl validateActivityInstance( MigratingActivityInstance migratingActivityInstance, MigratingProcessInstance migratingProcessInstance, List migratingActivityInstanceValidators) { MigratingActivityInstanceValidationReportImpl instanceReport = new MigratingActivityInstanceValidationReportImpl(migratingActivityInstance); for (MigratingActivityInstanceValidator migratingActivityInstanceValidator : migratingActivityInstanceValidators) { migratingActivityInstanceValidator.validate(migratingActivityInstance, migratingProcessInstance, instanceReport); } return instanceReport; } protected MigratingTransitionInstanceValidationReportImpl validateTransitionInstance( MigratingTransitionInstance migratingTransitionInstance, MigratingProcessInstance migratingProcessInstance, List migratingTransitionInstanceValidators) { MigratingTransitionInstanceValidationReportImpl instanceReport = new MigratingTransitionInstanceValidationReportImpl(migratingTransitionInstance); for (MigratingTransitionInstanceValidator migratingTransitionInstanceValidator : migratingTransitionInstanceValidators) { migratingTransitionInstanceValidator.validate(migratingTransitionInstance, migratingProcessInstance, instanceReport); } return instanceReport; } protected void validateEventScopeInstance(MigratingEventScopeInstance eventScopeInstance, MigratingProcessInstance migratingProcessInstance, List migratingTransitionInstanceValidators, MigratingActivityInstanceValidationReportImpl instanceReport ) { for (MigratingCompensationInstanceValidator validator : migratingTransitionInstanceValidators) { validator.validate(eventScopeInstance, migratingProcessInstance, instanceReport); } } protected void validateCompensateSubscriptionInstance( MigratingCompensationEventSubscriptionInstance eventSubscriptionInstance, MigratingProcessInstance migratingProcessInstance, List migratingTransitionInstanceValidators, MigratingActivityInstanceValidationReportImpl instanceReport ) { for (MigratingCompensationInstanceValidator validator : migratingTransitionInstanceValidators) { validator.validate(eventSubscriptionInstance, migratingProcessInstance, instanceReport); } } /** * Migrate activity instances to their new activities and process definition. Creates new * scope instances as necessary. */ protected void migrateProcessInstance(MigratingProcessInstance migratingProcessInstance) { MigratingActivityInstance rootActivityInstance = migratingProcessInstance.getRootInstance(); MigratingProcessElementInstanceTopDownWalker walker = new MigratingProcessElementInstanceTopDownWalker(rootActivityInstance); walker.addPreVisitor( new MigratingActivityInstanceVisitor( executionBuilder.isSkipCustomListeners(), executionBuilder.isSkipIoMappings())); walker.addPreVisitor(new MigrationCompensationInstanceVisitor()); walker.walkUntil(); } protected void ensureProcessInstanceExist(String processInstanceId, ExecutionEntity processInstance) { if (processInstance == null) { throw LOGGER.processInstanceDoesNotExist(processInstanceId); } } protected void ensureSameProcessDefinition(ExecutionEntity processInstance, String processDefinitionId) { if (!processDefinitionId.equals(processInstance.getProcessDefinitionId())) { throw LOGGER.processDefinitionOfInstanceDoesNotMatchMigrationPlan(processInstance, processDefinitionId); } } protected void ensureOperationAllowed(CommandContext commandContext, ExecutionEntity processInstance, ProcessDefinitionEntity targetProcessDefinition) { List commandCheckers = commandContext.getProcessEngineConfiguration() .getCommandCheckers(); for(CommandChecker checker : commandCheckers) { checker.checkMigrateProcessInstance(processInstance, targetProcessDefinition); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy