/**
   * Update a quota
   *
   * @prereq none
   * @param tenant_id the URN of the tenant
   * @param target_tenant_id the URN of the target tenant for which quota is being modified
   * @brief Update Quota
   * @return Quota details of target_tenant_id
   */
  @PUT
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{target_tenant_id}")
  @CheckPermission(
      roles = {Role.SYSTEM_MONITOR, Role.TENANT_ADMIN},
      acls = {ACL.ANY})
  public Response updateQuota(
      @PathParam("tenant_id") String openstack_tenant_id,
      @PathParam("target_tenant_id") String openstack_target_tenant_id,
      CinderQuotaDetails quotaUpdates,
      @Context HttpHeaders header) {

    _log.info("Updating Quota");
    Project project =
        getCinderHelper().getProject(openstack_target_tenant_id.toString(), getUserFromContext());
    if (project == null) {
      throw APIException.badRequests.projectWithTagNonexistent(openstack_target_tenant_id);
    }

    long maxQuota = 0L;
    if (project.getQuotaEnabled()) {
      maxQuota = (long) (project.getQuota().intValue());
    } else {
      maxQuota = DEFAULT_PROJECT_TOTALGB_QUOTA;
    }

    // bVpoolQuotaUpdate will be set to true if the user is updating the quota of a vpool w.r.t a
    // project
    // bVpoolQuotaUpdate will be set to false if the user is updating the quota of the project
    boolean bVpoolQuotaUpdate = isVpoolQuotaUpdate(quotaUpdates.quota_set);
    String vpoolName = null;
    VirtualPool objVpool = null;

    if (bVpoolQuotaUpdate) {
      vpoolName = getVpoolName(quotaUpdates.quota_set);
      _log.info("Vpool for which quota is being updated is {}", vpoolName);
      objVpool = getCinderHelper().getVpool(vpoolName);

      if (objVpool == null) {
        _log.info("vpool with the given name doesnt exist");
        throw APIException.badRequests.parameterIsNotValid(vpoolName);
      }
      _log.info("objVpool.getLabel() is {}", objVpool.getLabel());
    }

    List<URI> quotas = _dbClient.queryByType(QuotaOfCinder.class, true);
    boolean noEntriesInDB = true;
    for (URI quota : quotas) {
      QuotaOfCinder quotaObj = _dbClient.queryObject(QuotaOfCinder.class, quota);
      if ((quotaObj.getProject() != null)
          && (quotaObj.getProject().toString().equalsIgnoreCase(project.getId().toString()))) {
        _log.info("QuotaObj being updated is {}", quotaObj.toString());

        URI vpoolUri = quotaObj.getVpool();

        if ((!bVpoolQuotaUpdate) && (vpoolUri != null)) {
          // The user requested update of project quota.
          // But the current db entry quota for vpool w.r.t project.
          // Hence just skip the db entry as this is not our concern.
          continue;
        }

        if ((bVpoolQuotaUpdate) && (vpoolUri != null)) {
          // The user requested quota update for a vpool w.r.t a project.
          // The current db entry that we looking into has vpool entry.
          // Hence we should further check if the vpool value is same as the vpool for which the
          // user wants to set quota
          VirtualPool pool = _dbClient.queryObject(VirtualPool.class, vpoolUri);
          if ((pool != null)
              && (pool.getLabel().equals(vpoolName))
              && (vpoolName != null)
              && (vpoolName.length() > 0)) {

            if (quotaUpdates.quota_set.containsKey("gigabytes_" + vpoolName))
              quotaObj.setTotalQuota(
                  new Long(quotaUpdates.quota_set.get("gigabytes_" + vpoolName)));
            if (quotaUpdates.quota_set.containsKey("volumes_" + vpoolName))
              quotaObj.setVolumesLimit(
                  new Long(quotaUpdates.quota_set.get("volumes_" + vpoolName)));
            if (quotaUpdates.quota_set.containsKey("snapshots_" + vpoolName))
              quotaObj.setSnapshotsLimit(
                  new Long(quotaUpdates.quota_set.get("snapshots_" + vpoolName)));
            noEntriesInDB = false;
            _dbClient.updateObject(quotaObj);
            return getQuotaDetailFormat(header, quotaUpdates);
          }
        } else if (!bVpoolQuotaUpdate) {
          // The user requested update of project quota.
          // The current db entry is a project quota entity.(because to reach here vpoolUri should
          // be Null.
          if (quotaUpdates.quota_set.containsKey("gigabytes"))
            quotaObj.setTotalQuota(new Long(quotaUpdates.quota_set.get("gigabytes")));
          if (quotaUpdates.quota_set.containsKey("volumes"))
            quotaObj.setVolumesLimit(new Long(quotaUpdates.quota_set.get("volumes")));
          if (quotaUpdates.quota_set.containsKey("snapshots"))
            quotaObj.setSnapshotsLimit(new Long(quotaUpdates.quota_set.get("snapshots")));
          noEntriesInDB = false;
          _dbClient.updateObject(quotaObj);
          return getQuotaDetailFormat(header, quotaUpdates);
        }
      }
    }

    if (noEntriesInDB) {
      _log.info("No entries in the QuotaOfCinder column family");
      QuotaOfCinder objQuotaOfCinder = new QuotaOfCinder();
      objQuotaOfCinder.setProject(project.getId());

      if (bVpoolQuotaUpdate) {
        objQuotaOfCinder.setVpool(objVpool.getId());
        _log.info("Updating Quota of Vpool");
        if (quotaUpdates.quota_set.containsKey("gigabytes_" + vpoolName))
          objQuotaOfCinder.setTotalQuota(
              new Long(quotaUpdates.quota_set.get("gigabytes_" + vpoolName)));
        else objQuotaOfCinder.setTotalQuota(DEFAULT_VOLUME_TYPE_TOTALGB_QUOTA);

        if (quotaUpdates.quota_set.containsKey("volumes_" + vpoolName))
          objQuotaOfCinder.setVolumesLimit(
              new Long(quotaUpdates.quota_set.get("volumes_" + vpoolName)));
        else objQuotaOfCinder.setVolumesLimit(DEFAULT_VOLUME_TYPE_VOLUMES_QUOTA);

        if (quotaUpdates.quota_set.containsKey("snapshots_" + vpoolName))
          objQuotaOfCinder.setSnapshotsLimit(
              new Long(quotaUpdates.quota_set.get("snapshots_" + vpoolName)));
        else objQuotaOfCinder.setSnapshotsLimit(DEFAULT_VOLUME_TYPE_SNAPSHOTS_QUOTA);

      } else {
        if (quotaUpdates.quota_set.containsKey("gigabytes"))
          objQuotaOfCinder.setTotalQuota(new Long(quotaUpdates.quota_set.get("gigabytes")));
        else objQuotaOfCinder.setTotalQuota(maxQuota);

        if (quotaUpdates.quota_set.containsKey("volumes"))
          objQuotaOfCinder.setVolumesLimit(new Long(quotaUpdates.quota_set.get("volumes")));
        else objQuotaOfCinder.setVolumesLimit(DEFAULT_PROJECT_VOLUMES_QUOTA);

        if (quotaUpdates.quota_set.containsKey("snapshots"))
          objQuotaOfCinder.setSnapshotsLimit(new Long(quotaUpdates.quota_set.get("snapshots")));
        else objQuotaOfCinder.setSnapshotsLimit(DEFAULT_PROJECT_SNAPSHOTS_QUOTA);
      }
      objQuotaOfCinder.setId(URI.create(UUID.randomUUID().toString()));
      _dbClient.createObject(objQuotaOfCinder);
      return getQuotaDetailFormat(header, quotaUpdates);
    }
    return getQuotaDetailFormat(header, quotaUpdates);
  }
  /**
   * Get the summary list of all Quotas for the given tenant
   *
   * @prereq none
   * @param tenant_id the URN of the tenant asking for quotas
   * @param target_tenant_id
   * @brief Get the summary list of all Quotas
   * @return Quota details of target_tenant_id
   */
  @GET
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{target_tenant_id}")
  @CheckPermission(
      roles = {Role.SYSTEM_MONITOR, Role.TENANT_ADMIN},
      acls = {ACL.ANY})
  public Response getQuotaDetails(
      @PathParam("target_tenant_id") String openstack_target_tenant_id,
      @Context HttpHeaders header) {

    Project project =
        getCinderHelper().getProject(openstack_target_tenant_id.toString(), getUserFromContext());

    if (project == null) {
      throw APIException.badRequests.projectWithTagNonexistent(openstack_target_tenant_id);
    }

    long maxQuota = 0;
    if (project.getQuotaEnabled()) {
      maxQuota = (long) (project.getQuota().intValue());
    } else {
      maxQuota = DEFAULT_PROJECT_TOTALGB_QUOTA;
    }

    List<URI> quotas = _dbClient.queryByType(QuotaOfCinder.class, true);
    Map<String, String> vpoolsMap = new HashMap<String, String>();
    boolean bDefProjQuotasExist = false;

    CinderQuotaDetails respCinderQuota = new CinderQuotaDetails();

    for (URI quota : quotas) {
      QuotaOfCinder quotaObj = _dbClient.queryObject(QuotaOfCinder.class, quota);

      if ((quotaObj.getProject() != null)
          && (quotaObj.getProject().toString().equalsIgnoreCase(project.getId().toString()))) {
        if (quotaObj.getVpool() != null) {
          VirtualPool pool = _dbClient.queryObject(VirtualPool.class, quotaObj.getVpool());
          respCinderQuota.quota_set.put(
              "gigabytes" + "_" + pool.getLabel(), String.valueOf(quotaObj.getTotalQuota()));
          respCinderQuota.quota_set.put(
              "snapshots" + "_" + pool.getLabel(), String.valueOf(quotaObj.getSnapshotsLimit()));
          respCinderQuota.quota_set.put(
              "volumes" + "_" + pool.getLabel(), String.valueOf(quotaObj.getVolumesLimit()));
          vpoolsMap.put(pool.getLabel(), pool.getLabel());
        } else {
          respCinderQuota.quota_set.put("gigabytes", String.valueOf(quotaObj.getTotalQuota()));
          respCinderQuota.quota_set.put("snapshots", String.valueOf(quotaObj.getSnapshotsLimit()));
          respCinderQuota.quota_set.put(
              "volumes", String.valueOf(quotaObj.getVolumesLimit().intValue()));
          bDefProjQuotasExist = true;
        }
      }
    }

    if (!bDefProjQuotasExist) {
      respCinderQuota.quota_set.put("gigabytes", String.valueOf(maxQuota));
      respCinderQuota.quota_set.put("snapshots", String.valueOf(DEFAULT_PROJECT_SNAPSHOTS_QUOTA));
      respCinderQuota.quota_set.put("volumes", String.valueOf(DEFAULT_PROJECT_VOLUMES_QUOTA));
      getCinderHelper().createProjectDefaultQuota(project);
    }

    StorageOSUser user = getUserFromContext();
    URI tenantId = URI.create(user.getTenantId());

    List<URI> vpools = _dbClient.queryByType(VirtualPool.class, true);
    for (URI vpool : vpools) {
      VirtualPool pool = _dbClient.queryObject(VirtualPool.class, vpool);
      _log.debug("Looking up vpool {}", pool.getLabel());
      if (pool != null && pool.getType().equalsIgnoreCase(VirtualPool.Type.block.name())) {
        if (_permissionsHelper.tenantHasUsageACL(tenantId, pool)) {
          if (vpoolsMap.containsKey(pool.getLabel())) {
            continue;
          } else {
            respCinderQuota.quota_set.put(
                "gigabytes" + "_" + pool.getLabel(),
                String.valueOf(DEFAULT_VOLUME_TYPE_TOTALGB_QUOTA));
            respCinderQuota.quota_set.put(
                "snapshots" + "_" + pool.getLabel(),
                String.valueOf(DEFAULT_VOLUME_TYPE_SNAPSHOTS_QUOTA));
            respCinderQuota.quota_set.put(
                "volumes" + "_" + pool.getLabel(),
                String.valueOf(DEFAULT_VOLUME_TYPE_VOLUMES_QUOTA));
            getCinderHelper().createVpoolDefaultQuota(project, pool);
          }
        }
      }
    }

    return getQuotaDetailFormat(header, respCinderQuota);
  }
  /**
   * Updates Bucket values like Quota and Retention.
   *
   * @param id Bucket ID
   * @param param Bucket update parameter
   * @return Task resource representation
   * @throws InternalException if update fails
   */
  @PUT
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}")
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(
      roles = {Role.TENANT_ADMIN},
      acls = {ACL.OWN, ACL.ALL})
  public TaskResourceRep updateBucket(@PathParam("id") URI id, BucketUpdateParam param)
      throws InternalException {
    Bucket bucket = null;
    ArgValidator.checkFieldUriType(id, Bucket.class, "id");
    bucket = _dbClient.queryObject(Bucket.class, id);
    ArgValidator.checkEntity(bucket, id, isIdEmbeddedInURL(id));

    Long softQuota = SizeUtil.translateSize(param.getSoftQuota());
    Long hardQuota = SizeUtil.translateSize(param.getHardQuota());
    Integer retention = null != param.getRetention() ? Integer.valueOf(param.getRetention()) : 0;

    // if no softquota is provided, use the old value
    if (softQuota == 0) {
      softQuota = bucket.getSoftQuota();
    }

    // if no hardquota is provided, use the old value
    if (hardQuota == 0) {
      hardQuota = bucket.getHardQuota();
    }

    // Hard Quota should be more than SoftQuota
    verifyQuotaValues(softQuota, hardQuota, bucket.getLabel());

    // if no retention is provided, use the old value
    if (retention == 0) {
      retention = bucket.getRetention();
    }

    VirtualPool cos = _dbClient.queryObject(VirtualPool.class, bucket.getVirtualPool());
    // verify retention. Its validated only if Retention is configured.
    if (retention != 0 && cos.getMaxRetention() != 0 && retention > cos.getMaxRetention()) {
      throw APIException.badRequests.insufficientRetentionForVirtualPool(cos.getLabel(), "bucket");
    }

    String task = UUID.randomUUID().toString();
    _log.info(String.format("BucketUpdate --- Bucket id: %1$s, Task: %2$s", id, task));

    StorageSystem storageSystem =
        _dbClient.queryObject(StorageSystem.class, bucket.getStorageDevice());

    Operation op =
        _dbClient.createTaskOpStatus(
            Bucket.class, bucket.getId(), task, ResourceOperationTypeEnum.UPDATE_BUCKET);
    op.setDescription("Bucket update");
    ObjectController controller =
        getController(ObjectController.class, storageSystem.getSystemType());

    controller.updateBucket(bucket.getStorageDevice(), id, softQuota, hardQuota, retention, task);

    auditOp(
        OperationTypeEnum.UPDATE_BUCKET,
        true,
        AuditLogManager.AUDITOP_BEGIN,
        bucket.getId().toString(),
        bucket.getStorageDevice().toString());

    return toTask(bucket, task, op);
  }
  private TaskResourceRep initiateBucketCreation(
      BucketParam param, Project project, TenantOrg tenant, DataObject.Flag[] flags)
      throws InternalException {
    ArgValidator.checkFieldUriType(param.getVpool(), VirtualPool.class, "vpool");
    ArgValidator.checkFieldUriType(param.getVarray(), VirtualArray.class, "varray");

    Long softQuota = SizeUtil.translateSize(param.getSoftQuota());
    Long hardQuota = SizeUtil.translateSize(param.getHardQuota());
    Integer retention = Integer.valueOf(param.getRetention());

    // Hard Quota should be more than SoftQuota
    verifyQuotaValues(softQuota, hardQuota, param.getLabel());

    // check varray
    VirtualArray neighborhood = _dbClient.queryObject(VirtualArray.class, param.getVarray());
    ArgValidator.checkEntity(neighborhood, param.getVarray(), false);
    _permissionsHelper.checkTenantHasAccessToVirtualArray(tenant.getId(), neighborhood);

    // check vpool reference
    VirtualPool cos = _dbClient.queryObject(VirtualPool.class, param.getVpool());
    _permissionsHelper.checkTenantHasAccessToVirtualPool(tenant.getId(), cos);
    ArgValidator.checkEntity(cos, param.getVpool(), false);
    if (!VirtualPool.Type.object.name().equals(cos.getType())) {
      throw APIException.badRequests.virtualPoolNotForObjectStorage(VirtualPool.Type.object.name());
    }

    // verify retention. Its validated only if Retention is configured.
    if (retention != 0 && cos.getMaxRetention() != 0 && retention > cos.getMaxRetention()) {
      throw APIException.badRequests.insufficientRetentionForVirtualPool(cos.getLabel(), "bucket");
    }

    VirtualPoolCapabilityValuesWrapper capabilities = new VirtualPoolCapabilityValuesWrapper();

    capabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, Integer.valueOf(1));
    capabilities.put(VirtualPoolCapabilityValuesWrapper.THIN_PROVISIONING, Boolean.FALSE);

    List<BucketRecommendation> placement =
        _bucketScheduler.placeBucket(neighborhood, cos, capabilities);
    if (placement.isEmpty()) {
      throw APIException.badRequests.noMatchingStoragePoolsForVpoolAndVarray(
          cos.getId(), neighborhood.getId());
    }

    // Randomly select a recommended pool
    Collections.shuffle(placement);
    BucketRecommendation recommendation = placement.get(0);

    String task = UUID.randomUUID().toString();
    Bucket bucket = prepareBucket(param, project, tenant, neighborhood, cos, flags, recommendation);

    _log.info(
        String.format(
            "createBucket --- Bucket: %1$s, StoragePool: %2$s, StorageSystem: %3$s",
            bucket.getId(),
            recommendation.getSourceStoragePool(),
            recommendation.getSourceStorageSystem()));

    Operation op =
        _dbClient.createTaskOpStatus(
            Bucket.class, bucket.getId(), task, ResourceOperationTypeEnum.CREATE_BUCKET);
    op.setDescription("Bucket Create");

    // Controller invocation
    StorageSystem system =
        _dbClient.queryObject(StorageSystem.class, recommendation.getSourceStorageSystem());
    ObjectController controller = getController(ObjectController.class, system.getSystemType());
    controller.createBucket(
        recommendation.getSourceStorageSystem(),
        recommendation.getSourceStoragePool(),
        bucket.getId(),
        bucket.getName(),
        bucket.getNamespace(),
        bucket.getRetention(),
        bucket.getHardQuota(),
        bucket.getSoftQuota(),
        bucket.getOwner(),
        task);

    auditOp(
        OperationTypeEnum.CREATE_BUCKET,
        true,
        AuditLogManager.AUDITOP_BEGIN,
        param.getLabel(),
        param.getHardQuota(),
        neighborhood.getId().toString(),
        project == null ? null : project.getId().toString());

    return toTask(bucket, task, op);
  }
  /**
   * Filter vpools from the qualified list. rpSource true: Filter out anything other than RP source
   * vpools rpSource false: Filter out RP and SRDF source vpools
   *
   * @param dbClient dbclient
   * @param unManagedVolume unmanaged volume
   * @param personality SOURCE, TARGET, or METADATA
   */
  private void filterProtectedVpools(
      DbClient dbClient, UnManagedVolume unManagedVolume, String personality) {

    if (unManagedVolume.getSupportedVpoolUris() != null
        && !unManagedVolume.getSupportedVpoolUris().isEmpty()) {
      Iterator<VirtualPool> vpoolItr =
          dbClient.queryIterativeObjects(
              VirtualPool.class, URIUtil.toURIList(unManagedVolume.getSupportedVpoolUris()));
      while (vpoolItr.hasNext()) {
        boolean remove = false;
        VirtualPool vpool = vpoolItr.next();

        // If this is an SRDF source vpool, we can filter out since we're dealing with an RP volume
        if (vpool.getProtectionRemoteCopySettings() != null) {
          remove = true;
        }

        // If this is not an RP source, the vpool should be filtered out if:
        // The vpool is an RP vpool (has settings) and target vpools are non-null
        if (vpool.getProtectionVarraySettings() != null
            && ((Volume.PersonalityTypes.TARGET.name().equalsIgnoreCase(personality))
                || Volume.PersonalityTypes.METADATA.name().equalsIgnoreCase(personality))) {
          boolean foundEmptyTargetVpool = false;
          Map<URI, VpoolProtectionVarraySettings> settings =
              VirtualPool.getProtectionSettings(vpool, dbClient);
          for (Map.Entry<URI, VpoolProtectionVarraySettings> setting : settings.entrySet()) {
            if (NullColumnValueGetter.isNullURI(setting.getValue().getVirtualPool())) {
              foundEmptyTargetVpool = true;
              break;
            }
          }

          // If this is a journal volume, also check the journal vpools. If they're not set, we
          // cannot filter out this vpool.
          if (Volume.PersonalityTypes.METADATA.name().equalsIgnoreCase(personality)
              && (NullColumnValueGetter.isNullValue(vpool.getJournalVpool())
                  || NullColumnValueGetter.isNullValue(vpool.getStandbyJournalVpool()))) {
            foundEmptyTargetVpool = true;
          }

          // If every relevant target (and journal for journal volumes) vpool is filled-in, then
          // you would never assign your target volume to this source vpool, so filter it out.
          if (!foundEmptyTargetVpool) {
            remove = true;
          }
        }

        if (Volume.PersonalityTypes.SOURCE.name().equalsIgnoreCase(personality)) {
          if (!VirtualPool.vPoolSpecifiesProtection(vpool)) {
            // If this an RP source, the vpool must be an RP vpool
            remove = true;
          } else if (unManagedVolume
                  .getVolumeInformation()
                  .containsKey(SupportedVolumeInformation.RP_STANDBY_INTERNAL_SITENAME.toString())
              && !VirtualPool.vPoolSpecifiesMetroPoint(vpool)) {
            // Since this is a Source volume with the presence of RP_STANDBY_INTERNAL_SITENAME
            // it indicates that this volume is MetroPoint, if we get here, this is vpool
            // must be filtered out since it's not MP.
            remove = true;
          }
        }

        if (remove) {
          log.info(
              "Removing virtual pool "
                  + vpool.getLabel()
                  + " from supported vpools for unmanaged volume: "
                  + unManagedVolume.getLabel());
          unManagedVolume.getSupportedVpoolUris().remove(vpool.getId().toString());
        }
      }
    }
  }
 // replace all Special Characters ; /-+!@#$%^&())";:[]{}\ |
 public String getVPoolNameWithNoSpecialCharacters() {
   return stripSpecialCharacters(vPool.getLabel());
 }
 public String getVPoolName() {
   return vPool.getLabel();
 }