class QueryImpl implements Query, ResourceInstance {

  protected Map<Resource, Set<Map<String, Object>>> getJoinedResourceProperties(Set<String> propertyIds,
                                                                                Resource parentResource,
                                                                                String category)
      throws SystemException, UnsupportedPropertyException, NoSuchParentResourceException, NoSuchResourceException {

    Map<Resource, Set<Map<String, Object>>> resourcePropertyMaps =
      new HashMap<>();

    Map<String, String> categoryPropertyIdMap =
        getPropertyIdsForCategory(propertyIds, category);

    for (Map.Entry<Resource, QueryResult> queryResultEntry : populatedQueryResults.entrySet()) {
      QueryResult queryResult         = queryResultEntry.getValue();
      Resource    queryParentResource = queryResultEntry.getKey();

      // for each resource for the given parent ...
      if (queryParentResource == parentResource) {

        Iterable<Resource> iterResource = clusterController.getIterable(
            resourceDefinition.getType(), queryResult.getQueryResponse(),
            queryResult.getRequest(), queryResult.getPredicate(), null, null);

        for (Resource resource : iterResource) {
          // get the resource properties
          Map<String, Object> resourcePropertyMap = new HashMap<>();
          for (Map.Entry<String, String> categoryPropertyIdEntry : categoryPropertyIdMap.entrySet()) {
            Object value = resource.getPropertyValue(categoryPropertyIdEntry.getValue());
            if (value != null) {
              resourcePropertyMap.put(categoryPropertyIdEntry.getKey(), value);
            }
          }

          Set<Map<String, Object>> propertyMaps = new HashSet<>();

          // For each sub category get the property maps for the sub resources
          for (Map.Entry<String, QueryImpl> entry : requestedSubResources.entrySet()) {
            String subResourceCategory = category == null ? entry.getKey() : category + "/" + entry.getKey();

            QueryImpl subResource = entry.getValue();

            Map<Resource, Set<Map<String, Object>>> subResourcePropertyMaps =
                subResource.getJoinedResourceProperties(propertyIds, resource, subResourceCategory);

            Set<Map<String, Object>> combinedSubResourcePropertyMaps = new HashSet<>();
            for (Set<Map<String, Object>> maps : subResourcePropertyMaps.values()) {
              combinedSubResourcePropertyMaps.addAll(maps);
            }
            propertyMaps = joinPropertyMaps(propertyMaps, combinedSubResourcePropertyMaps);
          }
          // add parent resource properties to joinedResources
          if (!resourcePropertyMap.isEmpty()) {
            if (propertyMaps.isEmpty()) {
              propertyMaps.add(resourcePropertyMap);
            } else {
              for (Map<String, Object> propertyMap : propertyMaps) {
                propertyMap.putAll(resourcePropertyMap);
              }
            }
          }
          resourcePropertyMaps.put(resource, propertyMaps);
        }
      }
    }
    return resourcePropertyMaps;
  }

  public  QueryImpl(Map<Resource.Type, String> keyValueMap,
                   ResourceDefinition resourceDefinition,
                   ClusterController clusterController);

}