private List<CifsShareACL> queryDBShareACLs() {

    try {
      ContainmentConstraint containmentConstraint = null;

      if (this.fs != null) {
        _log.info(
            "Querying DB for Share ACLs of share {} of filesystemId {} ",
            this.shareName,
            fs.getId());
        containmentConstraint =
            ContainmentConstraint.Factory.getFileCifsShareAclsConstraint(this.fs.getId());
      } else {
        // Snapshot
        _log.info(
            "Querying DB for Share ACLs of share {} of snapshotId {} ",
            this.shareName,
            this.snapshot.getId());
        containmentConstraint =
            ContainmentConstraint.Factory.getSnapshotCifsShareAclsConstraint(this.snapshot.getId());
      }

      List<CifsShareACL> shareAclList =
          CustomQueryUtility.queryActiveResourcesByConstraint(
              this.dbClient, CifsShareACL.class, containmentConstraint);

      return shareAclList;

    } catch (Exception e) {
      _log.error("Error while querying DB for ACL of a share {}", e);
    }

    return null;
  }
  public static void setSystemResourcesIncompatible(
      DbClient dbClient, CoordinatorClient coordinator, URI storageSystemId) {
    // Mark all Pools as incompatible
    URIQueryResultList storagePoolURIs = new URIQueryResultList();
    dbClient.queryByConstraint(
        ContainmentConstraint.Factory.getStorageDeviceStoragePoolConstraint(storageSystemId),
        storagePoolURIs);
    Iterator<URI> storagePoolIter = storagePoolURIs.iterator();
    List<StoragePool> modifiedPools = new ArrayList<StoragePool>();
    while (storagePoolIter.hasNext()) {
      StoragePool pool = dbClient.queryObject(StoragePool.class, storagePoolIter.next());
      modifiedPools.add(pool);
      pool.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.INCOMPATIBLE.name());
      dbClient.persistObject(pool);
    }
    ImplicitPoolMatcher.matchModifiedStoragePoolsWithAllVirtualPool(
        modifiedPools, dbClient, coordinator);
    ;

    // Mark all Ports as incompatible
    URIQueryResultList storagePortURIs = new URIQueryResultList();
    dbClient.queryByConstraint(
        ContainmentConstraint.Factory.getStorageDeviceStoragePortConstraint(storageSystemId),
        storagePortURIs);
    Iterator<URI> storagePortIter = storagePortURIs.iterator();
    while (storagePortIter.hasNext()) {
      StoragePort port = dbClient.queryObject(StoragePort.class, storagePortIter.next());
      port.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.INCOMPATIBLE.name());
      dbClient.persistObject(port);
    }
  }
  /**
   * This method cleans up UnManaged Volumes in DB, which had been deleted manually from the Array
   * 1. Get All UnManagedVolumes from DB 2. Store URIs of unmanaged volumes returned from the
   * Provider in unManagedVolumesBookKeepingList. 3. If unmanaged volume is found only in DB, but
   * not in unManagedVolumesBookKeepingList, then set unmanaged volume to inactive.
   *
   * <p>DB | Provider
   *
   * <p>x,y,z | y,z.a [a --> new entry has been added but indexes didn't get added yet into DB]
   *
   * <p>x--> will be set to inactive
   *
   * @param storagePoolUri
   * @throws IOException
   */
  private void performStorageUnManagedVolumeBookKeeping(URI storagePoolUri) throws IOException {
    @SuppressWarnings("deprecation")
    List<URI> unManagedVolumesInDB =
        _dbClient.queryByConstraint(
            ContainmentConstraint.Factory.getPoolUnManagedVolumeConstraint(storagePoolUri));

    Set<URI> unManagedVolumesInDBSet = new HashSet<URI>(unManagedVolumesInDB);
    SetView<URI> onlyAvailableinDB =
        Sets.difference(unManagedVolumesInDBSet, unManagedVolumesReturnedFromProvider);

    _logger.info("Diff :" + Joiner.on("\t").join(onlyAvailableinDB));
    if (onlyAvailableinDB.size() > 0) {
      List<UnManagedVolume> unManagedVolumeTobeDeleted = new ArrayList<UnManagedVolume>();
      Iterator<UnManagedVolume> unManagedVolumes =
          _dbClient.queryIterativeObjects(
              UnManagedVolume.class, new ArrayList<URI>(onlyAvailableinDB));

      while (unManagedVolumes.hasNext()) {
        UnManagedVolume volume = unManagedVolumes.next();
        if (null == volume || volume.getInactive()) {
          continue;
        }

        _logger.info("Setting unManagedVolume {} inactive", volume.getId());
        volume.setStoragePoolUri(NullColumnValueGetter.getNullURI());
        volume.setStorageSystemUri(NullColumnValueGetter.getNullURI());
        volume.setInactive(true);
        unManagedVolumeTobeDeleted.add(volume);
      }
      if (unManagedVolumeTobeDeleted.size() > 0) {
        _partitionManager.updateAndReIndexInBatches(
            unManagedVolumeTobeDeleted, 1000, _dbClient, "UnManagedVolume");
      }
    }
  }
 /**
  * Get search results by project alone.
  *
  * @return SearchedResRepList
  */
 @Override
 protected SearchedResRepList getProjectSearchResults(URI projectId) {
   SearchedResRepList resRepList = new SearchedResRepList(getResourceType());
   _dbClient.queryByConstraint(
       ContainmentConstraint.Factory.getProjectBucketConstraint(projectId), resRepList);
   return resRepList;
 }
  /**
   * get Matched Virtual Pools For Pool. This is called to calculate supported vpools during
   * unmanaged objects discovery
   *
   * @param poolUri
   * @return
   */
  public static StringSet getMatchedVirtualPoolsForPool(
      DbClient dbClient, URI poolUri, String isThinlyProvisionedUnManagedObject) {
    StringSet vpoolUriSet = new StringSet();
    // We should match all virtual pools as below:
    // 1) Virtual pools which have useMatchedPools set to true and have the storage pool in their
    // matched pools
    // 2) Virtual pools which have the storage pool in their assigned pools

    URIQueryResultList vpoolMatchedPoolsResultList = new URIQueryResultList();
    dbClient.queryByConstraint(
        ContainmentConstraint.Factory.getMatchedPoolVirtualPoolConstraint(poolUri),
        vpoolMatchedPoolsResultList);
    List<VirtualPool> vPoolsMatchedPools =
        dbClient.queryObject(VirtualPool.class, vpoolMatchedPoolsResultList);
    String provisioningTypeUnManagedObject =
        UnManagedVolume.SupportedProvisioningType.getProvisioningType(
            isThinlyProvisionedUnManagedObject);
    StoragePool storagePool = dbClient.queryObject(StoragePool.class, poolUri);
    for (VirtualPool vPool : vPoolsMatchedPools) {
      if (!VirtualPool.vPoolSpecifiesHighAvailability(vPool)) {
        List<StoragePool> validPools = VirtualPool.getValidStoragePools(vPool, dbClient, true);
        for (StoragePool sPool : validPools) {
          if (sPool.getId().equals(storagePool.getId())
              && provisioningTypeUnManagedObject.equalsIgnoreCase(
                  vPool.getSupportedProvisioningType())) {
            vpoolUriSet.add(vPool.getId().toString());
            break;
          }
        }
      }
    }

    return vpoolUriSet;
  }
  // Getting all the vpools
  public static StringSet getMatchedVirtualPoolsForPool(DbClient dbClient, URI poolUri) {
    StringSet vpoolUriSet = new StringSet();
    // We should match all virtual pools as below:
    // 1) Virtual pools which have useMatchedPools set to true and have the storage pool in their
    // matched pools
    // 2) Virtual pools which have the storage pool in their assigned pools

    URIQueryResultList vpoolMatchedPoolsResultList = new URIQueryResultList();
    dbClient.queryByConstraint(
        ContainmentConstraint.Factory.getMatchedPoolVirtualPoolConstraint(poolUri),
        vpoolMatchedPoolsResultList);
    List<VirtualPool> vPoolsMatchedPools =
        dbClient.queryObject(VirtualPool.class, vpoolMatchedPoolsResultList);
    StoragePool storagePool = dbClient.queryObject(StoragePool.class, poolUri);
    for (VirtualPool vPool : vPoolsMatchedPools) {
      List<StoragePool> validPools = VirtualPool.getValidStoragePools(vPool, dbClient, true);
      for (StoragePool sPool : validPools) {
        if (sPool.getId().equals(storagePool.getId())) {
          vpoolUriSet.add(vPool.getId().toString());
          break;
        }
      }
    }

    return vpoolUriSet;
  }
 @Override
 public void injectColumnsDetails(Stat statObj, DbClient client) throws Exception {
   ProtectionSystem protectionObj =
       client.queryObject(ProtectionSystem.class, statObj.getResourceId());
   // Given a protection system, find a volume protected by this protection system,
   // and then extract the project and vpool
   Volume protectedVolume = null;
   URIQueryResultList resultList = new URIQueryResultList();
   client.queryByConstraint(
       ContainmentConstraint.Factory.getProtectionSystemVolumesConstraint(protectionObj.getId()),
       resultList);
   for (Iterator<URI> volumeItr = resultList.iterator(); volumeItr.hasNext(); ) {
     Volume volume = client.queryObject(Volume.class, volumeItr.next());
     if (volume.getProtectionController().equals(protectionObj.getId())) {
       protectedVolume = volume;
       break;
     }
   }
   if (protectedVolume != null) {
     _logger.info(
         "Found volume "
             + protectedVolume.getWWN()
             + " protected by this protection controller.  Get the Cos/Project/Tenant.");
     statObj.setProject(protectedVolume.getProject().getURI());
     statObj.setVirtualPool(protectedVolume.getVirtualPool());
     statObj.setTenant(protectedVolume.getTenant().getURI());
   } else {
     statObj.setProject(null);
     statObj.setVirtualPool(null);
     statObj.setTenant(null);
     throw new SMIPluginException(
         "Cassandra Database Insertion Error.  Cannot identify Project/CoS/Tenant for ProtectionSystem",
         -1);
   }
 }
  /**
   * Cleans up instances of {@link BlockSnapshot} that failed to be created. Also, any stale entries
   * in {@link BlockSnapshotSession#getLinkedTargets()} will be cleaned up.
   *
   * @param volume Volume URI to process.
   * @param itemsToUpdate Items to be updated.
   * @param itemsToDelete Items to be deleted.
   */
  @Override
  public void process(
      URI volume, Collection<DataObject> itemsToUpdate, Collection<DataObject> itemsToDelete) {
    List<BlockSnapshot> snapshots =
        CustomQueryUtility.queryActiveResourcesByConstraint(
            getDbClient(),
            BlockSnapshot.class,
            ContainmentConstraint.Factory.getVolumeSnapshotConstraint(volume));
    List<BlockSnapshot> failedSnapshots = new ArrayList<>();
    List<BlockSnapshotSession> updateSessions = new ArrayList<>();

    failedSnapshots.addAll(
        Collections2.filter(
            snapshots,
            new Predicate<BlockSnapshot>() {
              @Override
              public boolean apply(BlockSnapshot snapshot) {
                return Strings.isNullOrEmpty(snapshot.getNativeId());
              }
            }));

    // Removed failed snapshots from any existing sessions
    for (BlockSnapshot failedSnapshot : failedSnapshots) {
      log.info("Removing failed snapshot: {}", failedSnapshot.getLabel());
      List<BlockSnapshotSession> sessions =
          CustomQueryUtility.queryActiveResourcesByConstraint(
              getDbClient(),
              BlockSnapshotSession.class,
              ContainmentConstraint.Factory.getLinkedTargetSnapshotSessionConstraint(
                  failedSnapshot.getId()));

      for (BlockSnapshotSession session : sessions) {
        log.info("Updating existing session: {}", session.getSessionLabel());
        StringSet linkedTargets = session.getLinkedTargets();
        linkedTargets.remove(failedSnapshot.getId().toString());
        updateSessions.add(session);
      }
    }

    itemsToUpdate.addAll(updateSessions);
    itemsToDelete.addAll(failedSnapshots);
  }
  /**
   * This method cleans up UnManaged Volumes in DB, which had been deleted manually from the Array
   * 1. Get All UnManagedVolumes from DB 2. Store URIs of unmanaged volumes returned from the
   * Provider in unManagedVolumesBookKeepingList. 3. If unmanaged volume is found only in DB, but
   * not in unManagedVolumesBookKeepingList, then set unmanaged volume to inactive.
   *
   * <p>DB | Provider
   *
   * <p>x,y,z | y,z.a [a --> new entry has been added but indexes didn't get added yet into DB]
   *
   * <p>x--> will be set to inactive
   *
   * @param storageSystem
   * @param discoveredUnManagedVolumes
   * @param dbClient
   * @param partitionManager
   */
  public static void markInActiveUnManagedVolumes(
      StorageSystem storageSystem,
      Set<URI> discoveredUnManagedVolumes,
      DbClient dbClient,
      PartitionManager partitionManager) {

    _log.info(
        " -- Processing {} discovered UnManaged Volumes Objects from -- {}",
        discoveredUnManagedVolumes.size(),
        storageSystem.getLabel());
    if (discoveredUnManagedVolumes.isEmpty()) {
      return;
    }
    // Get all available existing unmanaged Volume URIs for this array from DB
    URIQueryResultList allAvailableUnManagedVolumesInDB = new URIQueryResultList();
    dbClient.queryByConstraint(
        ContainmentConstraint.Factory.getStorageDeviceUnManagedVolumeConstraint(
            storageSystem.getId()),
        allAvailableUnManagedVolumesInDB);

    Set<URI> unManagedVolumesInDBSet = new HashSet<URI>();
    Iterator<URI> allAvailableUnManagedVolumesItr = allAvailableUnManagedVolumesInDB.iterator();
    while (allAvailableUnManagedVolumesItr.hasNext()) {
      unManagedVolumesInDBSet.add(allAvailableUnManagedVolumesItr.next());
    }

    SetView<URI> onlyAvailableinDB =
        Sets.difference(unManagedVolumesInDBSet, discoveredUnManagedVolumes);

    _log.info("Diff :" + Joiner.on("\t").join(onlyAvailableinDB));
    if (!onlyAvailableinDB.isEmpty()) {
      List<UnManagedVolume> unManagedVolumeTobeDeleted = new ArrayList<UnManagedVolume>();
      Iterator<UnManagedVolume> unManagedVolumes =
          dbClient.queryIterativeObjects(
              UnManagedVolume.class, new ArrayList<URI>(onlyAvailableinDB));

      while (unManagedVolumes.hasNext()) {
        UnManagedVolume volume = unManagedVolumes.next();
        if (null == volume || volume.getInactive()) {
          continue;
        }

        _log.info("Setting unManagedVolume {} inactive", volume.getId());
        volume.setStoragePoolUri(NullColumnValueGetter.getNullURI());
        volume.setStorageSystemUri(NullColumnValueGetter.getNullURI());
        volume.setInactive(true);
        unManagedVolumeTobeDeleted.add(volume);
      }
      if (!unManagedVolumeTobeDeleted.isEmpty()) {
        partitionManager.updateAndReIndexInBatches(
            unManagedVolumeTobeDeleted, 1000, dbClient, UNMANAGED_VOLUME);
      }
    }
  }
  public static void markInActiveUnManagedExportMask(
      URI storageSystemUri,
      Set<URI> discoveredUnManagedExportMasks,
      DbClient dbClient,
      PartitionManager partitionManager) {

    URIQueryResultList result = new URIQueryResultList();
    dbClient.queryByConstraint(
        ContainmentConstraint.Factory.getStorageSystemUnManagedExportMaskConstraint(
            storageSystemUri),
        result);
    Set<URI> allMasksInDatabase = new HashSet<URI>();
    Iterator<URI> it = result.iterator();
    while (it.hasNext()) {
      allMasksInDatabase.add(it.next());
    }

    SetView<URI> onlyAvailableinDB =
        Sets.difference(allMasksInDatabase, discoveredUnManagedExportMasks);

    if (!onlyAvailableinDB.isEmpty()) {
      _log.info(
          "these UnManagedExportMasks are orphaned and will be cleaned up:"
              + Joiner.on("\t").join(onlyAvailableinDB));

      List<UnManagedExportMask> unManagedExportMasksToBeDeleted =
          new ArrayList<UnManagedExportMask>();
      Iterator<UnManagedExportMask> unManagedExportMasks =
          dbClient.queryIterativeObjects(
              UnManagedExportMask.class, new ArrayList<URI>(onlyAvailableinDB));

      while (unManagedExportMasks.hasNext()) {

        UnManagedExportMask uem = unManagedExportMasks.next();
        if (null == uem || uem.getInactive()) {
          continue;
        }

        _log.info("Setting UnManagedExportMask {} inactive", uem.getMaskingViewPath());
        uem.setStorageSystemUri(NullColumnValueGetter.getNullURI());
        uem.setInactive(true);
        unManagedExportMasksToBeDeleted.add(uem);
      }
      if (!unManagedExportMasksToBeDeleted.isEmpty()) {
        partitionManager.updateAndReIndexInBatches(
            unManagedExportMasksToBeDeleted,
            Constants.DEFAULT_PARTITION_SIZE,
            dbClient,
            UNMANAGED_EXPORT_MASK);
      }
    }
  }
 private Iterator<FCEndpoint> getNetworkSystemEndPoints(NetworkSystem networkSystem)
     throws IOException {
   URIQueryResultList uriList = new URIQueryResultList();
   dbClient.queryByConstraint(
       ContainmentConstraint.Factory.getNetworkSystemFCPortConnectionConstraint(
           networkSystem.getId()),
       uriList);
   List<URI> uris = new ArrayList<URI>();
   while (uriList.iterator().hasNext()) {
     uris.add(uriList.iterator().next());
   }
   return dbClient.queryIterativeObjects(FCEndpoint.class, uris);
 }
  private List<QuotaDirectory> queryDBQuotaDirectories(FileShare fs) {
    _log.info("Querying all quota directories Using FsId {}", fs.getId());
    try {
      ContainmentConstraint containmentConstraint =
          ContainmentConstraint.Factory.getQuotaDirectoryConstraint(fs.getId());
      List<QuotaDirectory> fsQuotaDirs =
          CustomQueryUtility.queryActiveResourcesByConstraint(
              _dbClient, QuotaDirectory.class, containmentConstraint);
      return fsQuotaDirs;
    } catch (Exception e) {
      _log.error("Error while querying {}", e);
    }

    return null;
  }
  public static List<StoragePort> checkStoragePortsNotVisible(
      List<StoragePort> discoveredPorts, DbClient dbClient, URI storageSystemId) {
    List<StoragePort> modifiedPorts = new ArrayList<StoragePort>();
    // Get the pools previousy discovered
    URIQueryResultList storagePortURIs = new URIQueryResultList();
    dbClient.queryByConstraint(
        ContainmentConstraint.Factory.getStorageDeviceStoragePortConstraint(storageSystemId),
        storagePortURIs);
    Iterator<URI> storagePortIter = storagePortURIs.iterator();

    List<URI> existingPortsURI = new ArrayList<URI>();
    while (storagePortIter.hasNext()) {
      existingPortsURI.add(storagePortIter.next());
    }

    List<URI> discoveredPortsURI = new ArrayList<URI>();
    for (StoragePort port : discoveredPorts) {
      discoveredPortsURI.add(port.getId());
    }

    Set<URI> portsDiff =
        Sets.difference(new HashSet<URI>(existingPortsURI), new HashSet<URI>(discoveredPortsURI));

    if (!portsDiff.isEmpty()) {
      Iterator<StoragePort> storagePortIt =
          dbClient.queryIterativeObjects(StoragePort.class, portsDiff, true);
      while (storagePortIt.hasNext()) {
        StoragePort port = storagePortIt.next();
        modifiedPorts.add(port);
        _log.info(
            "Setting discovery status of port {} : {} as NOTVISIBLE",
            port.getLabel(),
            port.getId());
        port.setDiscoveryStatus(DiscoveredDataObject.DiscoveryStatus.NOTVISIBLE.name());
        dbClient.persistObject(port);
      }
    }

    return modifiedPorts;
  }
  /**
   * Gets list of active ports belonging to a storage system.
   *
   * @return
   */
  private List<StoragePort> getStoragePortList(boolean isRefresh) {
    logger.debug("Start getStoragePortList");
    if (null == allStoragePortsList || isRefresh) {
      allStoragePortsList = new ArrayList<StoragePort>();
      URIQueryResultList storagePortURIs = new URIQueryResultList();
      URI sysid = storageSystem.getId();
      dbClient.queryByConstraint(
          ContainmentConstraint.Factory.getStorageDeviceStoragePortConstraint(sysid),
          storagePortURIs);

      Iterator<URI> storagePortsIter = storagePortURIs.iterator();
      while (storagePortsIter.hasNext()) {
        URI storagePortURI = storagePortsIter.next();
        StoragePort storagePort = dbClient.queryObject(StoragePort.class, storagePortURI);
        if (storagePort != null && !storagePort.getInactive()) {
          allStoragePortsList.add(storagePort);
        }
      }
    }

    logger.debug("End getStoragePortList");

    return allStoragePortsList;
  }
  /**
   * get the DB metrics for each data mover or VDM
   *
   * @param storageSystem
   * @param dbClient
   * @param dmFsMountMap
   * @param dmCapacityMap
   * @param vdmFsMountMap
   * @param vdmCapacityMap
   */
  private void prepareDBMetrics(
      StorageSystem storageSystem,
      DbClient dbClient,
      final Map<String, List<String>> dmFsMountMap,
      final Map<String, Long> dmCapacityMap,
      final Map<String, List<String>> vdmFsMountMap,
      final Map<String, Long> vdmCapacityMap) {

    List<VirtualNAS> modifiedVNas = new ArrayList<VirtualNAS>();
    List<PhysicalNAS> modifiedPNas = new ArrayList<PhysicalNAS>();

    for (Entry<String, List<String>> eachNas : dmFsMountMap.entrySet()) {
      _logger.info(" Computing metrics for data mover {}  ", eachNas.getKey());
      // Get Physical NAS from db!!
      PhysicalNAS pNAS = findPhysicalNasByNativeId(storageSystem, dbClient, eachNas.getKey());

      List<VirtualNAS> vNasList = new ArrayList<VirtualNAS>();

      if (null != pNAS) {
        URIQueryResultList virtualNASUris = new URIQueryResultList();
        dbClient.queryByConstraint(
            ContainmentConstraint.Factory.getVirtualNASByParentConstraint(pNAS.getId()),
            virtualNASUris);

        Long totalDmObjects = 0L;
        Long totalDmCapacity = 0L;

        Iterator<URI> virtualNASIter = virtualNASUris.iterator();
        while (virtualNASIter.hasNext()) {
          // Get Each vNAS on Physical NAS
          VirtualNAS virtualNAS = dbClient.queryObject(VirtualNAS.class, virtualNASIter.next());
          if (virtualNAS != null && !virtualNAS.getInactive()) {

            vNasList.add(virtualNAS);
            int vNasObjects = 0;

            if (vdmFsMountMap.get(virtualNAS.getNativeId()) != null) {
              vNasObjects = vdmFsMountMap.get(virtualNAS.getNativeId()).size();
              totalDmObjects = totalDmObjects + vNasObjects;
            }

            Long vNasCapacity = 0L;
            if (vdmCapacityMap.get(virtualNAS.getNativeId()) != null) {
              vNasCapacity = vdmCapacityMap.get(virtualNAS.getNativeId());
              totalDmCapacity = totalDmCapacity + vNasCapacity;
            }

            // Update dbMetrics for vNAS!!
            StringMap vNasDbMetrics = virtualNAS.getMetrics();
            vNasDbMetrics.put(MetricsKeys.storageObjects.name(), String.valueOf(vNasObjects));
            vNasDbMetrics.put(MetricsKeys.usedStorageCapacity.name(), String.valueOf(vNasCapacity));

            modifiedVNas.add(virtualNAS);
          }
        }

        if (dmFsMountMap.get(pNAS.getNativeId()) != null) {

          totalDmObjects = totalDmObjects + dmFsMountMap.get(pNAS.getNativeId()).size();
        }

        if (dmCapacityMap.get(pNAS.getNativeId()) != null) {
          totalDmCapacity = totalDmCapacity + dmCapacityMap.get(pNAS.getNativeId());
        }

        for (VirtualNAS vNas : vNasList) {
          // Update dbMetrics for vNAS!!
          StringMap vNasDbMetrics = vNas.getMetrics();
          long StorageObj = MetricsKeys.getLong(MetricsKeys.storageObjects, vNas.getMetrics());
          double percentageLoad = ((double) StorageObj / totalDmObjects) * 100;
          vNasDbMetrics.put(MetricsKeys.percentLoad.name(), String.valueOf(percentageLoad));
        }

        StringMap pNasDbMetrics = pNAS.getMetrics();
        pNasDbMetrics.put(MetricsKeys.storageObjects.name(), String.valueOf(totalDmObjects));
        pNasDbMetrics.put(MetricsKeys.usedStorageCapacity.name(), String.valueOf(totalDmCapacity));

        long maxObjects = MetricsKeys.getLong(MetricsKeys.maxStorageObjects, pNasDbMetrics);
        long maxCapacity = MetricsKeys.getLong(MetricsKeys.maxStorageCapacity, pNasDbMetrics);
        double percentageLoad = ((double) totalDmObjects / maxObjects) * 100;
        pNasDbMetrics.put(MetricsKeys.percentLoad.name(), String.valueOf(percentageLoad));
        if (totalDmObjects >= maxObjects || totalDmCapacity >= maxCapacity) {
          pNasDbMetrics.put(MetricsKeys.overLoaded.name(), "true");
          // All vNas under should be updated!!!
          for (VirtualNAS vNas : vNasList) {
            // Update dbMetrics for vNAS!!
            StringMap vNasDbMetrics = vNas.getMetrics();
            vNasDbMetrics.put(MetricsKeys.overLoaded.name(), "true");
          }
        } else {
          pNasDbMetrics.put(MetricsKeys.overLoaded.name(), "false");
          // All vNas under should be updated!!!
          for (VirtualNAS vNas : vNasList) {
            // Update dbMetrics for vNAS!!
            StringMap vNasDbMetrics = vNas.getMetrics();
            vNasDbMetrics.put(MetricsKeys.overLoaded.name(), "false");
          }
        }
        modifiedPNas.add(pNAS);
      }

      // Update the db
      if (!modifiedVNas.isEmpty()) {
        dbClient.persistObject(modifiedVNas);
      }

      if (!modifiedPNas.isEmpty()) {
        dbClient.persistObject(modifiedPNas);
      }
    }
    return;
  }
  /**
   * Reconciles the current set of a Device's endpoints with what is persisted. Updates the database
   * accordingly.
   *
   * @param dev
   * @param currentConnections
   * @throws IOException
   */
  private void reconcileFCEndpoints(NetworkSystem dev, List<FCEndpoint> currentConnections)
      throws IOException {
    // First, read all the existing connections from the device, and put them into a map
    // keyed by remote wwpn.
    URIQueryResultList uriList = new URIQueryResultList();
    dbClient.queryByConstraint(
        ContainmentConstraint.Factory.getNetworkSystemFCPortConnectionConstraint(dev.getId()),
        uriList);
    Map<String, FCEndpoint> existingEndpoints = new HashMap<String, FCEndpoint>();
    for (URI uriold : uriList) {
      FCEndpoint connection = dbClient.queryObject(FCEndpoint.class, uriold);
      if (connection != null) {
        existingEndpoints.put(connection.getRemotePortName().toUpperCase(), connection);
      }
    }
    // Now, scan the new endpoints, looking for added or updated records by
    // comparing them with the existing endpoints. Keep track of what was processed
    // so can do deletions on anything not seen in the currentConnections.
    List<FCEndpoint> updated = new ArrayList<FCEndpoint>();
    List<FCEndpoint> created = new ArrayList<FCEndpoint>();
    Set<String> processedWwpns = new HashSet<String>();
    int conflictingEndpoints = 0;
    for (FCEndpoint current : currentConnections) {
      String key = current.getRemotePortName().toUpperCase();
      processedWwpns.add(key);
      FCEndpoint existing = existingEndpoints.get(key);
      if (existing == null) {
        current.setNetworkDevice(dev.getId());
        current.setId(URIUtil.createId(FCEndpoint.class));
        created.add(current);
        conflictingEndpoints +=
            removeConflictingEndpoints(key, current.getFabricWwn(), dev.getId());
      } else {
        boolean modified = checkUpdated(existing, current);
        if (existing.getAwolCount() > 0) {
          modified = true;
          existing.setAwolCount(0);
          existing.setAwolTime(null);
        }
        if (modified) {
          updated.add(existing);
          conflictingEndpoints +=
              removeConflictingEndpoints(key, current.getFabricWwn(), dev.getId());
        }
      }
    }

    // Determine those to be deleted. Remove all the processed records from the existing set.
    // What was left were not seen this time.
    for (String key : processedWwpns) {
      existingEndpoints.remove(key);
    }
    // The remaining existingEndpoints can be processed for removal.
    // They are removed after a minimum number of samples and minimum amount of time has transpired.
    Integer removedCount = 0;
    for (FCEndpoint entry : existingEndpoints.values()) {
      int count = entry.getAwolCount();
      if (count == 0) {
        entry.setAwolTime(System.currentTimeMillis());
      }
      entry.setAwolCount(++count);
      if (count >= _minAwolSamples
          && (System.currentTimeMillis() - entry.getAwolTime()) > _minAwolTime) {
        removedCount++;
        dbClient.removeObject(entry);
      } else {
        updated.add(entry); // update counters
      }
    }
    // Persist created, modified.
    dbClient.createObject(created);
    dbClient.updateAndReindexObject(updated);
    _log.info(MessageFormat.format("{0} new connections persisted", created.size()).toString());
    _log.info(MessageFormat.format("{0} updated connections persisted", updated.size()).toString());
    _log.info(
        MessageFormat.format("{0} missing connections", existingEndpoints.values().size())
            .toString());
    _log.info(MessageFormat.format("{0} removed connections", removedCount.toString()));
    _log.info(MessageFormat.format("{0} conflicting connections (removed)", conflictingEndpoints));
  }