@Override
  public Set<Resource> populateResources(Set<Resource> resources,
      Request request, Predicate predicate) throws SystemException {

    // only arrange for one instance of Ganglia and JMX instantiation
    Map<String, Map<String, PropertyInfo>> gangliaMap = new HashMap<>();
    Map<String, Map<String, PropertyInfo>> jmxMap = new HashMap<>();

    List<PropertyProvider> additional = new ArrayList<>();
    Map<String, String> overriddenHosts = new HashMap<>();
    Map<String, UriInfo> overriddenJmxUris = new HashMap<>();

    try {
      for (Resource r : resources) {
        String clusterName = r.getPropertyValue(clusterNamePropertyId).toString();
        String componentName = r.getPropertyValue(componentNamePropertyId).toString();

        Cluster cluster = clusters.getCluster(clusterName);
        Service service = null;

        try {
          service = cluster.getServiceByComponentName(componentName);
        } catch (ServiceNotFoundException e) {
          LOG.debug("Could not load component {}", componentName);
          continue;
        }

        StackId stack = service.getDesiredStackId();

        List<MetricDefinition> defs = metaInfo.getMetrics(
            stack.getStackName(), stack.getStackVersion(), service.getName(), componentName, type.name());

        if (null == defs || 0 == defs.size()) {
          continue;
        }

        for (MetricDefinition m : defs) {
          if (m.getType().equals("ganglia")) {
            gangliaMap.put(componentName, getPropertyInfo(m));
            m.getOverriddenHosts().ifPresent(host -> overriddenHosts.put(componentName, host));
          } else if (m.getType().equals("jmx")) {
            jmxMap.put(componentName, getPropertyInfo(m));
            m.getJmxSourceUri().ifPresent(uri -> overriddenJmxUris.put(componentName, uri));
          } else {
            PropertyProvider pp = getDelegate(m,
                streamProvider, metricHostProvider,
                clusterNamePropertyId, hostNamePropertyId,
                componentNamePropertyId, resourceStatePropertyId,
                componentName);
            if (pp == null) {
              pp = getDelegate(m);
            }
            if (pp != null) {
              additional.add(pp);
            }

          }
        }
      }

      if (gangliaMap.size() > 0) {
        PropertyProvider propertyProvider =
          MetricsPropertyProvider.createInstance(type, gangliaMap,
            streamProvider, sslConfig,
            cacheProvider,
            metricHostProvider(overriddenHosts),
            metricsServiceProvider, clusterNamePropertyId,
            hostNamePropertyId, componentNamePropertyId);

        propertyProvider.populateResources(resources, request, predicate);
      } else {
        defaultGanglia.populateResources(resources, request, predicate);
      }

      if (jmxMap.size() > 0) {
        JMXPropertyProvider jpp = metricPropertyProviderFactory.createJMXPropertyProvider(jmxMap,
            streamProvider,
            jmxHostProvider(overriddenJmxUris, jmxHostProvider, injector.getInstance(ConfigHelper.class)), metricHostProvider,
            clusterNamePropertyId, hostNamePropertyId,
            componentNamePropertyId, resourceStatePropertyId);

        jpp.populateResources(resources, request, predicate);
      } else {
        defaultJmx.populateResources(resources, request, predicate);
      }

      for (PropertyProvider pp : additional) {
        pp.populateResources(resources, request, predicate);
      }

    } catch (AuthorizationException e) {
      // Need to rethrow the catched 'AuthorizationException'.
      throw e;
    } catch (Exception e) {
      e.printStackTrace();
      LOG.error("Error loading deferred resources", e);
      throw new SystemException("Error loading deferred resources", e);
    }

    return resources;
  }
PropertyHelper/AbstractPropertyProvider expect map of maps,
that's why we wrap metrics into map
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackDefinedPropertyProvider.java