Bug 2983 - POST operation to list only accepts data for keys
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / rest / impl / JsonNormalizedNodeBodyReader.java
index dc989d2786baf14d33d762e5b40a2ff6ed283713..5d63c9c01162733a2b0734f17f5e0890a3346370 100644 (file)
@@ -7,7 +7,7 @@
  */
 package org.opendaylight.controller.sal.rest.impl;
 
-import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
 import com.google.gson.stream.JsonReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -27,10 +27,20 @@ import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
 import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.data.impl.schema.ResultAlreadySetException;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,14 +63,56 @@ public class JsonNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPr
             final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream) throws IOException,
             WebApplicationException {
         try {
-            Optional<InstanceIdentifierContext> path = getIdentifierWithSchema();
-            NormalizedNodeResult resultHolder = new NormalizedNodeResult();
-            NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
-            JsonParserStream jsonParser = JsonParserStream.create(writer, path.get().getSchemaContext());
-            JsonReader reader = new JsonReader(new InputStreamReader(entityStream));
+            final InstanceIdentifierContext<?> path = getInstanceIdentifierContext();
+            if (entityStream.available() < 1) {
+                return new NormalizedNodeContext(path, null);
+            }
+            final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+            final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+
+            final SchemaNode parentSchema;
+            if(isPost()) {
+                // FIXME: We need dispatch for RPC.
+                parentSchema = path.getSchemaNode();
+            } else if(path.getSchemaNode() instanceof SchemaContext) {
+                parentSchema = path.getSchemaContext();
+            } else {
+                if (SchemaPath.ROOT.equals(path.getSchemaNode().getPath().getParent())) {
+                    parentSchema = path.getSchemaContext();
+                } else {
+                    parentSchema = SchemaContextUtil.findDataSchemaNode(path.getSchemaContext(), path.getSchemaNode().getPath().getParent());
+                }
+            }
+
+            final JsonParserStream jsonParser = JsonParserStream.create(writer, path.getSchemaContext(), parentSchema);
+            final JsonReader reader = new JsonReader(new InputStreamReader(entityStream));
             jsonParser.parse(reader);
-            return new NormalizedNodeContext(path.get(),resultHolder.getResult());
-        } catch (Exception e) {
+
+            NormalizedNode<?, ?> partialResult = resultHolder.getResult();
+            final NormalizedNode<?, ?> result;
+
+            // FIXME: Also II should be updated unwrap result from augmentation and choice nodes on PUT
+            if (!isPost()) {
+                while (partialResult instanceof AugmentationNode || partialResult instanceof ChoiceNode) {
+                    final Object childNode = ((DataContainerNode) partialResult).getValue().iterator().next();
+                    partialResult = (NormalizedNode<?, ?>) childNode;
+                }
+            }
+
+            if (partialResult instanceof MapNode && !isPost()) {
+                result = Iterables.getOnlyElement(((MapNode) partialResult).getValue());
+            } else {
+                result = partialResult;
+            }
+            return new NormalizedNodeContext(path,result);
+        } catch (final RestconfDocumentedException e) {
+            throw e;
+        } catch (final ResultAlreadySetException e) {
+            LOG.debug("Error parsing json input:", e);
+
+            throw new RestconfDocumentedException("Error parsing json input: Failed to create new parse result data. " +
+                    "Are you creating multiple resources/subresources in POST request?");
+        } catch (final Exception e) {
             LOG.debug("Error parsing json input", e);
 
             throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL,