/**
   * Called to update the job status when the volume expand job completes.
   *
   * @param jobContext The job context.
   */
  public void updateStatus(JobContext jobContext) throws Exception {
    CloseableIterator<CIMObjectPath> associatorIterator = null;
    CloseableIterator<CIMInstance> instanceIterator = null;
    JobStatus jobStatus = getJobStatus();

    try {
      if (jobStatus == JobStatus.IN_PROGRESS) {
        return;
      }

      DbClient dbClient = jobContext.getDbClient();
      CIMConnectionFactory cimConnectionFactory = jobContext.getCimConnectionFactory();
      WBEMClient client = getWBEMClient(dbClient, cimConnectionFactory);

      // If terminal state update storage pool capacity and remove reservation for volume capacity
      // from pool's reserved capacity map.
      if (jobStatus == JobStatus.SUCCESS
          || jobStatus == JobStatus.FAILED
          || jobStatus == JobStatus.FATAL_ERROR) {
        SmisUtils.updateStoragePoolCapacity(dbClient, client, _storagePoolURI);

        StoragePool pool = dbClient.queryObject(StoragePool.class, _storagePoolURI);
        StringMap reservationMap = pool.getReservedCapacityMap();
        URI volumeId = getTaskCompleter().getId();
        // remove from reservation map
        reservationMap.remove(volumeId.toString());
        dbClient.persistObject(pool);
      }

      String opId = getTaskCompleter().getOpId();
      StringBuilder logMsgBuilder =
          new StringBuilder(
              String.format(
                  "Updating status of job %s to %s, task: %s",
                  this.getJobName(), jobStatus.name(), opId));

      if (jobStatus == JobStatus.SUCCESS) {
        VolumeExpandCompleter taskCompleter = (VolumeExpandCompleter) getTaskCompleter();
        Volume volume = dbClient.queryObject(Volume.class, taskCompleter.getId());
        // set requested capacity
        volume.setCapacity(taskCompleter.getSize());
        // set meta related properties
        volume.setTotalMetaMemberCapacity(taskCompleter.getTotalMetaMembersSize());
        volume.setMetaMemberCount(taskCompleter.getMetaMemberCount());
        volume.setMetaMemberSize(taskCompleter.getMetaMemberSize());
        volume.setIsComposite(taskCompleter.isComposite());
        volume.setCompositionType(taskCompleter.getMetaVolumeType());

        // set provisioned capacity
        associatorIterator =
            client.associatorNames(getCimJob(), null, SmisConstants.CIM_STORAGE_VOLUME, null, null);
        if (associatorIterator.hasNext()) {
          CIMObjectPath volumePath = associatorIterator.next();
          CIMInstance volumeInstance = client.getInstance(volumePath, true, false, null);
          if (volumeInstance != null) {
            CIMProperty consumableBlocks =
                volumeInstance.getProperty(SmisConstants.CP_CONSUMABLE_BLOCKS);
            CIMProperty blockSize = volumeInstance.getProperty(SmisConstants.CP_BLOCK_SIZE);
            // calculate provisionedCapacity = consumableBlocks * block size
            Long provisionedCapacity =
                Long.valueOf(consumableBlocks.getValue().toString())
                    * Long.valueOf(blockSize.getValue().toString());
            volume.setProvisionedCapacity(provisionedCapacity);
          }

          // set allocated capacity
          instanceIterator =
              client.referenceInstances(
                  volumePath,
                  SmisConstants.CIM_ALLOCATED_FROM_STORAGEPOOL,
                  null,
                  false,
                  SmisConstants.PS_SPACE_CONSUMED);
          if (instanceIterator.hasNext()) {
            CIMInstance allocatedFromStoragePoolPath = instanceIterator.next();
            CIMProperty spaceConsumed =
                allocatedFromStoragePoolPath.getProperty(SmisConstants.CP_SPACE_CONSUMED);
            if (null != spaceConsumed) {
              volume.setAllocatedCapacity(Long.valueOf(spaceConsumed.getValue().toString()));
            }
          }
        }
        logMsgBuilder.append(
            String.format(
                "%n   Capacity: %s, Provisioned capacity: %s, Allocated Capacity: %s",
                volume.getCapacity(),
                volume.getProvisionedCapacity(),
                volume.getAllocatedCapacity()));
        if (volume.getIsComposite()) {
          logMsgBuilder.append(
              String.format(
                  "%n   Is Meta: %s, Total meta member capacity: %s, Meta member count %s, Meta member size: %s",
                  volume.getIsComposite(),
                  volume.getTotalMetaMemberCapacity(),
                  volume.getMetaMemberCount(),
                  volume.getMetaMemberSize()));
        }

        _log.info(logMsgBuilder.toString());

        // Reset list of meta member volumes in the volume
        if (volume.getMetaVolumeMembers() != null) {
          volume.getMetaVolumeMembers().clear();
        }

        StorageSystem storageSystem =
            dbClient.queryObject(StorageSystem.class, volume.getStorageController());
        // set the RP tag on the volume if the volume is RP protected
        if (volume.checkForRp()
            && storageSystem.getSystemType() != null
            && storageSystem
                .getSystemType()
                .equalsIgnoreCase(DiscoveredDataObject.Type.vmax.toString())) {
          SmisCommandHelper helper = jobContext.getSmisCommandHelper();
          List<CIMObjectPath> volumePathList = new ArrayList<CIMObjectPath>();
          volumePathList.add(helper.getVolumeMember(storageSystem, volume));
          helper.setRecoverPointTag(storageSystem, volumePathList, true);
        }

        dbClient.persistObject(volume);
        // Reset list of meta members native ids in WF data (when meta is created meta members are
        // removed from array)
        WorkflowService.getInstance().storeStepData(opId, new ArrayList<String>());
      }
    } catch (Exception e) {
      _log.error("Caught an exception while trying to updateStatus for SmisVolumeExpandJob", e);
      setPostProcessingErrorStatus(
          "Encountered an internal error during volume expand job status processing : "
              + e.getMessage());
    } finally {
      _metaVolumeTaskCompleter.setLastStepStatus(jobStatus);
      if (associatorIterator != null) {
        associatorIterator.close();
      }
      if (instanceIterator != null) {
        instanceIterator.close();
      }
      super.updateStatus(jobContext);
    }
  }
  /** {@inheritDoc} */
  @Override
  public void updateStatus(JobContext jobContext) throws Exception {
    JobStatus jobStatus = getJobStatus();
    CloseableIterator<CIMObjectPath> volumeIter = null;
    try {
      DbClient dbClient = jobContext.getDbClient();
      TaskCompleter completer = getTaskCompleter();
      BlockSnapshot snapshot = dbClient.queryObject(BlockSnapshot.class, _snapshotURI);
      if (jobStatus == JobStatus.IN_PROGRESS) {
        return;
      }
      if (jobStatus == JobStatus.SUCCESS) {
        s_logger.info(
            "Post-processing successful link snapshot session target {} for task {}",
            snapshot.getId(),
            completer.getOpId());
        // Get the snapshot session to which the target is being linked.
        BlockSnapshotSession snapSession =
            dbClient.queryObject(BlockSnapshotSession.class, completer.getId());

        // Get the snapshot device ID and set it against the BlockSnapshot object.
        BlockObject sourceObj = BlockObject.fetch(dbClient, snapshot.getParent().getURI());
        CIMConnectionFactory cimConnectionFactory = jobContext.getCimConnectionFactory();
        WBEMClient client = getWBEMClient(dbClient, cimConnectionFactory);
        volumeIter =
            client.associatorNames(getCimJob(), null, SmisConstants.CIM_STORAGE_VOLUME, null, null);
        while (volumeIter.hasNext()) {
          // Get the sync volume native device id
          CIMObjectPath volumePath = volumeIter.next();
          s_logger.info("volumePath: {}", volumePath.toString());
          CIMInstance volume = client.getInstance(volumePath, false, false, null);
          String volumeDeviceId =
              volumePath.getKey(SmisConstants.CP_DEVICE_ID).getValue().toString();
          s_logger.info("volumeDeviceId: {}", volumeDeviceId);
          if (volumeDeviceId.equals(sourceObj.getNativeId())) {
            // Don't want the source, we want the linked target.
            continue;
          }
          String volumeElementName =
              CIMPropertyFactory.getPropertyValue(volume, SmisConstants.CP_ELEMENT_NAME);
          s_logger.info("volumeElementName: {}", volumeElementName);
          String volumeWWN = CIMPropertyFactory.getPropertyValue(volume, SmisConstants.CP_WWN_NAME);
          s_logger.info("volumeWWN: {}", volumeWWN);
          String volumeAltName = CIMPropertyFactory.getPropertyValue(volume, SmisConstants.CP_NAME);
          s_logger.info("volumeAltName: {}", volumeAltName);
          StorageSystem system = dbClient.queryObject(StorageSystem.class, getStorageSystemURI());
          snapshot.setNativeId(volumeDeviceId);
          snapshot.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(system, snapshot));
          snapshot.setDeviceLabel(volumeElementName);
          snapshot.setInactive(false);
          snapshot.setIsSyncActive(Boolean.TRUE);
          snapshot.setCreationTime(Calendar.getInstance());
          snapshot.setWWN(volumeWWN.toUpperCase());
          snapshot.setAlternateName(volumeAltName);
          snapshot.setSettingsInstance(snapSession.getSessionInstance());
          commonSnapshotUpdate(
              snapshot,
              volume,
              client,
              system,
              sourceObj.getNativeId(),
              volumeDeviceId,
              false,
              dbClient);
          s_logger.info(
              String.format(
                  "For target volume path %1$s, going to set blocksnapshot %2$s nativeId to %3$s (%4$s). Associated volume is %5$s (%6$s)",
                  volumePath.toString(),
                  snapshot.getId().toString(),
                  volumeDeviceId,
                  volumeElementName,
                  sourceObj.getNativeId(),
                  sourceObj.getDeviceLabel()));
          dbClient.updateObject(snapshot);
        }
      } else if (jobStatus == JobStatus.FAILED || jobStatus == JobStatus.FATAL_ERROR) {
        s_logger.info(
            "Failed to link snapshot session target {} for task {}",
            snapshot.getId(),
            completer.getOpId());
        snapshot.setInactive(true);
        dbClient.updateObject(snapshot);
      }
    } catch (Exception e) {
      setPostProcessingErrorStatus(
          "Encountered an internal error in link snapshot session target job status processing: "
              + e.getMessage());
      s_logger.error(
          "Encountered an internal error in link snapshot session target job status processing", e);
    } finally {
      if (volumeIter != null) {
        volumeIter.close();
      }
      super.updateStatus(jobContext);
    }
  }