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