You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by tb...@apache.org on 2013/06/03 20:28:05 UTC

svn commit: r1489093 - in /incubator/ambari/trunk/ambari-server/src: main/java/org/apache/ambari/server/api/query/ main/java/org/apache/ambari/server/api/resources/ main/java/org/apache/ambari/server/controller/predicate/ test/java/org/apache/ambari/se...

Author: tbeerbower
Date: Mon Jun  3 18:28:04 2013
New Revision: 1489093

URL: http://svn.apache.org/r1489093
Log:
AMBARI-2254 - Reduce number of requests when querying for subtasks

Removed:
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/query/QueryImplTest.java
Modified:
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceImpl.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/AlwaysPredicate.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/ArrayPredicate.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/CategoryIsEmptyPredicate.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/ComparisonPredicate.java
    incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/UnaryPredicate.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/TestSuite.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ResourceInstanceImplTest.java
    incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterControllerImplTest.java

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java?rev=1489093&r1=1489092&r2=1489093&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java Mon Jun  3 18:28:04 2013
@@ -31,12 +31,19 @@ public class ResourceInstanceFactoryImpl
   @Override
   public ResourceInstance createResource(Resource.Type type, Map<Resource.Type, String> mapIds) {
 
-    /**
-     * The resource definition for the specified type.
-     */
-    ResourceDefinition resourceDefinition;
+    return new ResourceInstanceImpl(mapIds, createResourceDefinition(type, mapIds));
+  }
 
-    //todo: consider ResourceDependencyManager : Map<Resource.Type, ResourceDefinition>
+  /**
+   * Create a resource definition for the specified type.
+   *
+   * @param type    the resource type
+   * @param mapIds  the ids
+   *
+   * @return the resource definition
+   */
+  protected static ResourceDefinition createResourceDefinition(Resource.Type type, Map<Resource.Type, String> mapIds) {
+    ResourceDefinition resourceDefinition;//todo: consider ResourceDependencyManager : Map<Resource.Type, ResourceDefinition>
     switch (type) {
       case Cluster:
         resourceDefinition = new ClusterResourceDefinition();
@@ -52,7 +59,7 @@ public class ResourceInstanceFactoryImpl
         break;
 
       case Component:
-        resourceDefinition = new  ComponentResourceDefinition();
+        resourceDefinition = new ComponentResourceDefinition();
         break;
 
       case HostComponent:
@@ -82,27 +89,27 @@ public class ResourceInstanceFactoryImpl
       case Stack:
         resourceDefinition = new StackResourceDefinition();
         break;
-        
+
       case StackVersion:
         resourceDefinition = new StackVersionResourceDefinition();
         break;
-        
+
       case StackService:
         resourceDefinition = new StackServiceResourceDefinition();
         break;
-        
+
       case StackServiceComponent:
         resourceDefinition = new StackServiceComponentResourceDefinition();
         break;
-        
+
       case StackConfiguration:
         resourceDefinition = new StackConfigurationResourceDefinition();
         break;
-        
+
       case OperatingSystem:
         resourceDefinition = new OperatingSystemResourceDefinition();
         break;
-        
+
       case Repository:
         resourceDefinition = new RepositoryResourceDefinition();
         break;
@@ -134,7 +141,6 @@ public class ResourceInstanceFactoryImpl
       default:
         throw new IllegalArgumentException("Unsupported resource type: " + type);
     }
-
-    return new ResourceInstanceImpl(mapIds, resourceDefinition, this);
+    return resourceDefinition;
   }
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceImpl.java?rev=1489093&r1=1489092&r2=1489093&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceImpl.java Mon Jun  3 18:28:04 2013
@@ -20,24 +20,37 @@
 package org.apache.ambari.server.api.resources;
 
 import org.apache.ambari.server.api.query.Query;
-import org.apache.ambari.server.api.query.QueryImpl;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultImpl;
+import org.apache.ambari.server.api.util.TreeNode;
+import org.apache.ambari.server.controller.predicate.AndPredicate;
+import org.apache.ambari.server.controller.predicate.EqualsPredicate;
+import org.apache.ambari.server.controller.predicate.OrPredicate;
 import org.apache.ambari.server.controller.spi.ClusterController;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Schema;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.TemporalInfo;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
 /**
  * Resource instance which contains request specific state.
  */
-public class ResourceInstanceImpl implements ResourceInstance {
-
-  /**
-   * Query associated with the resource definition.
-   */
-  private Query m_query;
+public class ResourceInstanceImpl implements ResourceInstance, Query{
 
   /**
    * Map of primary and foreign keys and values necessary to identify the resource.
@@ -54,31 +67,62 @@ public class ResourceInstanceImpl implem
    * Sub-resource instances of this resource.
    * Map of resource resource name to resource instance.
    */
-  private Map<String, ResourceInstance> m_mapSubResources;
+  private Map<String, ResourceInstanceImpl> m_mapSubResources;
+
+  /**
+   * Sub-resources of the resource which is being operated on.
+   */
+  private Map<String, ResourceInstanceImpl> m_mapQuerySubResources = new HashMap<String, ResourceInstanceImpl>();
+
+  /**
+   * Properties of the query which make up the select portion of the query.
+   */
+  private Set<String> m_setQueryProperties = new HashSet<String>();
 
   /**
-   * Factory for creating resource instances.
-   * Used to create sub-resource instances.
+   * Indicates that the query should include all available properties.
    */
-  private ResourceInstanceFactory m_resourceFactory;
+  private boolean allProperties = false;
 
   /**
-   * Cluster controller reference.
+   * Map that associates each property set on the query to temporal data.
    */
-  //todo: should be injected.
-  private ClusterController m_controller = ClusterControllerHelper.getClusterController();
+  private Map<String, TemporalInfo> m_mapPropertyTemporalInfo = new HashMap<String, TemporalInfo>();
 
+  /**
+   * Map that associates categories with temporal data.
+   */
+  private Map<String, TemporalInfo> m_mapCategoryTemporalInfo = new HashMap<String, TemporalInfo>();
 
-  public ResourceInstanceImpl(Map<Resource.Type, String> mapIds, ResourceDefinition resourceDefinition,
-                              ResourceInstanceFactory resourceFactory) {
+  /**
+   * The user supplied predicate.
+   */
+  private Predicate m_userPredicate;
+
+  /**
+   * The predicate to use for this query.
+   */
+  private Predicate m_predicate;
+
+  /**
+   * The logger.
+   */
+  private final static Logger LOG =
+      LoggerFactory.getLogger(ResourceInstanceImpl.class);
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  public ResourceInstanceImpl(Map<Resource.Type, String> mapIds, ResourceDefinition resourceDefinition) {
 
     m_resourceDefinition = resourceDefinition;
-    m_query              = new QueryImpl(this);
-    m_resourceFactory    = resourceFactory;
 
     setIds(mapIds);
   }
 
+
+  // ----- ResourceInstance --------------------------------------------------
+
   @Override
   public void setIds(Map<Resource.Type, String> mapIds) {
     m_mapResourceIds.putAll(mapIds);
@@ -91,7 +135,7 @@ public class ResourceInstanceImpl implem
 
   @Override
   public Query getQuery() {
-    return m_query;
+    return this;
   }
 
   @Override
@@ -99,38 +143,86 @@ public class ResourceInstanceImpl implem
     return m_resourceDefinition;
   }
 
-
   @Override
   public Map<String, ResourceInstance> getSubResources() {
-    if (m_mapSubResources == null) {
-      m_mapSubResources = new HashMap<String, ResourceInstance>();
-      Set<SubResourceDefinition> setSubResourceDefs = getResourceDefinition().getSubResourceDefinitions();
+    return new HashMap<String, ResourceInstance>(ensureSubResources());
+  }
 
-      for (SubResourceDefinition subResDef : setSubResourceDefs) {
-        ResourceInstance resource = m_resourceFactory.createResource(subResDef.getType(), getIds());
+  @Override
+  public boolean isCollectionResource() {
+    return getIds().get(getResourceDefinition().getType()) == null;
+  }
 
-        // ensure pk is returned
-        resource.getQuery().addLocalProperty(m_controller.getSchema(
-            subResDef.getType()).getKeyPropertyId(subResDef.getType()));
-        // add additionally required fk properties
-        for (Resource.Type fkType : subResDef.getAdditionalForeignKeys()) {
-          resource.getQuery().addLocalProperty(m_controller.getSchema(subResDef.getType()).getKeyPropertyId(fkType));
+
+  // ----- Query -------------------------------------------------------------
+
+  @Override
+  public void addProperty(String category, String name, TemporalInfo temporalInfo) {
+    if (category == null && name.equals("*")) {
+      // wildcard
+      addAllProperties(temporalInfo);
+    } else{
+      if (addPropertyToSubResource(category, name, temporalInfo)){
+        // add pk/fk properties of the resource to this query
+        Resource.Type resourceType = getResourceDefinition().getType();
+        Schema schema              = getClusterController().getSchema(resourceType);
+
+        for (Resource.Type type : getIds().keySet()) {
+          addLocalProperty(schema.getKeyPropertyId(type));
         }
+      } else {
+        String propertyId = PropertyHelper.getPropertyId(category, name.equals("*") ? null : name);
+        addLocalProperty(propertyId);
+        if (temporalInfo != null) {
+          m_mapCategoryTemporalInfo.put(propertyId, temporalInfo);
+        }
+      }
+    }
+  }
 
-        String subResourceName = subResDef.isCollection() ? resource.getResourceDefinition().getPluralName() :
-            resource.getResourceDefinition().getSingularName();
+  @Override
+  public void addLocalProperty(String property) {
+    m_setQueryProperties.add(property);
+  }
 
-        m_mapSubResources.put(subResourceName, resource);
+  @Override
+  public Result execute()
+      throws UnsupportedPropertyException, SystemException, NoSuchResourceException, NoSuchParentResourceException {
+
+    QueryResult queryResult = queryForResources();
+
+    return applyResult(queryResult, null);
+  }
+
+  @Override
+  public Predicate getPredicate() {
+    if (m_predicate == null) {
+      Predicate internalPredicate = createInternalPredicate(this);
+      if (internalPredicate == null) {
+        if (m_userPredicate != null) {
+          m_predicate = m_userPredicate;
+        }
+      } else {
+        m_predicate = (m_userPredicate == null ? internalPredicate :
+            new AndPredicate(m_userPredicate, internalPredicate));
       }
     }
-    return m_mapSubResources;
+    return m_predicate;
   }
 
   @Override
-  public boolean isCollectionResource() {
-    return getIds().get(getResourceDefinition().getType()) == null;
+  public Set<String> getProperties() {
+    return Collections.unmodifiableSet(m_setQueryProperties);
+  }
+
+  @Override
+  public void setUserPredicate(Predicate predicate) {
+    m_userPredicate = predicate;
   }
 
+
+  // ----- Object overrides --------------------------------------------------
+
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
@@ -139,10 +231,15 @@ public class ResourceInstanceImpl implem
     ResourceInstanceImpl that = (ResourceInstanceImpl) o;
 
     return m_mapResourceIds.equals(that.m_mapResourceIds) &&
-           m_query == that.m_query &&
-           m_resourceDefinition.equals(that.m_resourceDefinition) &&
-           m_mapSubResources == null ? that.m_mapSubResources == null :
-               m_mapSubResources.equals(that.m_mapSubResources);
+        m_resourceDefinition.equals(that.m_resourceDefinition) &&
+        m_mapSubResources == null ? that.m_mapSubResources == null :
+            m_mapSubResources.equals(that.m_mapSubResources) &&
+        m_mapQuerySubResources == null ? that.m_mapQuerySubResources == null :
+            m_mapQuerySubResources.equals(that.m_mapQuerySubResources) &&
+        m_mapCategoryTemporalInfo.equals(that.m_mapCategoryTemporalInfo) &&
+        m_mapPropertyTemporalInfo.equals(that.m_mapPropertyTemporalInfo) &&
+        m_setQueryProperties.equals(that.m_setQueryProperties) &&
+        m_userPredicate == null ? that.m_userPredicate == null : m_userPredicate.equals(that.m_userPredicate);
   }
 
   @Override
@@ -151,6 +248,369 @@ public class ResourceInstanceImpl implem
     result = 31 * result + m_mapResourceIds.hashCode();
     result = 31 * result + m_resourceDefinition.hashCode();
     result = 31 * result + (m_mapSubResources != null ? m_mapSubResources.hashCode() : 0);
+    result = 31 * result + (m_mapQuerySubResources != null ? m_mapQuerySubResources.hashCode() : 0);
+    result = 31 * result + m_setQueryProperties.hashCode();
+    result = 31 * result + m_mapPropertyTemporalInfo.hashCode();
+    result = 31 * result + m_mapCategoryTemporalInfo.hashCode();
+    result = 31 * result + (m_userPredicate != null ? m_userPredicate.hashCode() : 0);
+
     return result;
   }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Factory method.
+   */
+  private static ResourceInstanceImpl createResource(
+      Resource.Type type, Map<Resource.Type, String> mapIds) {
+
+    return new ResourceInstanceImpl(mapIds,
+        ResourceInstanceFactoryImpl.createResourceDefinition(type, mapIds));
+  }
+
+  /**
+   * Get the associated cluster controller.
+   */
+  protected ClusterController getClusterController() {
+    return ClusterControllerHelper.getClusterController();
+  }
+
+  /**
+   * Get the map of sub-resources.  Lazily construct it if necessary.
+   */
+  protected Map<String, ResourceInstanceImpl> ensureSubResources() {
+    if (m_mapSubResources == null) {
+      m_mapSubResources = new HashMap<String, ResourceInstanceImpl>();
+      Set<SubResourceDefinition> setSubResourceDefs = getResourceDefinition().getSubResourceDefinitions();
+
+      for (SubResourceDefinition subResDef : setSubResourceDefs) {
+
+        Map<Resource.Type, String> mapIds = getIds();
+
+        ResourceInstanceImpl resource =createResource(subResDef.getType(), mapIds);
+
+        // ensure pk is returned
+        resource.getQuery().addLocalProperty(getClusterController().getSchema(
+            subResDef.getType()).getKeyPropertyId(subResDef.getType()));
+        // add additionally required fk properties
+        for (Resource.Type fkType : subResDef.getAdditionalForeignKeys()) {
+          resource.getQuery().addLocalProperty(getClusterController().getSchema(subResDef.getType()).getKeyPropertyId(fkType));
+        }
+
+        String subResourceName = subResDef.isCollection() ? resource.getResourceDefinition().getPluralName() :
+            resource.getResourceDefinition().getSingularName();
+
+        m_mapSubResources.put(subResourceName, resource);
+      }
+    }
+    return m_mapSubResources;
+  }
+
+  /**
+   * Apply the query result to this resource.
+   */
+  private Result applyResult(QueryResult queryResult, Predicate parentPredicate) {
+    Result result = createResult();
+
+    Map<String, ResourceInstanceImpl> mapSubResources = queryResult.getResourceInstance().m_mapQuerySubResources;
+    ResourceInstance resourceInstance = queryResult.getResourceInstance();
+
+    Resource.Type resourceType = resourceInstance.getResourceDefinition().getType();
+    if (resourceInstance.getIds().get(resourceType) == null) {
+      addCollectionProperties(resourceType);
+      result.getResultTree().setProperty("isCollection", "true");
+    }
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    int count = 1;
+    for (Resource resource : queryResult.getResources()) {
+
+      if (parentPredicate == null || parentPredicate.evaluate(resource)) {
+        // add a child node for the resource and provide a unique name.  The name is never used.
+        //todo: provide a more meaningful node name
+        TreeNode<Resource> node = tree.addChild(resource, resource.getType() + ":" + count++);
+        for (Map.Entry<String, ResourceInstanceImpl> entry : mapSubResources.entrySet()) {
+          String subResCategory = entry.getKey();
+          ResourceInstanceImpl r = entry.getValue();
+
+          Resource.Type subResourceType = r.getResourceDefinition().getType();
+
+          QueryResult subQueryResult = queryResult.getSubResources().get(subResourceType);
+
+          if (subQueryResult != null) {
+
+            setParentIdsOnSubResource(resource, r);
+
+            Predicate subPredicate = r.getQuery().getPredicate();
+
+            TreeNode<Resource> childResult = r.applyResult(subQueryResult, subPredicate).getResultTree();
+            childResult.setName(subResCategory);
+            childResult.setProperty("isCollection", "false");
+            node.addChild(childResult);
+          }
+
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Query the cluster controller for the associated resources.
+   */
+  private QueryResult queryForResources()
+      throws UnsupportedPropertyException, SystemException, NoSuchResourceException, NoSuchParentResourceException {
+    Set<Resource> resources = new HashSet<Resource>();
+
+    Resource.Type resourceType = getResourceDefinition().getType();
+
+    Predicate predicate = getPredicate();
+
+    Request request = createRequest();
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Executing resource query: " + request + " where " + predicate);
+    }
+
+    if (m_setQueryProperties.isEmpty() && m_mapQuerySubResources.isEmpty()) {
+      //Add sub resource properties for default case where no fields are specified.
+      m_mapQuerySubResources.putAll(ensureSubResources());
+    }
+
+    Iterable<Resource> iterResource = getClusterController().getResources(
+        resourceType, request, predicate);
+
+    for (Resource resource : iterResource) {
+      resources.add(resource);
+    }
+
+    return new QueryResult(resources, queryForSubResources(this, resources), this);
+  }
+
+  /**
+   * Query the cluster controller for the associated sub-resources.
+   */
+  private Map<Resource.Type, QueryResult> queryForSubResources(ResourceInstanceImpl resourceInstance, Set<Resource> resources)
+      throws UnsupportedPropertyException, SystemException, NoSuchResourceException, NoSuchParentResourceException {
+
+    Map<Resource.Type, QueryResult> subResourceMap = new HashMap<Resource.Type, QueryResult>();
+
+    Map<String, Predicate> predicateMap = new HashMap<String, Predicate>();
+
+    for (Resource resource : resources) {
+
+      for (Map.Entry<String, ResourceInstanceImpl> entry : resourceInstance.m_mapQuerySubResources.entrySet()) {
+        String subResCategory = entry.getKey();
+        ResourceInstanceImpl r = entry.getValue();
+
+        Predicate predicate = predicateMap.get(subResCategory);
+
+        setParentIdsOnSubResource(resource, r);
+
+        if (predicate == null) {
+          predicate = r.getQuery().getPredicate();
+        } else {
+          predicate = new OrPredicate(predicate, r.getQuery().getPredicate());
+        }
+        predicateMap.put(subResCategory, predicate);
+      }
+    }
+
+    for (Map.Entry<String, ResourceInstanceImpl> entry : resourceInstance.m_mapQuerySubResources.entrySet()) {
+      String subResCategory = entry.getKey();
+      ResourceInstanceImpl subResource = entry.getValue();
+
+
+      Predicate predicate = predicateMap.get(subResCategory);
+
+      Request   request   = subResource.createRequest();
+
+      Resource.Type resourceType = subResource.getResourceDefinition().getType();
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Executing resource query: " + request + " where " + predicate);
+      }
+
+      Map<String, ResourceInstanceImpl> mapSubResources = subResource.m_mapQuerySubResources;
+      if (subResource.m_setQueryProperties.isEmpty() && mapSubResources.isEmpty()) {
+        //Add sub resource properties for default case where no fields are specified.
+        mapSubResources.putAll(subResource.ensureSubResources());
+      }
+
+      Iterable<Resource> iterResource = getClusterController().getResources(
+          resourceType, request, predicate);
+
+      Set<Resource> subResources = new HashSet<Resource>();
+      for (Resource resource : iterResource) {
+        subResources.add(resource);
+      }
+
+      subResourceMap.put(resourceType, new QueryResult(subResources, queryForSubResources(subResource, subResources), subResource));
+    }
+
+    return subResourceMap;
+  }
+
+  private void addCollectionProperties(Resource.Type resourceType) {
+    Schema schema = getClusterController().getSchema(resourceType);
+    // add pk
+    String property = schema.getKeyPropertyId(resourceType);
+    addProperty(PropertyHelper.getPropertyCategory(property), PropertyHelper.getPropertyName(property), null);
+
+    for (Resource.Type type : getIds().keySet()) {
+      // add fk's
+      String keyPropertyId = schema.getKeyPropertyId(type);
+      //todo: property id can be null in some cases such as host_component queries which obtain
+      //todo: component sub-resources.  Component will not have host fk.
+      //todo: refactor so that null check is not required.
+      if (keyPropertyId != null) {
+        addProperty(PropertyHelper.getPropertyCategory(keyPropertyId), PropertyHelper.getPropertyName(keyPropertyId), null);
+      }
+    }
+  }
+
+  private void addAllProperties(TemporalInfo temporalInfo) {
+    allProperties = true;
+    if (temporalInfo != null) {
+      m_mapCategoryTemporalInfo.put(null, temporalInfo);
+    }
+
+    for (Map.Entry<String, ResourceInstanceImpl> entry : ensureSubResources().entrySet()) {
+      String name = entry.getKey();
+      if (! m_mapQuerySubResources.containsKey(name)) {
+        m_mapQuerySubResources.put(name, entry.getValue());
+      }
+    }
+  }
+
+  private boolean addPropertyToSubResource(String path, String property, TemporalInfo temporalInfo) {
+    // cases:
+    // - path is null, property is path (all sub-resource props will have a path)
+    // - path is single token and prop in non null
+    //      (path only will presented as above case with property only)
+    // - path is multi level and prop is non null
+
+    boolean resourceAdded = false;
+    if (path == null) {
+      path = property;
+      property = null;
+    }
+
+    int i = path.indexOf("/");
+    String p = i == -1 ? path : path.substring(0, i);
+
+    ResourceInstanceImpl subResource = ensureSubResources().get(p);
+    if (subResource != null) {
+      m_mapQuerySubResources.put(p, subResource);
+      //todo: handle case of trailing '/' (for example fields=subResource/)
+
+      if (property != null || !path.equals(p)) {
+        //only add if a sub property is set or if a sub category is specified
+        subResource.getQuery().addProperty(i == -1 ? null : path.substring(i + 1), property, temporalInfo);
+      }
+      resourceAdded = true;
+    }
+    return resourceAdded;
+  }
+
+  private Predicate createInternalPredicate(ResourceInstance resource) {
+    Resource.Type resourceType = resource.getResourceDefinition().getType();
+    Map<Resource.Type, String> mapResourceIds = resource.getIds();
+    Schema schema = getClusterController().getSchema(resourceType);
+
+    Set<Predicate> setPredicates = new HashSet<Predicate>();
+    for (Map.Entry<Resource.Type, String> entry : mapResourceIds.entrySet()) {
+      if (entry.getValue() != null) {
+        String keyPropertyId = schema.getKeyPropertyId(entry.getKey());
+        if (keyPropertyId != null) {
+          setPredicates.add(new EqualsPredicate<String>(keyPropertyId, entry.getValue()));
+        }
+      }
+    }
+
+    if (setPredicates.size() == 1) {
+      return setPredicates.iterator().next();
+    } else if (setPredicates.size() > 1) {
+      return new AndPredicate(setPredicates.toArray(new Predicate[setPredicates.size()]));
+    } else {
+      return null;
+    }
+  }
+
+  private Request createRequest() {
+    Set<String> setProperties = new HashSet<String>();
+
+    Map<String, TemporalInfo> mapTemporalInfo    = new HashMap<String, TemporalInfo>();
+    TemporalInfo              globalTemporalInfo = m_mapCategoryTemporalInfo.get(null);
+
+    for (String group : m_setQueryProperties) {
+      TemporalInfo temporalInfo = m_mapCategoryTemporalInfo.get(group);
+      if (temporalInfo != null) {
+        mapTemporalInfo.put(group, temporalInfo);
+      } else if (globalTemporalInfo != null) {
+        mapTemporalInfo.put(group, globalTemporalInfo);
+      }
+      setProperties.add(group);
+    }
+
+    return PropertyHelper.getReadRequest(allProperties ? Collections.<String>emptySet() : setProperties, mapTemporalInfo);
+  }
+
+  private void setParentIdsOnSubResource(Resource resource, ResourceInstance r) {
+    Map<Resource.Type, String> mapParentIds = getIds();
+    Map<Resource.Type, String> mapResourceIds = new HashMap<Resource.Type, String>(mapParentIds.size());
+    for (Map.Entry<Resource.Type, String> resourceIdEntry : mapParentIds.entrySet()) {
+      Resource.Type type = resourceIdEntry.getKey();
+      String value = resourceIdEntry.getValue();
+
+      if (value == null) {
+        Object o = resource.getPropertyValue(getClusterController().getSchema(type).getKeyPropertyId(type));
+        value = o == null ? null : o.toString();
+      }
+      if (value != null) {
+        mapResourceIds.put(type, value);
+      }
+    }
+    String resourceKeyProp = getClusterController().getSchema(resource.getType()).
+        getKeyPropertyId(resource.getType());
+    //todo: shouldn't use toString here
+    mapResourceIds.put(resource.getType(), resource.getPropertyValue(resourceKeyProp).toString());
+    r.setIds(mapResourceIds);
+  }
+
+  protected Result createResult() {
+    return new ResultImpl(true);
+  }
+
+
+  // ----- inner classes -----------------------------------------------------
+
+  private static class QueryResult {
+    private  final ResourceInstanceImpl resourceInstance;
+    private final Set<Resource> resources;
+    private final Map<Resource.Type, QueryResult> subResourceMap;
+
+    private QueryResult(Set<Resource> resources,
+                        Map<Resource.Type, QueryResult> subResourceMap,
+                        ResourceInstanceImpl resourceInstance) {
+      this.resources        = resources;
+      this.subResourceMap   = subResourceMap;
+      this.resourceInstance = resourceInstance;
+    }
+
+    public ResourceInstanceImpl getResourceInstance() {
+      return resourceInstance;
+    }
+
+    public Set<Resource> getResources() {
+      return resources;
+    }
+
+    public Map<Resource.Type, QueryResult> getSubResources() {
+      return subResourceMap;
+    }
+  }
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/AlwaysPredicate.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/AlwaysPredicate.java?rev=1489093&r1=1489092&r2=1489093&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/AlwaysPredicate.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/AlwaysPredicate.java Mon Jun  3 18:28:04 2013
@@ -43,4 +43,12 @@ public class AlwaysPredicate implements 
   public void accept(PredicateVisitor visitor) {
     visitor.acceptAlwaysPredicate(this);
   }
+
+
+  // ----- Object overrides --------------------------------------------------
+
+  @Override
+  public String toString() {
+    return "TRUE";
+  }
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/ArrayPredicate.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/ArrayPredicate.java?rev=1489093&r1=1489092&r2=1489093&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/ArrayPredicate.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/ArrayPredicate.java Mon Jun  3 18:28:04 2013
@@ -87,4 +87,28 @@ public abstract class ArrayPredicate imp
   }
 
   public abstract String getOperator();
+
+
+  // ----- Object overrides --------------------------------------------------
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+
+    for (Predicate predicate : predicates) {
+
+      boolean arrayPredicate = predicate instanceof ArrayPredicate;
+
+      if (sb.length() > 0) {
+        sb.append(" ").append(getOperator()).append(" ");
+      }
+
+      if (arrayPredicate) {
+        sb.append("(").append(predicate).append(")");
+      } else {
+        sb.append(predicate);
+      }
+    }
+    return sb.toString();
+  }
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/CategoryIsEmptyPredicate.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/CategoryIsEmptyPredicate.java?rev=1489093&r1=1489092&r2=1489093&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/CategoryIsEmptyPredicate.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/CategoryIsEmptyPredicate.java Mon Jun  3 18:28:04 2013
@@ -46,4 +46,11 @@ public class CategoryIsEmptyPredicate ex
     Map<String, Object> properties = resource.getPropertiesMap().get(propertyId);
     return properties == null ? true : properties.isEmpty();
   }
+
+  // ----- Object overrides --------------------------------------------------
+
+  @Override
+  public String toString() {
+    return "isEmpty(" + getPropertyId() + ")";
+  }
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/ComparisonPredicate.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/ComparisonPredicate.java?rev=1489093&r1=1489092&r2=1489093&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/ComparisonPredicate.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/ComparisonPredicate.java Mon Jun  3 18:28:04 2013
@@ -105,4 +105,11 @@ public abstract class ComparisonPredicat
   }
 
   public abstract String getOperator();
+
+  // ----- Object overrides --------------------------------------------------
+
+  @Override
+  public String toString() {
+    return getPropertyId() + getOperator() + getValue();
+  }
 }

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/UnaryPredicate.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/UnaryPredicate.java?rev=1489093&r1=1489092&r2=1489093&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/UnaryPredicate.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/UnaryPredicate.java Mon Jun  3 18:28:04 2013
@@ -63,4 +63,12 @@ public abstract class UnaryPredicate imp
   }
 
   public abstract String getOperator();
+
+
+  // ----- Object overrides --------------------------------------------------
+
+  @Override
+  public String toString() {
+    return getOperator() + "(" + getPredicate() + ")";
+  }
 }

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/TestSuite.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/TestSuite.java?rev=1489093&r1=1489092&r2=1489093&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/TestSuite.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/TestSuite.java Mon Jun  3 18:28:04 2013
@@ -26,7 +26,6 @@ import org.apache.ambari.server.api.hand
 import org.apache.ambari.server.api.predicate.QueryLexerTest;
 import org.apache.ambari.server.api.predicate.QueryParserTest;
 import org.apache.ambari.server.api.predicate.operators.*;
-import org.apache.ambari.server.api.query.QueryImplTest;
 import org.apache.ambari.server.api.resources.ResourceInstanceImplTest;
 import org.apache.ambari.server.api.services.*;
 import org.apache.ambari.server.api.services.parsers.BodyParseExceptionTest;
@@ -37,7 +36,7 @@ import org.junit.runners.Suite;
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({ClusterServiceTest.class, HostServiceTest.class, ServiceServiceTest.class,
-    ComponentServiceTest.class, HostComponentServiceTest.class, ReadHandlerTest.class, QueryImplTest.class,
+    ComponentServiceTest.class, HostComponentServiceTest.class, ReadHandlerTest.class,
     JsonRequestBodyParserTest.class, CreateHandlerTest.class, UpdateHandlerTest.class, DeleteHandlerTest.class,
     PersistenceManagerImplTest.class, GetRequestTest.class, PutRequestTest.class, PostRequestTest.class,
     DeleteRequestTest.class, QueryPostRequestTest.class, JsonSerializerTest.class, QueryCreateHandlerTest.class,

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ResourceInstanceImplTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ResourceInstanceImplTest.java?rev=1489093&r1=1489092&r2=1489093&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ResourceInstanceImplTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ResourceInstanceImplTest.java Mon Jun  3 18:28:04 2013
@@ -20,11 +20,20 @@
 package org.apache.ambari.server.api.resources;
 
 
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.util.TreeNode;
+import org.apache.ambari.server.controller.internal.ClusterControllerImpl;
+import org.apache.ambari.server.controller.internal.ClusterControllerImplTest;
+import org.apache.ambari.server.controller.spi.ClusterController;
+import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
@@ -37,6 +46,7 @@ import static org.junit.Assert.assertTru
  * ResourceInstanceImpl unit tests.
  */
 public class ResourceInstanceImplTest {
+
   @Test
   public void testIsCollection__True() {
     ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
@@ -52,7 +62,7 @@ public class ResourceInstanceImplTest {
     replay(resourceDefinition);
 
     //test
-    ResourceInstance instance = new ResourceInstanceImpl(mapIds, resourceDefinition, null);
+    ResourceInstance instance = new ResourceInstanceImpl(mapIds, resourceDefinition);
     assertTrue(instance.isCollectionResource());
 
     verify(resourceDefinition);
@@ -73,9 +83,423 @@ public class ResourceInstanceImplTest {
     replay(resourceDefinition);
 
     //test
-    ResourceInstance instance = new ResourceInstanceImpl(mapIds, resourceDefinition, null);
+    ResourceInstance instance = new ResourceInstanceImpl(mapIds, resourceDefinition);
     assertFalse(instance.isCollectionResource());
 
     verify(resourceDefinition);
   }
+
+  @Test
+  public void testExecute__Cluster_instance_noSpecifiedProps() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, "cluster");
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Cluster).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+    setChildren.add(new SubResourceDefinition(Resource.Type.Host));
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(1, tree.getChildren().size());
+    TreeNode<Resource> clusterNode = tree.getChild("Cluster:1");
+    Assert.assertEquals("Cluster:1", clusterNode.getName());
+    Assert.assertEquals(Resource.Type.Cluster, clusterNode.getObject().getType());
+    Assert.assertEquals(1, clusterNode.getChildren().size());
+    TreeNode<Resource> hostNode = clusterNode.getChild("hosts");
+    Assert.assertEquals(4, hostNode.getChildren().size());
+  }
+
+  @Test
+ public void testExecute__Host_collection_noSpecifiedProps() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Host).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(4, tree.getChildren().size());
+    TreeNode<Resource> hostNode = tree.getChild("Host:1");
+    Assert.assertEquals("Host:1", hostNode.getName());
+    Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
+
+    hostNode = tree.getChild("Host:2");
+    Assert.assertEquals("Host:2", hostNode.getName());
+    Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
+
+    hostNode = tree.getChild("Host:3");
+    Assert.assertEquals("Host:3", hostNode.getName());
+    Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
+
+    hostNode = tree.getChild("Host:4");
+    Assert.assertEquals("Host:4", hostNode.getName());
+    Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
+  }
+
+  @Test
+  public void testExecute__collection_nullInternalPredicate_nullUserPredicate() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Cluster).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+    setChildren.add(new SubResourceDefinition(Resource.Type.Host));
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(1, tree.getChildren().size());
+    TreeNode<Resource> clusterNode = tree.getChild("Cluster:1");
+    Assert.assertEquals("Cluster:1", clusterNode.getName());
+    Assert.assertEquals(Resource.Type.Cluster, clusterNode.getObject().getType());
+    Assert.assertEquals(1, clusterNode.getChildren().size());
+    TreeNode<Resource> hostNode = clusterNode.getChild("hosts");
+    Assert.assertEquals(4, hostNode.getChildren().size());
+  }
+
+  @Test
+  public void testExecute__collection_nullInternalPredicate_nonNullUserPredicate() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, "cluster");
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Host).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    PredicateBuilder pb = new PredicateBuilder();
+    Predicate predicate = pb.property("Hosts/host_name").equals("host:2").toPredicate();
+
+    instance.setUserPredicate(predicate);
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(1, tree.getChildren().size());
+    TreeNode<Resource> hostNode = tree.getChild("Host:1");
+    Assert.assertEquals("Host:1", hostNode.getName());
+    Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
+    Assert.assertEquals("host:2", hostNode.getObject().getPropertyValue("Hosts/host_name"));
+  }
+
+  @Test
+  public void testExecute__collection_nonNullInternalPredicate_nonNullUserPredicate() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Host).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    PredicateBuilder pb = new PredicateBuilder();
+    Predicate predicate = pb.property("Hosts/host_name").equals("host:2").toPredicate();
+
+    instance.setUserPredicate(predicate);
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(1, tree.getChildren().size());
+    TreeNode<Resource> hostNode = tree.getChild("Host:1");
+    Assert.assertEquals("Host:1", hostNode.getName());
+    Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
+    Assert.assertEquals("host:2", hostNode.getObject().getPropertyValue("Hosts/host_name"));  }
+
+  @Test
+  public void testAddProperty__localProperty() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Host).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    instance.addLocalProperty("c1/p1");
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(4, tree.getChildren().size());
+    TreeNode<Resource> hostNode = tree.getChild("Host:1");
+    Assert.assertEquals("Host:1", hostNode.getName());
+    Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
+    Assert.assertNotNull(hostNode.getObject().getPropertyValue("c1/p1"));
+
+    hostNode = tree.getChild("Host:2");
+    Assert.assertEquals("Host:2", hostNode.getName());
+    Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
+    Assert.assertNotNull(hostNode.getObject().getPropertyValue("c1/p1"));
+
+    hostNode = tree.getChild("Host:3");
+    Assert.assertEquals("Host:3", hostNode.getName());
+    Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
+    Assert.assertNotNull(hostNode.getObject().getPropertyValue("c1/p1"));
+
+    hostNode = tree.getChild("Host:4");
+    Assert.assertEquals("Host:4", hostNode.getName());
+    Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
+    Assert.assertNotNull(hostNode.getObject().getPropertyValue("c1/p1"));
+  }
+
+  @Test
+  public void testAddProperty__allProperties() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, "cluster");
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Cluster).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+    setChildren.add(new SubResourceDefinition(Resource.Type.Host));
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(1, tree.getChildren().size());
+    TreeNode<Resource> clusterNode = tree.getChild("Cluster:1");
+    Assert.assertEquals("Cluster:1", clusterNode.getName());
+    Assert.assertEquals(Resource.Type.Cluster, clusterNode.getObject().getType());
+    Assert.assertEquals(1, clusterNode.getChildren().size());
+    TreeNode<Resource> hostNode = clusterNode.getChild("hosts");
+    Assert.assertEquals(4, hostNode.getChildren().size());
+  }
+
+  @Test
+  public void testAddProperty__allCategoryProperties() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, "cluster");
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Cluster).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+    setChildren.add(new SubResourceDefinition(Resource.Type.Host));
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(1, tree.getChildren().size());
+    TreeNode<Resource> clusterNode = tree.getChild("Cluster:1");
+    Assert.assertEquals("Cluster:1", clusterNode.getName());
+    Assert.assertEquals(Resource.Type.Cluster, clusterNode.getObject().getType());
+    Assert.assertEquals(1, clusterNode.getChildren().size());
+    TreeNode<Resource> hostNode = clusterNode.getChild("hosts");
+    Assert.assertEquals(4, hostNode.getChildren().size());
+  }
+
+  @Test
+  public void testAddProperty__localCategory_asPropertyName() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, "cluster");
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Cluster).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+    setChildren.add(new SubResourceDefinition(Resource.Type.Host));
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(1, tree.getChildren().size());
+    TreeNode<Resource> clusterNode = tree.getChild("Cluster:1");
+    Assert.assertEquals("Cluster:1", clusterNode.getName());
+    Assert.assertEquals(Resource.Type.Cluster, clusterNode.getObject().getType());
+    Assert.assertEquals(1, clusterNode.getChildren().size());
+    TreeNode<Resource> hostNode = clusterNode.getChild("hosts");
+    Assert.assertEquals(4, hostNode.getChildren().size());
+  }
+
+  @Test
+  public void testAddProperty__localSubCategory() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, "cluster");
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Cluster).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+    setChildren.add(new SubResourceDefinition(Resource.Type.Host));
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(1, tree.getChildren().size());
+    TreeNode<Resource> clusterNode = tree.getChild("Cluster:1");
+    Assert.assertEquals("Cluster:1", clusterNode.getName());
+    Assert.assertEquals(Resource.Type.Cluster, clusterNode.getObject().getType());
+    Assert.assertEquals(1, clusterNode.getChildren().size());
+    TreeNode<Resource> hostNode = clusterNode.getChild("hosts");
+    Assert.assertEquals(4, hostNode.getChildren().size());
+  }
+
+  @Test
+  public void testAddProperty__subProperty() throws Exception {
+    ResourceDefinition resourceDefinition = createNiceMock(ResourceDefinition.class);
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, "cluster");
+
+    // expectations
+    expect(resourceDefinition.getType()).andReturn(Resource.Type.Cluster).anyTimes();
+    Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
+    setChildren.add(new SubResourceDefinition(Resource.Type.Host));
+
+    expect(resourceDefinition.getSubResourceDefinitions()).andReturn(setChildren).anyTimes();
+
+    replay(resourceDefinition);
+
+    //test
+    ResourceInstanceImpl instance = new TestQuery(mapIds, resourceDefinition);
+
+    Result result = instance.execute();
+
+    verify(resourceDefinition);
+
+    TreeNode<Resource> tree = result.getResultTree();
+
+    Assert.assertEquals(1, tree.getChildren().size());
+    TreeNode<Resource> clusterNode = tree.getChild("Cluster:1");
+    Assert.assertEquals("Cluster:1", clusterNode.getName());
+    Assert.assertEquals(Resource.Type.Cluster, clusterNode.getObject().getType());
+    Assert.assertEquals(1, clusterNode.getChildren().size());
+    TreeNode<Resource> hostNode = clusterNode.getChild("hosts");
+    Assert.assertEquals(4, hostNode.getChildren().size());
+  }
+
+  private class TestQuery extends ResourceInstanceImpl {
+
+    private ClusterController m_controller;
+
+    public TestQuery(Map<Resource.Type, String> mapIds, ResourceDefinition resourceDefinition) {
+      super(mapIds, resourceDefinition);
+
+      ClusterControllerImplTest.TestProviderModule providerModule = new ClusterControllerImplTest.TestProviderModule();
+      m_controller = new ClusterControllerImpl(providerModule);
+
+    }
+
+    @Override
+    protected ClusterController getClusterController() {
+      return m_controller;
+    }
+  }
 }
+

Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterControllerImplTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterControllerImplTest.java?rev=1489093&r1=1489092&r2=1489093&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterControllerImplTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterControllerImplTest.java Mon Jun  3 18:28:04 2013
@@ -85,13 +85,16 @@ public class ClusterControllerImplTest {
   private static final Map<Resource.Type, String> keyPropertyIds = new HashMap<Resource.Type, String>();
 
   static {
-    keyPropertyIds.put(Resource.Type.Cluster, PropertyHelper.getPropertyId("c1", "p1"));
-    keyPropertyIds.put(Resource.Type.Host, PropertyHelper.getPropertyId("c1", "p2"));
+    keyPropertyIds.put(Resource.Type.Cluster, PropertyHelper.getPropertyId("Hosts", "cluster_name"));
+    keyPropertyIds.put(Resource.Type.Host, PropertyHelper.getPropertyId("Hosts", "host_name"));
   }
 
   private static final Set<String> resourceProviderProperties = new HashSet<String>();
 
   static {
+    resourceProviderProperties.add(PropertyHelper.getPropertyId("Hosts", "cluster_name"));
+    resourceProviderProperties.add(PropertyHelper.getPropertyId("Hosts", "host_name"));
+    resourceProviderProperties.add(PropertyHelper.getPropertyId("c1", "p1"));
     resourceProviderProperties.add(PropertyHelper.getPropertyId("c1", "p1"));
     resourceProviderProperties.add(PropertyHelper.getPropertyId("c1", "p2"));
     resourceProviderProperties.add(PropertyHelper.getPropertyId("c1", "p3"));
@@ -431,15 +434,12 @@ public class ClusterControllerImplTest {
 //    }
 //  }
 
-  private static class TestProviderModule implements ProviderModule {
+  public static class TestProviderModule implements ProviderModule {
     private Map<Resource.Type, ResourceProvider> providers = new HashMap<Resource.Type, ResourceProvider>();
 
-    private TestProviderModule() {
-      providers.put(Resource.Type.Cluster, new TestResourceProvider());
-      providers.put(Resource.Type.Service, new TestResourceProvider());
-      providers.put(Resource.Type.Component, new TestResourceProvider());
+    public TestProviderModule() {
+      providers.put(Resource.Type.Cluster, new TestClusterResourceProvider());
       providers.put(Resource.Type.Host, new TestResourceProvider());
-      providers.put(Resource.Type.HostComponent, new TestResourceProvider());
     }
 
     @Override
@@ -453,6 +453,42 @@ public class ClusterControllerImplTest {
     }
   }
 
+  private static class TestClusterResourceProvider implements ResourceProvider {
+    @Override
+    public RequestStatus createResources(Request request) throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException {
+      throw new UnsupportedOperationException(); // not needed for testing
+    }
+
+    @Override
+    public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+      ResourceImpl resource = new ResourceImpl(Resource.Type.Cluster);
+
+      resource.setProperty(PropertyHelper.getPropertyId("Clusters", "cluster_name"), "cluster");
+
+      return Collections.<Resource>singleton(resource);
+    }
+
+    @Override
+    public RequestStatus updateResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+      throw new UnsupportedOperationException(); // not needed for testing
+    }
+
+    @Override
+    public RequestStatus deleteResources(Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+      throw new UnsupportedOperationException(); // not needed for testing
+    }
+
+    @Override
+    public Map<Resource.Type, String> getKeyPropertyIds() {
+      return Collections.singletonMap(Resource.Type.Cluster, PropertyHelper.getPropertyId("Clusters", "cluster_name"));
+    }
+
+    @Override
+    public Set<String> checkPropertyIds(Set<String> propertyIds) {
+      return Collections.emptySet();
+    }
+  }
+
   private static class TestResourceProvider implements ResourceProvider {
     private Action lastAction = null;
     private Request lastRequest = null;
@@ -466,6 +502,9 @@ public class ClusterControllerImplTest {
       for (int cnt = 0; cnt < 4; ++ cnt) {
         ResourceImpl resource = new ResourceImpl(Resource.Type.Host);
 
+        resource.setProperty(PropertyHelper.getPropertyId("Hosts", "cluster_name"), "cluster");
+        resource.setProperty(PropertyHelper.getPropertyId("Hosts", "host_name"), "host:" + cnt);
+
         resource.setProperty(PropertyHelper.getPropertyId("c1", "p1"), cnt);
         resource.setProperty(PropertyHelper.getPropertyId("c1", "p2"), cnt % 2);
         resource.setProperty(PropertyHelper.getPropertyId("c1", "p3"), "foo");
@@ -532,7 +571,6 @@ public class ClusterControllerImplTest {
       Update,
       Delete
     }
-
   }
 
 }