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

org.camunda.bpm.engine.impl.migration.instance.MigratingProcessElementInstanceVisitor Maven / Gradle / Ivy

There is a newer version: 7.22.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.instance;

import java.util.LinkedList;
import java.util.List;

import org.camunda.bpm.engine.impl.migration.instance.MigratingProcessElementInstanceTopDownWalker.MigrationContext;
import org.camunda.bpm.engine.impl.pvm.process.ScopeImpl;
import org.camunda.bpm.engine.impl.tree.FlowScopeWalker;
import org.camunda.bpm.engine.impl.tree.ReferenceWalker;
import org.camunda.bpm.engine.impl.tree.TreeVisitor;

/**
 * @author Thorben Lindhauer
 *
 */
public abstract class MigratingProcessElementInstanceVisitor implements TreeVisitor {

  @Override
  public void visit(MigrationContext obj) {
    if (canMigrate(obj.processElementInstance)) {
      migrateProcessElementInstance(obj.processElementInstance, obj.scopeInstanceBranch);
    }
  }

  protected abstract boolean canMigrate(MigratingProcessElementInstance instance);

  protected abstract void instantiateScopes(
      MigratingScopeInstance ancestorScopeInstance,
      MigratingScopeInstanceBranch executionBranch,
      List scopesToInstantiate);

  protected void migrateProcessElementInstance(MigratingProcessElementInstance migratingInstance, MigratingScopeInstanceBranch migratingInstanceBranch) {
    final MigratingScopeInstance parentMigratingInstance = migratingInstance.getParent();

    ScopeImpl sourceScope = migratingInstance.getSourceScope();
    ScopeImpl targetScope = migratingInstance.getTargetScope();
    ScopeImpl targetFlowScope = targetScope.getFlowScope();
    ScopeImpl parentActivityInstanceTargetScope = parentMigratingInstance != null ? parentMigratingInstance.getTargetScope() : null;

    if (sourceScope != sourceScope.getProcessDefinition() && targetFlowScope != parentActivityInstanceTargetScope) {
      // create intermediate scopes

      // 1. manipulate execution tree

      // determine the list of ancestor scopes (parent, grandparent, etc.) for which
      //     no executions exist yet
      List nonExistingScopes = collectNonExistingFlowScopes(targetFlowScope, migratingInstanceBranch);

      // get the closest ancestor scope that is instantiated already
      ScopeImpl existingScope = nonExistingScopes.isEmpty() ?
          targetFlowScope :
          nonExistingScopes.get(0).getFlowScope();

      // and its scope instance
      MigratingScopeInstance ancestorScopeInstance = migratingInstanceBranch.getInstance(existingScope);

      // Instantiate the scopes as children of the scope execution
      instantiateScopes(ancestorScopeInstance, migratingInstanceBranch, nonExistingScopes);

      MigratingScopeInstance targetFlowScopeInstance = migratingInstanceBranch.getInstance(targetFlowScope);

      // 2. detach instance
      // The order of steps 1 and 2 avoids intermediate execution tree compaction
      // which in turn could overwrite some dependent instances (e.g. variables)
      migratingInstance.detachState();

      // 3. attach to newly created activity instance
      migratingInstance.attachState(targetFlowScopeInstance);
    }

    // 4. update state (e.g. activity id)
    migratingInstance.migrateState();

    // 5. migrate instance state other than execution-tree structure
    migratingInstance.migrateDependentEntities();
  }

  /**
   * Returns a list of flow scopes from the given scope until a scope is reached that is already present in the given
   * {@link MigratingScopeInstanceBranch} (exclusive). The order of the returned list is top-down, i.e. the highest scope
   * is the first element of the list.
   */
  protected List collectNonExistingFlowScopes(ScopeImpl scope, final MigratingScopeInstanceBranch migratingExecutionBranch) {
    FlowScopeWalker walker = new FlowScopeWalker(scope);
    final List result = new LinkedList();
    walker.addPreVisitor(new TreeVisitor() {

      @Override
      public void visit(ScopeImpl obj) {
        result.add(0, obj);
      }
    });

    walker.walkWhile(new ReferenceWalker.WalkCondition() {

      @Override
      public boolean isFulfilled(ScopeImpl element) {
        return migratingExecutionBranch.hasInstance(element);
      }
    });

    return result;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy