Bump MRI upstreams
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / jersey / providers / NormalizedNodeJsonBodyWriter.java
index e3c8b5996f684c49d6976b768ca1ae325c0d0ac7..0a040f44fb0037bff91d00901c89296e716a900f 100644 (file)
@@ -14,9 +14,9 @@ import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
-import java.net.URI;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import javax.ws.rs.Produces;
 import javax.ws.rs.WebApplicationException;
@@ -26,28 +26,28 @@ import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
 import org.opendaylight.restconf.common.context.NormalizedNodeContext;
-import org.opendaylight.restconf.nb.rfc8040.Rfc8040;
+import org.opendaylight.restconf.nb.rfc8040.MediaTypes;
 import org.opendaylight.restconf.nb.rfc8040.jersey.providers.api.RestconfNormalizedNodeWriter;
-import org.opendaylight.restconf.nb.rfc8040.utils.RestconfConstants;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 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.JSONCodecFactory;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
 import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
+import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 
 @Provider
-@Produces({ Rfc8040.MediaTypes.DATA + RestconfConstants.JSON, MediaType.APPLICATION_JSON })
+@Produces({ MediaTypes.APPLICATION_YANG_DATA_JSON, MediaType.APPLICATION_JSON })
 public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<NormalizedNodeContext> {
 
     private static final int DEFAULT_INDENT_SPACES_NUM = 2;
@@ -77,7 +77,7 @@ public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<Normalize
                         final MediaType mediaType,
                         final MultivaluedMap<String, Object> httpHeaders,
                         final OutputStream entityStream) throws IOException, WebApplicationException {
-        final NormalizedNode<?, ?> data = context.getData();
+        final NormalizedNode data = context.getData();
         if (data == null) {
             return;
         }
@@ -86,18 +86,24 @@ public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<Normalize
         final InstanceIdentifierContext<SchemaNode> identifierCtx =
                 (InstanceIdentifierContext<SchemaNode>) context.getInstanceIdentifierContext();
         final SchemaPath path = identifierCtx.getSchemaNode().getPath();
-        final JsonWriter jsonWriter = createJsonWriter(entityStream,
-                context.getWriterParameters().isPrettyPrint());
-
-        jsonWriter.beginObject();
-        writeNormalizedNode(jsonWriter, path, identifierCtx, data,
-                context.getWriterParameters().getDepth(), context.getWriterParameters().getFields());
-        jsonWriter.endObject();
-        jsonWriter.flush();
+
+        try (JsonWriter jsonWriter = createJsonWriter(entityStream, context.getWriterParameters().isPrettyPrint())) {
+            jsonWriter.beginObject();
+            writeNormalizedNode(jsonWriter, path, identifierCtx, data,
+                    context.getWriterParameters().getDepth(), context.getWriterParameters().getFields());
+            jsonWriter.endObject();
+            jsonWriter.flush();
+        }
+
+        if (httpHeaders != null) {
+            for (final Map.Entry<String, Object> entry : context.getNewHeaders().entrySet()) {
+                httpHeaders.add(entry.getKey(), entry.getValue());
+            }
+        }
     }
 
     private static void writeNormalizedNode(final JsonWriter jsonWriter,
-            final SchemaPath path, final InstanceIdentifierContext<SchemaNode> context, final NormalizedNode<?, ?> data,
+            final SchemaPath path, final InstanceIdentifierContext<SchemaNode> context, final NormalizedNode data,
             final Integer depth, final List<Set<QName>> fields) throws IOException {
         final RestconfNormalizedNodeWriter nnWriter;
 
@@ -112,7 +118,22 @@ public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<Normalize
                     jsonWriter,
                     depth,
                     fields);
-            jsonWriter.name("output");
+            final Module module = context.getSchemaContext().findModule(data.getIdentifier().getNodeType().getModule())
+                .get();
+            jsonWriter.name(module.getName() + ":output");
+            jsonWriter.beginObject();
+            writeChildren(nnWriter, (ContainerNode) data);
+            jsonWriter.endObject();
+        } else if (context.getSchemaNode() instanceof ActionDefinition) {
+            /*
+             *  ActionDefinition is not supported as initial codec in JSONStreamWriter,
+             *  so we need to emit initial output declaration..
+             */
+            nnWriter = createNormalizedNodeWriter(context,
+                ((ActionDefinition) context.getSchemaNode()).getOutput().getPath(), jsonWriter, depth, fields);
+            final Module module = context.getSchemaContext().findModule(data.getIdentifier().getNodeType().getModule())
+                .get();
+            jsonWriter.name(module.getName() + ":output");
             jsonWriter.beginObject();
             writeChildren(nnWriter, (ContainerNode) data);
             jsonWriter.endObject();
@@ -126,8 +147,9 @@ public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<Normalize
             if (data instanceof MapEntryNode) {
                 // Restconf allows returning one list item. We need to wrap it
                 // in map node in order to serialize it properly
-                nnWriter.write(
-                        ImmutableNodes.mapNodeBuilder(data.getNodeType()).withChild((MapEntryNode) data).build());
+                nnWriter.write(ImmutableNodes.mapNodeBuilder(data.getIdentifier().getNodeType())
+                    .withChild((MapEntryNode) data)
+                    .build());
             } else {
                 nnWriter.write(data);
             }
@@ -136,9 +158,9 @@ public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<Normalize
         nnWriter.flush();
     }
 
-    private static void writeChildren(final RestconfNormalizedNodeWriter nnWriter,
-                                      final ContainerNode data) throws IOException {
-        for (final DataContainerChild<? extends PathArgument, ?> child : data.getValue()) {
+    private static void writeChildren(final RestconfNormalizedNodeWriter nnWriter, final ContainerNode data)
+            throws IOException {
+        for (final DataContainerChild child : data.body()) {
             nnWriter.write(child);
         }
     }
@@ -150,21 +172,20 @@ public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<Normalize
         final SchemaNode schema = context.getSchemaNode();
         final JSONCodecFactory codecs = getCodecFactory(context);
 
-        final URI initialNs;
-        if (schema instanceof DataSchemaNode
-                && !((DataSchemaNode)schema).isAugmenting()
-                && !(schema instanceof SchemaContext)) {
-            initialNs = schema.getQName().getNamespace();
-        } else if (schema instanceof RpcDefinition) {
-            initialNs = schema.getQName().getNamespace();
-        } else {
-            initialNs = null;
-        }
         final NormalizedNodeStreamWriter streamWriter = JSONNormalizedNodeStreamWriter.createNestedWriter(
-                codecs, path, initialNs, jsonWriter);
+                codecs, path, initialNamespaceFor(schema), jsonWriter);
+
         return ParameterAwareNormalizedNodeWriter.forStreamWriter(streamWriter, depth, fields);
     }
 
+    private static XMLNamespace initialNamespaceFor(final SchemaNode schema) {
+        if (schema instanceof RpcDefinition) {
+            return schema.getQName().getNamespace();
+        }
+        // For top-level elements we always want to use namespace prefix, hence use a null initial namespace
+        return null;
+    }
+
     private static JsonWriter createJsonWriter(final OutputStream entityStream, final boolean prettyPrint) {
         if (prettyPrint) {
             return JsonWriterFactory.createJsonWriter(
@@ -175,6 +196,6 @@ public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<Normalize
 
     private static JSONCodecFactory getCodecFactory(final InstanceIdentifierContext<?> context) {
         // TODO: Performance: Cache JSON Codec factory and schema context
-        return JSONCodecFactory.getShared(context.getSchemaContext());
+        return JSONCodecFactorySupplier.RFC7951.getShared(context.getSchemaContext());
     }
 }