/*
  * 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);
 }
 /*
  * 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);
 }
 /*
  * 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);
 }
  /**
   * 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);
  }
  /**
   * Release a file system from its current tenant & project for internal object usage
   *
   * @param id the URN of a ViPR file system to be released
   * @return the updated file system
   * @throws InternalException
   */
  @POST
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}/release")
  public FileShareRestRep releaseFileSystemInternal(@PathParam("id") URI id)
      throws InternalException {

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

    // if the FS is already marked as internal, we can skip all this logic
    // and just return success down at the bottom
    if (!fs.checkInternalFlags(Flag.INTERNAL_OBJECT)) {
      URI tenantURI = fs.getTenant().getURI();
      if (!_permissionsHelper.userHasGivenRole(
          getUserFromContext(), tenantURI, Role.TENANT_ADMIN)) {
        throw APIException.forbidden.onlyAdminsCanReleaseFileSystems(Role.TENANT_ADMIN.toString());
      }

      // we can't release a fs that has exports
      FSExportMap exports = fs.getFsExports();
      if ((exports != null) && (!exports.isEmpty())) {
        throw APIException.badRequests.cannotReleaseFileSystemExportExists(
            exports.keySet().toString());
      }

      // we can't release a fs that has shares
      SMBShareMap shares = fs.getSMBFileShares();
      if ((shares != null) && (!shares.isEmpty())) {
        throw APIException.badRequests.cannotReleaseFileSystemSharesExists(
            shares.keySet().toString());
      }

      // files systems with pending operations can't be released
      if (fs.getOpStatus() != null) {
        for (String opId : fs.getOpStatus().keySet()) {
          Operation op = fs.getOpStatus().get(opId);
          if (Operation.Status.pending.name().equals(op.getStatus())) {
            throw APIException.badRequests.cannotReleaseFileSystemWithTasksPending();
          }
        }
      }

      // file systems with snapshots can't be released
      Integer snapCount = _fileService.getNumSnapshots(fs);
      if (snapCount > 0) {
        throw APIException.badRequests.cannotReleaseFileSystemSnapshotExists(snapCount);
      }

      TenantOrg rootTenant = _permissionsHelper.getRootTenant();

      // we can't release the file system to the root tenant if the root tenant has no access
      // to the filesystem's virtual pool
      ArgValidator.checkFieldNotNull(fs.getVirtualPool(), "virtualPool");
      VirtualPool virtualPool =
          _permissionsHelper.getObjectById(fs.getVirtualPool(), VirtualPool.class);
      ArgValidator.checkEntity(virtualPool, fs.getVirtualPool(), false);
      if (!_permissionsHelper.tenantHasUsageACL(rootTenant.getId(), virtualPool)) {
        throw APIException.badRequests.cannotReleaseFileSystemRootTenantLacksVPoolACL(
            virtualPool.getId().toString());
      }

      fs.setOriginalProject(fs.getProject().getURI());
      fs.setTenant(new NamedURI(rootTenant.getId(), fs.getLabel()));
      fs.setProject(new NamedURI(_internalProject.getId(), fs.getLabel()));
      fs.addInternalFlags(INTERNAL_FILESHARE_FLAGS);
      _dbClient.updateAndReindexObject(fs);

      // audit against the source project, not the new dummy internal project
      auditOp(
          OperationTypeEnum.RELEASE_FILE_SYSTEM,
          true,
          null,
          fs.getId().toString(),
          fs.getOriginalProject().toString());
    }

    return map(fs);
  }