@Override
 public void fractureSingleVolumeMirror(
     StorageSystem storage, URI mirror, Boolean sync, TaskCompleter taskCompleter)
     throws DeviceControllerException {
   _log.info("fractureSingleVolumeMirror operation START");
   CloseableIterator<CIMObjectPath> storageSyncRefs = null;
   try {
     BlockMirror mirrorObj = _dbClient.queryObject(BlockMirror.class, mirror);
     CIMObjectPath mirrorPath = _cimPath.getBlockObjectPath(storage, mirrorObj);
     // Get reference to the CIM_StorageSynchronized instance
     storageSyncRefs =
         _helper.getReference(storage, mirrorPath, SmisConstants.CIM_STORAGE_SYNCHRONIZED, null);
     boolean isVmax3 = storage.checkIfVmax3();
     while (storageSyncRefs.hasNext()) {
       CIMObjectPath storageSync = storageSyncRefs.next();
       CIMArgument[] inArgs =
           isVmax3
               ? _helper.getFractureMirrorInputArgumentsWithCopyState(storageSync, sync)
               : _helper.getFractureMirrorInputArguments(storageSync, sync);
       CIMArgument[] outArgs = new CIMArgument[5];
       // Invoke method to fracture the synchronization
       _helper.callModifyReplica(storage, inArgs, outArgs);
       taskCompleter.ready(_dbClient);
     }
   } catch (Exception e) {
     _log.info("Problem making SMI-S call", e);
     ServiceError serviceError = DeviceControllerException.errors.jobFailed(e);
     taskCompleter.error(_dbClient, serviceError);
   } finally {
     if (storageSyncRefs != null) {
       storageSyncRefs.close();
     }
   }
 }
  @Override
  public void deleteSingleVolumeMirror(
      StorageSystem storage, URI mirror, TaskCompleter taskCompleter)
      throws DeviceControllerException {
    _log.info("deleteSingleVolumeMirror operation START");
    try {
      BlockMirror mirrorObj = _dbClient.queryObject(BlockMirror.class, mirror);
      if (storage.checkIfVmax3()) {
        _helper.removeVolumeFromParkingSLOStorageGroup(storage, mirrorObj.getNativeId(), false);
        _log.info(
            "Done invoking remove volume {} from parking SLO storage group",
            mirrorObj.getNativeId());
      }

      CIMObjectPath mirrorPath = _cimPath.getBlockObjectPath(storage, mirrorObj);
      CIMObjectPath configSvcPath = _cimPath.getConfigSvcPath(storage);
      CIMArgument[] inArgs = _helper.getDeleteMirrorInputArguments(storage, mirrorPath);
      CIMArgument[] outArgs = new CIMArgument[5];
      _helper.invokeMethod(
          storage, configSvcPath, SmisConstants.RETURN_TO_STORAGE_POOL, inArgs, outArgs);
      CIMObjectPath job = _cimPath.getCimObjectPathFromOutputArgs(outArgs, SmisConstants.JOB);
      if (job != null) {
        ControllerServiceImpl.enqueueJob(
            new QueueJob(new SmisBlockDeleteMirrorJob(job, storage.getId(), taskCompleter)));
      }
    } catch (Exception e) {
      _log.info("Problem making SMI-S call: ", e);
      ServiceError serviceError =
          DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
      taskCompleter.error(_dbClient, serviceError);
    }
  }
  /**
   * Include only Unified,Virtual [Thin] and Device Storage Pools (Thick Pool)
   *
   * @param poolInstance
   * @return String [] array of pool class name (as a first element) and supported volume types (as
   *     a second element)
   */
  private String[] determinePoolClassNameAndSupportedVolumeTypes(
      CIMInstance poolInstance, StorageSystem system) {

    if (StoragePool.PoolClassNames.Clar_DeviceStoragePool.toString()
        .equalsIgnoreCase(poolInstance.getClassName())) {
      return new String[] {
        StoragePool.PoolClassNames.Clar_DeviceStoragePool.toString(),
        StoragePool.SupportedResourceTypes.THICK_ONLY.toString()
      };
    } else if (StoragePool.PoolClassNames.Clar_UnifiedStoragePool.toString()
        .equalsIgnoreCase(poolInstance.getClassName())) {
      return new String[] {
        StoragePool.PoolClassNames.Clar_UnifiedStoragePool.toString(),
        StoragePool.SupportedResourceTypes.THIN_AND_THICK.toString()
      };
    }

    if (!system.checkIfVmax3()) {
      if (StoragePool.PoolClassNames.Symm_DeviceStoragePool.toString()
              .equalsIgnoreCase(poolInstance.getClassName())
          && !SupportedProvisioningTypes.THIN
              .toString()
              .equalsIgnoreCase(system.getSupportedProvisioningType())) {
        return new String[] {
          StoragePool.PoolClassNames.Symm_DeviceStoragePool.toString(),
          StoragePool.SupportedResourceTypes.THICK_ONLY.toString()
        };
      } else if (StoragePool.PoolClassNames.Symm_VirtualProvisioningPool.toString()
              .equalsIgnoreCase(poolInstance.getClassName())
          && !SupportedProvisioningTypes.THICK
              .toString()
              .equalsIgnoreCase(system.getSupportedProvisioningType())) {
        return new String[] {
          StoragePool.PoolClassNames.Symm_VirtualProvisioningPool.toString(),
          StoragePool.SupportedResourceTypes.THIN_ONLY.toString()
        };
      }
    } else {
      // VMAX3 has StorageResourcePools (SRP). These are composed of ThinPools, which we can
      // discover, but would not have write access to. So, we will only discovery SRP pools
      // and skip over other pool discoveries.
      if (StoragePool.PoolClassNames.Symm_SRPStoragePool.toString()
          .equalsIgnoreCase(poolInstance.getClassName())) {
        return new String[] {
          StoragePool.PoolClassNames.Symm_SRPStoragePool.toString(),
          StoragePool.SupportedResourceTypes.THIN_ONLY.toString()
        };
      }
    }
    return null;
  }
  /**
   * Determines if the storage system for the passed BlockSnapshot instance supports snapshot
   * sessions.
   *
   * @param snapshot A reference to the snapshot.
   * @return true if the system for the passed snapshot supports snapshot sessions, false otherwise.
   */
  private boolean isSnapshotSessionSupported(BlockSnapshot snapshot) {
    boolean isSupported = false;
    URI systemURI = snapshot.getStorageController();
    StorageSystem system = dbClient.queryObject(StorageSystem.class, systemURI);
    if ((system != null) && (system.checkIfVmax3())) {
      s_logger.info(
          "BlockSnapshotSession supported for snapshot {}:{}",
          snapshot.getId(),
          snapshot.getLabel());
      isSupported = true;
    }

    return isSupported;
  }
 private void setCompatibilityByACLXFlag(
     StorageSystem storageSystem, CIMInstance portInstance, StoragePort port) {
   Object portAttributesValue = portInstance.getPropertyValue(EMC_PORT_ATTRIBUTES);
   if (portAttributesValue != null && storageSystem.checkIfVmax3()) {
     boolean foundACLXFlag = false;
     UnsignedInteger16[] portAttributes = (UnsignedInteger16[]) portAttributesValue;
     for (UnsignedInteger16 portAttribute : portAttributes) {
       if (portAttribute.equals(EMC_PORT_ATTRIBUTE_ACLX_FLAG)) {
         foundACLXFlag = true;
         break;
       }
     }
     String compatibilityStatus =
         (foundACLXFlag)
             ? DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name()
             : DiscoveredDataObject.CompatibilityStatus.INCOMPATIBLE.name();
     _logger.info(
         String.format(
             "setCompatibilityByACLXFlag(%s) = %s", port.getNativeGuid(), compatibilityStatus));
     port.setCompatibilityStatus(compatibilityStatus);
   }
 }
  @Override
  public void createSingleVolumeMirror(
      StorageSystem storage, URI mirror, Boolean createInactive, TaskCompleter taskCompleter)
      throws DeviceControllerException {
    _log.info("createSingleVolumeMirror operation START");
    try {
      BlockMirror mirrorObj = _dbClient.queryObject(BlockMirror.class, mirror);
      StoragePool targetPool = _dbClient.queryObject(StoragePool.class, mirrorObj.getPool());
      Volume source = _dbClient.queryObject(Volume.class, mirrorObj.getSource());
      TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, source.getTenant().getURI());
      String tenantName = tenant.getLabel();
      String targetLabelToUse =
          _nameGenerator.generate(
              tenantName,
              mirrorObj.getLabel(),
              mirror.toString(),
              '-',
              SmisConstants.MAX_VOLUME_NAME_LENGTH);
      CIMObjectPath replicationSvcPath = _cimPath.getControllerReplicationSvcPath(storage);
      CIMArgument[] inArgs = null;
      if (storage.checkIfVmax3()) {
        CIMObjectPath volumeGroupPath = _helper.getVolumeGroupPath(storage, source, targetPool);
        CIMInstance replicaSettingData = getDefaultReplicationSettingData(storage);
        inArgs =
            _helper.getCreateElementReplicaMirrorInputArguments(
                storage,
                source,
                targetPool,
                createInactive,
                targetLabelToUse,
                volumeGroupPath,
                replicaSettingData);
      } else {
        inArgs =
            _helper.getCreateElementReplicaMirrorInputArguments(
                storage, source, targetPool, createInactive, targetLabelToUse);
      }

      CIMArgument[] outArgs = new CIMArgument[5];
      _helper.invokeMethod(
          storage, replicationSvcPath, SmisConstants.CREATE_ELEMENT_REPLICA, inArgs, outArgs);
      CIMObjectPath job = _cimPath.getCimObjectPathFromOutputArgs(outArgs, SmisConstants.JOB);
      if (job != null) {
        ControllerServiceImpl.enqueueJob(
            new QueueJob(
                new SmisBlockCreateMirrorJob(
                    job, storage.getId(), !createInactive, taskCompleter)));
        // Resynchronizing state applies to the initial copy as well as future
        // re-synchronization's.
        mirrorObj.setSyncState(SynchronizationState.RESYNCHRONIZING.toString());
        _dbClient.persistObject(mirrorObj);
      }
    } catch (final InternalException e) {
      _log.info("Problem making SMI-S call: ", e);
      taskCompleter.error(_dbClient, e);
    } catch (Exception e) {
      _log.info("Problem making SMI-S call: ", e);
      ServiceError serviceError =
          DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
      taskCompleter.error(_dbClient, serviceError);
    }
  }
  @Override
  public void deleteGroupMirrors(
      StorageSystem storage, List<URI> mirrorList, TaskCompleter taskCompleter)
      throws DeviceControllerException {
    _log.info("deleteGroupMirrors operation START");
    if (!((storage.getUsingSmis80() && storage.deviceIsType(Type.vmax))
        || storage.deviceIsType(Type.vnxblock))) {
      throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
    }

    try {
      String[] deviceIds = null;
      BlockMirror firstMirror = _dbClient.queryObject(BlockMirror.class, mirrorList.get(0));
      String repGroupName = firstMirror.getReplicationGroupInstance();
      if (NullColumnValueGetter.isNotNullValue(repGroupName)) {
        CIMObjectPath repGroupPath = _cimPath.getReplicationGroupPath(storage, repGroupName);
        Set<String> deviceIdsSet =
            _helper.getVolumeDeviceIdsFromStorageGroup(storage, repGroupPath);
        deviceIds = deviceIdsSet.toArray(new String[deviceIdsSet.size()]);

        // Delete replication group
        ReplicationUtils.deleteReplicationGroup(
            storage, repGroupName, _dbClient, _helper, _cimPath);
        // Set mirrors replication group to null
        List<BlockMirror> mirrors = _dbClient.queryObject(BlockMirror.class, mirrorList);
        for (BlockMirror mirror : mirrors) {
          mirror.setConsistencyGroup(NullColumnValueGetter.getNullURI());
          mirror.setReplicationGroupInstance(NullColumnValueGetter.getNullStr());
        }

        _dbClient.persistObject(mirrors);
      } else {
        deviceIds = _helper.getBlockObjectNativeIds(mirrorList);
      }

      if (storage.checkIfVmax3()) {
        for (String deviceId : deviceIds) {
          _helper.removeVolumeFromParkingSLOStorageGroup(storage, deviceId, false);
          _log.info("Done invoking remove volume {} from parking SLO storage group", deviceId);
        }
      }

      CIMObjectPath[] mirrorPaths = _cimPath.getVolumePaths(storage, deviceIds);
      CIMObjectPath configSvcPath = _cimPath.getConfigSvcPath(storage);
      CIMArgument[] inArgs = null;
      if (storage.deviceIsType(Type.vnxblock)) {
        inArgs = _helper.getReturnElementsToStoragePoolArguments(mirrorPaths);
      } else {
        inArgs =
            _helper.getReturnElementsToStoragePoolArguments(
                mirrorPaths, SmisConstants.CONTINUE_ON_NONEXISTENT_ELEMENT);
      }
      CIMArgument[] outArgs = new CIMArgument[5];
      _helper.invokeMethod(
          storage, configSvcPath, SmisConstants.RETURN_ELEMENTS_TO_STORAGE_POOL, inArgs, outArgs);
      CIMObjectPath job = _cimPath.getCimObjectPathFromOutputArgs(outArgs, SmisConstants.JOB);
      ControllerServiceImpl.enqueueJob(
          new QueueJob(new SmisBlockDeleteCGMirrorJob(job, storage.getId(), taskCompleter)));
    } catch (Exception e) {
      _log.error("Problem making SMI-S call: ", e);
      ServiceError serviceError =
          DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
      taskCompleter.error(_dbClient, serviceError);
    }
  }
 @Override
 public void resumeSingleVolumeMirror(
     StorageSystem storage, URI mirror, TaskCompleter taskCompleter)
     throws DeviceControllerException {
   _log.info("resumeSingleVolumeMirror operation START");
   CloseableIterator<CIMObjectPath> storageSyncRefs = null;
   try {
     BlockMirror mirrorObj = _dbClient.queryObject(BlockMirror.class, mirror);
     CIMObjectPath mirrorPath = _cimPath.getBlockObjectPath(storage, mirrorObj);
     // Get reference to the CIM_StorageSynchronized instance
     storageSyncRefs =
         _helper.getReference(storage, mirrorPath, SmisConstants.CIM_STORAGE_SYNCHRONIZED, null);
     if (!storageSyncRefs.hasNext()) {
       _log.error("No synchronization instance found for {}", mirror);
       taskCompleter.error(
           _dbClient, DeviceControllerException.exceptions.resumeVolumeMirrorFailed(mirror));
       return;
     }
     boolean isVmax3 = storage.checkIfVmax3();
     while (storageSyncRefs.hasNext()) {
       CIMObjectPath storageSync = storageSyncRefs.next();
       _log.debug(storageSync.toString());
       /**
        * JIRA CTRL-11855 User created mirror and did pause operation using SMI 4.6.2. Then He
        * upgraded to SMI 8.0.3. While doing mirror resume getting exception from SMI because of
        * the existing mirrorObj.getSynchronizedInstance() contains
        * SystemName=\"SYMMETRIX+000195701573\"" This is wrong with 8.0.3 as
        * SystemName=\"SYMMETRIX-+-000195701573\"". To resolve this issue setting new value
        * collected from current smis provider here.
        */
       mirrorObj.setSynchronizedInstance(storageSync.toString());
       _dbClient.persistObject(mirrorObj);
       CIMArgument[] inArgs =
           isVmax3
               ? _helper.getResumeSynchronizationInputArgumentsWithCopyState(storageSync)
               : _helper.getResumeSynchronizationInputArguments(storageSync);
       CIMArgument[] outArgs = new CIMArgument[5];
       _helper.callModifyReplica(storage, inArgs, outArgs);
       CIMObjectPath job = _cimPath.getCimObjectPathFromOutputArgs(outArgs, SmisConstants.JOB);
       if (job != null) {
         ControllerServiceImpl.enqueueJob(
             new QueueJob(new SmisBlockResumeMirrorJob(job, storage.getId(), taskCompleter)));
       } else {
         CIMInstance syncObject =
             _helper.getInstance(
                 storage, storageSync, false, false, new String[] {SmisConstants.CP_SYNC_STATE});
         mirrorObj.setSyncState(
             CIMPropertyFactory.getPropertyValue(syncObject, SmisConstants.CP_SYNC_STATE));
         _dbClient.persistObject(mirrorObj);
         taskCompleter.ready(_dbClient);
       }
     }
   } catch (Exception e) {
     _log.error("Failed to resume single volume mirror: {}", mirror);
     ServiceError serviceError = DeviceControllerException.errors.jobFailed(e);
     taskCompleter.error(_dbClient, serviceError);
   } finally {
     if (storageSyncRefs != null) {
       storageSyncRefs.close();
     }
   }
 }
  /**
   * create StorageVolume Info Object
   *
   * @param unManagedVolume
   * @param volumeInstance
   * @param unManagedVolumeNativeGuid
   * @param pool
   * @return
   */
  private UnManagedVolume createUnManagedVolume(
      UnManagedVolume unManagedVolume,
      CIMInstance volumeInstance,
      String unManagedVolumeNativeGuid,
      StoragePool pool,
      StorageSystem system,
      String volumeNativeGuid,
      // to make the code uniform, passed in all the below sets as
      // arguments
      Map<String, VolHostIOObject> exportedVolumes,
      Set<String> existingVolumesInCG,
      Map<String, RemoteMirrorObject> volumeToRAGroupMap,
      Map<String, LocalReplicaObject> volumeToLocalReplicaMap,
      Set<String> poolSupportedSLONames,
      Map<String, Object> keyMap) {
    _logger.info("Process UnManagedVolume {}", unManagedVolumeNativeGuid);
    try {
      boolean created = false;
      if (null == unManagedVolume) {
        unManagedVolume = new UnManagedVolume();
        unManagedVolume.setId(URIUtil.createId(UnManagedVolume.class));
        unManagedVolume.setNativeGuid(unManagedVolumeNativeGuid);
        unManagedVolume.setStorageSystemUri(system.getId());
        created = true;
      }

      // reset the auto-tiering info for unmanaged volumes already present
      // in db
      // so that the tiering info is updated correctly later
      if (!created) {
        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.AUTO_TIERING_POLICIES.toString(), "");
        unManagedVolume.putVolumeCharacterstics(
            SupportedVolumeCharacterstics.IS_AUTO_TIERING_ENABLED.toString(), "false");

        // reset local replica info
        unManagedVolume.putVolumeCharacterstics(
            SupportedVolumeCharacterstics.IS_FULL_COPY.name(), FALSE);
        unManagedVolume.putVolumeCharacterstics(
            SupportedVolumeCharacterstics.IS_LOCAL_MIRROR.name(), FALSE);
        unManagedVolume.putVolumeCharacterstics(
            SupportedVolumeCharacterstics.IS_SNAP_SHOT.name(), FALSE);
        unManagedVolume.putVolumeCharacterstics(
            SupportedVolumeCharacterstics.HAS_REPLICAS.name(), FALSE);

        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.REPLICA_STATE.name(), new StringSet());

        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.LOCAL_REPLICA_SOURCE_VOLUME.name(), new StringSet());
        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.SYNC_STATE.name(), new StringSet());
        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.SYNC_TYPE.name(), new StringSet());
        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.SYNCHRONIZED_INSTANCE.name(), new StringSet());

        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.IS_SYNC_ACTIVE.name(), new StringSet());
        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.NEEDS_COPY_TO_TARGET.name(), new StringSet());
        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.TECHNOLOGY_TYPE.name(), new StringSet());
        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.SETTINGS_INSTANCE.name(), new StringSet());

        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.FULL_COPIES.name(), new StringSet());
        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.MIRRORS.name(), new StringSet());
        unManagedVolume
            .getVolumeInformation()
            .put(SupportedVolumeInformation.SNAPSHOTS.name(), new StringSet());
      }

      Map<String, StringSet> unManagedVolumeInformation = new HashMap<String, StringSet>();
      Map<String, String> unManagedVolumeCharacteristics = new HashMap<String, String>();

      if (null != system) {
        StringSet systemTypes = new StringSet();
        systemTypes.add(system.getSystemType());
        unManagedVolumeInformation.put(
            SupportedVolumeInformation.SYSTEM_TYPE.toString(), systemTypes);
      }

      if (exportedVolumes != null && exportedVolumes.containsKey(volumeNativeGuid)) {
        VolHostIOObject obj = exportedVolumes.get(volumeNativeGuid);
        if (null != obj) {
          StringSet bwValues = new StringSet();
          bwValues.add(obj.getHostIoBw());
          if (unManagedVolumeInformation.get(
                  SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH.toString())
              == null) {
            unManagedVolumeInformation.put(
                SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH.toString(), bwValues);
          } else {
            unManagedVolumeInformation
                .get(SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH.toString())
                .replace(bwValues);
          }

          StringSet iopsVal = new StringSet();
          iopsVal.add(obj.getHostIops());

          if (unManagedVolumeInformation.get(SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString())
              == null) {
            unManagedVolumeInformation.put(
                SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString(), iopsVal);
          } else {
            unManagedVolumeInformation
                .get(SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString())
                .replace(iopsVal);
          }
        }
        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.IS_VOLUME_EXPORTED.toString(), TRUE);

      } else {
        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.IS_VOLUME_EXPORTED.toString(), FALSE);
        StringSet bwValues = new StringSet();
        bwValues.add("0");

        if (unManagedVolumeInformation.get(
                SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH.toString())
            == null) {
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH.toString(), bwValues);
        } else {
          unManagedVolumeInformation
              .get(SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH.toString())
              .replace(bwValues);
        }

        StringSet iopsVal = new StringSet();
        iopsVal.add("0");

        if (unManagedVolumeInformation.get(SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString())
            == null) {
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString(), iopsVal);
        } else {
          unManagedVolumeInformation
              .get(SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString())
              .replace(iopsVal);
        }
      }

      // Set SLOName only for VMAX3 exported volumes
      if (system.checkIfVmax3()) {
        // If there are no slonames defined for a pool or no slo
        // set for a volume, update the tiering_enabled to false.
        if (poolSupportedSLONames.isEmpty() || !keyMap.containsKey(Constants.VOLUMES_WITH_SLOS)) {
          unManagedVolumeCharacteristics.put(
              SupportedVolumeCharacterstics.IS_AUTO_TIERING_ENABLED.toString(),
              Boolean.FALSE.toString());
        } else {
          Map<String, String> volumesWithSLO =
              (Map<String, String>) keyMap.get(Constants.VOLUMES_WITH_SLOS);
          if (volumesWithSLO.containsKey(volumeNativeGuid)) {
            String sloName = volumesWithSLO.get(volumeNativeGuid);
            _logger.debug("formattedSLOName: {}", sloName);
            updateSLOPolicies(
                poolSupportedSLONames,
                unManagedVolumeInformation,
                unManagedVolumeCharacteristics,
                sloName);
          } else {
            unManagedVolumeCharacteristics.put(
                SupportedVolumeCharacterstics.IS_AUTO_TIERING_ENABLED.toString(),
                Boolean.FALSE.toString());
          }
        }
      }

      if (existingVolumesInCG != null && existingVolumesInCG.contains(volumeNativeGuid)) {
        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.IS_VOLUME_ADDED_TO_CONSISTENCYGROUP.toString(), TRUE);
      } else {
        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.IS_VOLUME_ADDED_TO_CONSISTENCYGROUP.toString(), FALSE);
      }

      Object raidLevelObj;
      boolean isIngestable;
      String isBound;
      String isThinlyProvisioned;
      String isMetaVolume;
      String allocCapacity;
      // Set the attributes for new smis version.
      if (keyMap.containsKey(Constants.IS_NEW_SMIS_PROVIDER)
          && Boolean.valueOf(keyMap.get(Constants.IS_NEW_SMIS_PROVIDER).toString())) {
        unManagedVolume.setLabel(getCIMPropertyValue(volumeInstance, NAME));
        raidLevelObj =
            volumeInstance.getPropertyValue(
                SupportedVolumeInformation.RAID_LEVEL.getAlternateKey());
        isBound =
            getCIMPropertyValue(
                volumeInstance, SupportedVolumeCharacterstics.IS_BOUND.getAlterCharacterstic());
        isIngestable = isVolumeIngestable(volumeInstance, isBound, USAGE);
        isThinlyProvisioned = getCIMPropertyValue(volumeInstance, THINLY_PROVISIONED);
        isMetaVolume =
            getCIMPropertyValue(
                volumeInstance,
                SupportedVolumeCharacterstics.IS_METAVOLUME.getAlterCharacterstic());
        allocCapacity =
            getAllocatedCapacity(volumeInstance, _volumeToSpaceConsumedMap, system.checkIfVmax3());
      } else {
        unManagedVolume.setLabel(getCIMPropertyValue(volumeInstance, SVELEMENT_NAME));
        isBound =
            getCIMPropertyValue(
                volumeInstance, SupportedVolumeCharacterstics.IS_BOUND.getCharacterstic());
        raidLevelObj =
            volumeInstance.getPropertyValue(SupportedVolumeInformation.RAID_LEVEL.getInfoKey());
        isIngestable = isVolumeIngestable(volumeInstance, isBound, SVUSAGE);
        isThinlyProvisioned = getCIMPropertyValue(volumeInstance, EMC_THINLY_PROVISIONED);
        isMetaVolume =
            getCIMPropertyValue(
                volumeInstance, SupportedVolumeCharacterstics.IS_METAVOLUME.getCharacterstic());
        allocCapacity = getCIMPropertyValue(volumeInstance, EMC_ALLOCATED_CAPACITY);
      }

      if (null != raidLevelObj) {
        StringSet raidLevels = new StringSet();
        raidLevels.add(raidLevelObj.toString());
        unManagedVolumeInformation.put(
            SupportedVolumeInformation.RAID_LEVEL.toString(), raidLevels);
      }

      if (null != isBound) {
        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.IS_BOUND.toString(), isBound);
      }
      if (null != isThinlyProvisioned) {
        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.IS_THINLY_PROVISIONED.toString(), isThinlyProvisioned);
      }

      if (null != isMetaVolume) {
        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.IS_METAVOLUME.toString(), isMetaVolume);
      }

      // only Volumes with Usage 2 can be ingestable, other volumes
      // [SAVE,VAULT...] apart from replicas have usage other than 2
      // Volumes which are set EMCIsBound as false cannot be ingested
      if (isIngestable) {
        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.IS_INGESTABLE.toString(), TRUE);
      } else {
        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.IS_INGESTABLE.toString(), FALSE);
      }

      if (volumeToRAGroupMap.containsKey(unManagedVolume.getNativeGuid())) {
        RemoteMirrorObject rmObj = volumeToRAGroupMap.get(unManagedVolume.getNativeGuid());
        _logger.info("Found RA Object {}", rmObj.toString());
        if (RemoteMirrorObject.Types.SOURCE.toString().equalsIgnoreCase(rmObj.getType())) {
          _logger.info("Found Source, updating targets {}", rmObj.getTargetVolumenativeGuids());
          // setting target Volumes
          if (unManagedVolumeInformation.get(SupportedVolumeInformation.REMOTE_MIRRORS.toString())
              == null) {
            unManagedVolumeInformation.put(
                SupportedVolumeInformation.REMOTE_MIRRORS.toString(),
                rmObj.getTargetVolumenativeGuids());
          } else {
            if (null == rmObj.getTargetVolumenativeGuids()
                || rmObj.getTargetVolumenativeGuids().size() == 0) {
              unManagedVolumeInformation
                  .get(SupportedVolumeInformation.REMOTE_MIRRORS.toString())
                  .clear();
            } else {
              unManagedVolumeInformation
                  .get(SupportedVolumeInformation.REMOTE_MIRRORS.toString())
                  .replace(rmObj.getTargetVolumenativeGuids());
            }
          }
        } else if (RemoteMirrorObject.Types.TARGET.toString().equalsIgnoreCase(rmObj.getType())) {

          _logger.info(
              "Found Target {}, updating copyMode {}, RA Group",
              unManagedVolume.getNativeGuid(),
              rmObj.getCopyMode());
          // setting srdfParent
          StringSet parentVolume = new StringSet();
          parentVolume.add(rmObj.getSourceVolumeNativeGuid());
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.REMOTE_MIRROR_SOURCE_VOLUME.toString(), parentVolume);

          // setting RAGroup
          StringSet raGroup = new StringSet();
          raGroup.add(rmObj.getRaGroupUri().toString());
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.REMOTE_MIRROR_RDF_GROUP.toString(), raGroup);
        }
        // setting Copy Modes
        StringSet copyModes = new StringSet();
        copyModes.add(rmObj.getCopyMode());
        if (unManagedVolumeInformation.get(SupportedVolumeInformation.REMOTE_COPY_MODE.toString())
            == null) {
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.REMOTE_COPY_MODE.toString(), copyModes);
        } else {
          unManagedVolumeInformation
              .get(SupportedVolumeInformation.REMOTE_COPY_MODE.toString())
              .replace(copyModes);
        }
        // setting Volume Type

        StringSet volumeType = new StringSet();
        volumeType.add(rmObj.getType());
        unManagedVolumeInformation.put(
            SupportedVolumeInformation.REMOTE_VOLUME_TYPE.toString(), volumeType);

        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.REMOTE_MIRRORING.toString(), TRUE);
      } else {
        unManagedVolumeCharacteristics.put(
            SupportedVolumeCharacterstics.REMOTE_MIRRORING.toString(), FALSE);
      }

      // handle clones, local mirrors and snapshots
      boolean isLocalReplica = false;
      if (volumeToLocalReplicaMap.containsKey(unManagedVolume.getNativeGuid())) {
        _logger.info("Found in localReplicaMap {}", unManagedVolume.getNativeGuid());
        LocalReplicaObject lrObj = volumeToLocalReplicaMap.get(unManagedVolume.getNativeGuid());
        isLocalReplica = lrObj.isReplica();

        // setting targets
        StringSet fullCopies = lrObj.getFullCopies();
        if (fullCopies != null && !fullCopies.isEmpty()) {
          unManagedVolumeInformation.put(SupportedVolumeInformation.FULL_COPIES.name(), fullCopies);
        }

        StringSet mirrors = lrObj.getMirrors();
        if (mirrors != null && !mirrors.isEmpty()) {
          unManagedVolumeInformation.put(SupportedVolumeInformation.MIRRORS.name(), mirrors);
        }

        StringSet snapshots = lrObj.getSnapshots();
        if (snapshots != null && !snapshots.isEmpty()) {
          unManagedVolumeInformation.put(SupportedVolumeInformation.SNAPSHOTS.name(), snapshots);
        }

        if (lrObj.hasReplica()) {
          // set the HAS_REPLICAS property
          unManagedVolumeCharacteristics.put(
              SupportedVolumeCharacterstics.HAS_REPLICAS.name(), TRUE);
        }

        if (LocalReplicaObject.Types.FullCopy.equals(lrObj.getType())) {
          _logger.info("Found Clone {}", unManagedVolume.getNativeGuid());
          // setting clone specific info
          unManagedVolumeCharacteristics.put(
              SupportedVolumeCharacterstics.IS_FULL_COPY.name(), TRUE);
          StringSet sourceVolume = new StringSet();
          sourceVolume.add(lrObj.getSourceNativeGuid());
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.LOCAL_REPLICA_SOURCE_VOLUME.name(), sourceVolume);

          StringSet isSyncActive = new StringSet();
          isSyncActive.add(new Boolean(lrObj.isSyncActive()).toString());
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.IS_SYNC_ACTIVE.name(), isSyncActive);

          StringSet replicaState = new StringSet();
          replicaState.add(lrObj.getReplicaState());
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.REPLICA_STATE.name(), replicaState);
        } else if (LocalReplicaObject.Types.BlockMirror.equals(lrObj.getType())) {
          _logger.info("Found Local Mirror {}", unManagedVolume.getNativeGuid());
          // setting local mirror specific info
          unManagedVolumeCharacteristics.put(
              SupportedVolumeCharacterstics.IS_LOCAL_MIRROR.name(), TRUE);
          StringSet sourceVolume = new StringSet();
          sourceVolume.add(lrObj.getSourceNativeGuid());
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.LOCAL_REPLICA_SOURCE_VOLUME.name(), sourceVolume);

          StringSet syncState = new StringSet();
          syncState.add(lrObj.getSyncState());
          unManagedVolumeInformation.put(SupportedVolumeInformation.SYNC_STATE.name(), syncState);

          StringSet syncType = new StringSet();
          syncType.add(lrObj.getSyncType());
          unManagedVolumeInformation.put(SupportedVolumeInformation.SYNC_TYPE.name(), syncType);

          String syncedInst = lrObj.getSynchronizedInstance();
          if (syncedInst != null) {
            StringSet synchronizedInstance = new StringSet();
            synchronizedInstance.add(syncedInst);
            unManagedVolumeInformation.put(
                SupportedVolumeInformation.SYNCHRONIZED_INSTANCE.name(), synchronizedInstance);
          }
        } else if (LocalReplicaObject.Types.BlockSnapshot.equals(lrObj.getType())) {
          _logger.info("Found Snapshot {}", unManagedVolume.getNativeGuid());
          // setting snapshot specific info
          unManagedVolumeCharacteristics.put(
              SupportedVolumeCharacterstics.IS_SNAP_SHOT.name(), TRUE);
          StringSet sourceVolume = new StringSet();
          sourceVolume.add(lrObj.getSourceNativeGuid());
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.LOCAL_REPLICA_SOURCE_VOLUME.name(), sourceVolume);

          StringSet isSyncActive = new StringSet();
          isSyncActive.add(new Boolean(lrObj.isSyncActive()).toString());
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.IS_SYNC_ACTIVE.name(), isSyncActive);

          StringSet needsCopyToTarget = new StringSet();
          needsCopyToTarget.add(new Boolean(lrObj.isNeedsCopyToTarget()).toString());
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.NEEDS_COPY_TO_TARGET.name(), needsCopyToTarget);

          StringSet technologyType = new StringSet();
          technologyType.add(lrObj.getTechnologyType());
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.TECHNOLOGY_TYPE.name(), technologyType);

          String settingsInst = lrObj.getSettingsInstance();
          if (settingsInst != null) {
            StringSet settingsInstance = new StringSet();
            settingsInstance.add(settingsInst);
            unManagedVolumeInformation.put(
                SupportedVolumeInformation.SETTINGS_INSTANCE.name(), settingsInstance);
          }
        }
      }

      // set volume's isSyncActive
      if (!isLocalReplica) {
        StringSet isSyncActive = new StringSet();
        isSyncActive.add(TRUE);
        unManagedVolumeInformation.put(
            SupportedVolumeInformation.IS_SYNC_ACTIVE.name(), isSyncActive);
      }

      if (null != pool) {
        unManagedVolume.setStoragePoolUri(pool.getId());
        StringSet pools = new StringSet();
        pools.add(pool.getId().toString());
        unManagedVolumeInformation.put(SupportedVolumeInformation.STORAGE_POOL.toString(), pools);
        StringSet driveTypes = pool.getSupportedDriveTypes();
        if (null != driveTypes) {
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.DISK_TECHNOLOGY.toString(), driveTypes);
        }
        StringSet matchedVPools =
            DiscoveryUtils.getMatchedVirtualPoolsForPool(
                _dbClient,
                pool.getId(),
                unManagedVolumeCharacteristics.get(
                    SupportedVolumeCharacterstics.IS_THINLY_PROVISIONED.toString()));
        if (unManagedVolumeInformation.containsKey(
            SupportedVolumeInformation.SUPPORTED_VPOOL_LIST.toString())) {

          _logger.debug("Matched Pools :" + Joiner.on("\t").join(matchedVPools));
          if (null != matchedVPools && matchedVPools.size() == 0) {
            // replace with empty string set doesn't work, hence
            // added explicit code to remove all
            unManagedVolumeInformation
                .get(SupportedVolumeInformation.SUPPORTED_VPOOL_LIST.toString())
                .clear();
          } else {
            // replace with new StringSet
            unManagedVolumeInformation
                .get(SupportedVolumeInformation.SUPPORTED_VPOOL_LIST.toString())
                .replace(matchedVPools);
            _logger.info(
                "Replaced Pools :"
                    + Joiner.on("\t")
                        .join(
                            unManagedVolumeInformation.get(
                                SupportedVolumeInformation.SUPPORTED_VPOOL_LIST.toString())));
          }
        } else {
          unManagedVolumeInformation.put(
              SupportedVolumeInformation.SUPPORTED_VPOOL_LIST.toString(), matchedVPools);
        }
      }

      // set allocated capacity
      if (allocCapacity != null) {
        StringSet allocCapacitySet = new StringSet();
        allocCapacitySet.add(allocCapacity);
        unManagedVolumeInformation.put(
            SupportedVolumeInformation.ALLOCATED_CAPACITY.toString(), allocCapacitySet);
      }

      StringSet provCapacity = new StringSet();
      provCapacity.add(String.valueOf(returnProvisionedCapacity(volumeInstance, keyMap)));
      unManagedVolumeInformation.put(
          SupportedVolumeInformation.PROVISIONED_CAPACITY.toString(), provCapacity);
      injectVolumeInformation(unManagedVolume, volumeInstance, unManagedVolumeInformation);
      injectVolumeCharacterstics(unManagedVolume, volumeInstance, unManagedVolumeCharacteristics);
      unManagedVolume.getUnmanagedExportMasks().clear();
      unManagedVolume.getInitiatorUris().clear();
      unManagedVolume.getInitiatorNetworkIds().clear();
      if (created) {
        _unManagedVolumesInsert.add(unManagedVolume);
      } else {
        _unManagedVolumesUpdate.add(unManagedVolume);
      }

    } catch (Exception e) {
      _logger.error("Exception: ", e);
    }
    return unManagedVolume;
  }
  /** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public void processResult(Operation operation, Object resultObj, Map<String, Object> keyMap)
      throws BaseCollectionException {
    final Iterator<CIMInstance> it = (Iterator<CIMInstance>) resultObj;
    profile = (AccessProfile) keyMap.get(Constants.ACCESSPROFILE);
    try {
      _newPoolList = new ArrayList<StoragePool>();
      _updatePoolList = new ArrayList<StoragePool>();
      _dbClient = (DbClient) keyMap.get(Constants.dbClient);
      _cimClient = (WBEMClient) keyMap.get(Constants._cimClient);
      _coordinator = (CoordinatorClient) keyMap.get(Constants.COORDINATOR_CLIENT);
      _eventManager = (RecordableEventManager) keyMap.get(Constants.EVENT_MANAGER);
      _logger.info("StoragePoolProcessor --- event manager: " + _eventManager);
      StorageSystem device = getStorageSystem(_dbClient, profile.getSystemId());
      if (SupportedProvisioningTypes.NONE
          .toString()
          .equalsIgnoreCase(device.getSupportedProvisioningType())) {
        _logger.info(
            "Storage System doesn't support volume creations :" + device.getSerialNumber());
        return;
      }
      Set<String> protocols = (Set<String>) keyMap.get(Constants.PROTOCOLS);
      Map<URI, StoragePool> poolsToMatchWithVpool =
          (Map<URI, StoragePool>) keyMap.get(Constants.MODIFIED_STORAGEPOOLS);
      while (it.hasNext()) {
        CIMInstance poolInstance = null;
        try {
          poolInstance = it.next();

          // Supporting both thick and thin pools
          String[] poolClassNameAndSupportedVolumeTypes =
              determinePoolClassNameAndSupportedVolumeTypes(poolInstance, device);
          if (null != poolClassNameAndSupportedVolumeTypes) {
            String instanceID = getCIMPropertyValue(poolInstance, Constants.INSTANCEID);
            addPath(keyMap, operation.getResult(), poolInstance.getObjectPath());
            StoragePool pool =
                checkStoragePoolExistsInDB(getNativeIDFromInstance(instanceID), _dbClient, device);
            createStoragePool(
                pool,
                poolInstance,
                profile,
                poolClassNameAndSupportedVolumeTypes[0],
                poolClassNameAndSupportedVolumeTypes[1],
                protocols,
                poolsToMatchWithVpool,
                device);

            if (DiscoveredDataObject.Type.vnxblock
                .toString()
                .equalsIgnoreCase(device.getSystemType())) {
              addPath(keyMap, Constants.VNXPOOLS, poolInstance.getObjectPath());
            }

            if (DiscoveredDataObject.Type.vmax
                .toString()
                .equalsIgnoreCase(device.getSystemType())) {
              addPath(keyMap, Constants.VMAXPOOLS, poolInstance.getObjectPath());
              if (!device.checkIfVmax3()) {
                addPath(keyMap, Constants.VMAX2POOLS, poolInstance.getObjectPath());
              }
            }
            // This approach deviates from the existing built plugin framework for plugin
            // Discovery
            // To follow the existing pattern, we need to have different SMI-S calls
            // 1st to get Device StoragePools alone ,and 2nd to get Thin Pools.
            // Its a tradeoff between whether to go with the current plugin design or
            // reduce the number of calls to SMI Provider.
            // I chose the 2nd option.
            if (!poolClassNameAndSupportedVolumeTypes[0].contains(DEVICE_STORAGE_POOL)) {
              addPath(keyMap, Constants.THINPOOLS, poolInstance.getObjectPath());
            }

            addPath(keyMap, Constants.DEVICEANDTHINPOOLS, poolInstance.getObjectPath());
          } else {
            _logger.debug(
                "Skipping Pools other than Unified & Virtual & Device : {}",
                poolInstance.getObjectPath().toString());
          }
        } catch (Exception e) {
          _logger.warn(
              "StoragePool Discovery failed for {}",
              getCIMPropertyValue(poolInstance, Constants.INSTANCEID),
              e);
        }
      }

      _dbClient.createObject(_newPoolList);
      _dbClient.updateAndReindexObject(_updatePoolList);

      // find the pools not visible in this discovery
      List<StoragePool> discoveredPools = new ArrayList<StoragePool>(_newPoolList);
      discoveredPools.addAll(_updatePoolList);
      List<StoragePool> notVisiblePools =
          DiscoveryUtils.checkStoragePoolsNotVisible(discoveredPools, _dbClient, device.getId());
      for (StoragePool notVisiblePool : notVisiblePools) {
        poolsToMatchWithVpool.put(notVisiblePool.getId(), notVisiblePool);
      }
      // If any storage ports on the storage system are in a transport
      // zone, there is an implicit connection to the transport zone
      // varray. We need to add these implicit varray
      // connections for the new storage pool.
      StoragePoolAssociationHelper.setStoragePoolVarrays(device.getId(), _newPoolList, _dbClient);
    } catch (Exception e) {
      _logger.error("StoragePool Discovery failed --> {}", getMessage(e));
    } finally {
      _newPoolList = null;
      _updatePoolList = null;
    }
  }
  /**
   * Create StoragePool Record, if not present already, else update only the properties.
   *
   * @param pool
   * @param poolInstance
   * @param profile
   * @param poolClassName
   * @param supportedVolumeTypes
   * @param protocols
   * @param poolsToMatchWithVpool
   * @throws URISyntaxException
   * @throws IOException
   */
  private void createStoragePool(
      StoragePool pool,
      CIMInstance poolInstance,
      AccessProfile profile,
      String poolClassName,
      String supportedVolumeTypes,
      Set<String> protocols,
      Map<URI, StoragePool> poolsToMatchWithVpool,
      StorageSystem device)
      throws URISyntaxException, IOException {
    boolean newPool = false;
    boolean modifiedPool = false; // indicates whether to add to modified pools list or not
    if (null == pool) {
      String instanceID = getCIMPropertyValue(poolInstance, Constants.INSTANCEID);
      String nativeIdFromInstance = getNativeIDFromInstance(instanceID);
      newPool = true;
      pool = new StoragePool();
      pool.setId(URIUtil.createId(StoragePool.class));
      pool.setPoolName(getCIMPropertyValue(poolInstance, POOL_ID));
      pool.setNativeId(nativeIdFromInstance);
      pool.setStorageDevice(profile.getSystemId());
      pool.setPoolServiceType(PoolServiceType.block.toString());
      String poolNativeGuid = NativeGUIDGenerator.generateNativeGuid(_dbClient, pool);
      pool.setNativeGuid(poolNativeGuid);
      pool.setLabel(poolNativeGuid);
      // setting default values on Pool Creation for VMAX and VNX
      pool.setMaximumThickVolumeSize(0L);
      pool.setMinimumThickVolumeSize(0L);
      pool.setMaximumThinVolumeSize(0L);
      pool.setMinimumThinVolumeSize(0L);
      if (device.getAutoTieringEnabled()) {
        pool.setAutoTieringEnabled(Boolean.TRUE);
      } else {
        pool.setAutoTieringEnabled(Boolean.FALSE);
      }
      _logger.info(
          String.format(
              "Maximum default limits for volume capacity in storage pool %s / %s : \n   "
                  + "max thin volume capacity: %s, max thick volume capacity: %s ",
              pool.getPoolName(),
              pool.getId(),
              pool.getMaximumThinVolumeSize(),
              pool.getMaximumThickVolumeSize()));

      // set default utilization/subscription limits
      double poolSubscriptionPercent =
          CapacityMatcher.getMaxPoolSubscriptionPercentage(pool, _coordinator);
      double poolUtilizationPercent =
          CapacityMatcher.getMaxPoolUtilizationPercentage(pool, _coordinator);
      pool.setMaxThinPoolSubscriptionPercentage((int) poolSubscriptionPercent);
      pool.setMaxPoolUtilizationPercentage((int) poolUtilizationPercent);
    }

    String maxSubscriptionPercent =
        getCIMPropertyValue(poolInstance, SmisConstants.CP_EMCMAXSUBSCRIPTIONPERCENT);
    _logger.info(
        String.format(
            "Discovered maximum subscription percent of storage pool %s from array : %s ",
            pool.getPoolName(), maxSubscriptionPercent));
    // null value indicates "not available".
    Integer newMaxSubscriptionPercentFromArray =
        maxSubscriptionPercent == null ? null : new Integer(maxSubscriptionPercent);
    _logger.info(
        String.format(
            "New maximum subscription percent of storage pool %s from array : %s ",
            pool.getPoolName(), newMaxSubscriptionPercentFromArray));
    processMaxSubscriptionPercent(
        newMaxSubscriptionPercentFromArray, pool, _dbClient, _eventManager);

    String subscribedCapacity =
        getCIMPropertyValue(poolInstance, SmisConstants.CP_SUBSCRIBEDCAPACITY);
    if (null != subscribedCapacity) {
      pool.setSubscribedCapacity(ControllerUtils.convertBytesToKBytes(subscribedCapacity));
    }
    pool.setFreeCapacity(SmisUtils.getFreeCapacity(poolInstance));
    pool.setTotalCapacity(SmisUtils.getTotalCapacity(poolInstance));
    pool.setPoolClassName(poolClassName);
    pool.setSupportedResourceTypes(supportedVolumeTypes);
    String operationalStatus = determineOperationalStatus(poolInstance);
    if (!newPool
        && (ImplicitPoolMatcher.checkPoolPropertiesChanged(
                pool.getOperationalStatus(), operationalStatus)
            || ImplicitPoolMatcher.checkPoolPropertiesChanged(pool.getProtocols(), protocols)
            || ImplicitPoolMatcher.checkPoolPropertiesChanged(
                pool.getCompatibilityStatus(),
                DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name())
            || ImplicitPoolMatcher.checkPoolPropertiesChanged(
                pool.getDiscoveryStatus(), DiscoveredDataObject.DiscoveryStatus.VISIBLE.name()))) {
      modifiedPool = true;
    }
    pool.addProtocols(protocols);
    pool.setOperationalStatus(operationalStatus);
    pool.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name());
    pool.setDiscoveryStatus(DiscoveredDataObject.DiscoveryStatus.VISIBLE.name());

    Set<String> diskDrives = new HashSet<String>();
    String driveTypes = getCIMPropertyValue(poolInstance, EMC_DRIVE_TYPE);
    if (null != driveTypes) {
      String driveTypesArr[] = driveTypes.split(SPACE_STR_DELIM);
      if (device.checkIfVmax3()
          && driveTypesArr.length == 1
          && driveTypesArr[0].equals(MIXED_DRIVE_TYPE)) {
        driveTypesArr = getVMAX3PoolDriveTypes(device, poolInstance);
      }
      for (String driveType : driveTypesArr) {
        String driveDisplayName = SupportedDriveTypeValues.getDiskDriveDisplayName(driveType);
        if (null == driveDisplayName) {
          _logger.warn(
              "UnSupported DiskDrive Type : {} resulting in drives not getting discovered for this pool: {}",
              driveType,
              getCIMPropertyValue(poolInstance, Constants.INSTANCEID));
          continue;
        }

        diskDrives.add(driveDisplayName);
      }
      if (!newPool
          && !modifiedPool
          && ImplicitPoolMatcher.checkPoolPropertiesChanged(
              pool.getSupportedDriveTypes(), diskDrives)) {
        modifiedPool = true;
      }
      pool.addDriveTypes(diskDrives);
    }
    _logger.info("Discovered disk drives:[{}] for pool id:{}", driveTypes, pool.getId());

    if (newPool) {
      _newPoolList.add(pool);
      // add new pools to modified pools list to consider them for implicit pool matching.
      if (!poolsToMatchWithVpool.containsKey(pool.getId())) {
        poolsToMatchWithVpool.put(pool.getId(), pool);
      }
    } else {
      _updatePoolList.add(pool);
      // add to modified pool list if pool's property which is required for vPool matcher, has
      // changed.
      // No need to check whether the pool is already there in the list here
      // because this processor is the first to discover pools.
      if (modifiedPool && !poolsToMatchWithVpool.containsKey(pool.getId())) {
        poolsToMatchWithVpool.put(pool.getId(), pool);
      }
    }
  }