/**
  * Validate the SourceVolume VArray details with ingested target volumes VArray.
  *
  * @param unManagedVolume
  * @param VirtualPool
  * @return
  */
 private void validateSourceVolumeVarrayWithTargetVPool(
     UnManagedVolume unManagedVolume, VirtualPool sourceVPool) {
   StringSetMap unManagedVolumeInformation = unManagedVolume.getVolumeInformation();
   // find whether all targets are ingested
   StringSet targetUnManagedVolumeGuids =
       unManagedVolumeInformation.get(SupportedVolumeInformation.REMOTE_MIRRORS.toString());
   if (null != targetUnManagedVolumeGuids && !targetUnManagedVolumeGuids.isEmpty()) {
     StringSet targetVolumeNativeGuids =
         VolumeIngestionUtil.getListofVolumeIds(targetUnManagedVolumeGuids);
     // check whether target exists
     List<URI> targetUris = VolumeIngestionUtil.getVolumeUris(targetVolumeNativeGuids, _dbClient);
     if (null == targetUris || targetUris.isEmpty()) {
       _logger.info(
           "None of the targets ingested for source volume: {}", unManagedVolume.getNativeGuid());
     } else {
       List<Volume> targetVolumes = _dbClient.queryObject(Volume.class, targetUris);
       for (Volume targetVolume : targetVolumes) {
         Map<URI, VpoolRemoteCopyProtectionSettings> settings =
             sourceVPool.getRemoteProtectionSettings(sourceVPool, _dbClient);
         if (null == settings
             || settings.size() == 0
             || !settings.containsKey(targetVolume.getVirtualArray())) {
           _logger.info(
               "Target Volume's VArray {} is not matching already ingested source volume virtual pool's remote VArray {}",
               targetVolume.getVirtualArray(),
               Joiner.on(",").join(settings.keySet()));
           throw IngestionException.exceptions.unmanagedSRDFSourceVolumeVArrayMismatch(
               unManagedVolume.getLabel(), targetVolume.getVirtualArray().toString());
         }
       }
     }
   }
 }
  /**
   * Return the rdfGroupId based on the personality. For source volume, we will not have RDFGroup
   * hence we should get it from its targets.
   *
   * @param unManagedVolumeInformation
   * @return
   */
  private URI getRDFGroupBasedOnPersonality(StringSetMap unManagedVolumeInformation) {
    String type =
        PropertySetterUtil.extractValueFromStringSet(
            SupportedVolumeInformation.REMOTE_VOLUME_TYPE.toString(), unManagedVolumeInformation);
    URI rdfGroupId = null;
    if (RemoteMirrorObject.Types.SOURCE.toString().equalsIgnoreCase(type)) {
      StringSet targetUnManagedVolumeGuids =
          unManagedVolumeInformation.get(SupportedVolumeInformation.REMOTE_MIRRORS.toString());
      if (null != targetUnManagedVolumeGuids && !targetUnManagedVolumeGuids.isEmpty()) {
        StringSet targetVolumeNativeGuids =
            VolumeIngestionUtil.getListofVolumeIds(targetUnManagedVolumeGuids);
        List<URI> targetUris =
            VolumeIngestionUtil.getVolumeUris(targetVolumeNativeGuids, _dbClient);
        if (null == targetUris || targetUris.isEmpty()) {
          List<URI> unmanagedTargetVolumes =
              VolumeIngestionUtil.getUnManagedVolumeUris(targetUnManagedVolumeGuids, _dbClient);
          for (URI targetUmv : unmanagedTargetVolumes) {
            _logger.info("RDFGroup Found using unmanaged Target volume {}", targetUmv);
            UnManagedVolume umv = _dbClient.queryObject(UnManagedVolume.class, targetUmv);
            rdfGroupId =
                URI.create(
                    PropertySetterUtil.extractValueFromStringSet(
                        SupportedVolumeInformation.REMOTE_MIRROR_RDF_GROUP.toString(),
                        umv.getVolumeInformation()));
            break;
          }
        } else {
          // If targets are already ingested.
          List<Volume> targetVolumes = _dbClient.queryObject(Volume.class, targetUris);
          if (null != targetVolumes && !targetVolumes.isEmpty()) {
            for (Volume targetVolume : targetVolumes) {
              _logger.info(
                  "RDFGroup Found for using ingested Target volumes {}.",
                  targetVolume.getNativeGuid());
              rdfGroupId = targetVolume.getSrdfGroup();
              break;
            }
          }
        }
      }

    } else if (RemoteMirrorObject.Types.TARGET.toString().equalsIgnoreCase(type)) {
      rdfGroupId =
          URI.create(
              PropertySetterUtil.extractValueFromStringSet(
                  SupportedVolumeInformation.REMOTE_MIRROR_RDF_GROUP.toString(),
                  unManagedVolumeInformation));
    }

    return rdfGroupId;
  }
  @Override
  public <T extends BlockObject> T ingestBlockObjects(
      List<URI> systemCache,
      List<URI> poolCache,
      StorageSystem system,
      UnManagedVolume unManagedVolume,
      VirtualPool vPool,
      VirtualArray virtualArray,
      Project project,
      TenantOrg tenant,
      List<UnManagedVolume> unManagedVolumesToBeDeleted,
      Map<String, BlockObject> createdObjectMap,
      Map<String, List<DataObject>> updatedObjectMap,
      boolean unManagedVolumeExported,
      Class<T> clazz,
      Map<String, StringBuffer> taskStatusMap)
      throws IngestionException {
    // For VPLEX volumes, verify that it is OK to ingest the unmanaged
    // volume into the requested virtual array.

    long timeRightNow = new Date().getTime();
    if (timeRightNow > (cacheLastRefreshed + CACHE_TIMEOUT)) {
      _logger.debug("clearing vplex ingestion api info cache");
      clusterIdToNameMap.clear();
      varrayToClusterIdMap.clear();
      cacheLastRefreshed = timeRightNow;
    }

    if (!VolumeIngestionUtil.isValidVarrayForUnmanagedVolume(
        unManagedVolume,
        virtualArray.getId(),
        clusterIdToNameMap,
        varrayToClusterIdMap,
        _dbClient)) {
      _logger.warn(
          "UnManaged Volume {} cannot be ingested into the requested varray. Skipping Ingestion.",
          unManagedVolume.getLabel());

      throw IngestionException.exceptions.varrayIsInvalidForVplexVolume(
          virtualArray.getLabel(), unManagedVolume.getLabel());
    }

    return super.ingestBlockObjects(
        systemCache,
        poolCache,
        system,
        unManagedVolume,
        vPool,
        virtualArray,
        project,
        tenant,
        unManagedVolumesToBeDeleted,
        createdObjectMap,
        updatedObjectMap,
        unManagedVolumeExported,
        clazz,
        taskStatusMap);
  }
  @Override
  public <T extends BlockObject> T ingestBlockObjects(
      IngestionRequestContext requestContext, Class<T> clazz) throws IngestionException {

    UnManagedVolume unManagedVolume = requestContext.getCurrentUnmanagedVolume();

    String volumeNativeGuid =
        unManagedVolume
            .getNativeGuid()
            .replace(VolumeIngestionUtil.UNMANAGEDVOLUME, VolumeIngestionUtil.VOLUME);
    BlockObject blockObject =
        VolumeIngestionUtil.checkIfVolumeExistsInDB(volumeNativeGuid, _dbClient);

    // validate srdf blockObjects.
    validateUnManagedVolumeProperties(
        unManagedVolume,
        requestContext.getVarray(unManagedVolume),
        requestContext.getVpool(unManagedVolume),
        requestContext.getProject());
    // Check if ingested volume has exportmasks pending for ingestion.
    if (isExportIngestionPending(
        blockObject,
        unManagedVolume.getId(),
        requestContext.getVolumeContext().isVolumeExported())) {
      return clazz.cast(blockObject);
    }

    if (null == blockObject) {
      blockObject = super.ingestBlockObjects(requestContext, clazz);

      if (null == blockObject) {
        _logger.warn(
            "SRDF Volume ingestion failed for unmanagedVolume {}", unManagedVolume.getNativeGuid());
        throw IngestionException.exceptions.unmanagedVolumeMasksNotIngested(
            unManagedVolume.getNativeGuid(), "none.");
      }
    } else {
      // blockObject already ingested, now just update internalflags &
      // srdf relationships. Run this logic always when volume NO_PUBLIC_ACCESS
      if (markUnManagedVolumeInactive(requestContext, blockObject)) {
        _logger.info(
            "All the related replicas and parent of unManagedVolume {} has been ingested ",
            unManagedVolume.getNativeGuid());
        unManagedVolume.setInactive(true);
        requestContext.getUnManagedVolumesToBeDeleted().add(unManagedVolume);
      } else {
        _logger.info(
            "Not all the parent/replicas of unManagedVolume {} have been ingested , hence marking as internal",
            unManagedVolume.getNativeGuid());
        blockObject.addInternalFlags(INTERNAL_VOLUME_FLAGS);
      }
    }
    // Decorate blockobjects with SRDF Properties.
    decorateBlockObjectWithSRDFProperties(blockObject, unManagedVolume);

    return clazz.cast(blockObject);
  }
 @Override
 protected URI getConsistencyGroupUri(
     UnManagedVolume unManagedVolume,
     VirtualPool vPool,
     URI project,
     URI tenant,
     URI virtualArray,
     DbClient dbClient) {
   return VolumeIngestionUtil.getVplexConsistencyGroup(
       unManagedVolume, vPool, project, tenant, virtualArray, dbClient);
 }
 @Override
 protected void checkUnManagedVolumeAddedToCG(
     UnManagedVolume unManagedVolume,
     VirtualArray virtualArray,
     TenantOrg tenant,
     Project project,
     VirtualPool vPool) {
   if (VolumeIngestionUtil.checkUnManagedResourceAddedToConsistencyGroup(unManagedVolume)) {
     URI consistencyGroupUri =
         VolumeIngestionUtil.getVplexConsistencyGroup(
             unManagedVolume,
             vPool,
             project.getId(),
             tenant.getId(),
             virtualArray.getId(),
             _dbClient);
     if (null == consistencyGroupUri) {
       _logger.warn(
           "A Consistency Group for the VPLEX volume could not be determined. Skipping Ingestion.");
       throw IngestionException.exceptions
           .unmanagedVolumeVplexConsistencyGroupCouldNotBeIdentified(unManagedVolume.getLabel());
     }
   }
 }