protected static Set<HostResponse> getHosts(
      AmbariManagementController controller, HostRequest request) throws AmbariException {

    // TODO/FIXME host can only belong to a single cluster so get host directly from Cluster
    // TODO/FIXME what is the requirement for filtering on host attributes?

    List<Host> hosts;
    Set<HostResponse> response = new HashSet<HostResponse>();
    Cluster cluster = null;

    Clusters clusters = controller.getClusters();

    String clusterName = request.getClusterName();
    String hostName = request.getHostname();

    if (clusterName != null) {
      // validate that cluster exists, throws exception if it doesn't.
      try {
        cluster = clusters.getCluster(clusterName);
      } catch (ObjectNotFoundException e) {
        throw new ParentObjectNotFoundException("Parent Cluster resource doesn't exist", e);
      }
    }

    if (hostName == null) {
      hosts = clusters.getHosts();
    } else {
      hosts = new ArrayList<Host>();
      try {
        hosts.add(clusters.getHost(request.getHostname()));
      } catch (HostNotFoundException e) {
        // add cluster name
        throw new HostNotFoundException(clusterName, hostName);
      }
    }

    for (Host h : hosts) {
      if (clusterName != null) {
        if (clusters.getClustersForHost(h.getHostName()).contains(cluster)) {
          HostResponse r = h.convertToResponse();

          r.setClusterName(clusterName);
          r.setDesiredHostConfigs(h.getDesiredHostConfigs(cluster));
          r.setMaintenanceState(h.getMaintenanceState(cluster.getClusterId()));

          response.add(r);
        } else if (hostName != null) {
          throw new HostNotFoundException(clusterName, hostName);
        }
      } else {
        HostResponse r = h.convertToResponse();

        Set<Cluster> clustersForHost = clusters.getClustersForHost(h.getHostName());
        // todo: host can only belong to a single cluster
        if (clustersForHost != null && clustersForHost.size() != 0) {
          r.setClusterName(clustersForHost.iterator().next().getClusterName());
        }
        response.add(r);
      }
    }
    return response;
  }
  @Override
  public Set<Resource> getResources(Request request, Predicate predicate)
      throws SystemException, UnsupportedPropertyException, NoSuchResourceException,
          NoSuchParentResourceException {

    final Set<HostRequest> requests = new HashSet<HostRequest>();

    if (predicate == null) {
      requests.add(getRequest(null));
    } else {
      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
        requests.add(getRequest(propertyMap));
      }
    }

    Set<HostResponse> responses =
        getResources(
            new Command<Set<HostResponse>>() {
              @Override
              public Set<HostResponse> invoke() throws AmbariException {
                return getHosts(requests);
              }
            });

    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
    Set<Resource> resources = new HashSet<Resource>();

    for (HostResponse response : responses) {
      Resource resource = new ResourceImpl(Resource.Type.Host);

      // TODO : properly handle more than one cluster
      if (response.getClusterName() != null && !response.getClusterName().isEmpty()) {
        setResourceProperty(
            resource, HOST_CLUSTER_NAME_PROPERTY_ID, response.getClusterName(), requestedIds);
      }
      setResourceProperty(resource, HOST_NAME_PROPERTY_ID, response.getHostname(), requestedIds);
      setResourceProperty(
          resource, HOST_PUBLIC_NAME_PROPERTY_ID, response.getPublicHostName(), requestedIds);
      setResourceProperty(resource, HOST_IP_PROPERTY_ID, response.getIpv4(), requestedIds);
      setResourceProperty(
          resource, HOST_TOTAL_MEM_PROPERTY_ID, response.getTotalMemBytes(), requestedIds);
      setResourceProperty(
          resource, HOST_CPU_COUNT_PROPERTY_ID, (long) response.getCpuCount(), requestedIds);
      setResourceProperty(
          resource,
          HOST_PHYSICAL_CPU_COUNT_PROPERTY_ID,
          (long) response.getPhCpuCount(),
          requestedIds);
      setResourceProperty(resource, HOST_OS_ARCH_PROPERTY_ID, response.getOsArch(), requestedIds);
      setResourceProperty(resource, HOST_OS_TYPE_PROPERTY_ID, response.getOsType(), requestedIds);

      String hostOsFamily = osFamily.find(response.getOsType());
      if (hostOsFamily == null) {
        LOG.error(
            "Can not find host OS family. For OS type = '{}' and host name = '{}'",
            response.getOsType(),
            response.getHostname());
      }
      setResourceProperty(resource, HOST_OS_FAMILY_PROPERTY_ID, hostOsFamily, requestedIds);

      setResourceProperty(
          resource, HOST_RACK_INFO_PROPERTY_ID, response.getRackInfo(), requestedIds);
      setResourceProperty(
          resource,
          HOST_LAST_HEARTBEAT_TIME_PROPERTY_ID,
          response.getLastHeartbeatTime(),
          requestedIds);
      setResourceProperty(
          resource, HOST_LAST_AGENT_ENV_PROPERTY_ID, response.getLastAgentEnv(), requestedIds);
      setResourceProperty(
          resource,
          HOST_LAST_REGISTRATION_TIME_PROPERTY_ID,
          response.getLastRegistrationTime(),
          requestedIds);
      setResourceProperty(
          resource, HOST_HOST_STATUS_PROPERTY_ID, response.getStatus(), requestedIds);
      setResourceProperty(
          resource,
          HOST_HOST_HEALTH_REPORT_PROPERTY_ID,
          response.getHealthStatus().getHealthReport(),
          requestedIds);
      setResourceProperty(
          resource, HOST_RECOVERY_REPORT_PROPERTY_ID, response.getRecoveryReport(), requestedIds);
      setResourceProperty(
          resource, HOST_RECOVERY_SUMMARY_PROPERTY_ID, response.getRecoverySummary(), requestedIds);
      setResourceProperty(
          resource, HOST_DISK_INFO_PROPERTY_ID, response.getDisksInfo(), requestedIds);
      setResourceProperty(resource, HOST_STATE_PROPERTY_ID, response.getHostState(), requestedIds);
      setResourceProperty(
          resource,
          HOST_DESIRED_CONFIGS_PROPERTY_ID,
          response.getDesiredHostConfigs(),
          requestedIds);

      // only when a cluster request
      if (null != response.getMaintenanceState()) {
        setResourceProperty(
            resource,
            HOST_MAINTENANCE_STATE_PROPERTY_ID,
            response.getMaintenanceState(),
            requestedIds);
      }

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