/**
   * Adds the tenant to the vCenter acls if the tenant admin is creating it. This always sets the
   * vCenter tenant (the old deprecated filed to null).
   *
   * @param tenant a valid tenant org if the tenant admin is creating it.
   * @param vcenter the vCenter being created.
   */
  private void addVcenterAclIfTenantAdmin(TenantOrg tenant, Vcenter vcenter) {
    // Always set the deprecated tenant field of a vCenter to null.
    vcenter.setTenant(NullColumnValueGetter.getNullURI());

    if (isSystemAdmin()) {
      return;
    }

    URI tenantId;
    if (tenant != null) {
      tenantId = tenant.getId();
    } else {
      // If the tenant org is not valid, try to use the
      // user's tenant org.
      tenantId = URI.create(getUserFromContext().getTenantId());
    }

    // If the User is an admin in the tenant org, allow the
    // operation otherwise, report the insufficient permission
    // exception.
    if (_permissionsHelper.userHasGivenRole(getUserFromContext(), tenantId, Role.TENANT_ADMIN)) {
      // Generate the acl entry and add to the vCenters acls.
      String aclKey = _permissionsHelper.getTenantUsePermissionKey(tenantId.toString());
      vcenter.addAcl(aclKey, ACL.USE.name());
      _log.debug("Adding {} to the vCenter {} acls", aclKey, vcenter.getLabel());
    }
  }
  /**
   * Check if the vCenter being updated is used by any of its vCenterDataCenters or clusters or
   * hosts or not. This validates only with respect to the tenant that is being removed from the
   * vCenter acls. If the tenant that is getting removed teh vCenter has any exports with the
   * vCenter's vCenterDataCenter or its clusters or hosts.
   *
   * @param vcenter the vCenter being updated.
   * @param changes new acl assignment changes for the vCenter.
   */
  private void checkVcenterUsage(Vcenter vcenter, ACLAssignmentChanges changes) {
    // Make a copy of the vCenter's existing tenant list.
    List<ACLEntry> existingAclEntries = _permissionsHelper.convertToACLEntries(vcenter.getAcls());
    if (CollectionUtils.isEmpty(existingAclEntries)) {
      // If there no existing acl entries for the vCenter
      // there is nothing to validate if it is in user or not.
      _log.debug("vCenter {} does not have any existing acls", vcenter.getLabel());
      return;
    }

    // If there are no tenants to be removed from the vCenter acls,
    // there is nothing to check for usage.
    if (CollectionUtils.isEmpty(changes.getRemove())) {
      _log.debug("There are not acls to remove from vCenter {}", vcenter.getLabel());
      return;
    }

    Set<String> tenantsInUse = new HashSet<String>();

    Set<URI> removingTenants = _permissionsHelper.getUsageURIsFromAclEntries(changes.getRemove());
    Set<URI> existingTenants = _permissionsHelper.getUsageURIsFromAclEntries(existingAclEntries);

    Iterator<URI> removingTenantsIterator = removingTenants.iterator();
    while (removingTenantsIterator.hasNext()) {
      URI removingTenant = removingTenantsIterator.next();
      if (!existingTenants.contains(removingTenant)) {
        continue;
      }

      // Check if vCenter is in use for the removing tenant or not.
      // This checks for all the datacenters of this vcenter that belong to the
      // removing tenant and finds if the datacenter or it clusters or hosts
      // use the exports from the removing tenant or not.
      if (ComputeSystemHelper.isVcenterInUseForTheTenant(
          _dbClient, vcenter.getId(), removingTenant)) {
        TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, removingTenant);
        tenantsInUse.add(tenant.getLabel());
      }
    }

    if (!CollectionUtils.isEmpty(tenantsInUse)) {
      throw APIException.badRequests.cannotRemoveTenant("vCener", vcenter.getLabel(), tenantsInUse);
    }
  }
  /**
   * Validates the create/update vCenter input data
   *
   * @param param the input parameter
   * @param vcenter the vcenter being updated in case of update operation. This parameter must be
   *     null for create operations.
   */
  protected void validateVcenter(VcenterParam param, Vcenter vcenter, Boolean validateConnection) {
    if (vcenter == null
        || (param.findIpAddress() != null
            && !param.findIpAddress().equals(vcenter.getIpAddress()))) {
      checkDuplicateAltId(Vcenter.class, "ipAddress", param.findIpAddress(), "vcenter");
    }
    if (vcenter == null
        || (param.getName() != null && !param.getName().equals(vcenter.getLabel()))) {
      checkDuplicateLabel(Vcenter.class, param.getName(), "vcenter");
    }
    validateVcenterCredentials(param, vcenter);

    if (validateConnection != null && validateConnection == true) {
      String errorMessage = VCenterConnectionValidator.isVCenterConnectionValid(param);
      if (StringUtils.isNotBlank(errorMessage)) {
        throw APIException.badRequests.invalidVCenterConnection(errorMessage);
      }
    }
  }
  /**
   * 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));
  }
 /**
  * Check if the other tenants using the vCenter before deleting it. SysAdmin deleting the vCenter
  * is always allowed whereas, if the vCenter is shared with multiple tenants then it cannot be
  * deleted by the Tenant Admin.
  *
  * @param vcenter to be deleted.
  */
 private void checkIfOtherTenantsUsingTheVcenter(Vcenter vcenter) {
   if (!isSystemAdmin() && vcenter.getAcls().size() > 1) {
     throw APIException.forbidden.tenantAdminCannotDeleteVcenter(
         getUserFromContext().getName(), vcenter.getLabel());
   }
 }