Bump versions to 4.0.0-SNAPSHOT
[netconf.git] / restconf / restconf-nb-bierman02 / src / main / java / org / opendaylight / netconf / sal / rest / impl / RestconfDocumentedExceptionMapper.java
index b6ad9da112494781a3672b6217242ea4b7aada75..ff0be39a807e4a41f232d143e1a62959d4e4f75a 100644 (file)
@@ -10,9 +10,7 @@ package org.opendaylight.netconf.sal.rest.impl;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
-import static org.opendaylight.netconf.sal.rest.api.Draft02.RestConfModule.ERRORS_CONTAINER_QNAME;
 
-import com.google.common.collect.Iterables;
 import com.google.gson.stream.JsonWriter;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -20,7 +18,6 @@ import java.io.OutputStreamWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.stream.Collectors;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
@@ -33,7 +30,7 @@ import javax.xml.stream.FactoryConfigurationError;
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
-import org.opendaylight.netconf.sal.rest.api.Draft02.RestConfModule;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
 import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
 import org.opendaylight.restconf.common.ErrorTags;
 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
@@ -41,11 +38,8 @@ import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
 import org.opendaylight.restconf.common.errors.RestconfError;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.XMLNamespace;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 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;
@@ -62,14 +56,10 @@ import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
 import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -86,11 +76,6 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
 
     private static final XMLOutputFactory XML_FACTORY;
 
-    private static final YangInstanceIdentifier ERRORS = YangInstanceIdentifier.builder()
-            .node(ERRORS_CONTAINER_QNAME)
-            .node(ERRORS_CONTAINER_QNAME)
-            .build();
-
     static {
         XML_FACTORY = XMLOutputFactory.newFactory();
         XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
@@ -131,19 +116,18 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
         }
 
         final Status status = ErrorTags.statusOf(errors.iterator().next().getErrorTag());
-        final DataNodeContainer errorsSchemaNode =
-                (DataNodeContainer) controllerContext.getRestconfModuleErrorsSchemaNode();
-        if (errorsSchemaNode == null) {
+        final var errorsEntry = controllerContext.getRestconfModuleErrorsSchemaNode();
+        if (errorsEntry == null) {
             return Response.status(status).type(MediaType.TEXT_PLAIN_TYPE).entity(exception.getMessage()).build();
         }
 
-        checkState(errorsSchemaNode instanceof ContainerSchemaNode, "Found Errors SchemaNode isn't ContainerNode");
+        final var errorsSchemaNode = errorsEntry.getValue();
         final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> errContBuild =
-                SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) errorsSchemaNode);
+                SchemaAwareBuilders.containerBuilder(errorsSchemaNode);
 
-        final List<DataSchemaNode> schemaList = ControllerContext.findInstanceDataChildrenByName(errorsSchemaNode,
-                RestConfModule.ERROR_LIST_SCHEMA_NODE);
-        final DataSchemaNode errListSchemaNode = Iterables.getFirst(schemaList, null);
+        final var schemaList = ControllerContext.findInstanceDataChildrenByName(errorsSchemaNode,
+                Draft02.RestConfModule.ERROR_LIST_SCHEMA_NODE);
+        final DataSchemaNode errListSchemaNode = ControllerContext.getFirst(schemaList);
         checkState(errListSchemaNode instanceof ListSchemaNode, "Found Error SchemaNode isn't ListSchemaNode");
         final CollectionNodeBuilder<MapEntryNode, SystemMapNode> listErorsBuilder = SchemaAwareBuilders
                 .mapBuilder((ListSchemaNode) errListSchemaNode);
@@ -154,14 +138,14 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
         }
         errContBuild.withChild(listErorsBuilder.build());
 
-        final NormalizedNodeContext errContext =  new NormalizedNodeContext(new InstanceIdentifierContext<>(ERRORS,
-                (DataSchemaNode) errorsSchemaNode, null, controllerContext.getGlobalSchema()), errContBuild.build());
+        final NormalizedNodeContext errContext = new NormalizedNodeContext(
+            InstanceIdentifierContext.ofStack(errorsEntry.getKey(), null), errContBuild.build());
 
-        Object responseBody;
+        final String responseBody;
         if (mediaType.getSubtype().endsWith("json")) {
-            responseBody = toJsonResponseBody(errContext, errorsSchemaNode);
+            responseBody = toJsonResponseBody(errContext);
         } else {
-            responseBody = toXMLResponseBody(errContext, errorsSchemaNode);
+            responseBody = toXMLResponseBody(errContext);
         }
 
         return Response.status(status).type(mediaType).entity(responseBody).build();
@@ -174,16 +158,16 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> errNodeValues = SchemaAwareBuilders
                 .mapEntryBuilder(listStreamSchemaNode);
 
-        List<DataSchemaNode> lsChildDataSchemaNode = ControllerContext.findInstanceDataChildrenByName(
+        var lsChildDataSchemaNode = ControllerContext.findInstanceDataChildrenByName(
                 listStreamSchemaNode, "error-type");
-        final DataSchemaNode errTypSchemaNode = Iterables.getFirst(lsChildDataSchemaNode, null);
+        final DataSchemaNode errTypSchemaNode = ControllerContext.getFirst(lsChildDataSchemaNode);
         checkState(errTypSchemaNode instanceof LeafSchemaNode);
         errNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) errTypSchemaNode)
                 .withValue(error.getErrorType().elementBody()).build());
 
         lsChildDataSchemaNode = ControllerContext.findInstanceDataChildrenByName(
                 listStreamSchemaNode, "error-tag");
-        final DataSchemaNode errTagSchemaNode = Iterables.getFirst(lsChildDataSchemaNode, null);
+        final DataSchemaNode errTagSchemaNode = ControllerContext.getFirst(lsChildDataSchemaNode);
         checkState(errTagSchemaNode instanceof LeafSchemaNode);
         errNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) errTagSchemaNode)
                 .withValue(error.getErrorTag().elementBody()).build());
@@ -191,7 +175,7 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
         if (error.getErrorAppTag() != null) {
             lsChildDataSchemaNode = ControllerContext.findInstanceDataChildrenByName(
                     listStreamSchemaNode, "error-app-tag");
-            final DataSchemaNode errAppTagSchemaNode = Iterables.getFirst(lsChildDataSchemaNode, null);
+            final DataSchemaNode errAppTagSchemaNode = ControllerContext.getFirst(lsChildDataSchemaNode);
             checkState(errAppTagSchemaNode instanceof LeafSchemaNode);
             errNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) errAppTagSchemaNode)
                     .withValue(error.getErrorAppTag()).build());
@@ -199,7 +183,7 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
 
         lsChildDataSchemaNode = ControllerContext.findInstanceDataChildrenByName(
                 listStreamSchemaNode, "error-message");
-        final DataSchemaNode errMsgSchemaNode = Iterables.getFirst(lsChildDataSchemaNode, null);
+        final DataSchemaNode errMsgSchemaNode = ControllerContext.getFirst(lsChildDataSchemaNode);
         checkState(errMsgSchemaNode instanceof LeafSchemaNode);
         errNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) errMsgSchemaNode)
                 .withValue(error.getErrorMessage()).build());
@@ -208,7 +192,7 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
             // Oddly, error-info is defined as an empty container in the restconf yang. Apparently the
             // intention is for implementors to define their own data content so we'll just treat it as a leaf
             // with string data.
-            errNodeValues.withChild(ImmutableNodes.leafNode(RestConfModule.ERROR_INFO_QNAME,
+            errNodeValues.withChild(ImmutableNodes.leafNode(Draft02.RestConfModule.ERROR_INFO_QNAME,
                     error.getErrorInfo()));
         }
 
@@ -217,11 +201,10 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
         return errNodeValues.build();
     }
 
-    private static Object toJsonResponseBody(final NormalizedNodeContext errorsNode,
-                                             final DataNodeContainer errorsSchemaNode) {
+    private static String toJsonResponseBody(final NormalizedNodeContext errorsNode) {
         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
         NormalizedNode data = errorsNode.getData();
-        final InstanceIdentifierContext<?> context = errorsNode.getInstanceIdentifierContext();
+        final InstanceIdentifierContext context = errorsNode.getInstanceIdentifierContext();
         final DataSchemaNode schema = (DataSchemaNode) context.getSchemaNode();
 
         final OutputStreamWriter outputWriter = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);
@@ -229,28 +212,25 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
             throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
         }
 
-        boolean isDataRoot = false;
-        XMLNamespace initialNs = null;
-        SchemaPath path;
-        if (context.getSchemaNode() instanceof SchemaContext) {
+        final boolean isDataRoot;
+        final var stack = context.inference().toSchemaInferenceStack();
+        if (stack.isEmpty()) {
             isDataRoot = true;
-            path = SchemaPath.ROOT;
         } else {
-            final List<QName> qNames = context.getInstanceIdentifier().getPathArguments().stream()
-                    .filter(arg -> !(arg instanceof NodeIdentifierWithPredicates))
-                    .filter(arg -> !(arg instanceof AugmentationIdentifier))
-                    .map(PathArgument::getNodeType)
-                    .collect(Collectors.toList());
-            path = SchemaPath.of(Absolute.of(qNames)).getParent();
+            isDataRoot = false;
+            stack.exit();
+            // FIXME: Add proper handling of reading root.
         }
+
+        XMLNamespace initialNs = null;
         if (!schema.isAugmenting() && !(schema instanceof SchemaContext)) {
             initialNs = schema.getQName().getNamespace();
         }
 
         final JsonWriter jsonWriter = JsonWriterFactory.createJsonWriter(outputWriter);
         final NormalizedNodeStreamWriter jsonStreamWriter = JSONNormalizedNodeStreamWriter.createExclusiveWriter(
-            JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(context.getSchemaContext()), path,
-            initialNs, jsonWriter);
+            JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(context.getSchemaContext()),
+            stack.toInference(), initialNs, jsonWriter);
 
         // We create a delegating writer to special-case error-info as error-info is defined as an empty
         // container in the restconf yang schema but we create a leaf node so we can output it. The delegate
@@ -267,9 +247,9 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
 
             @Override
             public void startLeafNode(final NodeIdentifier name) throws IOException {
-                if (name.getNodeType().equals(RestConfModule.ERROR_INFO_QNAME)) {
+                if (name.getNodeType().equals(Draft02.RestConfModule.ERROR_INFO_QNAME)) {
                     inOurLeaf = true;
-                    jsonWriter.name(RestConfModule.ERROR_INFO_QNAME.getLocalName());
+                    jsonWriter.name(Draft02.RestConfModule.ERROR_INFO_QNAME.getLocalName());
                 } else {
                     super.startLeafNode(name);
                 }
@@ -321,9 +301,8 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
         return outStream.toString(StandardCharsets.UTF_8);
     }
 
-    private static Object toXMLResponseBody(final NormalizedNodeContext errorsNode,
-                                            final DataNodeContainer errorsSchemaNode) {
-        final InstanceIdentifierContext<?> pathContext = errorsNode.getInstanceIdentifierContext();
+    private static String toXMLResponseBody(final NormalizedNodeContext errorsNode) {
+        final InstanceIdentifierContext pathContext = errorsNode.getInstanceIdentifierContext();
         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
 
         final XMLStreamWriter xmlWriter;
@@ -333,22 +312,18 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
             throw new IllegalStateException(e);
         }
         NormalizedNode data = errorsNode.getData();
-        SchemaPath schemaPath;
-        boolean isDataRoot = false;
-        if (pathContext.getSchemaNode() instanceof SchemaContext) {
+
+        final boolean isDataRoot;
+        final var stack = pathContext.inference().toSchemaInferenceStack();
+        if (stack.isEmpty()) {
             isDataRoot = true;
-            schemaPath = SchemaPath.ROOT;
         } else {
-            final List<QName> qNames = pathContext.getInstanceIdentifier().getPathArguments().stream()
-                    .filter(arg -> !(arg instanceof NodeIdentifierWithPredicates))
-                    .filter(arg -> !(arg instanceof AugmentationIdentifier))
-                    .map(PathArgument::getNodeType)
-                    .collect(Collectors.toList());
-            schemaPath = SchemaPath.of(Absolute.of(qNames)).getParent();
+            isDataRoot = false;
+            stack.exit();
         }
 
         final NormalizedNodeStreamWriter xmlStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,
-                pathContext.getSchemaContext(), schemaPath);
+                stack.toInference());
 
         // We create a delegating writer to special-case error-info as error-info is defined as an empty
         // container in the restconf yang schema but we create a leaf node so we can output it. The delegate
@@ -365,11 +340,11 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
 
             @Override
             public void startLeafNode(final NodeIdentifier name) throws IOException {
-                if (name.getNodeType().equals(RestConfModule.ERROR_INFO_QNAME)) {
-                    String ns = RestConfModule.ERROR_INFO_QNAME.getNamespace().toString();
+                if (name.getNodeType().equals(Draft02.RestConfModule.ERROR_INFO_QNAME)) {
+                    String ns = Draft02.RestConfModule.ERROR_INFO_QNAME.getNamespace().toString();
                     try {
                         xmlWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX,
-                                RestConfModule.ERROR_INFO_QNAME.getLocalName(), ns);
+                                Draft02.RestConfModule.ERROR_INFO_QNAME.getLocalName(), ns);
                     } catch (XMLStreamException e) {
                         throw new IOException("Error writing error-info", e);
                     }