Repository: ambari
Updated Branches:
  refs/heads/trunk 7e50afca6 -> 81b755c60


AMBARI-6028 - Views: View managed resources need @Produces({text/plain}) to 
generate JSON


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/81b755c6
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/81b755c6
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/81b755c6

Branch: refs/heads/trunk
Commit: 81b755c6065230ec7ee064e95371f7f1928caf03
Parents: 7e50afc
Author: tbeerbower <[email protected]>
Authored: Thu Jun 5 09:38:06 2014 -0400
Committer: tbeerbower <[email protected]>
Committed: Thu Jun 5 17:34:13 2014 -0400

----------------------------------------------------------------------
 .../ambari/server/api/services/BaseService.java |  83 ++++++++++-
 .../api/services/ViewSubResourceService.java    |  19 ++-
 .../services/ViewSubResourceServiceTest.java    | 144 ++++++++++++++++++-
 .../apache/ambari/view/weather/CityService.java |   5 +-
 .../apache/ambari/view/ViewResourceHandler.java |  20 ++-
 5 files changed, 252 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/81b755c6/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
index 8953796..fa3b3ba 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
@@ -27,8 +27,10 @@ import 
org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.JsonSerializer;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.eclipse.jetty.util.ajax.JSON;
 
 import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import java.util.Iterator;
@@ -52,8 +54,9 @@ public abstract class BaseService {
 
 
   /**
-   * All requests are funneled through this method so that common logic can be 
executed.
-   * Creates a request instance and invokes it's process method.
+   * Requests are funneled through this method so that common logic can be 
executed.
+   * Creates a request instance and invokes it's process method.  Uses the 
default
+   * media type.
    *
    * @param headers      http headers
    * @param body         http body
@@ -66,6 +69,26 @@ public abstract class BaseService {
   protected Response handleRequest(HttpHeaders headers, String body, UriInfo 
uriInfo,
                                    Request.Type requestType, ResourceInstance 
resource) {
 
+    return handleRequest(headers, body, uriInfo, requestType, null, resource);
+  }
+
+  /**
+   * Requests are funneled through this method so that common logic can be 
executed.
+   * Creates a request instance and invokes it's process method.
+   *
+   * @param headers      http headers
+   * @param body         http body
+   * @param uriInfo      uri information
+   * @param requestType  http request type
+   * @param mediaType    the requested media type; may be null
+   * @param resource     resource instance that is being acted on
+   *
+   * @return the response of the operation in serialized form
+   */
+  protected Response handleRequest(HttpHeaders headers, String body,
+                                   UriInfo uriInfo, Request.Type requestType,
+                                   MediaType mediaType, ResourceInstance 
resource) {
+
     Result result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.OK));
     try {
       Set<RequestBody> requestBodySet = getBodyParser().parse(body);
@@ -83,8 +106,16 @@ public abstract class BaseService {
       result =  new ResultImpl(new 
ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e.getMessage()));
     }
 
-    return Response.status(result.getStatus().getStatusCode()).entity(
-        getResultSerializer().serialize(result)).build();
+    ResultSerializer serializer = mediaType == null ? getResultSerializer() : 
getResultSerializer(mediaType);
+
+    Response.ResponseBuilder builder = 
Response.status(result.getStatus().getStatusCode()).entity(
+        serializer.serialize(result));
+
+    if (mediaType != null) {
+      builder.type(mediaType);
+    }
+
+    return builder.build();
   }
 
   /**
@@ -108,6 +139,50 @@ public abstract class BaseService {
     return m_resourceFactory.createResource(type, mapIds);
   }
 
+  /**
+   * Get a serializer for the given media type.
+   *
+   * @param mediaType  the media type
+   *
+   * @return the result serializer
+   */
+  protected ResultSerializer getResultSerializer(final MediaType mediaType) {
+
+    final ResultSerializer serializer = getResultSerializer();
+
+    if (mediaType.equals(MediaType.TEXT_PLAIN_TYPE)){
+      return new ResultSerializer() {
+        @Override
+        public Object serialize(Result result) {
+          return serializer.serialize(result).toString();
+        }
+
+        @Override
+        public Object serializeError(ResultStatus error) {
+          return serializer.serializeError(error).toString();
+        }
+      };
+    } else if (mediaType.equals(MediaType.APPLICATION_JSON_TYPE)){
+      return new ResultSerializer() {
+        @Override
+        public Object serialize(Result result) {
+          return JSON.parse(serializer.serialize(result).toString());
+        }
+
+        @Override
+        public Object serializeError(ResultStatus error) {
+          return JSON.parse(serializer.serializeError(error).toString());
+        }
+      };
+    }
+    throw new IllegalArgumentException("The media type " + mediaType + " is 
not supported.");
+  }
+
+  /**
+   * Get the default serializer.
+   *
+   * @return the default serializer
+   */
   protected ResultSerializer getResultSerializer() {
     return m_serializer;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/81b755c6/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
index 135cd78..dae586b 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
@@ -73,9 +73,11 @@ public class ViewSubResourceService extends BaseService 
implements ViewResourceH
   // ----- ViewResourceHandler -----------------------------------------------
 
   @Override
-  public Response handleRequest(HttpHeaders headers, UriInfo ui, RequestType 
requestType, String resourceId) {
+  public Response handleRequest(HttpHeaders headers, UriInfo ui,
+                                RequestType requestType, MediaType mediaType,
+                                String resourceId) {
     return handleRequest(headers, null, ui, getRequestType(requestType),
-        createResource(resourceId));
+        getMediaType(mediaType), createResource(resourceId));
   }
 
   @Override
@@ -115,6 +117,17 @@ public class ViewSubResourceService extends BaseService 
implements ViewResourceH
       case QUERY_POST:
         return Request.Type.QUERY_POST;
     }
-    throw new IllegalArgumentException("Unknown type " + type);
+    throw new IllegalArgumentException("Unknown resource type " + type);
+  }
+
+  // get the JAX-RS media type from the view media type
+  private javax.ws.rs.core.MediaType getMediaType(MediaType type) {
+    switch (type) {
+      case TEXT_PLAIN:
+        return javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
+      case APPLICATION_JSON:
+        return javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
+    }
+    throw new IllegalArgumentException("Unknown media type " + type);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/81b755c6/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewSubResourceServiceTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewSubResourceServiceTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewSubResourceServiceTest.java
index 2b2c269..aaa0d62 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewSubResourceServiceTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewSubResourceServiceTest.java
@@ -21,18 +21,31 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.TreeNode;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntityTest;
+import org.junit.Test;
 
 import javax.ws.rs.PathParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 /**
  * ViewSubResourceService tests
@@ -80,6 +93,124 @@ public class ViewSubResourceServiceTest extends 
BaseServiceTest {
     return listInvocations;
   }
 
+  @Test
+  public void testGetResultSerializer_Text() throws Exception {
+    UriInfo uriInfo = createMock(UriInfo.class);
+    Resource resource = createMock(Resource.class);
+
+    Result result = new ResultImpl(true);
+    result.setResultStatus(new ResultStatus(ResultStatus.STATUS.OK));
+    TreeNode<Resource> tree = result.getResultTree();
+    TreeNode<Resource> child = tree.addChild(resource, "resource1");
+    child.setProperty("href", "this is an href");
+
+    // resource properties
+    HashMap<String, Object> mapRootProps = new HashMap<String, Object>();
+    mapRootProps.put("prop1", "value1");
+    mapRootProps.put("prop2", "value2");
+
+    HashMap<String, Object> mapCategoryProps = new HashMap<String, Object>();
+    mapCategoryProps.put("catProp1", "catValue1");
+    mapCategoryProps.put("catProp2", "catValue2");
+
+    Map<String, Map<String, Object>> propertyMap = new HashMap<String, 
Map<String, Object>>();
+
+    propertyMap.put(null, mapRootProps);
+    propertyMap.put("category", mapCategoryProps);
+
+    //expectations
+    expect(resource.getPropertiesMap()).andReturn(propertyMap).anyTimes();
+    expect(resource.getType()).andReturn(Resource.Type.Cluster).anyTimes();
+
+    replay(uriInfo, resource);
+
+    //execute test
+    ViewInstanceEntity viewInstanceEntity = 
ViewInstanceEntityTest.getViewInstanceEntity();
+
+    Resource.Type type = new Resource.Type("subResource");
+
+    // get resource
+    ViewSubResourceService service = new ViewSubResourceService(type, 
viewInstanceEntity);
+
+    ResultSerializer serializer = 
service.getResultSerializer(MediaType.TEXT_PLAIN_TYPE);
+
+    Object o = serializer.serialize(result);
+
+    String expected = "{\n" +
+        "  \"href\" : \"this is an href\",\n" +
+        "  \"prop2\" : \"value2\",\n" +
+        "  \"prop1\" : \"value1\",\n" +
+        "  \"category\" : {\n" +
+        "    \"catProp1\" : \"catValue1\",\n" +
+        "    \"catProp2\" : \"catValue2\"\n" +
+        "  }\n" +
+        "}";
+
+    assertEquals(expected, o);
+
+    verify(uriInfo, resource);
+  }
+
+  @Test
+  public void testGetResultSerializer_Json() throws Exception {
+    UriInfo uriInfo = createMock(UriInfo.class);
+    Resource resource = createMock(Resource.class);
+
+    Result result = new ResultImpl(true);
+    result.setResultStatus(new ResultStatus(ResultStatus.STATUS.OK));
+    TreeNode<Resource> tree = result.getResultTree();
+    TreeNode<Resource> child = tree.addChild(resource, "resource1");
+    child.setProperty("href", "this is an href");
+
+    // resource properties
+    HashMap<String, Object> mapRootProps = new HashMap<String, Object>();
+    mapRootProps.put("prop1", "value1");
+    mapRootProps.put("prop2", "value2");
+
+    HashMap<String, Object> mapCategoryProps = new HashMap<String, Object>();
+    mapCategoryProps.put("catProp1", "catValue1");
+    mapCategoryProps.put("catProp2", "catValue2");
+
+    Map<String, Map<String, Object>> propertyMap = new HashMap<String, 
Map<String, Object>>();
+
+    propertyMap.put(null, mapRootProps);
+    propertyMap.put("category", mapCategoryProps);
+
+    //expectations
+    expect(resource.getPropertiesMap()).andReturn(propertyMap).anyTimes();
+    expect(resource.getType()).andReturn(Resource.Type.Cluster).anyTimes();
+
+    replay(uriInfo, resource);
+
+    //execute test
+    ViewInstanceEntity viewInstanceEntity = 
ViewInstanceEntityTest.getViewInstanceEntity();
+
+    Resource.Type type = new Resource.Type("subResource");
+
+    // get resource
+    ViewSubResourceService service = new ViewSubResourceService(type, 
viewInstanceEntity);
+
+    ResultSerializer serializer = 
service.getResultSerializer(MediaType.APPLICATION_JSON_TYPE);
+
+    Object o = serializer.serialize(result);
+
+    assertTrue(o instanceof Map);
+    Map map = (Map) o;
+    assertEquals(4, map.size());
+    assertEquals("value1", map.get("prop1"));
+    assertEquals("value2", map.get("prop2"));
+    assertEquals("this is an href", map.get("href"));
+    Object o2 = map.get("category");
+    assertNotNull(o2);
+    assertTrue(o2 instanceof Map);
+    Map subMap = (Map) o2;
+    assertEquals(2, subMap.size());
+    assertEquals("catValue1", subMap.get("catProp1"));
+    assertEquals("catValue2", subMap.get("catProp2"));
+
+    verify(uriInfo, resource);
+  }
+
   private class TestViewSubResourceService extends ViewSubResourceService {
 
     /**
@@ -98,25 +229,25 @@ public class ViewSubResourceServiceTest extends 
BaseServiceTest {
     public Response getSubResource2(@Context HttpHeaders headers, @Context 
UriInfo ui,
                                    @PathParam("resourceId") String resourceId) 
{
 
-      return handleRequest(headers, ui, RequestType.GET, resourceId);
+      return handleRequest(headers, ui, RequestType.GET, MediaType.TEXT_PLAIN, 
resourceId);
     }
 
     public Response postSubResource(@Context HttpHeaders headers, @Context 
UriInfo ui,
                                    @PathParam("resourceId") String resourceId) 
{
 
-      return handleRequest(headers, ui, RequestType.POST, resourceId);
+      return handleRequest(headers, ui, RequestType.POST, 
MediaType.TEXT_PLAIN, resourceId);
     }
 
     public Response putSubResource(@Context HttpHeaders headers, @Context 
UriInfo ui,
                                     @PathParam("resourceId") String 
resourceId) {
 
-      return handleRequest(headers, ui, RequestType.PUT, resourceId);
+      return handleRequest(headers, ui, RequestType.PUT, MediaType.TEXT_PLAIN, 
resourceId);
     }
 
     public Response deleteSubResource(@Context HttpHeaders headers, @Context 
UriInfo ui,
                                     @PathParam("resourceId") String 
resourceId) {
 
-      return handleRequest(headers, ui, RequestType.DELETE, resourceId);
+      return handleRequest(headers, ui, RequestType.DELETE, 
MediaType.TEXT_PLAIN, resourceId);
     }
 
     @Override
@@ -138,6 +269,11 @@ public class ViewSubResourceServiceTest extends 
BaseServiceTest {
     protected ResultSerializer getResultSerializer() {
       return getTestResultSerializer();
     }
+
+    @Override
+    protected ResultSerializer getResultSerializer(javax.ws.rs.core.MediaType 
mediaType) {
+      return getTestResultSerializer();
+    }
   }
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/81b755c6/ambari-views/examples/weather-view/src/main/java/org/apache/ambari/view/weather/CityService.java
----------------------------------------------------------------------
diff --git 
a/ambari-views/examples/weather-view/src/main/java/org/apache/ambari/view/weather/CityService.java
 
b/ambari-views/examples/weather-view/src/main/java/org/apache/ambari/view/weather/CityService.java
index 0c7f0c5..e5a8696 100644
--- 
a/ambari-views/examples/weather-view/src/main/java/org/apache/ambari/view/weather/CityService.java
+++ 
b/ambari-views/examples/weather-view/src/main/java/org/apache/ambari/view/weather/CityService.java
@@ -51,10 +51,11 @@ public class CityService {
    */
   @GET
   @Path("{cityName}")
-  @Produces({"text/plain", "application/json"})
+  @Produces({"application/json"})
   public Response getCity(@Context HttpHeaders headers, @Context UriInfo ui,
                           @PathParam("cityName") String cityName) {
-    return resourceHandler.handleRequest(headers, ui, cityName);
+    return resourceHandler.handleRequest(headers, ui, 
ViewResourceHandler.RequestType.GET,
+        ViewResourceHandler.MediaType.APPLICATION_JSON, cityName);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/81b755c6/ambari-views/src/main/java/org/apache/ambari/view/ViewResourceHandler.java
----------------------------------------------------------------------
diff --git 
a/ambari-views/src/main/java/org/apache/ambari/view/ViewResourceHandler.java 
b/ambari-views/src/main/java/org/apache/ambari/view/ViewResourceHandler.java
index 2d42454..9256318 100644
--- a/ambari-views/src/main/java/org/apache/ambari/view/ViewResourceHandler.java
+++ b/ambari-views/src/main/java/org/apache/ambari/view/ViewResourceHandler.java
@@ -28,7 +28,7 @@ import javax.ws.rs.core.UriInfo;
  */
 public interface ViewResourceHandler {
   /**
-   * Enum of request types.
+   * Request types.
    */
   public enum RequestType {
     GET,
@@ -39,21 +39,29 @@ public interface ViewResourceHandler {
   }
 
   /**
-   * Handle the API request.
+   * Supported media types.
+   */
+  public enum MediaType {
+    TEXT_PLAIN,
+    APPLICATION_JSON
+  }
+
+  /**
+   * Handle the API request for the given request and media type.
    *
    * @param headers      the headers
    * @param ui           the URI info
    * @param requestType  the request type
+   * @param mediaType    the requested media type
    * @param resourceId   the resource id; may be null for collection resources
    *
    * @return the response
    */
-  public Response handleRequest(HttpHeaders headers, UriInfo ui, RequestType 
requestType, String resourceId);
+  public Response handleRequest(HttpHeaders headers, UriInfo ui, RequestType 
requestType,
+                                MediaType mediaType, String resourceId);
 
   /**
-   * Handle the API request with a request type of GET. Same as
-   * {@link ViewResourceHandler#handleRequest(HttpHeaders, UriInfo, 
ViewResourceHandler.RequestType, String)}
-   * for {@link ViewResourceHandler.RequestType#GET}.
+   * Handle the API request with a request type of GET and media type of 
TEXT_PLAIN.
    *
    * @param headers     the headers
    * @param ui          the URI info

Reply via email to