Integrate netconf-mapping-api into netconf-server
[netconf.git] / netconf / mdsal-netconf-connector / src / main / java / org / opendaylight / netconf / mdsal / connector / ops / get / AbstractGet.java
index 94a7bfb2477d954bbcc20cf8bc26e9b7d7033598..d0e7686835aa334e66286e223df4aabbe422a740 100644 (file)
@@ -7,8 +7,9 @@
  */
 package org.opendaylight.netconf.mdsal.connector.ops.get;
 
+import static com.google.common.base.Preconditions.checkArgument;
+
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Iterables;
 import java.io.IOException;
 import java.util.Optional;
 import javax.xml.stream.XMLOutputFactory;
@@ -16,34 +17,29 @@ import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 import javax.xml.transform.dom.DOMResult;
 import org.opendaylight.netconf.api.DocumentedException;
-import org.opendaylight.netconf.api.DocumentedException.ErrorTag;
-import org.opendaylight.netconf.api.DocumentedException.ErrorType;
 import org.opendaylight.netconf.api.xml.XmlElement;
 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.netconf.mdsal.connector.CurrentSchemaContext;
 import org.opendaylight.netconf.mdsal.connector.ops.Datastore;
-import org.opendaylight.netconf.util.mapping.AbstractSingletonNetconfOperation;
+import org.opendaylight.netconf.server.api.operations.AbstractSingletonNetconfOperation;
 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-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;
-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.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.YangInstanceIdentifierWriter;
 import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
-public abstract class AbstractGet extends AbstractSingletonNetconfOperation {
+// FIXME: seal when we have JDK17+
+abstract class AbstractGet extends AbstractSingletonNetconfOperation {
     private static final XMLOutputFactory XML_OUTPUT_FACTORY;
-    private static final YangInstanceIdentifier ROOT = YangInstanceIdentifier.empty();
     private static final String FILTER = "filter";
 
     static {
@@ -51,94 +47,72 @@ public abstract class AbstractGet extends AbstractSingletonNetconfOperation {
         XML_OUTPUT_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
     }
 
-    protected final CurrentSchemaContext schemaContext;
+    private final CurrentSchemaContext schemaContext;
     private final FilterContentValidator validator;
 
-    public AbstractGet(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext) {
+    AbstractGet(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext) {
         super(netconfSessionIdForReporting);
         this.schemaContext = schemaContext;
-        this.validator = new FilterContentValidator(schemaContext);
+        validator = new FilterContentValidator(schemaContext);
     }
 
-    protected Node transformNormalizedNode(final Document document, final NormalizedNode data,
-                                           final YangInstanceIdentifier dataRoot) {
-
+    // FIXME: throw a DocumentedException
+    private Node transformNormalizedNode(final Document document, final NormalizedNode data,
+                                         final YangInstanceIdentifier dataRoot) {
         final DOMResult result = new DOMResult(document.createElement(XmlNetconfConstants.DATA_KEY));
-
         final XMLStreamWriter xmlWriter = getXmlStreamWriter(result);
+        final EffectiveModelContext currentContext = schemaContext.getCurrentContext();
 
         final NormalizedNodeStreamWriter nnStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,
-                schemaContext.getCurrentContext(), getSchemaPath(dataRoot));
-
-        final NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter, true);
+            currentContext);
 
-        if (data instanceof ContainerNode) {
-            writeRootElement(xmlWriter, nnWriter, (ContainerNode) data);
-        } else if (data instanceof MapNode) {
-            writeRootElement(xmlWriter, nnWriter, (MapNode) data);
-        } else {
-            throw new IllegalArgumentException("Unable to transform node of type: " +  data.getClass().toString()
-                    + " offending node: " + data.toString());
+        try {
+            if (dataRoot.isEmpty()) {
+                writeRoot(nnStreamWriter, data);
+            } else {
+                write(nnStreamWriter, currentContext, dataRoot.coerceParent(), data);
+            }
+        } catch (IOException e) {
+            // FIXME: throw DocumentedException
+            throw new IllegalStateException(e);
         }
 
         return result.getNode();
     }
 
-    private static XMLStreamWriter getXmlStreamWriter(final DOMResult result) {
-        try {
-            return XML_OUTPUT_FACTORY.createXMLStreamWriter(result);
-        } catch (final XMLStreamException e) {
-            throw new RuntimeException(e);
+    private static void write(final NormalizedNodeStreamWriter nnStreamWriter,
+            final EffectiveModelContext currentContext, final YangInstanceIdentifier parent, final NormalizedNode data)
+                throws IOException {
+        try (var yiidWriter = YangInstanceIdentifierWriter.open(nnStreamWriter, currentContext, parent)) {
+            try (var nnWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter, true)) {
+                nnWriter.write(data);
+            }
         }
     }
 
-    private static SchemaPath getSchemaPath(final YangInstanceIdentifier dataRoot) {
-        return SchemaPath.create(
-                Iterables.transform(dataRoot.getPathArguments(), PathArgument::getNodeType), dataRoot.equals(ROOT));
-    }
+    private static void writeRoot(final NormalizedNodeStreamWriter nnStreamWriter, final NormalizedNode data)
+            throws IOException {
+        checkArgument(data instanceof ContainerNode, "Unexpected root data %s", data);
 
-    private static void writeRootElement(final XMLStreamWriter xmlWriter, final NormalizedNodeWriter nnWriter,
-                                         final ContainerNode data) {
-        try {
-            if (data.getIdentifier().getNodeType().equals(SchemaContext.NAME)) {
-                for (final DataContainerChild child : data.body()) {
-                    nnWriter.write(child);
-                }
-            } else {
-                nnWriter.write(data);
+        try (var nnWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter, true)) {
+            for (var child : ((ContainerNode) data).body()) {
+                nnWriter.write(child);
             }
-            nnWriter.flush();
-            xmlWriter.flush();
-        } catch (XMLStreamException | IOException e) {
-            throw new RuntimeException(e);
         }
     }
 
-    private static void writeRootElement(final XMLStreamWriter xmlWriter, final NormalizedNodeWriter nnWriter,
-                                         final MapNode data) {
+    private static XMLStreamWriter getXmlStreamWriter(final DOMResult result) {
         try {
-            if (data.getIdentifier().getNodeType().equals(SchemaContext.NAME)) {
-                for (final MapEntryNode child : data.body()) {
-                    nnWriter.write(child);
-                }
-            } else {
-                nnWriter.write(data);
-            }
-            nnWriter.flush();
-            xmlWriter.flush();
-        } catch (XMLStreamException | IOException e) {
-            throw new RuntimeException(e);
+            return XML_OUTPUT_FACTORY.createXMLStreamWriter(result);
+        } catch (final XMLStreamException e) {
+            // FIXME: throw DocumentedException
+            throw new IllegalStateException(e);
         }
     }
 
-    protected Element serializeNodeWithParentStructure(final Document document, final YangInstanceIdentifier dataRoot,
-                                                       final NormalizedNode node) {
-        if (!dataRoot.equals(ROOT)) {
-            return (Element) transformNormalizedNode(document,
-                    ImmutableNodes.fromInstanceId(schemaContext.getCurrentContext(), dataRoot, node),
-                    ROOT);
-        }
-        return (Element) transformNormalizedNode(document, node, ROOT);
+    final Element serializeNodeWithParentStructure(final Document document, final YangInstanceIdentifier dataRoot,
+                                                   final NormalizedNode node) {
+        return (Element) transformNormalizedNode(document, node, dataRoot);
     }
 
     /**
@@ -150,21 +124,22 @@ public abstract class AbstractGet extends AbstractSingletonNetconfOperation {
      *      container in the response. If filter is not present we want to read the entire datastore - return ROOT.
      * @throws DocumentedException if not possible to get identifier from filter
      */
-    protected Optional<YangInstanceIdentifier> getDataRootFromFilter(final XmlElement operationElement)
+    final Optional<YangInstanceIdentifier> getDataRootFromFilter(final XmlElement operationElement)
             throws DocumentedException {
-        final Optional<XmlElement> filterElement = operationElement.getOnlyChildElementOptionally(FILTER);
-        if (filterElement.isPresent()) {
-            if (filterElement.get().getChildElements().size() == 0) {
-                return Optional.empty();
-            }
-            return Optional.of(getInstanceIdentifierFromFilter(filterElement.get()));
+        final var optFilterElement = operationElement.getOnlyChildElementOptionally(FILTER);
+        if (optFilterElement.isEmpty()) {
+            return Optional.of(YangInstanceIdentifier.empty());
         }
 
-        return Optional.of(ROOT);
+        final var filterElement = optFilterElement.orElseThrow();
+        if (filterElement.getChildElements().isEmpty()) {
+            return Optional.empty();
+        }
+        return Optional.of(getInstanceIdentifierFromFilter(filterElement));
     }
 
     @VisibleForTesting
-    protected YangInstanceIdentifier getInstanceIdentifierFromFilter(final XmlElement filterElement)
+    protected final YangInstanceIdentifier getInstanceIdentifierFromFilter(final XmlElement filterElement)
             throws DocumentedException {
 
         if (filterElement.getChildElements().size() != 1) {
@@ -204,10 +179,9 @@ public abstract class AbstractGet extends AbstractSingletonNetconfOperation {
 
         private static Optional<Datastore> parseSource(final XmlElement xml) throws DocumentedException {
             final Optional<XmlElement> sourceElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SOURCE_KEY,
-                    XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
-            return sourceElement.isPresent()
-                    ? Optional.of(Datastore.valueOf(sourceElement.get().getOnlyChildElement().getName()))
-                    : Optional.empty();
+                XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+            return sourceElement.isEmpty() ? Optional.empty()
+                : Optional.of(Datastore.valueOf(sourceElement.orElseThrow().getOnlyChildElement().getName()));
         }
 
         private static void validateInputRpc(final XmlElement xml, final String operationName) throws