protected void migrateProcessInstance(MigratingProcessInstance migratingProcessInstance) {
    MigratingActivityInstance rootActivityInstance =
        migratingProcessInstance.getMigratingInstance(
            migratingProcessInstance.getProcessInstanceId());

    migrateActivityInstance(
        migratingProcessInstance, new MigratingExecutionBranch(), rootActivityInstance);
  }
  protected void migrateActivityInstance(
      MigratingProcessInstance migratingProcessInstance,
      MigratingExecutionBranch migratingExecutionBranch,
      MigratingActivityInstance migratingActivityInstance) {

    ActivityInstance activityInstance = migratingActivityInstance.getActivityInstance();

    if (!activityInstance.getId().equals(activityInstance.getProcessInstanceId())) {
      final MigratingActivityInstance parentMigratingInstance =
          migratingProcessInstance.getMigratingInstance(
              activityInstance.getParentActivityInstanceId());

      ScopeImpl targetFlowScope = migratingActivityInstance.getTargetScope().getFlowScope();
      ScopeImpl parentActivityInstanceTargetScope = parentMigratingInstance.getTargetScope();

      if (targetFlowScope != parentActivityInstanceTargetScope) {
        // create intermediate scopes

        ExecutionEntity flowScopeExecution = migratingActivityInstance.getFlowScopeExecution();

        // 1. detach activity instance
        migratingActivityInstance.detachState();

        // 2. manipulate execution tree
        ExecutionEntity targetExecution = migratingExecutionBranch.getExecution(targetFlowScope);

        if (targetExecution == null) {
          targetExecution =
              createMissingTargetFlowScopeExecution(
                  flowScopeExecution, (PvmActivity) targetFlowScope);
          migratingExecutionBranch.registerExecution(targetFlowScope, targetExecution);
        } else {
          targetExecution = (ExecutionEntity) targetExecution.createConcurrentExecution();
        }

        // 3. attach to newly created execution
        migratingActivityInstance.attachState(targetExecution);
      }
    }

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

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

    // Let activity instances on the same level of subprocess share the same execution context
    // of newly created scope executions.
    // This ensures that newly created scope executions
    // * are reused to attach activity instances to when the activity instances share a
    //   common ancestor path to the process instance
    // * are not reused when activity instances are in unrelated branches of the execution tree
    migratingExecutionBranch = migratingExecutionBranch.copy();

    for (ActivityInstance childInstance : activityInstance.getChildActivityInstances()) {
      MigratingActivityInstance migratingChildInstance =
          migratingProcessInstance.getMigratingInstance(childInstance.getId());
      migrateActivityInstance(
          migratingProcessInstance, migratingExecutionBranch, migratingChildInstance);
    }
  }