/**
   * Allows the user to get the id, name, and self link for all storage systems visible to the
   * provider with the passed id.
   *
   * @param id the URN of a ViPR Storage provider
   * @brief List Storage provider storage systems
   * @return A StorageSystemList reference specifying the id, name, and self link for the storage
   *     systems visible to the provider.
   */
  @GET
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}/storage-systems")
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR})
  public StorageSystemList getStorageSystems(@PathParam("id") URI id) {

    // Validate the provider
    ArgValidator.checkFieldUriType(id, StorageProvider.class, "id");
    StorageProvider provider = _dbClient.queryObject(StorageProvider.class, id);
    ArgValidator.checkEntityNotNull(provider, id, isIdEmbeddedInURL(id));

    // Return the list of storage systems for the provider.
    StorageSystemList storageSystemsForProvider = new StorageSystemList();
    StringSet providerSystemURIStrs = provider.getStorageSystems();
    if (providerSystemURIStrs != null) {
      for (String providerSystemURIStr : providerSystemURIStrs) {
        StorageSystem storageSystem =
            _dbClient.queryObject(StorageSystem.class, URI.create(providerSystemURIStr));
        if (storageSystem != null) {
          storageSystemsForProvider.getStorageSystems().add(toNamedRelatedResource(storageSystem));
        }
      }
    }

    return storageSystemsForProvider;
  }
  /**
   * Deactivate Quota directory of file system, this will move the Quota directory to a
   * "marked-for-delete" state
   *
   * <p>NOTE: This is an asynchronous operation.
   *
   * @param id the URN of the QuotaDirectory
   * @param param QuotaDirectory delete param for optional force delete
   * @brief Delete file system Quota Dir
   * @return Task resource representation
   * @throws com.emc.storageos.svcs.errorhandling.resources.InternalException
   */
  @POST
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}/deactivate")
  @CheckPermission(
      roles = {Role.TENANT_ADMIN},
      acls = {ACL.OWN, ACL.ALL})
  public TaskResourceRep deactivateQuotaDirectory(
      @PathParam("id") URI id, QuotaDirectoryDeleteParam param) throws InternalException {

    _log.info("FileService::deactivateQtree Request recieved {}", id);
    String task = UUID.randomUUID().toString();
    ArgValidator.checkFieldUriType(id, QuotaDirectory.class, "id");
    QuotaDirectory quotaDirectory = queryResource(id);
    FileShare fs = queryFileShareResource(quotaDirectory.getParent().getURI());
    ArgValidator.checkFieldNotNull(fs, "filesystem");

    // <TODO> Implement Force delete option when shares and exports for Quota Directory are
    // supported

    Operation op = new Operation();
    op.setResourceType(ResourceOperationTypeEnum.DELETE_FILE_SYSTEM_QUOTA_DIR);
    quotaDirectory.getOpStatus().createTaskStatus(task, op);
    fs.setOpStatus(new OpStatusMap());
    fs.getOpStatus().createTaskStatus(task, op);
    _dbClient.persistObject(fs);
    _dbClient.persistObject(quotaDirectory);

    // Now get ready to make calls into the controller
    StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice());
    FileController controller = getController(FileController.class, device.getSystemType());
    try {
      controller.deleteQuotaDirectory(device.getId(), quotaDirectory.getId(), fs.getId(), task);
      // If delete operation is successful, then remove obj from ViPR db by setting inactive=true
      quotaDirectory.setInactive(true);
      _dbClient.persistObject(quotaDirectory);

    } catch (InternalException e) {
      // treating all controller exceptions as internal error for now. controller
      // should discriminate between validation problems vs. internal errors

      throw e;
    }

    auditOp(
        OperationTypeEnum.DELETE_FILE_SYSTEM_QUOTA_DIR,
        true,
        AuditLogManager.AUDITOP_BEGIN,
        quotaDirectory.getLabel(),
        quotaDirectory.getId().toString(),
        fs.getId().toString());

    fs = _dbClient.queryObject(FileShare.class, fs.getId());
    _log.debug(
        "FileService::Quota directory Before sending response, FS ID : {}, Taks : {} ; Status {}",
        fs.getOpStatus().get(task),
        fs.getOpStatus().get(task).getStatus());

    return toTask(quotaDirectory, task, op);
  }
  /**
   * Allows the user to get data for the storage system with the passed system id that is associated
   * with the storage provider with the passed provider id.
   *
   * @param id the URN of a ViPR Storage provider
   * @param systemId The id of the storage system.
   * @brief Show Storage provider storage system
   * @return A StorageSystemRestRep reference specifying the data for the storage system.
   */
  @GET
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}/storage-systems/{systemId}")
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR})
  public StorageSystemRestRep getStorageSystem(
      @PathParam("id") URI id, @PathParam("systemId") URI systemId) {

    // Validate the provider.
    ArgValidator.checkFieldUriType(id, StorageProvider.class, "id");
    StorageProvider provider = _dbClient.queryObject(StorageProvider.class, id);
    ArgValidator.checkEntityNotNull(provider, id, isIdEmbeddedInURL(id));
    ArgValidator.checkFieldUriType(systemId, StorageSystem.class, "id");

    // Return the storage system if found.
    StringSet providerSystemURIStrs = provider.getStorageSystems();
    if (providerSystemURIStrs != null) {
      for (String providerSystemURIStr : providerSystemURIStrs) {
        if (providerSystemURIStr.equals(systemId.toString())) {
          StorageSystem storageSystem =
              _dbClient.queryObject(StorageSystem.class, URI.create(providerSystemURIStr));
          if (storageSystem != null) {
            return map(storageSystem);
          }
          break;
        }
      }
    }

    throw APIException.notFound.unableToFindEntityInURL(id);
  }
  /**
   * Creates bucket.
   *
   * <p>NOTE: This is an asynchronous operation.
   *
   * @param param Bucket parameters
   * @param id the URN of a ViPR Project
   * @brief Create Bucket
   * @return Task resource representation
   * @throws InternalException
   */
  @POST
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(
      roles = {Role.TENANT_ADMIN},
      acls = {ACL.OWN, ACL.ALL})
  public TaskResourceRep createBucket(BucketParam param, @QueryParam("project") URI id)
      throws InternalException {
    // check project
    ArgValidator.checkFieldUriType(id, Project.class, "project");

    // Check for all mandatory field
    ArgValidator.checkFieldNotNull(param.getLabel(), "name");

    Project project = _permissionsHelper.getObjectById(id, Project.class);
    ArgValidator.checkEntity(project, id, isIdEmbeddedInURL(id));
    ArgValidator.checkFieldNotNull(project.getTenantOrg(), "project");
    TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg().getURI());

    final String namespace = tenant.getNamespace();
    if (null == namespace || namespace.isEmpty()) {
      throw APIException.badRequests.objNoNamespaceForTenant(tenant.getId());
    }

    // Check if there already exist a bucket with same name in a Project.
    checkForDuplicateName(
        param.getLabel().replaceAll(SPECIAL_CHAR_REGEX, ""),
        Bucket.class,
        id,
        "project",
        _dbClient);

    return initiateBucketCreation(param, project, tenant, null);
  }
 @Override
 protected Bucket queryResource(URI id) {
   ArgValidator.checkUri(id);
   Bucket bucket = _permissionsHelper.getObjectById(id, Bucket.class);
   ArgValidator.checkEntityNotNull(bucket, id, isIdEmbeddedInURL(id));
   return bucket;
 }
 @Override
 protected QuotaDirectory queryResource(URI id) {
   ArgValidator.checkUri(id);
   QuotaDirectory qd = _permissionsHelper.getObjectById(id, QuotaDirectory.class);
   ArgValidator.checkEntityNotNull(qd, id, isIdEmbeddedInURL(id));
   return qd;
 }
  @POST
  @Path("/{id}/deactivate")
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN})
  public Response deleteStorageProvider(@PathParam("id") URI id) {
    // Validate the provider
    ArgValidator.checkFieldUriType(id, StorageProvider.class, "id");
    StorageProvider provider = _dbClient.queryObject(StorageProvider.class, id);
    ArgValidator.checkEntityNotNull(provider, id, isIdEmbeddedInURL(id));
    // Verify the provider can be removed without leaving "dangling" storages.
    StringSet providerStorageSystems = provider.getStorageSystems();
    if (null != providerStorageSystems && !providerStorageSystems.isEmpty()) {
      // First we need to verify that all related storage systems has at least   2 providers
      for (String system : providerStorageSystems) {
        StorageSystem storageSys = _dbClient.queryObject(StorageSystem.class, URI.create(system));
        if (storageSys != null
            && !storageSys.getInactive()
            && storageSys.getProviders() != null
            && storageSys.getProviders().size() == 1) {
          throw APIException.badRequests.cannotDeleteProviderWithManagedStorageSystems(
              storageSys.getId());
        }
      }
      // Next we can clear this provider from storage systems.
      for (String system : providerStorageSystems) {
        StorageSystem storageSys = _dbClient.queryObject(StorageSystem.class, URI.create(system));
        provider.removeStorageSystem(_dbClient, storageSys);
      }
    }

    StringSet decommissionedSystems = provider.getDecommissionedSystems();
    if (null != decommissionedSystems && !decommissionedSystems.isEmpty()) {
      for (String decommissioned : decommissionedSystems) {
        DecommissionedResource oldRes =
            _dbClient.queryObject(DecommissionedResource.class, URI.create(decommissioned));
        if (oldRes != null) {
          _dbClient.markForDeletion(oldRes);
        }
      }
    }

    // Set to inactive.
    _dbClient.markForDeletion(provider);

    auditOp(
        OperationTypeEnum.DELETE_STORAGEPROVIDER,
        true,
        null,
        provider.getId().toString(),
        provider.getLabel(),
        provider.getIPAddress(),
        provider.getPortNumber(),
        provider.getUserName(),
        provider.getInterfaceType());

    return Response.ok().build();
  }
  /**
   * Validates vCenter user credentials from create or update parameters.
   *
   * @param param either vCenter create or update param.
   * @param vcenter vCenter object.
   */
  private void validateVcenterCredentials(VcenterParam param, Vcenter vcenter) {
    if (StringUtils.isBlank(param.getPassword()) && vcenter != null) {
      param.setPassword(StringUtils.trimToNull(vcenter.getPassword()));
    }

    if (StringUtils.isBlank(param.getUserName()) && vcenter != null) {
      param.setUserName(StringUtils.trimToNull(vcenter.getUsername()));
    }

    ArgValidator.checkFieldNotNull(param.getUserName(), "username");
    ArgValidator.checkFieldNotNull(param.getPassword(), "password");
  }
  /**
   * Allows the user to remove a storage system from the list of decommisioned resources After that
   * corresponding provider should be able to be rescanned and add this system back to the list of
   * managed systems.
   *
   * @param id id the URN of a ViPR Storage provider
   * @param param The storage system details.
   * @brief removes the storage system from the list of decommissioned systems and rescans the
   *     provider.
   * @return An asynchronous task corresponding to the scan job scheduled for the provider.
   * @throws BadRequestException When the system type is not valid or a storage system with the same
   *     native guid already exists.
   * @throws com.emc.storageos.db.exceptions.DatabaseException When an error occurs querying the
   *     database.
   * @throws ControllerException When an error occurs discovering the storage system.
   */
  @PUT
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(roles = {Role.SYSTEM_ADMIN})
  @Path("/{id}/storage-systems")
  public TaskResourceRep addStorageSystem(
      @PathParam("id") URI id, StorageSystemProviderRequestParam param) throws ControllerException {
    TaskResourceRep taskRep;
    URIQueryResultList list = new URIQueryResultList();

    ArgValidator.checkFieldNotEmpty(param.getSystemType(), "system_type");
    if (!StorageSystem.Type.isProviderStorageSystem(
        DiscoveredDataObject.Type.valueOf(param.getSystemType()))) {
      throw APIException.badRequests.cannotAddStorageSystemTypeToStorageProvider(
          param.getSystemType());
    }

    StorageProvider provider = _dbClient.queryObject(StorageProvider.class, id);
    ArgValidator.checkEntityNotNull(provider, id, isIdEmbeddedInURL(id));

    ArgValidator.checkFieldNotEmpty(param.getSerialNumber(), "serialNumber");

    String nativeGuid =
        NativeGUIDGenerator.generateNativeGuid(param.getSystemType(), param.getSerialNumber());
    // check for duplicate StorageSystem.

    List<StorageSystem> systems =
        CustomQueryUtility.getActiveStorageSystemByNativeGuid(_dbClient, nativeGuid);
    if (systems != null && !systems.isEmpty()) {
      throw APIException.badRequests.invalidParameterProviderStorageSystemAlreadyExists(
          "nativeGuid", nativeGuid);
    }

    int cleared =
        DecommissionedResource.removeDecommissionedFlag(_dbClient, nativeGuid, StorageSystem.class);
    if (cleared == 0) {
      log.info("Cleared {} decommissioned systems", cleared);
    } else {
      log.info("Did not find any decommissioned systems to clear. Continue to scan.");
    }

    ArrayList<AsyncTask> tasks = new ArrayList<AsyncTask>(1);
    String taskId = UUID.randomUUID().toString();
    tasks.add(new AsyncTask(StorageProvider.class, provider.getId(), taskId));

    BlockController controller = getController(BlockController.class, provider.getInterfaceType());
    DiscoveredObjectTaskScheduler scheduler =
        new DiscoveredObjectTaskScheduler(_dbClient, new ScanJobExec(controller));
    TaskList taskList = scheduler.scheduleAsyncTasks(tasks);
    return taskList.getTaskList().listIterator().next();
  }
  /**
   * Validates the individual list of acl entries. It is not valid acl entries list, when an acl
   * entry contains more than one privilege or privileges other than USE and if the tenant provided
   * in the acl entry is not a valid tenant org.
   *
   * @param aclEntries acl entries to be validated.
   */
  private void validateAclEntries(List<ACLEntry> aclEntries) {
    if (CollectionUtils.isEmpty(aclEntries)) {
      return;
    }

    Iterator<ACLEntry> aclEntryIterator = aclEntries.iterator();
    while (aclEntryIterator.hasNext()) {
      ACLEntry aclEntry = aclEntryIterator.next();

      // If more than one privileges provided the ACL Entry, it is not supported
      // for vCenter ACL. Only USE ACL can be provided.
      if (aclEntry.getAces().size() != 1) {
        throw APIException.badRequests.unsupportedNumberOfPrivileges(
            URI.create(aclEntry.getTenant()), aclEntry.getAces());
      }

      if (!aclEntry.getAces().get(0).equalsIgnoreCase(ACL.USE.name())) {
        throw APIException.badRequests.unsupportedPrivilege(
            URI.create(aclEntry.getTenant()), aclEntry.getAces().get(0));
      }

      // Validate if the provided tenant is a valid tenant or not.
      URI tenantId = URI.create(aclEntry.getTenant());
      TenantOrg tenant = queryObject(TenantOrg.class, tenantId, true);
      ArgValidator.checkEntity(tenant, tenantId, isIdEmbeddedInURL(tenantId));
    }
  }
  /**
   * Gets the current acl assignments of the requested vCenter.
   *
   * @param vcenterId
   * @return the list of acl assignments of the requested vCenter.
   */
  private ACLAssignments getAclAssignmentsResponse(URI vcenterId) {
    Vcenter vcenter = queryObject(Vcenter.class, vcenterId, true);
    ArgValidator.checkEntity(vcenter, vcenterId, isIdEmbeddedInURL(vcenterId));

    ACLAssignments response = new ACLAssignments();
    response.setAssignments(_permissionsHelper.convertToACLEntries(vcenter.getAcls()));

    return response;
  }
 /**
  * @brief Show Storage provider This call allows user to fetch Storage Provider details such as
  *     provider host access credential details.
  * @param id Storage Provider Identifier
  * @return Storage Provider details.
  */
 @GET
 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @Path("/{id}")
 @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR})
 public StorageProviderRestRep getStorageProvider(@PathParam("id") URI id) {
   ArgValidator.checkFieldUriType(id, StorageProvider.class, "id");
   StorageProvider mgmtProvider = queryResource(id);
   return map(mgmtProvider);
 }
 /*
  * GET filesystem by id
  */
 @GET
 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @Path("/{id}")
 public FileShareRestRep getFileSystemInternal(@PathParam("id") URI id) {
   ArgValidator.checkFieldUriType(id, FileShare.class, "id");
   FileShare fs = _fileService.queryResource(id);
   checkFileShareInternal(fs);
   return map(fs);
 }
  /**
   * Discovers (refreshes) a vCenter. This is an asynchronous call.
   *
   * @param id The URI of the vCenter.
   * @prereq none
   * @brief Discover vCenter
   * @return TaskResourceRep (asynchronous call)
   */
  @POST
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}/discover")
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.TENANT_ADMIN})
  public TaskResourceRep discoverVcenter(@PathParam("id") URI id) {
    ArgValidator.checkFieldUriType(id, Vcenter.class, "id");
    Vcenter vcenter = queryObject(Vcenter.class, id, true);

    return doDiscoverVcenter(vcenter);
  }
  /**
   * Get virtual array object from id
   *
   * @param id the URN of a ViPR virtual array object
   * @return
   */
  private VirtualArray getVirtualArrayById(URI id, boolean checkInactive) {
    if (id == null) {
      return null;
    }

    VirtualArray n = _permissionsHelper.getObjectById(id, VirtualArray.class);
    ArgValidator.checkEntity(n, id, isIdEmbeddedInURL(id), checkInactive);

    return n;
  }
 /*
  * GET task status
  */
 @GET
 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @Path("/{id}/tasks/{op_id}/")
 public TaskResourceRep getTaskInternal(@PathParam("id") URI id, @PathParam("op_id") URI op_id)
     throws DatabaseException {
   ArgValidator.checkFieldUriType(id, FileShare.class, "id");
   FileShare fs = _fileService.queryResource(id);
   checkFileShareInternal(fs);
   return toTask(fs, op_id.toString());
 }
 /*
  * POST to create a new export
  */
 @POST
 @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @Path("/{id}/exports")
 public TaskResourceRep exportInternal(@PathParam("id") URI id, FileSystemExportParam param)
     throws InternalException {
   ArgValidator.checkFieldUriType(id, FileShare.class, "id");
   FileShare fs = _fileService.queryResource(id);
   checkFileShareInternal(fs);
   return _fileService.export(id, param);
 }
 /**
  * Get info for Bucket
  *
  * @param id the URN of a ViPR Bucket
  * @return Bucket details
  */
 @GET
 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @Path("/{id}")
 @CheckPermission(
     roles = {Role.SYSTEM_MONITOR, Role.TENANT_ADMIN},
     acls = {ACL.ANY})
 public BucketRestRep getBucket(@PathParam("id") URI id) {
   ArgValidator.checkFieldUriType(id, Bucket.class, "id");
   Bucket fs = queryResource(id);
   return map(fs);
 }
  /**
   * Deactivate Bucket, this will move the Bucket to a "marked-for-delete" state
   *
   * <p>NOTE: This is an asynchronous operation.
   *
   * @param id the URN of a ViPR Bucket
   * @param param Bucket delete param for optional force delete
   * @brief Delete Bucket
   * @return Task resource representation
   * @throws InternalException
   */
  @POST
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}/deactivate")
  @CheckPermission(
      roles = {Role.TENANT_ADMIN},
      acls = {ACL.OWN, ACL.ALL})
  public TaskResourceRep deactivateBucket(@PathParam("id") URI id, BucketDeleteParam param)
      throws InternalException {

    String task = UUID.randomUUID().toString();
    _log.info(
        String.format(
            "BucketDelete --- Bucket id: %1$s, Task: %2$s, ForceDelete: %3$s",
            id, task, param.getForceDelete()));
    ArgValidator.checkFieldUriType(id, Bucket.class, "id");
    Bucket bucket = queryResource(id);
    if (!param.getForceDelete()) {
      ArgValidator.checkReference(Bucket.class, id, checkForDelete(bucket));
    }
    StorageSystem device = _dbClient.queryObject(StorageSystem.class, bucket.getStorageDevice());

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

    ObjectController controller = getController(ObjectController.class, device.getSystemType());
    controller.deleteBucket(bucket.getStorageDevice(), id, task);

    auditOp(
        OperationTypeEnum.DELETE_BUCKET,
        true,
        AuditLogManager.AUDITOP_BEGIN,
        bucket.getId().toString(),
        device.getId().toString());

    return toTask(bucket, task, op);
  }
  /**
   * Lists the id and name of all the vCenters that belong to the given tenant organization if the
   * requesting user is a SysAdmin or SecAdmin. If the requested user is a TenantAdmin and user is a
   * tenant of the "tenant" given in the query param then all the vCenters of the tenant query param
   * will be returned otherwise returned only the vCenters that the user's tenant shares.
   *
   * @param tid tenant to filter the vCenters. "No-Filter" or "null" indicates, listing all the
   *     vCenters in the system. "Not-Assigned" indicates, list all the vCenters with no tenants
   *     assigned to it.
   * @return a list of vCenters that belong to the tenant organization.
   * @throws DatabaseException when a DB error occurs
   */
  @GET
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  public VcenterList listVcenters(@QueryParam("tenant") final URI tid) throws DatabaseException {
    VcenterList list = new VcenterList();
    List<Vcenter> vcenters = null;

    if (isSecurityAdmin() || isSystemAdmin()) {
      _log.debug("Fetching vCenters for {}", tid);
      if (NullColumnValueGetter.isNullURI(tid)
          || Vcenter.NO_TENANT_SELECTOR.equalsIgnoreCase(tid.toString())) {
        vcenters = getDataObjects(Vcenter.class);
        list.setVcenters(
            map(
                ResourceTypeEnum.VCENTER,
                getNamedElementsList(Vcenter.class, DATAOBJECT_NAME_FIELD, vcenters)));
      } else if (Vcenter.TENANT_SELECTOR_FOR_UNASSIGNED.equalsIgnoreCase(tid.toString())) {
        vcenters = getDataObjects(Vcenter.class);
        list.setVcenters(
            map(
                ResourceTypeEnum.VCENTER,
                getNamedElementsWithNoAcls(Vcenter.class, DATAOBJECT_NAME_FIELD, vcenters)));
      } else {
        ArgValidator.checkEntity(_dbClient.queryObject(tid), tid, isIdEmbeddedInURL(tid));
        list.setVcenters(
            map(
                ResourceTypeEnum.VCENTER,
                listChildrenWithAcls(tid, Vcenter.class, DATAOBJECT_NAME_FIELD)));
      }
      return list;
    }

    vcenters = getDataObjects(Vcenter.class);
    if (!CollectionUtils.isEmpty(vcenters)) {
      List<Vcenter> tenantVcenterList = null;
      if (shouldTenantAdminUseTenantParam(tid)) {
        // If the tenant admin can use the tid query param, then the filtering should
        // happen based on the tenant query param.
        tenantVcenterList = filterVcentersByTenant(vcenters, tid);
      } else {
        // Get the vCenters based on the User's tenant org. If the user is not a tenant admin,
        // insufficient
        // permission exception will be thrown.
        tenantVcenterList = filterVcentersByTenant(vcenters, NullColumnValueGetter.getNullURI());
      }
      list.setVcenters(
          map(
              ResourceTypeEnum.VCENTER,
              getNamedElementsList(Vcenter.class, DATAOBJECT_NAME_FIELD, tenantVcenterList)));
    }
    return list;
  }
  /**
   * Undo the release of a file system
   *
   * @param id the URN of a ViPR file system to undo
   * @return the updated file system
   * @throws InternalException
   */
  @POST
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}/release/undo")
  public FileShareRestRep undoReleaseFileSystemInternal(@PathParam("id") URI id)
      throws InternalException {

    ArgValidator.checkFieldUriType(id, FileShare.class, "id");
    FileShare fs = _fileService.queryResource(id);
    checkFileShareInternal(fs);

    URI releasedProject = fs.getOriginalProject();
    if (releasedProject == null) {
      throw APIException.forbidden.onlyPreviouslyReleasedFileSystemsCanBeUndone();
    }

    Project project = _permissionsHelper.getObjectById(releasedProject, Project.class);
    ArgValidator.checkEntity(project, releasedProject, false);
    ArgValidator.checkFieldNotNull(project.getTenantOrg(), "tenantOrg");
    ArgValidator.checkFieldNotNull(project.getTenantOrg().getURI(), "tenantOrg");

    fs.setTenant(new NamedURI(project.getTenantOrg().getURI(), fs.getLabel()));
    fs.setProject(new NamedURI(releasedProject, fs.getLabel()));
    fs.setOriginalProject(null);
    fs.clearInternalFlags(INTERNAL_FILESHARE_FLAGS);
    _dbClient.updateAndReindexObject(fs);

    // audit against the new project, not the old dummy internal project
    auditOp(
        OperationTypeEnum.UNDO_RELEASE_FILE_SYSTEM,
        true,
        null,
        fs.getId().toString(),
        project.getId().toString());

    return map(fs);
  }
 /*
  * POST to deactivate filesystem
  */
 @POST
 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @Path("/{id}/deactivate")
 public TaskResourceRep deactivateFileSystemInternal(
     @PathParam("id") URI id, FileSystemDeleteParam param) throws InternalException {
   ArgValidator.checkFieldUriType(id, FileShare.class, "id");
   FileShare fs = _fileService.queryResource(id);
   checkFileShareInternal(fs);
   TenantOrg tenant = _permissionsHelper.getRootTenant();
   if (!_permissionsHelper.userHasGivenRole(
       getUserFromContext(), tenant.getId(), Role.SYSTEM_ADMIN, Role.TENANT_ADMIN)) {
     throw APIException.forbidden.onlyAdminsCanDeactivateFileSystems(
         Role.SYSTEM_ADMIN.toString(), Role.TENANT_ADMIN.toString());
   }
   return _fileService.deactivateFileSystem(id, param);
 }
 /*
  * DELETE filesystem export
  */
 @DELETE
 @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @Path("/{id}/exports/{protocol},{secType},{perm},{root_mapping}")
 public TaskResourceRep unexportInternal(
     @PathParam("id") URI id,
     @PathParam("protocol") String protocol,
     @PathParam("secType") String securityType,
     @PathParam("perm") String permissions,
     @PathParam("root_mapping") String rootUserMapping,
     @QueryParam("subDirectory") String subDirectory)
     throws InternalException {
   ArgValidator.checkFieldUriType(id, FileShare.class, "id");
   FileShare fs = _fileService.queryResource(id);
   checkFileShareInternal(fs);
   return _fileService.unexport(
       id, protocol, securityType, permissions, rootUserMapping, subDirectory);
 }
  /**
   * Detaches storage from the vcenter.
   *
   * @param id the URN of a ViPR vcenter
   * @brief Detach storage from vcenter
   * @return task
   * @throws DatabaseException when a DB error occurs
   */
  @POST
  @Path("/{id}/detach-storage")
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.TENANT_ADMIN})
  public TaskResourceRep detachStorage(@PathParam("id") URI id) throws DatabaseException {
    Vcenter vcenter = queryObject(Vcenter.class, id, true);
    ArgValidator.checkEntity(vcenter, id, true);

    checkIfOtherTenantsUsingTheVcenter(vcenter);

    String taskId = UUID.randomUUID().toString();
    Operation op =
        _dbClient.createTaskOpStatus(
            Vcenter.class,
            vcenter.getId(),
            taskId,
            ResourceOperationTypeEnum.DETACH_VCENTER_DATACENTER_STORAGE);
    ComputeSystemController controller = getController(ComputeSystemController.class, null);
    controller.detachVcenterStorage(vcenter.getId(), false, taskId);
    return toTask(vcenter, taskId, op);
  }
  /**
   * Add or remove individual Access Control List entry(s). When the vCenter is created with no
   * shared access (Vcenter.shared = Boolean.FALSE), there cannot be multiple Access Control List
   * Entries associated with this vCenter.
   *
   * @param changes Access Control List assignment changes. Request body must include at least one
   *     add or remove operation
   * @param id the URN of a ViPR Project.
   * @return the vCenter discovery async task.
   */
  @PUT
  @Path("/{id}/acl")
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(roles = {Role.SECURITY_ADMIN, Role.SYSTEM_ADMIN})
  public TaskResourceRep updateAclAssignments(
      @PathParam("id") URI id, ACLAssignmentChanges changes) {
    // Make sure the vCenter is a valid one.
    Vcenter vcenter = queryObject(Vcenter.class, id, true);
    ArgValidator.checkEntity(vcenter, id, isIdEmbeddedInURL(id));

    // Validate the acl assignment changes. It is not valid when an
    // acl entry contains more than one privilege or privileges
    // other than USE.
    validateAclAssignments(changes);

    // Make sure that the vCenter with respect to the tenants
    // that we are removing is not in use (means the datacenters
    // and its clusters and hosts with the removing tenant do not
    // have any exports).
    checkVcenterUsage(vcenter, changes);

    _permissionsHelper.updateACLs(
        vcenter, changes, new PermissionsHelper.UsageACLFilter(_permissionsHelper));

    _dbClient.updateAndReindexObject(vcenter);

    auditOp(
        OperationTypeEnum.UPDATE_VCENTER,
        true,
        null,
        vcenter.getId().toString(),
        vcenter.getLabel(),
        changes);

    // Rediscover the vCenter, this will update the updated
    // list of tenants based its latest acls to its datacenters
    // and hosts and clusters.
    return doDiscoverVcenter(queryObject(Vcenter.class, vcenter.getId(), true));
  }
  /**
   * List the vCenter data centers of the vCenter.
   *
   * @param id the URN of a ViPR vCenter
   * @param tid tenant to filter the vCenter data centers. "No-Filter" or "null" indicates, listing
   *     all the vCenters in the system. "Not-Assigned" indicates, list all the vCenters with no
   *     tenants assigned to it.
   * @prereq none
   * @brief List vCenter data centers
   * @return All the list of vCenter data centers.
   * @throws DatabaseException when a DB error occurs.
   */
  @GET
  @Path("/{id}/vcenter-data-centers")
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  public VcenterDataCenterList getVcenterDataCenters(
      @PathParam("id") URI id, @QueryParam("tenant") URI tid) throws DatabaseException {
    Vcenter vcenter = queryObject(Vcenter.class, id, false);
    ArgValidator.checkEntity(vcenter, id, isIdEmbeddedInURL(id));

    // check the user permissions for this tenant org
    verifyAuthorizedSystemOrTenantOrgUser(
        _permissionsHelper.convertToACLEntries(vcenter.getAcls()));

    URI tenantId;
    if (isSecurityAdmin() || isSystemAdmin()) {
      tenantId = tid;
    } else {
      if (shouldTenantAdminUseTenantParam(tid)) {
        tenantId = tid;
      } else {
        tenantId = URI.create(getUserFromContext().getTenantId());
      }
    }

    _log.debug("Fetching the vCenterDataCenters for the tenant {}", tenantId);

    // get the vcenters
    VcenterDataCenterList list = new VcenterDataCenterList();
    List<NamedElementQueryResultList.NamedElement> elements =
        listChildren(id, VcenterDataCenter.class, DATAOBJECT_NAME_FIELD, "vcenter");

    // Filter the vCenterDataCenters based on the tenant.
    list.setDataCenters(
        map(
            ResourceTypeEnum.VCENTERDATACENTER,
            id,
            filterTenantResourcesByTenant(tenantId, VcenterDataCenter.class, elements)));
    return list;
  }
  /**
   * List the clusters in a vCenter
   *
   * @param id the URN of a ViPR vCenter
   * @prereq none
   * @brief List vCenter clusters
   * @return The list of clusters of the vCenter.
   * @throws DatabaseException when a DB error occurs.
   */
  @GET
  @Path("/{id}/clusters")
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  public ClusterList getVcenterClusters(@PathParam("id") URI id) throws DatabaseException {
    Vcenter vcenter = queryObject(Vcenter.class, id, false);
    ArgValidator.checkEntity(vcenter, id, isIdEmbeddedInURL(id));

    // check the user permissions for this tenant org
    verifyAuthorizedInTenantOrg(_permissionsHelper.convertToACLEntries(vcenter.getAcls()));

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

    List<NamedElementQueryResultList.NamedElement> vCentersDataCenters =
        filterTenantResourcesByTenant(
            tenantId,
            VcenterDataCenter.class,
            listChildren(id, VcenterDataCenter.class, DATAOBJECT_NAME_FIELD, "vcenter"));

    ClusterList list = new ClusterList();
    Iterator<NamedElementQueryResultList.NamedElement> dataCentersIterator =
        vCentersDataCenters.iterator();
    while (dataCentersIterator.hasNext()) {
      NamedElementQueryResultList.NamedElement dataCenterElement = dataCentersIterator.next();
      list.getClusters()
          .addAll(
              map(
                  ResourceTypeEnum.CLUSTER,
                  listChildren(
                      dataCenterElement.getId(),
                      Cluster.class,
                      DATAOBJECT_NAME_FIELD,
                      "vcenterDataCenter")));
    }

    return list;
  }
  /**
   * 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);
  }
  /**
   * Update the Storage Provider. This is useful when we move arrays to some other provider.
   *
   * @param id the URN of a ViPR Storage Provider
   * @brief Update Storage provider
   * @return Updated Storage Provider information.
   */
  @PUT
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}")
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN})
  public StorageProviderRestRep updateStorageProvider(
      @PathParam("id") URI id, StorageProviderUpdateParam param) {
    StorageProvider storageProvider = _dbClient.queryObject(StorageProvider.class, id);
    if (null == storageProvider || storageProvider.getInactive()) {
      throw APIException.notFound.unableToFindEntityInURL(id);
    } else {
      /* Usecase is not to remove the provider instead we can update the old storage provider with
      new provider details. */
      if (param.getName() != null
          && !param.getName().equals("")
          && !param.getName().equalsIgnoreCase(storageProvider.getLabel())) {
        checkForDuplicateName(param.getName(), StorageProvider.class);
        storageProvider.setLabel(param.getName());
      }

      // if the ip or port passed are different from the existing one
      // check to ensure a provider does not exist with the new ip + port combo
      String existingIPAddress = storageProvider.getIPAddress();
      Integer existingPortNumber = storageProvider.getPortNumber();
      if ((param.getIpAddress() != null && !param.getIpAddress().equals(existingIPAddress))
          || (param.getPortNumber() != null && !param.getPortNumber().equals(existingPortNumber))) {
        String ipAddress =
            (param.getIpAddress() != null) ? param.getIpAddress() : existingIPAddress;
        Integer portNumber =
            (param.getPortNumber() != null) ? param.getPortNumber() : existingPortNumber;
        ArgValidator.checkFieldRange(portNumber, 1, 65535, "port_number");

        String providerKey = ipAddress + "-" + portNumber;
        List<StorageProvider> providers =
            CustomQueryUtility.getActiveStorageProvidersByProviderId(_dbClient, providerKey);
        if (providers != null && !providers.isEmpty()) {
          throw APIException.badRequests.invalidParameterStorageProviderAlreadyRegistered(
              providerKey);
        }

        // User can update IP address for an existing Provider object
        // if and only if the connection with old IP is not alive.
        if (!existingIPAddress.equals(param.getIpAddress())
            && isOldConnectionAlive(
                existingIPAddress, existingPortNumber, storageProvider.getInterfaceType())
            && (storageProvider.getStorageSystems() != null
                && !storageProvider.getStorageSystems().isEmpty())) {
          throw APIException.badRequests.cannotUpdateProviderIP(
              existingIPAddress + "-" + existingPortNumber);
        }

        storageProvider.setIPAddress(ipAddress);
        storageProvider.setPortNumber(portNumber);
      }
      if (param.getUserName() != null && StringUtils.isNotBlank(param.getUserName())) {
        storageProvider.setUserName(param.getUserName());
      }
      if (param.getPassword() != null && StringUtils.isNotBlank(param.getPassword())) {
        storageProvider.setPassword(param.getPassword());
      }
      if (param.getUseSSL() != null) {
        storageProvider.setUseSSL(param.getUseSSL());
      }

      if (param.getInterfaceType() != null) {
        ArgValidator.checkFieldValueFromEnum(
            param.getInterfaceType(),
            "interface_type",
            EnumSet.of(
                StorageProvider.InterfaceType.hicommand,
                StorageProvider.InterfaceType.smis,
                StorageProvider.InterfaceType.scaleio,
                StorageProvider.InterfaceType.ibmxiv));
        storageProvider.setInterfaceType(param.getInterfaceType());
      }

      if (param.getSecondaryUsername() != null) {
        storageProvider.setSecondaryUsername(param.getSecondaryUsername());
      }
      if (param.getSecondaryPassword() != null) {
        storageProvider.setSecondaryPassword(param.getSecondaryPassword());
      }
      if (param.getElementManagerURL() != null) {
        storageProvider.setElementManagerURL(param.getElementManagerURL());
      }

      _dbClient.persistObject(storageProvider);
    }

    auditOp(
        OperationTypeEnum.UPDATE_STORAGEPROVIDER,
        true,
        null,
        storageProvider.getId().toString(),
        storageProvider.getLabel(),
        storageProvider.getIPAddress(),
        storageProvider.getPortNumber(),
        storageProvider.getUserName(),
        storageProvider.getInterfaceType());

    return map(storageProvider);
  }