/** {@inheritDoc} */
  @Override
  public Map<URI, Volume> getFullCopySetMap(BlockObject fcSourceObj, Volume fullCopyVolume) {
    Map<URI, Volume> fullCopyMap = new HashMap<URI, Volume>();

    // Get the source side backend volume of the VPLEX source Volume.
    Volume sourceVolume = (Volume) fcSourceObj;
    Volume srcBackendSrcVolume =
        VPlexUtil.getVPLEXBackendVolume(sourceVolume, true, _dbClient, true);

    // Get the source side backend volume of the VPLEX volume copy.
    // This is the backend volume full copy.
    Volume fcBackendSrcVolume =
        VPlexUtil.getVPLEXBackendVolume(fullCopyVolume, true, _dbClient, true);

    // Get the backend full copy set.
    Map<URI, Volume> backendFullCopyMap =
        super.getFullCopySetMap(srcBackendSrcVolume, fcBackendSrcVolume);

    // Now we need to get the VPLEX volumes for these backend volumes.
    // These will be the VPLEX full copy volumes in the set.
    Iterator<URI> backendCopyIter = backendFullCopyMap.keySet().iterator();
    while (backendCopyIter.hasNext()) {
      URIQueryResultList queryResults = new URIQueryResultList();
      _dbClient.queryByConstraint(
          AlternateIdConstraint.Factory.getVolumeByAssociatedVolumesConstraint(
              backendCopyIter.next().toString()),
          queryResults);
      URI vplexCopyVolumeURI = queryResults.iterator().next();
      fullCopyMap.put(vplexCopyVolumeURI, _dbClient.queryObject(Volume.class, vplexCopyVolumeURI));
    }

    return fullCopyMap;
  }
  /** {@inheritDoc} */
  @Override
  public VolumeRestRep checkProgress(URI sourceURI, Volume fullCopyVolume) {
    // Get the native backend full copy volume for this VPLEX
    // full copy volume.
    Volume nativeFullCopyVolume = VPlexUtil.getVPLEXBackendVolume(fullCopyVolume, true, _dbClient);

    // Call super to check the progress of the backend full
    // copy volume.
    Integer percentSynced =
        getSyncPercentage(nativeFullCopyVolume.getAssociatedSourceVolume(), nativeFullCopyVolume);

    // The synchronization progress of the VPLEX full copy is that
    // of the backend full copy.
    VolumeRestRep volumeRestRep = BlockMapper.map(_dbClient, fullCopyVolume);
    volumeRestRep.getProtection().getFullCopyRep().setPercentSynced(percentSynced);
    return volumeRestRep;
  }
  /** {@inheritDoc} */
  @Override
  public void validateFullCopyCreateRequest(List<BlockObject> fcSourceObjList, int count) {
    if (fcSourceObjList.size() > 0) {
      URI fcSourceObjURI = fcSourceObjList.get(0).getId();
      if (URIUtil.isType(fcSourceObjURI, BlockSnapshot.class)) {
        // Currently you cannot create a full copy of a VPLEX snapshot.
        throw APIException.badRequests.cantCreateFullCopyForVPlexSnapshot();
      } else {
        // Call super first.
        super.validateFullCopyCreateRequest(fcSourceObjList, count);

        // Platform specific checks.
        for (BlockObject fcSourceObj : fcSourceObjList) {
          Volume fcSourceVolume = (Volume) fcSourceObj;
          StorageSystem system =
              _dbClient.queryObject(StorageSystem.class, fcSourceVolume.getStorageController());
          if (DiscoveredDataObject.Type.vplex.name().equals(system.getSystemType())) {
            // If the volume is a VPLEX volume, then we need to be sure that
            // storage pool of the source backend volume of the VPLEX volume,
            // which is volume used to create the native full copy, supports
            // full copy.
            Volume srcBackendVolume =
                VPlexUtil.getVPLEXBackendVolume(fcSourceVolume, true, _dbClient, true);
            StoragePool storagePool =
                _dbClient.queryObject(StoragePool.class, srcBackendVolume.getPool());
            verifyFullCopySupportedForStoragePool(storagePool);

            // If the full copy source is itself a full copy, it is not
            // detached, and the native full copy i.e., the source side
            // backend volume, is VNX, then creating a full copy of the
            // volume will fail. As such, we prevent it.
            if ((BlockFullCopyUtils.isVolumeFullCopy(fcSourceVolume, _dbClient))
                && (!BlockFullCopyUtils.isFullCopyDetached(fcSourceVolume, _dbClient))) {
              URI backendSystemURI = srcBackendVolume.getStorageController();
              StorageSystem backendSystem =
                  _dbClient.queryObject(StorageSystem.class, backendSystemURI);
              if (DiscoveredDataObject.Type.vnxblock.name().equals(backendSystem.getSystemType())) {
                throw APIException.badRequests.cantCreateFullCopyOfVPlexFullCopyUsingVNX();
              }
            }
          }
        }
      }
    }
  }
  /** {@inheritDoc} */
  @Override
  protected void verifyFullCopyRequestCount(BlockObject fcSourceObj, int count) {
    // Verify the requested copy count. You can only
    // have as many as is allowed by the source backend
    // volume.
    Volume fcSourceVolume = (Volume) fcSourceObj;
    Volume srcBackendVolume =
        VPlexUtil.getVPLEXBackendVolume(fcSourceVolume, true, _dbClient, true);
    // Verify if the source backend volume supports full copy
    URI systemURI = fcSourceObj.getStorageController();
    StorageSystem system = _dbClient.queryObject(StorageSystem.class, systemURI);
    int maxCount = Integer.MAX_VALUE;
    if (system != null) {
      maxCount = BlockFullCopyManager.getMaxFullCopiesForSystemType(system.getSystemType());
    }
    // If max count is 0, then the operation is not supported
    if (maxCount == 0) {
      throw APIException.badRequests.fullCopyNotSupportedByBackendSystem(fcSourceVolume.getId());
    }

    BlockFullCopyUtils.validateActiveFullCopyCount(srcBackendVolume, count, _dbClient);
  }