From: Tomas Cere Date: Thu, 27 Jan 2022 09:55:02 +0000 (+0100) Subject: Fix RFC8040 root access X-Git-Tag: v2.0.13~9 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=netconf.git;a=commitdiff_plain;h=18096bb34f1d328a40717dccb8e9a05a32437738 Fix RFC8040 root access Requests targetting root need to be wrapped in container to conform to the RFC, otherwise we end up with multiple roots when serializing requests targetting root(either rests/data or root of mounted device). JIRA: NETCONF-853 Change-Id: I6d2a8d7b235a11779da134ed9c9abec8e8afe27c Signed-off-by: Tomas Cere Signed-off-by: Robert Varga --- diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/XmlNormalizedNodeBodyWriter.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/XmlNormalizedNodeBodyWriter.java index d9af3d4c80..81a1c17b26 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/XmlNormalizedNodeBodyWriter.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/XmlNormalizedNodeBodyWriter.java @@ -35,7 +35,6 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; 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.xml.XMLStreamNormalizedNodeStreamWriter; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.opendaylight.yangtools.yang.model.api.ActionDefinition; @@ -129,25 +128,35 @@ public class XmlNormalizedNodeBodyWriter extends AbstractNormalizedNodeBodyWrite nnWriter.write(ImmutableNodes.mapNodeBuilder(data.getIdentifier().getNodeType()) .addChild((MapEntryNode) data) .build()); - } else { - if (isRoot && data instanceof ContainerNode && ((ContainerNode) data).isEmpty()) { + } else if (isRoot) { + if (data instanceof ContainerNode && ((ContainerNode) data).isEmpty()) { writeEmptyDataNode(xmlWriter, data); } else { - nnWriter.write(data); + writeAndWrapInDataNode(xmlWriter, nnWriter, data); } + } else { + nnWriter.write(data); } } nnWriter.flush(); } - private static void writeEmptyDataNode(final XMLStreamWriter xmlWriter, final NormalizedNode data) - throws IOException { + private static RestconfNormalizedNodeWriter createNormalizedNodeWriter(final XMLStreamWriter xmlWriter, + final EffectiveModelContext schemaContext, final SchemaPath schemaPath, final DepthParam depth, + final List> fields) { + return ParameterAwareNormalizedNodeWriter.forStreamWriter( + XMLStreamNormalizedNodeStreamWriter.create(xmlWriter, schemaContext, schemaPath), depth, fields); + } + + private static void writeAndWrapInDataNode(final XMLStreamWriter xmlWriter, + final RestconfNormalizedNodeWriter nnWriter, final NormalizedNode data) throws IOException { final QName nodeType = data.getIdentifier().getNodeType(); final String namespace = nodeType.getNamespace().toString(); try { xmlWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, nodeType.getLocalName(), namespace); xmlWriter.writeDefaultNamespace(namespace); + nnWriter.write(data); xmlWriter.writeEndElement(); xmlWriter.flush(); } catch (XMLStreamException e) { @@ -155,21 +164,27 @@ public class XmlNormalizedNodeBodyWriter extends AbstractNormalizedNodeBodyWrite } } - private static RestconfNormalizedNodeWriter createNormalizedNodeWriter(final XMLStreamWriter xmlWriter, - final EffectiveModelContext schemaContext, final SchemaPath schemaPath, final DepthParam depth, - final List> fields) { - final NormalizedNodeStreamWriter xmlStreamWriter = XMLStreamNormalizedNodeStreamWriter - .create(xmlWriter, schemaContext, schemaPath); - return ParameterAwareNormalizedNodeWriter.forStreamWriter(xmlStreamWriter, depth, fields); + private static void writeEmptyDataNode(final XMLStreamWriter xmlWriter, final NormalizedNode data) + throws IOException { + final QName nodeType = data.getIdentifier().getNodeType(); + final String namespace = nodeType.getNamespace().toString(); + try { + xmlWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, nodeType.getLocalName(), namespace); + xmlWriter.writeDefaultNamespace(namespace); + xmlWriter.writeEndElement(); + xmlWriter.flush(); + } catch (XMLStreamException e) { + throw new IOException("Failed to write elements", e); + } } private static void writeElements(final XMLStreamWriter xmlWriter, final RestconfNormalizedNodeWriter nnWriter, final ContainerNode data) throws IOException { - final QName name = data.getIdentifier().getNodeType(); + final QName nodeType = data.getIdentifier().getNodeType(); + final String namespace = nodeType.getNamespace().toString(); try { - xmlWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, - name.getLocalName(), name.getNamespace().toString()); - xmlWriter.writeDefaultNamespace(name.getNamespace().toString()); + xmlWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, nodeType.getLocalName(), namespace); + xmlWriter.writeDefaultNamespace(namespace); for (final NormalizedNode child : data.body()) { nnWriter.write(child); } diff --git a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/XmlNormalizedNodeBodyWriterTest.java b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/XmlNormalizedNodeBodyWriterTest.java index f45ce5df9d..7d0b37d4d2 100644 --- a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/XmlNormalizedNodeBodyWriterTest.java +++ b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/XmlNormalizedNodeBodyWriterTest.java @@ -8,50 +8,74 @@ package org.opendaylight.restconf.nb.rfc8040.jersey.providers; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import java.io.ByteArrayOutputStream; -import java.io.OutputStream; +import java.nio.charset.StandardCharsets; import javax.ws.rs.core.MediaType; -import org.junit.BeforeClass; import org.junit.Test; -import org.mockito.Mockito; import org.opendaylight.restconf.common.context.InstanceIdentifierContext; +import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils; import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload; +import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaPath; public class XmlNormalizedNodeBodyWriterTest { + @Test + public void testWriteEmptyRootContainer() throws Exception { + final EffectiveModelContext schemaContext = mock(EffectiveModelContext.class); - private static final String EMPTY_OUTPUT = ""; + final SchemaNode schemaNode = mock(SchemaNode.class); + doReturn(SchemaPath.ROOT).when(schemaNode).getPath(); - private static EffectiveModelContext schemaContext; + final NormalizedNodePayload nodePayload = NormalizedNodePayload.of( + new InstanceIdentifierContext<>(YangInstanceIdentifier.empty(), schemaNode, null, schemaContext), + Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(SchemaContext.NAME)).build()); - @BeforeClass - public static void initialization() throws Exception { - schemaContext = Mockito.mock(EffectiveModelContext.class); + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + final XmlNormalizedNodeBodyWriter xmlWriter = new XmlNormalizedNodeBodyWriter(); + xmlWriter.writeTo(nodePayload, null, null, null, MediaType.APPLICATION_XML_TYPE, null, output); + + assertEquals("", + output.toString(StandardCharsets.UTF_8)); } @Test - public void testWriteEmptyRootContainer() throws Exception { - final SchemaNode schemaNode = Mockito.mock(SchemaNode.class); - when(schemaNode.getPath()).thenReturn(SchemaPath.ROOT); + public void testRootContainerWrite() throws Exception { + final EffectiveModelContext schemaContext = + TestRestconfUtils.loadSchemaContext("/instanceidentifier/yang", null); + + final SchemaNode schemaNode = mock(SchemaNode.class); + doReturn(SchemaPath.ROOT).when(schemaNode).getPath(); - final InstanceIdentifierContext identifierContext = - new InstanceIdentifierContext<>(YangInstanceIdentifier.empty(), schemaNode, null, schemaContext); - final ContainerNode data = ImmutableContainerNodeBuilder.create() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SchemaContext.NAME)).build(); - final NormalizedNodePayload nodePayload = NormalizedNodePayload.of(identifierContext, data); + final NormalizedNodePayload nodePayload = NormalizedNodePayload.of( + new InstanceIdentifierContext<>(YangInstanceIdentifier.empty(), schemaNode, null, schemaContext), + Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(SchemaContext.NAME)) + .withChild(Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier( + QName.create("foo:module", "2016-09-29", "foo-bar-container"))) + .build()) + .withChild(Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier( + QName.create("bar:module", "2016-09-29", "foo-bar-container"))) + .build()) + .build()); - final OutputStream output = new ByteArrayOutputStream(); + final ByteArrayOutputStream output = new ByteArrayOutputStream(); final XmlNormalizedNodeBodyWriter xmlWriter = new XmlNormalizedNodeBodyWriter(); xmlWriter.writeTo(nodePayload, null, null, null, MediaType.APPLICATION_XML_TYPE, null, output); - assertEquals(EMPTY_OUTPUT, output.toString()); + assertEquals("" + + "" + + "" + + "", output.toString(StandardCharsets.UTF_8)); } } \ No newline at end of file