You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by js...@apache.org on 2015/01/21 23:45:11 UTC

ambari git commit: AMBARI-9243. Preserve nested map structures for artifact resource data

Repository: ambari
Updated Branches:
  refs/heads/trunk 07c78ba39 -> fcc6a4ccf


AMBARI-9243.  Preserve nested map structures for artifact resource data


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

Branch: refs/heads/trunk
Commit: fcc6a4ccf7bd4e49e5ad0d6062c0ce727183b4b2
Parents: 07c78ba
Author: John Speidel <js...@hortonworks.com>
Authored: Wed Jan 21 13:23:45 2015 -0500
Committer: John Speidel <js...@hortonworks.com>
Committed: Wed Jan 21 17:45:00 2015 -0500

----------------------------------------------------------------------
 .../ambari/server/api/services/RequestBody.java |   2 +
 .../internal/ArtifactResourceProvider.java      |  37 +++---
 .../ambari/server/controller/spi/Request.java   |   4 +
 .../parsers/JsonRequestBodyParserTest.java      |   3 +-
 .../internal/ArtifactResourceProviderTest.java  | 120 ++++++++++++++++++-
 5 files changed, 146 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/fcc6a4cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestBody.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestBody.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestBody.java
index f4c5647..548922d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestBody.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestBody.java
@@ -144,12 +144,14 @@ public class RequestBody {
 
   /**
    * Set the body from the request.
+   * Also sets the body as a request info property.
    *
    * @param body the request body
    */
   public void setBody(String body) {
     if (body != null && ! body.isEmpty()) {
       m_body = body;
+      m_requestInfoProps.put("RAW_REQUEST_BODY", body);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/fcc6a4cc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ArtifactResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ArtifactResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ArtifactResourceProvider.java
index b3eb159..e476f62 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ArtifactResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ArtifactResourceProvider.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import com.google.gson.Gson;
 import com.google.inject.Inject;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.DuplicateResourceException;
@@ -105,6 +106,11 @@ public class ArtifactResourceProvider extends AbstractResourceProvider {
       new HashMap<String, TypeRegistration>();
 
   /**
+   * serializer used to convert json to map
+   */
+  private static final Gson jsonSerializer = new Gson();
+
+  /**
    * artifact data access object
    */
   @Inject
@@ -181,7 +187,7 @@ public class ArtifactResourceProvider extends AbstractResourceProvider {
              NoSuchParentResourceException {
 
     for (Map<String, Object> properties : request.getProperties()) {
-      createResources(getCreateCommand(properties));
+      createResources(getCreateCommand(properties, request.getRequestInfoProperties()));
     }
     notifyCreate(Resource.Type.Artifact, request);
 
@@ -232,11 +238,13 @@ public class ArtifactResourceProvider extends AbstractResourceProvider {
   /**
    * Create a command to create the resource.
    *
-   * @param properties  request properties
+   * @param properties        request properties
+   * @param requestInfoProps  request info properties
    *
    * @return a new create command
    */
-  private Command<Void> getCreateCommand(final Map<String, Object> properties) {
+  private Command<Void> getCreateCommand(final Map<String, Object> properties,
+                                         final Map<String, String> requestInfoProps) {
     return new Command<Void>() {
       @Override
       public Void invoke() throws AmbariException {
@@ -255,7 +263,7 @@ public class ArtifactResourceProvider extends AbstractResourceProvider {
         LOG.debug("Creating Artifact Resource with name '{}'. Parent information: {}",
             artifactName, getRequestForeignKeys(properties));
 
-        artifactDAO.create(toEntity(properties));
+        artifactDAO.create(toEntity(properties, requestInfoProps.get(Request.REQUEST_INFO_BODY_PROPERTY)));
 
         return null;
       }
@@ -369,7 +377,8 @@ public class ArtifactResourceProvider extends AbstractResourceProvider {
    *
    * @return new artifact entity
    */
-  private ArtifactEntity toEntity(Map<String, Object> properties)
+  @SuppressWarnings("unchecked")
+  private ArtifactEntity toEntity(Map<String, Object> properties, String rawRequestBody)
       throws AmbariException {
 
     String name = (String) properties.get(ARTIFACT_NAME_PROPERTY);
@@ -379,17 +388,17 @@ public class ArtifactResourceProvider extends AbstractResourceProvider {
 
     ArtifactEntity artifact = new ArtifactEntity();
     artifact.setArtifactName(name);
-    Map<String, Object> dataMap = new HashMap<String, Object>();
-    for (Map.Entry<String, Object> entry : properties.entrySet()) {
-      String key = entry.getKey();
-      //todo: should we handle scalar value?
-      if (key.startsWith(ARTIFACT_DATA_PROPERTY)) {
-        dataMap.put(key.split("/")[1], entry.getValue());
-      }
-    }
-    artifact.setArtifactData(dataMap);
     artifact.setForeignKeys(createForeignKeyMap(properties));
 
+    Map<String, Object> rawBodyMap = jsonSerializer.<Map<String, Object>>fromJson(
+        rawRequestBody, Map.class);
+
+    Object artifactData = rawBodyMap.get(ARTIFACT_DATA_PROPERTY);
+    if (! (artifactData instanceof Map)) {
+      throw new IllegalArgumentException("artifact_data property must be a map");
+    }
+    artifact.setArtifactData((Map<String, Object>) artifactData);
+
     return artifact;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/fcc6a4cc/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Request.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Request.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Request.java
index f937a4c..50eed9a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Request.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Request.java
@@ -26,6 +26,10 @@ import java.util.Set;
  * temporal (date range) information, if any, for each requested property.
  */
 public interface Request {
+  /**
+   * Constant for request info property which contains the raw request body.
+   */
+  public static final String REQUEST_INFO_BODY_PROPERTY = "RAW_REQUEST_BODY";
 
   /**
    * Get the set of property ids being requested.  Used for requests to get

http://git-wip-us.apache.org/repos/asf/ambari/blob/fcc6a4cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParserTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParserTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParserTest.java
index 8b78524..f89b1b3 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParserTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParserTest.java
@@ -552,10 +552,11 @@ public class JsonRequestBodyParserTest {
     assertEquals("foo=bar", body.getQueryString());
 
     Map<String, String > mapRequestInfoProps = body.getRequestInfoProperties();
-    assertEquals(3, mapRequestInfoProps.size());
+    assertEquals(4, mapRequestInfoProps.size());
     assertEquals("val1", mapRequestInfoProps.get("prop1"));
     assertEquals("val2", mapRequestInfoProps.get("prop2"));
     assertEquals("foo=bar", mapRequestInfoProps.get("query"));
+    assertEquals(bodyWithRequestInfoProperties, mapRequestInfoProps.get("RAW_REQUEST_BODY"));
 
     //assert body is correct by checking that properties match
     String b = body.getBody();

http://git-wip-us.apache.org/repos/asf/ambari/blob/fcc6a4cc/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ArtifactResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ArtifactResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ArtifactResourceProviderTest.java
index 4ed1a51..046c5d8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ArtifactResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ArtifactResourceProviderTest.java
@@ -35,6 +35,7 @@ import javax.persistence.EntityManager;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -62,7 +63,7 @@ public class ArtifactResourceProviderTest {
   private ArtifactDAO dao = createStrictMock(ArtifactDAO.class);
   private EntityManager em = createStrictMock(EntityManager.class);
   private AmbariManagementController controller = createStrictMock(AmbariManagementController.class);
-  private Request request = createStrictMock(Request.class);
+  private Request request = createMock(Request.class);
   private Clusters clusters = createStrictMock(Clusters.class);
   private Cluster cluster = createStrictMock(Cluster.class);
   private ArtifactEntity entity = createMock(ArtifactEntity.class);
@@ -83,7 +84,20 @@ public class ArtifactResourceProviderTest {
     TreeMap<String, String> foreignKeys = new TreeMap<String, String>();
     foreignKeys.put("cluster", "500");
 
-    Map<String, Object> artifact_data = Collections.<String, Object>singletonMap("foo", "bar");
+    Map<String, Object> childMap = new TreeMap<String, Object>();
+    childMap.put("childKey", "childValue");
+    Map<String, Object> child2Map = new TreeMap<String, Object>();
+    childMap.put("child2", child2Map);
+    child2Map.put("child2Key", "child2Value");
+    Map<String, Object> child3Map = new TreeMap<String, Object>();
+    child2Map.put("child3", child3Map);
+    Map<String, Object> child4Map = new TreeMap<String, Object>();
+    child3Map.put("child4", child4Map);
+    child4Map.put("child4Key", "child4Value");
+
+    Map<String, Object> artifact_data = new TreeMap<String, Object>();
+    artifact_data.put("foo", "bar");
+    artifact_data.put("child", childMap);
 
     Map<String, String> responseForeignKeys = new HashMap<String, String>();
     responseForeignKeys.put("cluster", "500");
@@ -113,9 +127,18 @@ public class ArtifactResourceProviderTest {
     Set<Resource> response = resourceProvider.getResources(request, predicate);
     assertEquals(1, response.size());
     Resource resource = response.iterator().next();
+    Map<String, Map<String, Object>> responseProperties = resource.getPropertiesMap();
+    assertEquals(5, responseProperties.size());
+
+    Map<String, Object> artifactDataMap = responseProperties.get("artifact_data");
+    assertEquals("bar", artifactDataMap.get("foo"));
+
     assertEquals("test-artifact", resource.getPropertyValue("Artifacts/artifact_name"));
     assertEquals("test-cluster", resource.getPropertyValue("Artifacts/cluster_name"));
     assertEquals("bar", resource.getPropertyValue("artifact_data/foo"));
+    assertEquals("childValue", resource.getPropertyValue("artifact_data/child/childKey"));
+    assertEquals("child2Value", resource.getPropertyValue("artifact_data/child/child2/child2Key"));
+    assertEquals("child4Value", resource.getPropertyValue("artifact_data/child/child2/child3/child4/child4Key"));
   }
 
   @Test
@@ -183,19 +206,100 @@ public class ArtifactResourceProviderTest {
   @Test
   public void testCreateResource() throws Exception {
     Capture<ArtifactEntity> createEntityCapture = new Capture<ArtifactEntity>();
-
-    Map<String, Object> artifact_data = Collections.<String, Object>singletonMap("foo", "bar");
+    Map<String, Object> outerMap = new TreeMap<String, Object>();
+    Map<String, Object> childMap = new TreeMap<String, Object>();
+    outerMap.put("child", childMap);
+    childMap.put("childKey", "childValue");
+    Map<String, Object> child2Map = new TreeMap<String, Object>();
+    childMap.put("child2", child2Map);
+    child2Map.put("child2Key", "child2Value");
+    Map<String, Object> child3Map = new TreeMap<String, Object>();
+    child2Map.put("child3", child3Map);
+    Map<String, Object> child4Map = new TreeMap<String, Object>();
+    child3Map.put("child4", child4Map);
+    child4Map.put("child4Key", "child4Value");
+
+    Set<Map<String, Object>> propertySet = new HashSet<Map<String, Object>>();
+    propertySet.add(outerMap);
+    propertySet.add(child4Map);
+
+    Map<String, Object> artifact_data = new TreeMap<String, Object>();
+    artifact_data.put("foo", "bar");
+    artifact_data.put("child", childMap);
+    artifact_data.put("collection", propertySet);
 
     TreeMap<String, String> foreignKeys = new TreeMap<String, String>();
     foreignKeys.put("cluster", "500");
 
+
+    String bodyJson =
+        "{ " +
+        "  \"artifact_data\" : {" +
+        "    \"foo\" : \"bar\"," +
+        "    \"child\" : {" +
+        "      \"childKey\" : \"childValue\"," +
+        "      \"child2\" : {" +
+        "        \"child2Key\" : \"child2Value\"," +
+        "        \"child3\" : {" +
+        "          \"child4\" : {" +
+        "            \"child4Key\" : \"child4Value\"" +
+        "          }" +
+        "        }" +
+        "      }" +
+        "    }," +
+        "    \"collection\" : [" +
+        "      {" +
+        "        \"child\" : {" +
+        "          \"childKey\" : \"childValue\"," +
+        "          \"child2\" : {" +
+        "            \"child2Key\" : \"child2Value\"," +
+        "            \"child3\" : {" +
+        "              \"child4\" : {" +
+        "                \"child4Key\" : \"child4Value\"" +
+        "              }" +
+        "            }" +
+        "          }" +
+        "        }" +
+        "      }," +
+        "      {" +
+        "        \"child4Key\" : \"child4Value\"" +
+        "      } " +
+        "    ]" +
+        "  }" +
+        "}";
+
+    Map<String, String> requestInfoProps = new HashMap<String, String>();
+    requestInfoProps.put(Request.REQUEST_INFO_BODY_PROPERTY, bodyJson);
+
+
+    // map with flattened properties
     Map<String, Object> properties = new HashMap<String, Object>();
     properties.put("Artifacts/artifact_name", "test-artifact");
     properties.put("Artifacts/cluster_name", "test-cluster");
     properties.put("artifact_data/foo", "bar");
+    properties.put("artifact_data/child/childKey", "childValue");
+    properties.put("artifact_data/child/child2/child2Key", "child2Value");
+    properties.put("artifact_data/child/child2/child3/child4/child4Key", "child4Value");
+
+    Collection<Object> collectionProperties = new HashSet<Object>();
+    properties.put("artifact_data/collection", collectionProperties);
+
+    // collection with maps of flattened properties
+    Map<String, Object> map1 = new TreeMap<String, Object>();
+    collectionProperties.add(map1);
+    map1.put("foo", "bar");
+    map1.put("child/childKey", "childValue");
+    map1.put("child/child2/child2Key", "child2Value");
+    map1.put("child/child2/child3/child4/child4Key", "child4Value");
+
+    Map<String, Object> map2 = new TreeMap<String, Object>();
+    collectionProperties.add(map2);
+    map2.put("child4Key", "child4Value");
+
     Set<Map<String, Object>> requestProperties = Collections.singleton(properties);
 
     // expectations
+    expect(request.getRequestInfoProperties()).andReturn(requestInfoProps).anyTimes();
     expect(request.getProperties()).andReturn(requestProperties).anyTimes();
     expect(controller.getClusters()).andReturn(clusters).anyTimes();
     expect(clusters.getCluster("test-cluster")).andReturn(cluster).anyTimes();
@@ -215,7 +319,13 @@ public class ArtifactResourceProviderTest {
 
     ArtifactEntity createEntity = createEntityCapture.getValue();
     assertEquals("test-artifact", createEntity.getArtifactName());
-    assertEquals(createEntity.getArtifactData(), artifact_data);
+    Map<String, Object> actualArtifactData = createEntity.getArtifactData();
+    // need to decompose actualArtifactData because actualArtifactData.get("collection") returns a set
+    // implementation that does not equal an identical(same elements) HashSet instance
+    assertEquals(artifact_data.size(), actualArtifactData.size());
+    assertEquals(artifact_data.get("foo"), actualArtifactData.get("foo"));
+    assertEquals(artifact_data.get("child"), actualArtifactData.get("child"));
+    assertEquals(artifact_data.get("collection"), new HashSet(((Collection) actualArtifactData.get("collection"))));
     assertEquals(foreignKeys, createEntity.getForeignKeys());
   }