/*
  * Send DELETE request to KittyHawk server in async mode
  *
  * @param resource webResource
  *
  * @param param parameters for delete
  *
  * @return VNXeCommandJob
  *
  * @throws VNXeException
  */
 public VNXeCommandJob deleteRequestAsync(Object param) throws VNXeException {
   _logger.debug("delete data: " + _url);
   setAsyncMode();
   ClientResponse response = deleteRequest(param);
   VNXeCommandJob job;
   String resString = response.getEntity(String.class);
   ObjectMapper mapper = new ObjectMapper();
   try {
     job = mapper.readValue(resString, VNXeCommandJob.class);
   } catch (JsonParseException e) {
     _logger.error(String.format("unexpected data returned: %s from: %s ", resString, _url), e);
     throw VNXeException.exceptions.unexpectedDataError(
         String.format("unexpected data returned: %s", resString), e);
   } catch (JsonMappingException e) {
     _logger.error(String.format("unexpected data returned: %s from: %s ", resString, _url), e);
     throw VNXeException.exceptions.unexpectedDataError(
         String.format("unexpected data returned: %s", resString), e);
   } catch (IOException e) {
     _logger.error(String.format("unexpected data returned: %s from: %s ", resString, _url), e);
     throw VNXeException.exceptions.unexpectedDataError(
         String.format("unexpected data returned: %s", resString), e);
   }
   if (job != null) {
     _logger.info("submitted the deleting file system job: {} ", job.getId());
   }
   return job;
 }
  public VNXeCommandJob postRequestAsync(ParamBase param) {
    setAsyncMode();
    ClientResponse response = postRequest(param);

    VNXeCommandJob job;
    String resString = response.getEntity(String.class);
    ObjectMapper mapper = new ObjectMapper();
    try {
      job = mapper.readValue(resString, VNXeCommandJob.class);
    } catch (JsonParseException e) {
      _logger.error(String.format("unexpected data returned: %s from: %s", resString, _url), e);
      throw VNXeException.exceptions.unexpectedDataError(
          "unexpected data returned:" + resString, e);
    } catch (JsonMappingException e) {
      _logger.error(String.format("unexpected data returned: %s from: %s", resString, _url), e);
      throw VNXeException.exceptions.unexpectedDataError(
          "unexpected data returned:" + resString, e);
    } catch (IOException e) {
      _logger.error(String.format("unexpected data returned: %s from: %s", resString, _url), e);
      throw VNXeException.exceptions.unexpectedDataError(
          "unexpected data returned:" + resString, e);
    }
    if (job != null) {
      _logger.info("submitted the job: " + job.getId());
    } else {
      _logger.warn("No job returned.");
    }
    return job;
  }
  @Override
  public void deleteSingleVolumeSnapshot(
      StorageSystem storage, URI snapshot, TaskCompleter taskCompleter)
      throws DeviceControllerException {

    try {
      BlockSnapshot snap = _dbClient.queryObject(BlockSnapshot.class, snapshot);
      VNXeApiClient apiClient = getVnxeClient(storage);
      VNXeLunSnap lunSnap = apiClient.getLunSnapshot(snap.getNativeId());
      if (lunSnap != null) {
        VNXeCommandJob job = apiClient.deleteLunSnap(lunSnap.getId());
        if (job != null) {
          ControllerServiceImpl.enqueueJob(
              new QueueJob(
                  new VNXeBlockDeleteSnapshotJob(job.getId(), storage.getId(), taskCompleter)));
        }
      } else {
        // Perhaps, it's already been deleted or was deleted on the array.
        // In that case, we'll just say all is well, so that this operation
        // is idempotent.
        snap.setInactive(true);
        snap.setIsSyncActive(false);
        _dbClient.updateObject(snap);
        taskCompleter.ready(_dbClient);
      }
    } catch (VNXeException e) {
      _log.error("Delete volume snapshot got the exception", e);
      taskCompleter.error(_dbClient, e);
    } catch (Exception ex) {
      _log.error("Delete volume snapshot got the exception", ex);
      ServiceError error = DeviceControllerErrors.vnxe.jobFailed("DeleteSnapshot", ex.getMessage());
      taskCompleter.error(_dbClient, error);
    }
  }
  @Override
  public void deleteGroupSnapshots(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter)
      throws DeviceControllerException {
    try {
      List<BlockSnapshot> snapshots =
          _dbClient.queryObject(BlockSnapshot.class, Arrays.asList(snapshot));
      BlockSnapshot snapshotObj = snapshots.get(0);

      VNXeApiClient apiClient = getVnxeClient(storage);
      VNXeLunGroupSnap lunGroupSnap =
          apiClient.getLunGroupSnapshot(snapshotObj.getReplicationGroupInstance());
      if (lunGroupSnap != null) {
        VNXeCommandJob job = apiClient.deleteLunGroupSnap(lunGroupSnap.getId());
        if (job != null) {
          ControllerServiceImpl.enqueueJob(
              new QueueJob(
                  new VNXeBlockDeleteSnapshotJob(job.getId(), storage.getId(), taskCompleter)));
        } else {
          // Should not take this path, but treat as an error if we do
          // happen to get a null job due to some error in the client.
          _log.error("Unexpected null job from VNXe client call to delete group snapshot.");
          ServiceCoded sc =
              DeviceControllerExceptions.vnxe.nullJobForDeleteGroupSnapshot(
                  snapshotObj.forDisplay(), snapshotObj.getReplicationGroupInstance());
          taskCompleter.error(_dbClient, sc);
        }
      } else {
        // Treat as in the single volume snapshot case and presume
        // the group snapshot has already been deleted.
        List<BlockSnapshot> grpSnapshots =
            ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshotObj, _dbClient);
        for (BlockSnapshot grpSnapshot : grpSnapshots) {
          grpSnapshot.setInactive(true);
          grpSnapshot.setIsSyncActive(false);
        }
        _dbClient.updateObject(grpSnapshots);
        taskCompleter.ready(_dbClient);
      }
    } catch (VNXeException e) {
      _log.error("Delete group snapshot got the exception", e);
      taskCompleter.error(_dbClient, e);
    } catch (Exception ex) {
      _log.error("Delete group snapshot got the exception", ex);
      ServiceError error =
          DeviceControllerErrors.vnxe.jobFailed("DeletGroupSnapshot", ex.getMessage());
      taskCompleter.error(_dbClient, error);
    }
  }
  @Override
  public void createGroupSnapshots(
      StorageSystem storage,
      List<URI> snapshotList,
      Boolean createInactive,
      Boolean readOnly,
      TaskCompleter taskCompleter)
      throws DeviceControllerException {
    try {
      URI snapshot = snapshotList.get(0);
      BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot);

      Volume volume = _dbClient.queryObject(Volume.class, snapshotObj.getParent());
      TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, volume.getTenant().getURI());
      String tenantName = tenant.getLabel();
      String snapLabelToUse =
          _nameGenerator.generate(
              tenantName,
              snapshotObj.getLabel(),
              snapshot.toString(),
              '-',
              SmisConstants.MAX_SNAPSHOT_NAME_LENGTH);
      String groupName = getConsistencyGroupName(snapshotObj);
      VNXeApiClient apiClient = getVnxeClient(storage);
      VNXeCommandJob job = apiClient.createLunGroupSnap(groupName, snapLabelToUse);
      if (job != null) {
        ControllerServiceImpl.enqueueJob(
            new QueueJob(
                new VNXeBlockCreateCGSnapshotJob(
                    job.getId(), storage.getId(), !createInactive, taskCompleter)));
      }

    } catch (VNXeException e) {
      _log.error("Create volume snapshot got the exception", e);
      taskCompleter.error(_dbClient, e);

    } catch (Exception ex) {
      _log.error("Create volume snapshot got the exception", ex);
      ServiceError error =
          DeviceControllerErrors.vnxe.jobFailed("CreateCGSnapshot", ex.getMessage());
      taskCompleter.error(_dbClient, error);
    }
  }
  @Override
  public void restoreGroupSnapshots(
      StorageSystem storage, URI volume, URI snapshot, TaskCompleter taskCompleter)
      throws DeviceControllerException {

    try {
      BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot);

      VNXeApiClient apiClient = getVnxeClient(storage);
      VNXeLunGroupSnap lunGroupSnap =
          apiClient.getLunGroupSnapshot(snapshotObj.getReplicationGroupInstance());
      // Error out if the snapshot is attached
      if (lunGroupSnap.getIsAttached()) {
        _log.error(
            "Snapshot {})is attached and cannot be used for restore", snapshotObj.getLabel());
        ServiceError error =
            DeviceControllerErrors.vnxe.cannotRestoreAttachedSnapshot(snapshot.toString());
        taskCompleter.error(_dbClient, error);
      }
      VNXeCommandJob job = apiClient.restoreLunGroupSnap(lunGroupSnap.getId());
      if (job != null) {
        ControllerServiceImpl.enqueueJob(
            new QueueJob(
                new VNXeBlockRestoreSnapshotJob(job.getId(), storage.getId(), taskCompleter)));
      }

    } catch (VNXeException e) {
      _log.error("Restore group snapshot got the exception", e);
      taskCompleter.error(_dbClient, e);

    } catch (Exception ex) {
      _log.error("Restore group snapshot got the exception", ex);
      ServiceError error =
          DeviceControllerErrors.vnxe.jobFailed("RestoreSnapshotJob", ex.getMessage());
      taskCompleter.error(_dbClient, error);
    }
  }