/**
   * Creates the consistency group used by the BlockObjects.
   *
   * @param name
   * @return
   */
  private BlockConsistencyGroup createBlockConsistencyGroup(
      String name, URI storageSystem, String type, boolean setType) {
    BlockConsistencyGroup cg = new BlockConsistencyGroup();
    URI cgURI = URIUtil.createId(BlockConsistencyGroup.class);
    cg.setId(cgURI);
    cg.setLabel(name);
    cg.setStorageController(storageSystem);

    if (type.equals(Types.LOCAL.name())) {
      // Set the 'old' field value so it can be migrated
      cg.setDeviceName("localArrayDeviceName");
    } else if (type.equals(Types.VPLEX.name())) {
      // Set the 'old' field value so it can be migrated
      cg.setDeviceName("vplexDeviceName");
    } else if (type.equals(Types.RP.name())) {
      // Set the 'old' field value so it can be migrated.
      cg.setDeviceName("rpDeviceName");
    } else if (type.equals(Types.SRDF.name())) {
      // Set the 'old' field value so it can be migrated
      cg.setDeviceName("srdfDeviceName");
    }

    if (setType) {
      cg.setType(type);
    }

    // Set the 'old' field value so it can be migrated
    _dbClient.createObject(cg);
    return cg;
  }
  /**
   * Verify the RP+VPlex consistency group and its volumes have been properly migrated.
   *
   * @throws Exception
   */
  private void verifyRpVplexConsistencyGroupMigration() throws Exception {
    log.info("Verifying RP+VPlex BlockConsistencyGroup and associated volume migration.");
    List<BlockObject> blockObjects = new ArrayList<BlockObject>();

    BlockConsistencyGroup rpVplexPrimaryCg =
        _dbClient.queryObject(BlockConsistencyGroup.class, rpVplexPrimaryConsistencyGroupURI);

    // Verify the RP+VPLEX consistency group was properly migrated
    verifyConsistencyGroupMigration(rpVplexPrimaryCg, Types.RP.name(), Types.VPLEX.name());

    Assert.assertNotNull(
        "The RP+VPlex BlockConsistencyGroup.systemConsistencyGroups field should be populated.",
        rpVplexPrimaryCg.getSystemConsistencyGroups());
    Assert.assertNotNull(
        "The RP+VPlex BlockConsistencyGroup.systemConsistencyGroups field should contain an entry for "
            + protectionSystemURI.toString(),
        rpVplexPrimaryCg.getSystemConsistencyGroups().get(protectionSystemURI.toString()));
    Assert.assertTrue(
        "The RP+VPlex BlockConsistencyGroup.systemConsistencyGroups field should contain a mapping for "
            + protectionSystemURI.toString()
            + "-> ViPR-"
            + rpVplexPrimaryCg.getLabel(),
        rpVplexPrimaryCg
            .getSystemConsistencyGroups()
            .get(protectionSystemURI.toString())
            .contains("ViPR-" + rpVplexPrimaryCg.getLabel()));

    // Verify that primary CG has a mapping reference for each of the VPlex storage system/cg name.
    for (URI rpVplexVolumeId : rpVplexVolumeToCgMapping.keySet()) {
      Volume rpVplexVolume = _dbClient.queryObject(Volume.class, rpVplexVolumeId);
      blockObjects.add(rpVplexVolume);

      // Get the VPlex consistency group
      URI cgUri = rpVplexVolumeToCgMapping.get(rpVplexVolumeId);
      BlockConsistencyGroup vplexCg = _dbClient.queryObject(BlockConsistencyGroup.class, cgUri);

      String cgName = vplexCg.getLabel();
      String clusterName = getVPlexClusterFromVolume(rpVplexVolume);
      String storageSystem = rpVplexVolume.getStorageController().toString();
      String clusterCgName = BlockConsistencyGroupUtils.buildClusterCgName(clusterName, cgName);

      // Verify that primary CG contains the correct mapping
      Assert.assertTrue(
          "The RP+VPlex BlockConsistencyGroup.systemConsistencyGroups field should contain a mapping for "
              + storageSystem
              + "->"
              + clusterCgName,
          rpVplexPrimaryCg.getSystemConsistencyGroups().get(storageSystem).contains(clusterCgName));

      // Verify that the VPlex CG has been marked for deletion
      Assert.assertTrue(
          "The VPlex BlockConsistencyGroup " + vplexCg.getLabel() + "should be inactive.",
          vplexCg.getInactive());
    }

    // Verify the volume migration took place correctly
    verifyBlockObjects(blockObjects);
  }
  /**
   * Prepare the VPlex volumes and associated consistency group data.
   *
   * @throws Exception
   */
  private void prepareVPlexConsistencyGroupData() throws Exception {
    // Create a VPlex storage system
    StorageSystem storageSystem = createStorageSystem(true);

    // Create the VPlex volumes and add them to the VPlex consistency group
    List<Volume> vplexVolumes = createVPlexVolumes("vplexVolume", 3, storageSystem.getId());
    // Prior to 2.2, VPlex only CGs (nothing to do with RP) did not set the CG type of VPLEX. So we
    // pass false here.
    BlockConsistencyGroup vplexCg =
        createBlockConsistencyGroup("vplexCg", storageSystem.getId(), Types.VPLEX.name(), false);
    // Save a references to the cg for migration verification
    vplexConsistencyGroupURI = vplexCg.getId();
    // Add the VPlex volumes to the VPlex consistency group
    addVolumesToBlockConsistencyGroup(vplexCg.getId(), vplexVolumes);
  }
  /**
   * Verify the VPlex consistency group and its volumes have been properly migrated.
   *
   * @throws Exception
   */
  private void verifyVplexConsistencyGroupMigration() throws Exception {
    log.info("Verifying VPlex BlockConsistencyGroup and associated volume migration.");

    BlockConsistencyGroup vplexCg =
        _dbClient.queryObject(BlockConsistencyGroup.class, vplexConsistencyGroupURI);
    Iterator<Volume> vplexVolumeItr =
        _dbClient.queryIterativeObjects(Volume.class, vplexVolumeURIs);

    // Verify the VPLEX consistency group was properly migrated
    verifyConsistencyGroupMigration(vplexCg, Types.VPLEX.name());

    while (vplexVolumeItr.hasNext()) {
      Volume vplexVolume = vplexVolumeItr.next();
      // Get the VPlex consistency group
      String cgName = vplexCg.getLabel();
      String clusterName = getVPlexClusterFromVolume(vplexVolume);
      String storageSystem = vplexVolume.getStorageController().toString();
      String clusterCgName = BlockConsistencyGroupUtils.buildClusterCgName(clusterName, cgName);

      // Verify that primary CG contains the correct mapping
      Assert.assertNotNull(
          "The VPlex BlockConsistencyGroup.vplexStorageSystemToCg field should be populated.",
          vplexCg.getSystemConsistencyGroups());
      Assert.assertTrue(
          "The VPlex BlockConsistencyGroup.vplexStorageSystemToCg should contain a key for storage system "
              + storageSystem,
          vplexCg.getSystemConsistencyGroups().containsKey(storageSystem));
      Assert.assertTrue(
          "The VPlex BlockConsistencyGroup.vplexStorageSystemToCg field should contain a mapping for "
              + storageSystem
              + "->"
              + clusterCgName,
          vplexCg.getSystemConsistencyGroups().get(storageSystem).contains(clusterCgName));
    }

    // Verify the volume migration took place correctly
    List<BlockObject> blockObjects = new ArrayList<BlockObject>();
    while (vplexVolumeItr.hasNext()) {
      blockObjects.add(vplexVolumeItr.next());
    }

    verifyBlockObjects(blockObjects);
  }
  /**
   * Creates the RP source volume/journal and the specified number of target/journal volumes.
   *
   * @param volumeName
   * @param numTargets
   */
  private List<Volume> createRpVolumes(
      String volumeName, int numTargets, ProtectionSet protectionSet, boolean isRpVPlex) {
    List<Volume> volumes = new ArrayList<Volume>();

    StringSet associatedVolumes = new StringSet();
    associatedVolumes.add("associatedVol1");

    StorageSystem storageSystem = null;
    if (isRpVPlex) {
      storageSystem = createStorageSystem(true);
    } else {
      storageSystem = createStorageSystem(false);
    }

    String rsetName = "RSet-" + volumeName;

    Volume sourceVolume = new Volume();
    URI sourceVolumeURI = URIUtil.createId(Volume.class);
    volumes.add(sourceVolume);
    sourceVolume.setId(sourceVolumeURI);
    sourceVolume.setLabel(volumeName);
    sourceVolume.setPersonality(Volume.PersonalityTypes.SOURCE.toString());
    sourceVolume.setRSetName(rsetName);
    sourceVolume.setProtectionSet(new NamedURI(protectionSet.getId(), sourceVolume.getLabel()));
    sourceVolume.setStorageController(storageSystem.getId());
    if (isRpVPlex) {
      sourceVolume.setAssociatedVolumes(associatedVolumes);
      sourceVolume.setNativeId(
          "/clusters/cluster-1/virtual-volumes/device_V000195701573-01E7A_vol");
      // Create a VPLEX ViPR BlockConsistencyGroup for the source volume
      BlockConsistencyGroup sourceVolumeCg =
          createBlockConsistencyGroup(
              sourceVolume.getLabel() + "-CG", storageSystem.getId(), Types.VPLEX.name(), true);
      addVolumeToBlockConsistencyGroup(sourceVolumeCg.getId(), sourceVolume);
      rpVplexVolumeToCgMapping.put(sourceVolumeURI, sourceVolumeCg.getId());
    } else {
      rpVolumeURIs.add(sourceVolumeURI);
    }
    _dbClient.createObject(sourceVolume);

    Volume sourceVolumeJournal = new Volume();
    URI sourceVolumeJournalURI = URIUtil.createId(Volume.class);
    volumes.add(sourceVolumeJournal);
    sourceVolumeJournal.setId(sourceVolumeJournalURI);
    sourceVolumeJournal.setLabel(volumeName + RP_SRC_JOURNAL_APPEND);
    sourceVolumeJournal.setPersonality(Volume.PersonalityTypes.METADATA.toString());
    sourceVolumeJournal.setProtectionSet(
        new NamedURI(protectionSet.getId(), sourceVolumeJournal.getLabel()));
    sourceVolumeJournal.setStorageController(storageSystem.getId());
    if (isRpVPlex) {
      sourceVolumeJournal.setAssociatedVolumes(associatedVolumes);
      sourceVolumeJournal.setNativeId(
          "/clusters/cluster-1/virtual-volumes/device_V000195701573-01E7B_vol");
      // Create a VPLEX ViPR BlockConsistencyGroup for the source journal volume
      BlockConsistencyGroup sourceVolumeJournalCg =
          createBlockConsistencyGroup(
              sourceVolumeJournal.getLabel() + "-CG",
              storageSystem.getId(),
              Types.VPLEX.name(),
              true);
      addVolumeToBlockConsistencyGroup(sourceVolumeJournalCg.getId(), sourceVolumeJournal);
      rpVplexVolumeToCgMapping.put(sourceVolumeJournalURI, sourceVolumeJournalCg.getId());
    } else {
      rpVolumeURIs.add(sourceVolumeJournalURI);
    }
    _dbClient.createObject(sourceVolumeJournal);

    for (int i = 1; i <= numTargets; i++) {
      Volume sourceVolumeTarget = new Volume();
      URI sourceVolumeTargetURI = URIUtil.createId(Volume.class);
      volumes.add(sourceVolumeTarget);
      sourceVolumeTarget.setId(sourceVolumeTargetURI);
      sourceVolumeTarget.setLabel(volumeName + RP_TGT_APPEND + "vArray" + i);
      sourceVolumeTarget.setPersonality(Volume.PersonalityTypes.TARGET.toString());
      sourceVolumeTarget.setRSetName(rsetName);
      sourceVolumeTarget.setProtectionSet(
          new NamedURI(protectionSet.getId(), sourceVolumeTarget.getLabel()));
      sourceVolumeTarget.setStorageController(storageSystem.getId());
      if (isRpVPlex) {
        sourceVolumeTarget.setAssociatedVolumes(associatedVolumes);
        sourceVolumeTarget.setNativeId(
            "/clusters/cluster-2/virtual-volumes/device_V000195701573-01E7C_vol" + i);
        // Create a VPLEX ViPR BlockConsistencyGroup for the target volume
        BlockConsistencyGroup sourceVolumeTargetCg =
            createBlockConsistencyGroup(
                sourceVolumeTarget.getLabel() + "-CG",
                storageSystem.getId(),
                Types.VPLEX.name(),
                true);
        addVolumeToBlockConsistencyGroup(sourceVolumeTargetCg.getId(), sourceVolumeTarget);
        rpVplexVolumeToCgMapping.put(sourceVolumeTargetURI, sourceVolumeTargetCg.getId());
      } else {
        rpVolumeURIs.add(sourceVolumeTargetURI);
      }

      _dbClient.createObject(sourceVolumeTarget);

      Volume sourceVolumeTargetJournal = new Volume();
      URI sourceVolumeTargetJournalURI = URIUtil.createId(Volume.class);
      volumes.add(sourceVolumeTargetJournal);
      sourceVolumeTargetJournal.setId(sourceVolumeTargetJournalURI);
      sourceVolumeTargetJournal.setLabel(volumeName + RP_TGT_JOURNAL_APPEND + "vArray" + i);
      sourceVolumeTargetJournal.setPersonality(Volume.PersonalityTypes.METADATA.toString());
      sourceVolumeTargetJournal.setProtectionSet(
          new NamedURI(protectionSet.getId(), sourceVolumeTargetJournal.getLabel()));
      sourceVolumeTargetJournal.setStorageController(storageSystem.getId());
      if (isRpVPlex) {
        sourceVolumeTargetJournal.setAssociatedVolumes(associatedVolumes);
        sourceVolumeTargetJournal.setNativeId(
            "/clusters/cluster-2/virtual-volumes/device_V000195701573-01ED_vol" + i);
        // Create a VPLEX ViPR BlockConsistencyGroup for the source target journal volume
        BlockConsistencyGroup sourceVolumeTargetJournalCg =
            createBlockConsistencyGroup(
                sourceVolumeTargetJournal.getLabel() + "-CG",
                storageSystem.getId(),
                Types.VPLEX.name(),
                true);
        addVolumeToBlockConsistencyGroup(
            sourceVolumeTargetJournalCg.getId(), sourceVolumeTargetJournal);
        rpVplexVolumeToCgMapping.put(
            sourceVolumeTargetJournalURI, sourceVolumeTargetJournalCg.getId());
      } else {
        rpVolumeURIs.add(sourceVolumeTargetJournalURI);
      }
      _dbClient.createObject(sourceVolumeTargetJournal);
    }

    return volumes;
  }