You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ma...@apache.org on 2012/10/08 03:38:08 UTC

svn commit: r1395430 [4/13] - in /incubator/ambari/branches/AMBARI-666: ./ ambari-agent/src/main/puppet/manifestloader/ ambari-agent/src/main/puppet/modules/configgenerator/manifests/ ambari-agent/src/main/puppet/modules/hdp-hadoop/manifests/ ambari-ag...

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/BaseResourceDefinition.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/BaseResourceDefinition.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/BaseResourceDefinition.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/BaseResourceDefinition.java Mon Oct  8 01:37:59 2012
@@ -22,29 +22,58 @@ package org.apache.ambari.api.resource;
 import org.apache.ambari.api.controller.utilities.ClusterControllerHelper;
 import org.apache.ambari.api.query.Query;
 import org.apache.ambari.api.query.QueryImpl;
-import org.apache.ambari.api.controller.spi.ClusterController;
-import org.apache.ambari.api.controller.spi.Resource;
+import org.apache.ambari.api.services.Request;
+import org.apache.ambari.server.controller.spi.ClusterController;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Schema;
+import org.apache.ambari.api.util.TreeNode;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
- *
+ * Base resource definition.  Contains behavior common to all resource types.
  */
 public abstract class BaseResourceDefinition implements ResourceDefinition {
 
+  /**
+   * Resource type.  One of {@link Resource.Type}
+   */
   private Resource.Type m_type;
+
+  /**
+   * Value of the id property for the resource.
+   */
   private String m_id;
-  private Query m_query = new QueryImpl(this);
-  Map<Resource.Type, String> m_mapResourceIds = new HashMap<Resource.Type, String>();
 
+  /**
+   * Query associated with the resource definition.
+   */
+  private Query m_query;
+
+  /**
+   * Map of primary and foreign keys and values necessary to identify the resource.
+   */
+  private Map<Resource.Type, String> m_mapResourceIds = new HashMap<Resource.Type, String>();
+
+
+  /**
+   * Constructor.
+   *
+   * @param resourceType resource type
+   * @param id           value of primary key
+   */
   public BaseResourceDefinition(Resource.Type resourceType, String id) {
     m_type = resourceType;
-    m_id = id;
+    setId(id);
+    m_query = new QueryImpl(this);
+  }
 
-    if (id != null) {
-      setResourceId(resourceType, id);
-    }
+  @Override
+  public void setParentId(Resource.Type type, String value) {
+    setResourceId(type, value);
   }
 
   @Override
@@ -52,6 +81,11 @@ public abstract class BaseResourceDefini
     return m_id;
   }
 
+  void setId(String val) {
+    setResourceId(getType(), val);
+    m_id = val;
+  }
+
   @Override
   public Resource.Type getType() {
     return m_type;
@@ -64,10 +98,7 @@ public abstract class BaseResourceDefini
   }
 
   protected void setResourceId(Resource.Type resourceType, String val) {
-    //todo: hack for case where service id is null when getting a component from hostComponent
-    if (val != null) {
-      m_mapResourceIds.put(resourceType, val);
-    }
+    m_mapResourceIds.put(resourceType, val);
   }
 
   @Override
@@ -75,6 +106,19 @@ public abstract class BaseResourceDefini
     return m_mapResourceIds;
   }
 
+  ClusterController getClusterController() {
+    return ClusterControllerHelper.getClusterController();
+  }
+
+  @Override
+  public List<PostProcessor> getPostProcessors() {
+    List<PostProcessor> listProcessors = new ArrayList<PostProcessor>();
+    listProcessors.add(new BaseHrefPostProcessor());
+
+    return listProcessors;
+  }
+
+
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
@@ -85,9 +129,9 @@ public abstract class BaseResourceDefini
     if (m_id != null ? !m_id.equals(that.m_id) : that.m_id != null) return false;
     if (m_mapResourceIds != null ? !m_mapResourceIds.equals(that.m_mapResourceIds) : that.m_mapResourceIds != null)
       return false;
-    if (m_type != that.m_type) return false;
 
-    return true;
+    return m_type == that.m_type;
+
   }
 
   @Override
@@ -98,7 +142,29 @@ public abstract class BaseResourceDefini
     return result;
   }
 
-  ClusterController getClusterController() {
-    return ClusterControllerHelper.getClusterController();
+  class BaseHrefPostProcessor implements PostProcessor {
+    @Override
+    public void process(Request request, TreeNode<Resource> resultNode, String href) {
+      Resource r = resultNode.getObject();
+      TreeNode<Resource> parent = resultNode.getParent();
+
+      if (parent.getName() != null) {
+        String parentName = parent.getName();
+        Schema schema = getClusterController().getSchema(r.getType());
+        String id = r.getPropertyValue(schema.getKeyPropertyId(r.getType()));
+
+        int i = href.indexOf("?");
+        if (i != -1) {
+          href = href.substring(0, i);
+        }
+
+        if (!href.endsWith("/")) {
+          href = href + '/';
+        }
+        String isCollectionResource = parent.getProperty("isCollection");
+        href = "true".equals(isCollectionResource) ? href + id : href + parentName + '/' + id;
+      }
+      resultNode.setProperty("href", href);
+    }
   }
 }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ClusterResourceDefinition.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ClusterResourceDefinition.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ClusterResourceDefinition.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ClusterResourceDefinition.java Mon Oct  8 01:37:59 2012
@@ -18,21 +18,21 @@
 
 package org.apache.ambari.api.resource;
 
-import org.apache.ambari.api.services.formatters.ClusterInstanceFormatter;
-import org.apache.ambari.api.services.formatters.CollectionFormatter;
-import org.apache.ambari.api.services.formatters.ResultFormatter;
-import org.apache.ambari.api.controller.spi.PropertyId;
-import org.apache.ambari.api.controller.spi.Resource;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
+import org.apache.ambari.server.controller.spi.PropertyId;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.*;
 
 /**
- *
+ * Cluster resource definition.
  */
 public class ClusterResourceDefinition extends BaseResourceDefinition {
 
+  /**
+   * Constructor.
+   *
+   * @param id value of primary key
+   */
   public ClusterResourceDefinition(String id) {
     super(Resource.Type.Cluster, id);
 
@@ -53,32 +53,21 @@ public class ClusterResourceDefinition e
   }
 
   @Override
-  public Set<ResourceDefinition> getChildren() {
-    Set<ResourceDefinition> setChildren = new HashSet<ResourceDefinition>();
+  public Map<String, ResourceDefinition> getSubResources() {
+    Map<String, ResourceDefinition> mapChildren = new HashMap<String, ResourceDefinition>();
 
     ServiceResourceDefinition serviceResource = new ServiceResourceDefinition(null, getId());
     PropertyId serviceIdProperty = getClusterController().getSchema(
         Resource.Type.Service).getKeyPropertyId(Resource.Type.Service);
     serviceResource.getQuery().addProperty(serviceIdProperty);
-    setChildren.add(serviceResource);
+    mapChildren.put(serviceResource.getPluralName(), serviceResource);
 
     HostResourceDefinition hostResource = new HostResourceDefinition(null, getId());
     PropertyId hostIdProperty = getClusterController().getSchema(
         Resource.Type.Host).getKeyPropertyId(Resource.Type.Host);
     hostResource.getQuery().addProperty(hostIdProperty);
-    setChildren.add(hostResource);
-
-    return setChildren;
-  }
+    mapChildren.put(hostResource.getPluralName(), hostResource);
 
-  @Override
-  public Set<ResourceDefinition> getRelations() {
-    return Collections.emptySet();
-  }
-
-  @Override
-  public ResultFormatter getResultFormatter() {
-    //todo: instance formatter
-    return getId() == null ? new CollectionFormatter(this) : new ClusterInstanceFormatter(this);
+    return mapChildren;
   }
 }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ComponentResourceDefinition.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ComponentResourceDefinition.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ComponentResourceDefinition.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ComponentResourceDefinition.java Mon Oct  8 01:37:59 2012
@@ -16,36 +16,43 @@
  * limitations under the License.
  */
 
+
 package org.apache.ambari.api.resource;
 
-import org.apache.ambari.api.services.formatters.CollectionFormatter;
-import org.apache.ambari.api.services.formatters.ComponentInstanceFormatter;
-import org.apache.ambari.api.services.formatters.ResultFormatter;
-import org.apache.ambari.api.controller.spi.PropertyId;
-import org.apache.ambari.api.controller.spi.Resource;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
+import org.apache.ambari.api.controller.utilities.ClusterControllerHelper;
+import org.apache.ambari.api.services.Request;
+import org.apache.ambari.server.controller.spi.PropertyId;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Schema;
+import org.apache.ambari.api.util.TreeNode;
+
+import org.apache.ambari.api.services.ResultPostProcessor;
+
+import java.util.*;
 
 /**
- *
+ * Component resource definition.
  */
 public class ComponentResourceDefinition extends BaseResourceDefinition {
 
+  /**
+   * value of clusterId foreign key
+   */
   private String m_clusterId;
-  private String m_serviceId;
 
-  @Override
-  public String getPluralName() {
-    return "components";
-  }
+  /**
+   * value of serviceId foreign key
+   */
+  private String m_serviceId;
 
-  @Override
-  public String getSingularName() {
-    return "component";
-  }
 
+  /**
+   * Constructor.
+   *
+   * @param id        value of component id
+   * @param clusterId value of cluster id
+   * @param serviceId value of service id
+   */
   public ComponentResourceDefinition(String id, String clusterId, String serviceId) {
     super(Resource.Type.Component, id);
     m_clusterId = clusterId;
@@ -55,26 +62,71 @@ public class ComponentResourceDefinition
   }
 
   @Override
-  public Set<ResourceDefinition> getChildren() {
-    return Collections.emptySet();
+  public String getPluralName() {
+    return "components";
   }
 
   @Override
-  public Set<ResourceDefinition> getRelations() {
-    Set<ResourceDefinition> setResourceDefinitions = new HashSet<ResourceDefinition>();
+  public String getSingularName() {
+    return "component";
+  }
+
+
+  @Override
+  public Map<String, ResourceDefinition> getSubResources() {
+    Map<String, ResourceDefinition> mapChildren = new HashMap<String, ResourceDefinition>();
+
     // for host_component collection need host id property
     HostComponentResourceDefinition hostComponentResource = new HostComponentResourceDefinition(
         getId(), m_clusterId, null);
     PropertyId hostIdProperty = getClusterController().getSchema(
         Resource.Type.HostComponent).getKeyPropertyId(Resource.Type.Host);
     hostComponentResource.getQuery().addProperty(hostIdProperty);
-    setResourceDefinitions.add(hostComponentResource);
-    return setResourceDefinitions;
+    mapChildren.put(hostComponentResource.getPluralName(), hostComponentResource);
+    return mapChildren;
+
+  }
+
+  @Override
+  public List<PostProcessor> getPostProcessors() {
+    List<PostProcessor> listProcessors = super.getPostProcessors();
+    listProcessors.add(new ComponentHrefProcessor());
+
+    return listProcessors;
   }
 
   @Override
-  public ResultFormatter getResultFormatter() {
-    //todo: instance formatter
-    return getId() == null ? new CollectionFormatter(this) : new ComponentInstanceFormatter(this);
+  public void setParentId(Resource.Type type, String value) {
+    if (type == Resource.Type.HostComponent) {
+      setId(value);
+    } else {
+      super.setParentId(type, value);
+    }
+  }
+
+  /**
+   * Base resource processor which generates href's.  This is called by the {@link ResultPostProcessor} during post
+   * processing of a result.
+   */
+  private class ComponentHrefProcessor extends BaseHrefPostProcessor {
+    @Override
+    public void process(Request request, TreeNode<Resource> resultNode, String href) {
+      TreeNode<Resource> parent = resultNode.getParent();
+
+      if (parent.getParent() != null && parent.getParent().getObject().getType() == Resource.Type.HostComponent) {
+        Resource r = resultNode.getObject();
+        String clusterId = getResourceIds().get(Resource.Type.Cluster);
+        Schema schema = ClusterControllerHelper.getClusterController().getSchema(r.getType());
+        String serviceId = r.getPropertyValue(schema.getKeyPropertyId(Resource.Type.Service));
+        String componentId = r.getPropertyValue(schema.getKeyPropertyId(r.getType()));
+
+        href = href.substring(0, href.indexOf(clusterId) + clusterId.length() + 1) +
+            "services/" + serviceId + "/components/" + componentId;
+
+        resultNode.setProperty("href", href);
+      } else {
+        super.process(request, resultNode, href);
+      }
+    }
   }
 }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/HostComponentResourceDefinition.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/HostComponentResourceDefinition.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/HostComponentResourceDefinition.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/HostComponentResourceDefinition.java Mon Oct  8 01:37:59 2012
@@ -18,34 +18,42 @@
 
 package org.apache.ambari.api.resource;
 
-import org.apache.ambari.api.services.formatters.CollectionFormatter;
-import org.apache.ambari.api.services.formatters.HostComponentInstanceFormatter;
-import org.apache.ambari.api.services.formatters.ResultFormatter;
-import org.apache.ambari.api.controller.spi.PropertyId;
-import org.apache.ambari.api.controller.spi.Resource;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
+import org.apache.ambari.api.controller.internal.ClusterControllerImpl;
+import org.apache.ambari.api.controller.internal.PropertyIdImpl;
+import org.apache.ambari.api.controller.utilities.ClusterControllerHelper;
+import org.apache.ambari.api.services.Request;
+import org.apache.ambari.server.controller.spi.PropertyId;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Schema;
+import org.apache.ambari.api.util.TreeNode;
+
+import org.apache.ambari.api.services.ResultPostProcessor;
+
+import java.util.*;
 
 /**
- *
+ * Host_Component resource definition.
  */
 public class HostComponentResourceDefinition extends BaseResourceDefinition {
 
+  /**
+   * value of cluster id foreign key
+   */
   private String m_clusterId;
-  private String m_hostId;
 
-  @Override
-  public String getPluralName() {
-    return "host_components";
-  }
+  /**
+   * value of host id foreign key
+   */
+  private String m_hostId;
 
-  @Override
-  public String getSingularName() {
-    return "host_component";
-  }
 
+  /**
+   * Constructor.
+   *
+   * @param id        value of host_component id
+   * @param clusterId value of cluster id foreign key
+   * @param hostId    value of host id foreign key
+   */
   public HostComponentResourceDefinition(String id, String clusterId, String hostId) {
     super(Resource.Type.HostComponent, id);
     m_clusterId = clusterId;
@@ -55,30 +63,90 @@ public class HostComponentResourceDefini
   }
 
   @Override
-  public Set<ResourceDefinition> getChildren() {
-    return Collections.emptySet();
+  public String getPluralName() {
+    return "host_components";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "host_component";
   }
 
+
   @Override
-  public Set<ResourceDefinition> getRelations() {
-    Set<ResourceDefinition> setRelated = new HashSet<ResourceDefinition>();
-    // already have all information necessary for host
-    //todo: adding host here causes a cycle
-    //setRelated.add(new HostResourceDefinition(m_hostId, m_clusterId));
-    // for component need service id property
+  public Map<String, ResourceDefinition> getSubResources() {
+    Map<String, ResourceDefinition> mapChildren = new HashMap<String, ResourceDefinition>();
+
     ComponentResourceDefinition componentResource = new ComponentResourceDefinition(
         getId(), m_clusterId, null);
     PropertyId serviceIdProperty = getClusterController().getSchema(
         Resource.Type.Component).getKeyPropertyId(Resource.Type.Service);
     componentResource.getQuery().addProperty(serviceIdProperty);
-    setRelated.add(componentResource);
+    mapChildren.put(componentResource.getSingularName(), componentResource);
 
-    return setRelated;
+    return mapChildren;
   }
 
   @Override
-  public ResultFormatter getResultFormatter() {
-    //todo: instance formatter
-    return getId() == null ? new CollectionFormatter(this) : new HostComponentInstanceFormatter(this);
+  public List<PostProcessor> getPostProcessors() {
+    List<PostProcessor> listProcessors = new ArrayList<PostProcessor>();
+    listProcessors.add(new HostComponentHrefProcessor());
+    listProcessors.add(new HostComponentHostProcessor());
+
+    return listProcessors;
+  }
+
+  @Override
+  public void setParentId(Resource.Type type, String value) {
+    if (type == Resource.Type.Component) {
+      setId(value);
+    } else {
+      super.setParentId(type, value);
+    }
+  }
+
+
+  /**
+   * Host_Component resource processor which is responsible for generating href's for host components.
+   * This is called by the {@link ResultPostProcessor} during post processing of a result.
+   */
+  private class HostComponentHrefProcessor extends BaseHrefPostProcessor {
+    @Override
+    public void process(Request request, TreeNode<Resource> resultNode, String href) {
+      TreeNode<Resource> parent = resultNode.getParent();
+
+      if (parent.getParent() != null && parent.getParent().getObject().getType() == Resource.Type.Component) {
+        Resource r = resultNode.getObject();
+        String clusterId = getResourceIds().get(Resource.Type.Cluster);
+        Schema schema = ClusterControllerHelper.getClusterController().getSchema(r.getType());
+        String host = r.getPropertyValue(schema.getKeyPropertyId(Resource.Type.Host));
+        String hostComponent = r.getPropertyValue(schema.getKeyPropertyId(r.getType()));
+
+        href = href.substring(0, href.indexOf(clusterId) + clusterId.length() + 1) +
+            "hosts/" + host + "/host_components/" + hostComponent;
+
+        resultNode.setProperty("href", href);
+      } else {
+        super.process(request, resultNode, href);
+      }
+
+    }
+  }
+
+  /**
+   * Host_Component resource processor which is responsible for generating a host section for host components.
+   * This is called by the {@link ResultPostProcessor} during post processing of a result.
+   */
+  private class HostComponentHostProcessor implements PostProcessor {
+    @Override
+    public void process(Request request, TreeNode<Resource> resultNode, String href) {
+      //todo: look at partial request fields to ensure that hosts should be returned
+      if (request.getResourceDefinition().getType() == getType()) {
+        // only add host if query host_resource was directly queried
+        String nodeHref = resultNode.getProperty("href");
+        resultNode.getObject().setProperty(new PropertyIdImpl("href", "host", false),
+            nodeHref.substring(0, nodeHref.indexOf("/host_components/")));
+      }
+    }
   }
 }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/HostResourceDefinition.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/HostResourceDefinition.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/HostResourceDefinition.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/HostResourceDefinition.java Mon Oct  8 01:37:59 2012
@@ -18,23 +18,33 @@
 
 package org.apache.ambari.api.resource;
 
-import org.apache.ambari.api.services.formatters.CollectionFormatter;
-import org.apache.ambari.api.services.formatters.HostInstanceFormatter;
-import org.apache.ambari.api.services.formatters.ResultFormatter;
-import org.apache.ambari.api.controller.spi.PropertyId;
-import org.apache.ambari.api.controller.spi.Resource;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
+import org.apache.ambari.server.controller.spi.PropertyId;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.*;
 
 /**
- *
+ * Host resource definition.
  */
 public class HostResourceDefinition extends BaseResourceDefinition {
 
+  /**
+   * value of cluster id foreign key
+   */
   private String m_clusterId;
 
+  /**
+   * Constructor.
+   *
+   * @param id        host id value
+   * @param clusterId cluster id value
+   */
+  public HostResourceDefinition(String id, String clusterId) {
+    super(Resource.Type.Host, id);
+    m_clusterId = clusterId;
+    setResourceId(Resource.Type.Cluster, m_clusterId);
+  }
+
   @Override
   public String getPluralName() {
     return "hosts";
@@ -45,33 +55,16 @@ public class HostResourceDefinition exte
     return "host";
   }
 
-  public HostResourceDefinition(String id, String clusterId) {
-    super(Resource.Type.Host, id);
-    m_clusterId = clusterId;
-    setResourceId(Resource.Type.Cluster, m_clusterId);
-  }
-
   @Override
-  public Set<ResourceDefinition> getChildren() {
-    Set<ResourceDefinition> setChildren = new HashSet<ResourceDefinition>();
+  public Map<String, ResourceDefinition> getSubResources() {
+    Map<String, ResourceDefinition> mapChildren = new HashMap<String, ResourceDefinition>();
 
     HostComponentResourceDefinition hostComponentResource = new HostComponentResourceDefinition(
         null, m_clusterId, getId());
     PropertyId hostComponentIdProperty = getClusterController().getSchema(
         Resource.Type.HostComponent).getKeyPropertyId(Resource.Type.HostComponent);
     hostComponentResource.getQuery().addProperty(hostComponentIdProperty);
-    setChildren.add(hostComponentResource);
-    return setChildren;
-  }
-
-  @Override
-  public Set<ResourceDefinition> getRelations() {
-    return Collections.emptySet();
-  }
-
-  @Override
-  public ResultFormatter getResultFormatter() {
-    //todo: instance formatter
-    return getId() == null ? new CollectionFormatter(this) : new HostInstanceFormatter(this);
+    mapChildren.put(hostComponentResource.getPluralName(), hostComponentResource);
+    return mapChildren;
   }
 }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ResourceDefinition.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ResourceDefinition.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ResourceDefinition.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ResourceDefinition.java Mon Oct  8 01:37:59 2012
@@ -19,31 +19,92 @@
 package org.apache.ambari.api.resource;
 
 import org.apache.ambari.api.query.Query;
-import org.apache.ambari.api.services.formatters.ResultFormatter;
-import org.apache.ambari.api.controller.spi.Resource;
+import org.apache.ambari.api.services.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.api.util.TreeNode;
 
+import org.apache.ambari.api.services.ResultPostProcessor;
+
+import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
- *
+ * Resource Definition.
+ * Provides information specific to a specific resource type.
  */
 public interface ResourceDefinition {
+  /**
+   * Obtain the plural name of the resource.
+   *
+   * @return the plural name of the resource
+   */
   public String getPluralName();
 
+  /**
+   * Obtain the singular name of the resource.
+   *
+   * @return the singular name of the resource
+   */
   public String getSingularName();
 
+  /**
+   * Obtain the value of the primary id of the resource.
+   *
+   * @return the value of the primary id of the resource
+   */
   public String getId();
 
-  public Set<ResourceDefinition> getChildren();
-
-  public Set<ResourceDefinition> getRelations();
+  /**
+   * Obtain the type of resource.  Is one of {@link Resource.Type}.
+   *
+   * @return the type of resource
+   */
+  public Resource.Type getType();
 
+  /**
+   * Set the value of the parent foreign key.
+   *
+   * @param type  resource type of the parent
+   * @param value vale of the parent id
+   */
+  public void setParentId(Resource.Type type, String value);
+
+  /**
+   * Obtain the primary and foreign key properties for the resource.
+   *
+   * @return map of primary and foreign key values keyed by resource type
+   */
   public Map<Resource.Type, String> getResourceIds();
 
-  public ResultFormatter getResultFormatter();
-
-  public Resource.Type getType();
-
+  /**
+   * Obtain sub-resources of this resource.  A sub-resource is a resource that is contained in
+   * another parent resource.
+   *
+   * @return map of sub resource definitions keyed by resource name
+   */
+  public Map<String, ResourceDefinition> getSubResources();
+
+  /**
+   * Return the query associated with the resource.
+   * Each resource has one query.
+   *
+   * @return the associated query
+   */
   public Query getQuery();
+
+  /**
+   * Obtain any resource post processors.  A resource processor is used to provide resource specific processing of
+   * results and is called by the {@link ResultPostProcessor} while post processing a result.
+   *
+   * @return list of resource specific result processors
+   */
+  public List<PostProcessor> getPostProcessors();
+
+  /**
+   * Resource specific result processor.
+   * Used to provide resource specific processing of a result.
+   */
+  public interface PostProcessor {
+    public void process(Request request, TreeNode<Resource> resultNode, String href);
+  }
 }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ServiceResourceDefinition.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ServiceResourceDefinition.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ServiceResourceDefinition.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/resource/ServiceResourceDefinition.java Mon Oct  8 01:37:59 2012
@@ -18,23 +18,33 @@
 
 package org.apache.ambari.api.resource;
 
-import org.apache.ambari.api.services.formatters.CollectionFormatter;
-import org.apache.ambari.api.services.formatters.ResultFormatter;
-import org.apache.ambari.api.services.formatters.ServiceInstanceFormatter;
-import org.apache.ambari.api.controller.spi.PropertyId;
-import org.apache.ambari.api.controller.spi.Resource;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
+import org.apache.ambari.server.controller.spi.PropertyId;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.*;
 
 /**
- *
+ * Service resource definition.
  */
 public class ServiceResourceDefinition extends BaseResourceDefinition {
 
+  /**
+   * value of cluster id foreign key
+   */
   private String m_clusterId;
 
+  /**
+   * Constructor.
+   *
+   * @param id        service id value
+   * @param clusterId cluster id value
+   */
+  public ServiceResourceDefinition(String id, String clusterId) {
+    super(Resource.Type.Service, id);
+    m_clusterId = clusterId;
+    setResourceId(Resource.Type.Cluster, m_clusterId);
+  }
+
   @Override
   public String getPluralName() {
     return "services";
@@ -45,33 +55,16 @@ public class ServiceResourceDefinition e
     return "service";
   }
 
-  public ServiceResourceDefinition(String id, String clusterId) {
-    super(Resource.Type.Service, id);
-    m_clusterId = clusterId;
-    setResourceId(Resource.Type.Cluster, m_clusterId);
-  }
-
   @Override
-  public Set<ResourceDefinition> getChildren() {
-    Set<ResourceDefinition> setChildren = new HashSet<ResourceDefinition>();
+  public Map<String, ResourceDefinition> getSubResources() {
+    Map<String, ResourceDefinition> mapChildren = new HashMap<String, ResourceDefinition>();
     // for component collection need id property
     ComponentResourceDefinition componentResourceDefinition =
         new ComponentResourceDefinition(null, m_clusterId, getId());
     PropertyId componentIdProperty = getClusterController().getSchema(
         Resource.Type.Component).getKeyPropertyId(Resource.Type.Component);
     componentResourceDefinition.getQuery().addProperty(componentIdProperty);
-    setChildren.add(componentResourceDefinition);
-    return setChildren;
-  }
-
-  @Override
-  public Set<ResourceDefinition> getRelations() {
-    return Collections.emptySet();
-  }
-
-  @Override
-  public ResultFormatter getResultFormatter() {
-    //todo: instance formatter
-    return getId() == null ? new CollectionFormatter(this) : new ServiceInstanceFormatter(this);
+    mapChildren.put(componentResourceDefinition.getPluralName(), componentResourceDefinition);
+    return mapChildren;
   }
 }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/BaseService.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/BaseService.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/BaseService.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/BaseService.java Mon Oct  8 01:37:59 2012
@@ -21,33 +21,62 @@ package org.apache.ambari.api.services;
 import org.apache.ambari.api.handlers.DelegatingRequestHandler;
 import org.apache.ambari.api.handlers.RequestHandler;
 import org.apache.ambari.api.resource.ResourceDefinition;
+import org.apache.ambari.api.services.serializers.ResultSerializer;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 /**
- *
+ * Provides common functionality to all services.
  */
-public class BaseService {
+public abstract class BaseService {
 
-  protected Response handleRequest(HttpHeaders headers, UriInfo uriInfo, Request.RequestType requestType,
+  /**
+   * All requests are funneled through this method so that common logic can be executed.
+   * This consists of creating a {@link Request} instance, invoking the correct {@link RequestHandler} and
+   * applying the proper {@link ResultSerializer} to the result.
+   *
+   * @param headers            http headers
+   * @param uriInfo            uri information
+   * @param requestType        http request type
+   * @param resourceDefinition resource definition that is being acted on
+   * @return the response of the operation in serialized form
+   */
+  protected Response handleRequest(HttpHeaders headers, UriInfo uriInfo, Request.Type requestType,
                                    ResourceDefinition resourceDefinition) {
 
-    Request req = getRequestFactory().createRequest(headers, uriInfo, requestType, resourceDefinition);
-    Result result = getRequestHandler().handleRequest(req);
-    Object formattedResult = resourceDefinition.getResultFormatter().format(result, uriInfo);
-    return getResponseFactory().createResponse(req.getSerializer().serialize(formattedResult));
+    Request request = getRequestFactory().createRequest(headers, uriInfo, requestType, resourceDefinition);
+    Result result = getRequestHandler().handleRequest(request);
+
+    return getResponseFactory().createResponse(request.getResultSerializer().serialize(result, uriInfo));
   }
 
+  /**
+   * Obtain the factory from which to create Request instances.
+   *
+   * @return the Request factory
+   */
   RequestFactory getRequestFactory() {
     return new RequestFactory();
   }
 
+  /**
+   * Obtain the factory from which to create Response instances.
+   *
+   * @return the Response factory
+   */
   ResponseFactory getResponseFactory() {
     return new ResponseFactory();
   }
 
+  /**
+   * Obtain the appropriate RequestHandler for the request.  At this time all requests are funneled through
+   * a delegating request handler which will ultimately delegate the request to the appropriate concrete
+   * request handler.
+   *
+   * @return the request handler to invoke
+   */
   RequestHandler getRequestHandler() {
     return new DelegatingRequestHandler();
   }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ClusterService.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ClusterService.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ClusterService.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ClusterService.java Mon Oct  8 01:37:59 2012
@@ -21,12 +21,10 @@ package org.apache.ambari.api.services;
 import org.apache.ambari.api.resource.ClusterResourceDefinition;
 import org.apache.ambari.api.resource.ResourceDefinition;
 
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
+import javax.ws.rs.*;
 import javax.ws.rs.core.*;
 
+
 /**
  * Service responsible for cluster resource requests.
  */
@@ -34,7 +32,7 @@ import javax.ws.rs.core.*;
 public class ClusterService extends BaseService {
 
   /**
-   * Handles URL: /clusters/{clusterID}
+   * Handles: GET /clusters/{clusterID}
    * Get a specific cluster.
    *
    * @param headers     http headers
@@ -48,11 +46,11 @@ public class ClusterService extends Base
   public Response getCluster(@Context HttpHeaders headers, @Context UriInfo ui,
                              @PathParam("clusterName") String clusterName) {
 
-    return handleRequest(headers, ui, Request.RequestType.GET, createResourceDefinition(clusterName));
+    return handleRequest(headers, ui, Request.Type.GET, createResourceDefinition(clusterName));
   }
 
   /**
-   * Handles URL:  /clusters
+   * Handles: GET  /clusters
    * Get all clusters.
    *
    * @param headers http headers
@@ -62,7 +60,58 @@ public class ClusterService extends Base
   @GET
   @Produces("text/plain")
   public Response getClusters(@Context HttpHeaders headers, @Context UriInfo ui) {
-    return handleRequest(headers, ui, Request.RequestType.GET, createResourceDefinition(null));
+    return handleRequest(headers, ui, Request.Type.GET, createResourceDefinition(null));
+  }
+
+  /**
+   * Handles: PUT /clusters/{clusterID}
+   * Create a specific cluster.
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param clusterName cluster id
+   * @return information regarding the created cluster
+   */
+  @PUT
+  @Produces("text/plain")
+  public Response createCluster(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("clusterName") String clusterName) {
+
+    return handleRequest(headers, ui, Request.Type.PUT, createResourceDefinition(clusterName));
+  }
+
+  /**
+   * Handles: POST /clusters/{clusterID}
+   * Update a specific cluster.
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param clusterName cluster id
+   * @return information regarding the updated cluster
+   */
+  @POST
+  @Produces("text/plain")
+  public Response updateCluster(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("clusterName") String clusterName) {
+
+    return handleRequest(headers, ui, Request.Type.POST, createResourceDefinition(clusterName));
+  }
+
+  /**
+   * Handles: DELETE /clusters/{clusterID}
+   * Delete a specific cluster.
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param clusterName cluster id
+   * @return information regarding the deleted cluster
+   */
+  @DELETE
+  @Produces("text/plain")
+  public Response deleteCluster(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("clusterName") String clusterName) {
+
+    return handleRequest(headers, ui, Request.Type.DELETE, createResourceDefinition(clusterName));
   }
 
   /**

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ComponentService.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ComponentService.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ComponentService.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ComponentService.java Mon Oct  8 01:37:59 2012
@@ -67,7 +67,7 @@ public class ComponentService extends Ba
   public Response getComponent(@Context HttpHeaders headers, @Context UriInfo ui,
                                @PathParam("componentName") String componentName) {
 
-    return handleRequest(headers, ui, Request.RequestType.GET,
+    return handleRequest(headers, ui, Request.Type.GET,
         createResourceDefinition(componentName, m_clusterName, m_serviceName));
   }
 
@@ -82,7 +82,7 @@ public class ComponentService extends Ba
   @GET
   @Produces("text/plain")
   public Response getComponents(@Context HttpHeaders headers, @Context UriInfo ui) {
-    return handleRequest(headers, ui, Request.RequestType.GET,
+    return handleRequest(headers, ui, Request.Type.GET,
         createResourceDefinition(null, m_clusterName, m_serviceName));
   }
 

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/HostComponentService.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/HostComponentService.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/HostComponentService.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/HostComponentService.java Mon Oct  8 01:37:59 2012
@@ -67,7 +67,7 @@ public class HostComponentService extend
   public Response getHostComponent(@Context HttpHeaders headers, @Context UriInfo ui,
                                    @PathParam("hostComponentName") String hostComponentName) {
 
-    return handleRequest(headers, ui, Request.RequestType.GET,
+    return handleRequest(headers, ui, Request.Type.GET,
         createResourceDefinition(hostComponentName, m_clusterName, m_hostName));
   }
 
@@ -82,7 +82,7 @@ public class HostComponentService extend
   @GET
   @Produces("text/plain")
   public Response getHostComponents(@Context HttpHeaders headers, @Context UriInfo ui) {
-    return handleRequest(headers, ui, Request.RequestType.GET,
+    return handleRequest(headers, ui, Request.Type.GET,
         createResourceDefinition(null, m_clusterName, m_hostName));
   }
 

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/HostService.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/HostService.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/HostService.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/HostService.java Mon Oct  8 01:37:59 2012
@@ -61,7 +61,7 @@ public class HostService extends BaseSer
   public Response getHost(@Context HttpHeaders headers, @Context UriInfo ui,
                           @PathParam("hostName") String hostName) {
 
-    return handleRequest(headers, ui, Request.RequestType.GET,
+    return handleRequest(headers, ui, Request.Type.GET,
         createResourceDefinition(hostName, m_clusterName));
   }
 
@@ -76,7 +76,7 @@ public class HostService extends BaseSer
   @GET
   @Produces("text/plain")
   public Response getHosts(@Context HttpHeaders headers, @Context UriInfo ui) {
-    return handleRequest(headers, ui, Request.RequestType.GET, createResourceDefinition(null, m_clusterName));
+    return handleRequest(headers, ui, Request.Type.GET, createResourceDefinition(null, m_clusterName));
   }
 
   /**

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/Request.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/Request.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/Request.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/Request.java Mon Oct  8 01:37:59 2012
@@ -19,6 +19,7 @@
 package org.apache.ambari.api.services;
 
 import org.apache.ambari.api.resource.ResourceDefinition;
+import org.apache.ambari.api.services.serializers.ResultSerializer;
 
 import java.net.URI;
 import java.util.List;
@@ -26,41 +27,89 @@ import java.util.Map;
 import java.util.Set;
 
 /**
- *
+ * Provides information on the current request.
  */
 public interface Request {
 
-  public enum RequestType {
+  /**
+   * Enum of request types.
+   */
+  public enum Type {
     GET,
     PUT,
     POST,
     DELETE
   }
 
-  public enum ResponseType {JSON}
-
-  public ResourceDefinition getResource();
-
+  /**
+   * Obtain the resource definition which corresponds to the resource being operated on by the request.
+   * The resource definition provides information about the resource type;
+   *
+   * @return the associated {@link ResourceDefinition}
+   */
+  public ResourceDefinition getResourceDefinition();
+
+  /**
+   * Obtain the URI of this request.
+   *
+   * @return the request uri
+   */
   public URI getURI();
 
-  public RequestType getRequestType();
-
+  /**
+   * Obtain the http request type.  Type is one of {@link Type}.
+   *
+   * @return the http request type
+   */
+  public Type getRequestType();
+
+  /**
+   * Obtain the api version of the request.  The api version is specified in the request URI.
+   *
+   * @return the api version of the request
+   */
   public int getAPIVersion();
 
-  public Map<String, List<String>> getQueryParameters();
-
-  public Map<String, List<String>> getQueryPredicates();
-
+  /**
+   * Obtain the query predicates that were provided in the URL query string.
+   *
+   * @return a map of request predicates
+   */
+  public Map<String, String> getQueryPredicates();
+
+  /**
+   * Obtain the set of partial response fields which were provided in the query string of the request uri.
+   *
+   * @return a set of the provided partial response fields
+   */
   public Set<String> getPartialResponseFields();
 
-  public Set<String> getExpandEntities();
-
-  public Map<String, List<String>> getHeaders();
-
-  public String getBody();
-
-  public Serializer getSerializer();
-
-  //todo: temporal information.  For now always specify in PR for each field.  Could use *[...] ?
-  //public Map<String, TemporalData> getTemporalFields();
+  /**
+   * Obtain the result serializer for the request. The default serializer is of type JSON.
+   *
+   * @return the result serializer fo rthe request
+   */
+  public ResultSerializer getResultSerializer();
+
+  /**
+   * Obtain the processor which processes the result returned from the request handler.
+   * The post processor adds additional information such as href fields to the result.
+   *
+   * @return the result processor associated with the request
+   */
+  public ResultPostProcessor getResultPostProcessor();
+
+  /**
+   * Obtain the http headers associated with the request.
+   *
+   * @return the http headers
+   */
+  public Map<String, List<String>> getHttpHeaders();
+
+  /**
+   * Obtain the http body associated with the request.
+   *
+   * @return the http body
+   */
+  public String getHttpBody();
 }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/RequestFactory.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/RequestFactory.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/RequestFactory.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/RequestFactory.java Mon Oct  8 01:37:59 2012
@@ -24,10 +24,19 @@ import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
 
 /**
- *
+ * Factory for {@link Request} instances.
  */
 public class RequestFactory {
-  public Request createRequest(HttpHeaders headers, UriInfo uriInfo, Request.RequestType requestType,
+  /**
+   * Create a request instance.
+   *
+   * @param headers            http headers
+   * @param uriInfo            uri information
+   * @param requestType        http request type
+   * @param resourceDefinition associated resource definition
+   * @return a new Request instance
+   */
+  public Request createRequest(HttpHeaders headers, UriInfo uriInfo, Request.Type requestType,
                                ResourceDefinition resourceDefinition) {
 
     return new RequestImpl(headers, uriInfo, requestType, resourceDefinition);

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/RequestImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/RequestImpl.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/RequestImpl.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/RequestImpl.java Mon Oct  8 01:37:59 2012
@@ -19,34 +19,56 @@
 package org.apache.ambari.api.services;
 
 import org.apache.ambari.api.resource.*;
+import org.apache.ambari.api.services.serializers.JsonSerializer;
+import org.apache.ambari.api.services.serializers.ResultSerializer;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
 import java.net.URI;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 /**
- *
+ * Request implementation.
  */
 public class RequestImpl implements Request {
 
+  /**
+   * URI information
+   */
   private UriInfo m_uriInfo;
+
+  /**
+   * Http headers
+   */
   private HttpHeaders m_headers;
-  private RequestType m_requestType;
-  private ResourceDefinition m_resourceDefinition;
 
+  /**
+   * Http request type
+   */
+  private Type m_Type;
+
+  /**
+   * Associated resource definition
+   */
+  private ResourceDefinition m_resourceDefinition;
 
-  public RequestImpl(HttpHeaders headers, UriInfo uriInfo, RequestType requestType, ResourceDefinition resourceDefinition) {
+  /**
+   * Constructor.
+   *
+   * @param headers            http headers
+   * @param uriInfo            uri information
+   * @param requestType        http request type
+   * @param resourceDefinition associated resource definition
+   */
+  public RequestImpl(HttpHeaders headers, UriInfo uriInfo, Type requestType, ResourceDefinition resourceDefinition) {
     m_uriInfo = uriInfo;
     m_headers = headers;
-    m_requestType = requestType;
+    m_Type = requestType;
     m_resourceDefinition = resourceDefinition;
   }
 
   @Override
-  public ResourceDefinition getResource() {
+  public ResourceDefinition getResourceDefinition() {
     return m_resourceDefinition;
   }
 
@@ -56,8 +78,8 @@ public class RequestImpl implements Requ
   }
 
   @Override
-  public RequestType getRequestType() {
-    return m_requestType;
+  public Type getRequestType() {
+    return m_Type;
   }
 
   @Override
@@ -66,38 +88,37 @@ public class RequestImpl implements Requ
   }
 
   @Override
-  public Map<String, List<String>> getQueryParameters() {
-    return m_uriInfo.getQueryParameters();
-  }
-
-  @Override
-  public Map<String, List<String>> getQueryPredicates() {
-    //todo: handle expand/fields ...
-    return getQueryParameters();
+  public Map<String, String> getQueryPredicates() {
+    return null;
   }
 
   @Override
   public Set<String> getPartialResponseFields() {
-    return null;
+    String partialResponseFields = m_uriInfo.getQueryParameters().getFirst("fields");
+    if (partialResponseFields == null) {
+      return Collections.emptySet();
+    } else {
+      return new HashSet<String>(Arrays.asList(partialResponseFields.split(",")));
+    }
   }
 
   @Override
-  public Set<String> getExpandEntities() {
-    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  public Map<String, List<String>> getHttpHeaders() {
+    return m_headers.getRequestHeaders();
   }
 
   @Override
-  public Map<String, List<String>> getHeaders() {
-    return m_headers.getRequestHeaders();
+  public String getHttpBody() {
+    return null;
   }
 
   @Override
-  public String getBody() {
-    return null;
+  public ResultSerializer getResultSerializer() {
+    return new JsonSerializer();
   }
 
   @Override
-  public Serializer getSerializer() {
-    return new JSONSerializer();
+  public ResultPostProcessor getResultPostProcessor() {
+    return new ResultPostProcessorImpl(this);
   }
 }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResponseFactory.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResponseFactory.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResponseFactory.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResponseFactory.java Mon Oct  8 01:37:59 2012
@@ -21,9 +21,16 @@ package org.apache.ambari.api.services;
 import javax.ws.rs.core.Response;
 
 /**
- *
+ * Factory for creating jax-rs responses from results.
  */
 public class ResponseFactory {
+  /**
+   * Create a response from a provided result.
+   *
+   * @param result  the result to wrap
+   *
+   * @return a new jax-rs Response instance for the provided result
+   */
   public Response createResponse(Object result) {
     return Response.ok(result).build();
   }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/Result.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/Result.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/Result.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/Result.java Mon Oct  8 01:37:59 2012
@@ -19,16 +19,17 @@
 package org.apache.ambari.api.services;
 
 
-import org.apache.ambari.api.controller.spi.Resource;
-
-import java.util.List;
-import java.util.Map;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.api.util.TreeNode;
 
 /**
- *
+ * Represents a result from a request handler invocation.
  */
 public interface Result {
-  public void addResources(String groupName, List<Resource> listResources);
-
-  public Map<String, List<Resource>> getResources();
+  /**
+   * the results of the request invocation as a Tree structure.
+   *
+   * @return the results of the request a a Tree structure
+   */
+  public TreeNode<Resource> getResultTree();
 }

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultImpl.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultImpl.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultImpl.java Mon Oct  8 01:37:59 2012
@@ -19,35 +19,25 @@
 package org.apache.ambari.api.services;
 
 
-import org.apache.ambari.api.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.api.util.TreeNode;
+import org.apache.ambari.api.util.TreeNodeImpl;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 
 /**
- *
+ * Result implementation.
  */
-//todo: at the moment only supports one level of nesting.
-//todo: need to allow arbitrary nesting depth for expansion.
-//todo: consider building a tree structure.
 public class ResultImpl implements Result {
 
-  private Map<String, List<Resource>> m_mapResources = new HashMap<String, List<Resource>>();
+  /**
+   * Tree structure which holds the results
+   */
+  private TreeNode<Resource> m_tree = new TreeNodeImpl<Resource>(null, null, null);
 
-  @Override
-  public void addResources(String groupName, List<Resource> listResources) {
-    List<Resource> resources = m_mapResources.get(groupName);
-    if (resources == null) {
-      m_mapResources.put(groupName, listResources);
-    } else {
-      resources.addAll(listResources);
-    }
-  }
 
   @Override
-  public Map<String, List<Resource>> getResources() {
-    return m_mapResources;
+  public TreeNode<Resource> getResultTree() {
+    return m_tree;
   }
 }
 

Added: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultPostProcessor.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultPostProcessor.java?rev=1395430&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultPostProcessor.java (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultPostProcessor.java Mon Oct  8 01:37:59 2012
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.api.services;
+
+/**
+ * Processor which processes result objects prior to them being returned to the service.
+ * Processing can include adding additional data such as hrefs, or modifying/deleting existing data.
+ */
+public interface ResultPostProcessor {
+  /**
+   * Process the given result.
+   * The passed in process is directly modified.
+   *
+   * @param result the result to process.
+   */
+  public void process(Result result);
+}

Added: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultPostProcessorImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultPostProcessorImpl.java?rev=1395430&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultPostProcessorImpl.java (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ResultPostProcessorImpl.java Mon Oct  8 01:37:59 2012
@@ -0,0 +1,115 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.api.services;
+
+import org.apache.ambari.api.resource.ResourceDefinition;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.api.util.TreeNode;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Processes returned results to add href's and other content.
+ */
+public class ResultPostProcessorImpl implements ResultPostProcessor {
+  /**
+   * the associated request
+   */
+  private Request m_request;
+
+  /**
+   * Map of resource post processors keyed by resource type.
+   * These are used to act on specific resource types contained in the result.
+   */
+  Map<Resource.Type, List<ResourceDefinition.PostProcessor>> m_mapPostProcessors =
+      new HashMap<Resource.Type, List<ResourceDefinition.PostProcessor>>();
+
+
+  /**
+   * Constructor.
+   *
+   * @param request the associated request
+   */
+  public ResultPostProcessorImpl(Request request) {
+    m_request = request;
+
+    registerResourceProcessors(m_request.getResourceDefinition());
+  }
+
+  @Override
+  public void process(Result result) {
+    processNode(result.getResultTree(), m_request.getURI().toString());
+  }
+
+  /**
+   * Process a node of the result tree.  Recursively calls child nodes.
+   *
+   * @param node the node to process
+   * @param href the current href
+   */
+  private void processNode(TreeNode<Resource> node, String href) {
+    Resource r = node.getObject();
+    if (r != null) {
+      List<ResourceDefinition.PostProcessor> listProcessors = m_mapPostProcessors.get(r.getType());
+      for (ResourceDefinition.PostProcessor processor : listProcessors) {
+        processor.process(m_request, node, href);
+      }
+      href = node.getProperty("href");
+      int i = href.indexOf('?');
+      if (i != -1) {
+        href = href.substring(0, i);
+      }
+    } else {
+      String isItemsCollection = node.getProperty("isCollection");
+      if (node.getName() == null && "true".equals(isItemsCollection)) {
+        node.setName("items");
+        node.setProperty("href", href);
+      }
+    }
+    for (TreeNode<Resource> child : node.getChildren()) {
+      processNode(child, href);
+    }
+  }
+
+  /**
+   * Registers the resource processors.
+   * Recursively registers child resource processors.
+   *
+   * @param resource the root resource
+   */
+  private void registerResourceProcessors(ResourceDefinition resource) {
+    List<ResourceDefinition.PostProcessor> listProcessors = m_mapPostProcessors.get(resource.getType());
+    if (listProcessors == null) {
+      listProcessors = new ArrayList<ResourceDefinition.PostProcessor>();
+      m_mapPostProcessors.put(resource.getType(), listProcessors);
+    }
+    listProcessors.addAll(resource.getPostProcessors());
+
+    for (ResourceDefinition child : resource.getSubResources().values()) {
+      // avoid cycle
+      if (!m_mapPostProcessors.containsKey(child.getType())) {
+        registerResourceProcessors(child);
+      }
+    }
+  }
+
+}

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ServiceService.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ServiceService.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ServiceService.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/ServiceService.java Mon Oct  8 01:37:59 2012
@@ -21,10 +21,7 @@ package org.apache.ambari.api.services;
 import org.apache.ambari.api.resource.ResourceDefinition;
 import org.apache.ambari.api.resource.ServiceResourceDefinition;
 
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
+import javax.ws.rs.*;
 import javax.ws.rs.core.*;
 
 /**
@@ -60,12 +57,12 @@ public class ServiceService extends Base
   public Response getService(@Context HttpHeaders headers, @Context UriInfo ui,
                              @PathParam("serviceName") String serviceName) {
 
-    return handleRequest(headers, ui, Request.RequestType.GET,
+    return handleRequest(headers, ui, Request.Type.GET,
         createResourceDefinition(serviceName, m_clusterName));
   }
 
   /**
-   * Handles URL: /clusters/{clusterID}/services
+   * Handles URL: /clusters/{clusterId}/services
    * Get all services for a cluster.
    *
    * @param headers http headers
@@ -75,11 +72,62 @@ public class ServiceService extends Base
   @GET
   @Produces("text/plain")
   public Response getServices(@Context HttpHeaders headers, @Context UriInfo ui) {
-    return handleRequest(headers, ui, Request.RequestType.GET,
+    return handleRequest(headers, ui, Request.Type.GET,
         createResourceDefinition(null, m_clusterName));
   }
 
   /**
+   * Handles: PUT /clusters/{clusterId}/services/{serviceId}
+   * Create a specific service.
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param serviceName service id
+   * @return information regarding the created service
+   */
+  @PUT
+  @Produces("text/plain")
+  public Response createService(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("serviceName") String serviceName) {
+
+    return handleRequest(headers, ui, Request.Type.PUT, createResourceDefinition(serviceName, m_clusterName));
+  }
+
+  /**
+   * Handles: POST /clusters/{clusterId}/services/{serviceId}
+   * Update a specific service.
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param serviceName service id
+   * @return information regarding the updated service
+   */
+  @POST
+  @Produces("text/plain")
+  public Response updateService(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("serviceName") String serviceName) {
+
+    return handleRequest(headers, ui, Request.Type.POST, createResourceDefinition(serviceName, m_clusterName));
+  }
+
+  /**
+   * Handles: DELETE /clusters/{clusterId}/services/{serviceId}
+   * Delete a specific service.
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param serviceName service id
+   * @return information regarding the deleted service
+   */
+  @DELETE
+  @Produces("text/plain")
+  public Response deleteService(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("serviceName") String serviceName) {
+
+    return handleRequest(headers, ui, Request.Type.DELETE, createResourceDefinition(serviceName, m_clusterName));
+  }
+
+  /**
    * Get the components sub-resource.
    *
    * @param serviceName service id

Added: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/serializers/JsonSerializer.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/serializers/JsonSerializer.java?rev=1395430&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/serializers/JsonSerializer.java (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/serializers/JsonSerializer.java Mon Oct  8 01:37:59 2012
@@ -0,0 +1,139 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.api.services.serializers;
+
+import org.apache.ambari.api.services.Result;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.api.util.TreeNode;
+import org.codehaus.jackson.JsonFactory;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.util.DefaultPrettyPrinter;
+
+import javax.ws.rs.core.UriInfo;
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.Map;
+
+/**
+ * JSON serializer.
+ * Responsible for representing a result as JSON.
+ */
+public class JsonSerializer implements ResultSerializer {
+
+  /**
+   * Factory used to create JSON generator.
+   */
+  JsonFactory m_factory = new JsonFactory();
+
+  /**
+   * Generator which writes JSON.
+   */
+  JsonGenerator m_generator;
+
+  @Override
+  public Object serialize(Result result, UriInfo uriInfo) {
+    try {
+      ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+      m_generator = createJsonGenerator(bytesOut);
+
+      DefaultPrettyPrinter p = new DefaultPrettyPrinter();
+      p.indentArraysWith(new DefaultPrettyPrinter.Lf2SpacesIndenter());
+      m_generator.setPrettyPrinter(p);
+
+      processNode(result.getResultTree());
+
+      m_generator.close();
+      return bytesOut.toString("UTF-8");
+    } catch (IOException e) {
+      throw new RuntimeException("Unable to serialize to json: " + e, e);
+    }
+  }
+
+  private void processNode(TreeNode<Resource> node) throws IOException {
+    String name = node.getName();
+    Resource r = node.getObject();
+
+    if (r == null) {
+      if (name != null) {
+        if (node.getParent() == null) {
+          m_generator.writeStartObject();
+          writeHref(node);
+        }
+        m_generator.writeArrayFieldStart(name);
+      }
+    } else {
+      m_generator.writeStartObject();
+      writeHref(node);
+      // resource props
+      handleResourceProperties(r.getCategories());
+    }
+
+    for (TreeNode<Resource> child : node.getChildren()) {
+      processNode(child);
+    }
+
+    if (r == null) {
+      if (name != null) {
+        m_generator.writeEndArray();
+        if (node.getParent() == null) {
+          m_generator.writeEndObject();
+        }
+      }
+    } else {
+      m_generator.writeEndObject();
+    }
+  }
+
+  private void handleResourceProperties(Map<String, Map<String, String>> mapCatProps) throws IOException {
+    for (Map.Entry<String, Map<String, String>> categoryEntry : mapCatProps.entrySet()) {
+      String category = categoryEntry.getKey();
+      Map<String, String> mapProps = categoryEntry.getValue();
+      if (category != null) {
+        m_generator.writeFieldName(category);
+        m_generator.writeStartObject();
+      }
+
+      for (Map.Entry<String, String> propEntry : mapProps.entrySet()) {
+        m_generator.writeStringField(propEntry.getKey(), propEntry.getValue());
+      }
+
+      if (category != null) {
+        m_generator.writeEndObject();
+      }
+    }
+  }
+
+  private JsonGenerator createJsonGenerator(ByteArrayOutputStream baos) throws IOException {
+    JsonGenerator generator = m_factory.createJsonGenerator(new OutputStreamWriter(baos,
+        Charset.forName("UTF-8").newEncoder()));
+
+    DefaultPrettyPrinter p = new DefaultPrettyPrinter();
+    p.indentArraysWith(new DefaultPrettyPrinter.Lf2SpacesIndenter());
+    generator.setPrettyPrinter(p);
+
+    return generator;
+  }
+
+  private void writeHref(TreeNode<Resource> node) throws IOException {
+    String hrefProp = node.getProperty("href");
+    if (hrefProp != null) {
+      m_generator.writeStringField("href", hrefProp);
+    }
+  }
+}

Added: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/serializers/ResultSerializer.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/serializers/ResultSerializer.java?rev=1395430&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/serializers/ResultSerializer.java (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/services/serializers/ResultSerializer.java Mon Oct  8 01:37:59 2012
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.api.services.serializers;
+
+
+import org.apache.ambari.api.services.Result;
+
+import javax.ws.rs.core.UriInfo;
+
+/**
+ * Format internal result to format expected by client.
+ */
+public interface ResultSerializer {
+  /**
+   * Serialize the given result to a format expected by client.
+   *
+   * @param result  internal result
+   * @param uriInfo URL info for request
+   * @return the serialized result
+   */
+  Object serialize(Result result, UriInfo uriInfo);
+}

Added: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/util/TreeNode.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/util/TreeNode.java?rev=1395430&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/util/TreeNode.java (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/util/TreeNode.java Mon Oct  8 01:37:59 2012
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.api.util;
+
+import java.util.List;
+
+/**
+ * Tree where each node can have a name, properties and an associated object.
+ */
+public interface TreeNode<T> {
+  /**
+   * Obtain the parent node or null if this node is the root.
+   *
+   * @return the parent node or null if this node is the root
+   */
+  public TreeNode<T> getParent();
+
+  /**
+   * Obtain the list of child nodes.
+   *
+   * @return a list of child nodes or an empty list if a leaf node
+   */
+  public List<TreeNode<T>> getChildren();
+
+  /**
+   * Obtain the object associated with this node.
+   *
+   * @return the object associated with this node or null
+   */
+  public T getObject();
+
+  /**
+   * Obtain the name of the node.
+   *
+   * @return the name of the node or null
+   */
+  public String getName();
+
+  /**
+   * Set the name of the node.
+   *
+   * @param name the name to set
+   */
+  public void setName(String name);
+
+  /**
+   * Set the parent node.
+   *
+   * @param parent the parent node to set
+   */
+  public void setParent(TreeNode<T> parent);
+
+  /**
+   * Add a child node for the provided object.
+   *
+   * @param child the object associated with the new child node
+   * @param name  the name of the child node
+   * @return the newly created child node
+   */
+  public TreeNode<T> addChild(T child, String name);
+
+  /**
+   * Add the specified child node.
+   *
+   * @param child the child node to add
+   * @return the added child node
+   */
+  public TreeNode<T> addChild(TreeNode<T> child);
+
+  /**
+   * Set a property on the node.
+   *
+   * @param name  the name of the property
+   * @param value the value of the property
+   */
+  public void setProperty(String name, String value);
+
+  /**
+   * Get the specified node property.
+   *
+   * @param name property name
+   * @return the requested property value or null
+   */
+  public String getProperty(String name);
+}

Added: incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/util/TreeNodeImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/util/TreeNodeImpl.java?rev=1395430&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/util/TreeNodeImpl.java (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/main/java/org/apache/ambari/api/util/TreeNodeImpl.java Mon Oct  8 01:37:59 2012
@@ -0,0 +1,127 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.api.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Basic implementation of TreeNode.
+ */
+public class TreeNodeImpl<T> implements TreeNode<T> {
+
+  /**
+   * name of the node
+   */
+  private String m_name;
+
+  /**
+   * parent of the node
+   */
+  private TreeNode<T> m_parent;
+
+  /**
+   * child nodes
+   */
+  private List<TreeNode<T>> m_listChildren = new ArrayList<TreeNode<T>>();
+
+  /**
+   * associated object
+   */
+  private T m_object;
+
+  /**
+   * properties
+   */
+  private Map<String, String> m_mapNodeProps;
+
+  /**
+   * Constructor.
+   *
+   * @param parent parent node
+   * @param object associated object
+   * @param name   node name
+   */
+  public TreeNodeImpl(TreeNode<T> parent, T object, String name) {
+    m_parent = parent;
+    m_object = object;
+    m_name = name;
+  }
+
+  @Override
+  public TreeNode<T> getParent() {
+    return m_parent;
+  }
+
+  @Override
+  public List<TreeNode<T>> getChildren() {
+    return m_listChildren;
+  }
+
+  @Override
+  public T getObject() {
+    return m_object;
+  }
+
+  @Override
+  public void setName(String name) {
+    m_name = name;
+  }
+
+  @Override
+  public String getName() {
+    return m_name;
+  }
+
+  @Override
+  public void setParent(TreeNode<T> parent) {
+    m_parent = parent;
+  }
+
+  @Override
+  public TreeNode<T> addChild(T child, String name) {
+    TreeNodeImpl<T> node = new TreeNodeImpl<T>(this, child, name);
+    m_listChildren.add(node);
+
+    return node;
+  }
+
+  @Override
+  public TreeNode<T> addChild(TreeNode<T> child) {
+    child.setParent(this);
+    m_listChildren.add(child);
+
+    return child;
+  }
+
+  @Override
+  public void setProperty(String name, String value) {
+    if (m_mapNodeProps == null) {
+      m_mapNodeProps = new HashMap<String, String>();
+    }
+    m_mapNodeProps.put(name, value);
+  }
+
+  @Override
+  public String getProperty(String name) {
+    return m_mapNodeProps == null ? null : m_mapNodeProps.get(name);
+  }
+}

Modified: incubator/ambari/branches/AMBARI-666/ambari-api/src/test/java/org/apache/ambari/api/TestSuite.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-api/src/test/java/org/apache/ambari/api/TestSuite.java?rev=1395430&r1=1395429&r2=1395430&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-api/src/test/java/org/apache/ambari/api/TestSuite.java (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-api/src/test/java/org/apache/ambari/api/TestSuite.java Mon Oct  8 01:37:59 2012
@@ -1,20 +1,3 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 package org.apache.ambari.api;
 
 /**
@@ -22,15 +5,18 @@ package org.apache.ambari.api;
  */
 
 import org.apache.ambari.api.handlers.DelegatingRequestHandlerTest;
-import org.apache.ambari.api.handlers.ReadRequestHandlerTest;
-import org.apache.ambari.api.query.QueryImplTest;
-import org.apache.ambari.api.services.*;
+import org.apache.ambari.api.handlers.ReadHandlerTest;
+import org.apache.ambari.api.services.ClusterServiceTest;
+import org.apache.ambari.api.services.ComponentServiceTest;
+import org.apache.ambari.api.services.HostComponentServiceTest;
+import org.apache.ambari.api.services.HostServiceTest;
+import org.apache.ambari.api.services.ServiceServiceTest;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({ClusterServiceTest.class, HostServiceTest.class, ServiceServiceTest.class,
     ComponentServiceTest.class, HostComponentServiceTest.class, DelegatingRequestHandlerTest.class,
-    ReadRequestHandlerTest.class, QueryImplTest.class})
+    ReadHandlerTest.class})
 public class TestSuite {
 }