From b53aceea5fc3294d620a5e1219cb6c1d8a27e5ba Mon Sep 17 00:00:00 2001 From: Tomas Cere Date: Tue, 4 Jan 2022 12:14:38 +0100 Subject: [PATCH] Fix empty get failing on mounted devices when using xml The ParameterAwareNormalizedNodeWriter was not setting an empty container node with root path as handled so fix that. Also make sure we actually return an empty data node when its processed instead of empty response. JIRA: NETCONF-847 Change-Id: Iab271a93fd13176dd061d5c26ab1d7f9a8b8263b Signed-off-by: Tomas Cere Signed-off-by: Robert Varga --- .../ParameterAwareNormalizedNodeWriter.java | 2 +- .../XmlNormalizedNodeBodyWriter.java | 23 +++++++- ...areNormalizedNodeWriterParametersTest.java | 11 ++++ .../XmlNormalizedNodeBodyWriterTest.java | 57 +++++++++++++++++++ 4 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/XmlNormalizedNodeBodyWriterTest.java diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/ParameterAwareNormalizedNodeWriter.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/ParameterAwareNormalizedNodeWriter.java index d023f4b13f..378e9ddda8 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/ParameterAwareNormalizedNodeWriter.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/ParameterAwareNormalizedNodeWriter.java @@ -273,8 +273,8 @@ public class ParameterAwareNormalizedNodeWriter implements RestconfNormalizedNod write(child); } currentDepth--; - processedAsCompositeNode = true; } + processedAsCompositeNode = true; } } else if (node instanceof MapEntryNode) { processedAsCompositeNode = writeMapEntryNode((MapEntryNode) node); 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 b5c085ca67..d9af3d4c80 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 @@ -116,7 +116,8 @@ public class XmlNormalizedNodeBodyWriter extends AbstractNormalizedNodeBodyWrite ((ActionDefinition) pathContext.getSchemaNode()).getOutput().getPath(), depth, fields); writeElements(xmlWriter, nnWriter, (ContainerNode) data); } else { - if (SchemaPath.ROOT.equals(path)) { + final boolean isRoot = SchemaPath.ROOT.equals(path); + if (isRoot) { nnWriter = createNormalizedNodeWriter(xmlWriter, schemaCtx, path, depth, fields); } else { nnWriter = createNormalizedNodeWriter(xmlWriter, schemaCtx, path.getParent(), depth, fields); @@ -129,13 +130,31 @@ public class XmlNormalizedNodeBodyWriter extends AbstractNormalizedNodeBodyWrite .addChild((MapEntryNode) data) .build()); } else { - nnWriter.write(data); + if (isRoot && data instanceof ContainerNode && ((ContainerNode) data).isEmpty()) { + writeEmptyDataNode(xmlWriter, data); + } else { + nnWriter.write(data); + } } } nnWriter.flush(); } + 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 RestconfNormalizedNodeWriter createNormalizedNodeWriter(final XMLStreamWriter xmlWriter, final EffectiveModelContext schemaContext, final SchemaPath schemaPath, final DepthParam depth, final List> fields) { diff --git a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/ParameterAwareNormalizedNodeWriterParametersTest.java b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/ParameterAwareNormalizedNodeWriterParametersTest.java index 5443e4b8b8..70ac6e80e7 100644 --- a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/ParameterAwareNormalizedNodeWriterParametersTest.java +++ b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/ParameterAwareNormalizedNodeWriterParametersTest.java @@ -30,6 +30,8 @@ import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; /** * Unit test for {@link ParameterAwareNormalizedNodeWriter} used with all parameters. @@ -131,4 +133,13 @@ public class ParameterAwareNormalizedNodeWriterParametersTest { inOrder.verify(writer, Mockito.times(2)).endNode(); Mockito.verifyNoMoreInteractions(writer); } + + @Test + public void writeEmptyRootContainerTest() throws Exception { + final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter( + writer, null, null); + + parameterWriter.write(ImmutableContainerNodeBuilder.create() + .withNodeIdentifier(new NodeIdentifier(SchemaContext.NAME)).build()); + } } \ No newline at end of file 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 new file mode 100644 index 0000000000..f45ce5df9d --- /dev/null +++ b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/XmlNormalizedNodeBodyWriterTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.restconf.nb.rfc8040.jersey.providers; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +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.legacy.NormalizedNodePayload; +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.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 { + + private static final String EMPTY_OUTPUT = ""; + + private static EffectiveModelContext schemaContext; + + @BeforeClass + public static void initialization() throws Exception { + schemaContext = Mockito.mock(EffectiveModelContext.class); + } + + @Test + public void testWriteEmptyRootContainer() throws Exception { + final SchemaNode schemaNode = Mockito.mock(SchemaNode.class); + when(schemaNode.getPath()).thenReturn(SchemaPath.ROOT); + + 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 OutputStream 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()); + } +} \ No newline at end of file -- 2.36.6