class PreUpgradeCheckResourceProvider extends ReadOnlyResourceProvider {

  @Override
  public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException,
    NoSuchResourceException, NoSuchParentResourceException {

    final Set<Resource> resources = new HashSet<>();
    final Set<String> requestedIds = getRequestPropertyIds(request, predicate);
    final Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);

    for (Map<String, Object> propertyMap: propertyMaps) {
      final String clusterName = propertyMap.get(UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID).toString();

      UpgradeType upgradeType = UpgradeType.ROLLING;
      if (propertyMap.containsKey(UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID)) {
        try {
          upgradeType = UpgradeType.valueOf(propertyMap.get(UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID).toString());
        } catch(Exception e){
          throw new SystemException(String.format("Property %s has an incorrect value of %s.", UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID, propertyMap.get(UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID)));
        }
      }

      final Cluster cluster;

      try {
        cluster = clustersProvider.get().getCluster(clusterName);
      } catch (AmbariException ambariException) {
        throw new NoSuchResourceException(ambariException.getMessage());
      }

      String repositoryVersionId = (String) propertyMap.get(
          UPGRADE_CHECK_TARGET_REPOSITORY_VERSION_ID_ID);

      if (StringUtils.isBlank(repositoryVersionId)) {
        throw new SystemException(
            String.format("%s is a required property when executing upgrade checks",
                UPGRADE_CHECK_TARGET_REPOSITORY_VERSION_ID_ID));
      }

      final PrereqCheckRequest upgradeCheckRequest = new PrereqCheckRequest(clusterName,
          upgradeType);

      StackId sourceStackId = cluster.getCurrentStackVersion();
      upgradeCheckRequest.setSourceStackId(cluster.getCurrentStackVersion());

      RepositoryVersionEntity repositoryVersion = repositoryVersionDAO.findByPK(
          Long.valueOf(repositoryVersionId));

      upgradeCheckRequest.setTargetRepositoryVersion(repositoryVersion);

      if (propertyMap.containsKey(UPGRADE_CHECK_FOR_REVERT_PROPERTY_ID)) {
        Boolean forRevert = BooleanUtils.toBooleanObject(propertyMap.get(UPGRADE_CHECK_FOR_REVERT_PROPERTY_ID).toString());
        upgradeCheckRequest.setRevert(forRevert);
      }

      //ambariMetaInfo.getStack(stackName, cluster.getCurrentStackVersion().getStackVersion()).getUpgradePacks()
      // TODO AMBARI-12698, filter the upgrade checks to run based on the stack and upgrade type, or the upgrade pack.
      UpgradePack upgradePack = null;
      String preferredUpgradePackName = propertyMap.containsKey(UPGRADE_CHECK_UPGRADE_PACK_PROPERTY_ID) ?
          (String) propertyMap.get(UPGRADE_CHECK_UPGRADE_PACK_PROPERTY_ID) : null;
      try{
        // Hint: PreChecks currently executing only before UPGRADE direction
        upgradePack = upgradeHelper.get().suggestUpgradePack(clusterName, sourceStackId,
            repositoryVersion.getStackId(), Direction.UPGRADE, upgradeType,
            preferredUpgradePackName);
      } catch (AmbariException e) {
        throw new SystemException(e.getMessage(), e);
      }

      if (upgradePack == null) {
        throw new SystemException(
            String.format("Upgrade pack not found for the target repository version %s",
                upgradeCheckRequest.getTargetRepositoryVersion()));
      }

      // ToDo: properly handle exceptions, i.e. create fake check with error description
      List<AbstractCheckDescriptor> upgradeChecksToRun = upgradeCheckRegistry.getFilteredUpgradeChecks(upgradePack);
      upgradeCheckRequest.setPrerequisiteCheckConfig(upgradePack.getPrerequisiteCheckConfig());

      try {
        // Register all the custom prechecks from the services
        Map<String, ServiceInfo> services = getManagementController().getAmbariMetaInfo().getServices(
            sourceStackId.getStackName(), sourceStackId.getStackVersion());

        List<AbstractCheckDescriptor> serviceLevelUpgradeChecksToRun = upgradeCheckRegistry.getServiceLevelUpgradeChecks(upgradePack, services);
        upgradeChecksToRun.addAll(serviceLevelUpgradeChecksToRun);
      } catch (ParentObjectNotFoundException parentNotFoundException) {
        LOG.error("Invalid stack version: {}", sourceStackId, parentNotFoundException);
      } catch (AmbariException ambariException) {
        LOG.error("Unable to register all the custom prechecks from the services", ambariException);
      } catch (Exception e) {
        LOG.error("Failed to register custom prechecks for the services", e);
      }

      for (PrerequisiteCheck prerequisiteCheck : checkHelper.performChecks(upgradeCheckRequest, upgradeChecksToRun, config.get())) {
        final Resource resource = new ResourceImpl(Resource.Type.PreUpgradeCheck);
        setResourceProperty(resource, UPGRADE_CHECK_ID_PROPERTY_ID, prerequisiteCheck.getId(), requestedIds);
        setResourceProperty(resource, UPGRADE_CHECK_CHECK_PROPERTY_ID, prerequisiteCheck.getDescription(), requestedIds);
        setResourceProperty(resource, UPGRADE_CHECK_STATUS_PROPERTY_ID, prerequisiteCheck.getStatus(), requestedIds);
        setResourceProperty(resource, UPGRADE_CHECK_REASON_PROPERTY_ID, prerequisiteCheck.getFailReason(), requestedIds);
        setResourceProperty(resource, UPGRADE_CHECK_FAILED_ON_PROPERTY_ID, prerequisiteCheck.getFailedOn(), requestedIds);
        setResourceProperty(resource, UPGRADE_CHECK_FAILED_DETAIL_PROPERTY_ID,prerequisiteCheck.getFailedDetail(), requestedIds);
        setResourceProperty(resource, UPGRADE_CHECK_CHECK_TYPE_PROPERTY_ID, prerequisiteCheck.getType(), requestedIds);
        setResourceProperty(resource, UPGRADE_CHECK_CLUSTER_NAME_PROPERTY_ID, prerequisiteCheck.getClusterName(), requestedIds);
        setResourceProperty(resource, UPGRADE_CHECK_UPGRADE_TYPE_PROPERTY_ID, upgradeType, requestedIds);

        setResourceProperty(resource, UPGRADE_CHECK_TARGET_REPOSITORY_VERSION_ID_ID, repositoryVersion.getId(), requestedIds);
        setResourceProperty(resource, UPGRADE_CHECK_TARGET_REPOSITORY_VERSION, repositoryVersion.getVersion(), requestedIds);

        resources.add(resource);
      }
    }
    return resources;
  }

  public  PreUpgradeCheckResourceProvider(AmbariManagementController managementController);

}