Bug 8803: check for null return NamespaceContext.getNamespaceURI() 36/60736/4
authorIgor Foltin <igor.foltin@pantheon.tech>
Tue, 25 Jul 2017 15:18:39 +0000 (17:18 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 25 Jul 2017 18:17:39 +0000 (20:17 +0200)
The javadoc indicates that for unbound prefixes this method should be
returning NULL_NS_URI (which is defined as an empty string), and there
is no mention of the possibility of returning null anywhere.

Nevertheless JDK8-default XMLOutputWriter returns null for unbound
prefixes, which leads to an infinite loop in RandomPrefix.

Fix this by adding an explicit check for null, too.

Change-Id: Ib8af7d03eb59b004f2fcb4d1806c0f4f256a974a
Signed-off-by: Igor Foltin <igor.foltin@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/RandomPrefix.java
yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Bug8803Test.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/bug8803/bar.yang [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/bug8803/baz.yang [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/bug8803/foo.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/bug8803/foo.yang [new file with mode: 0644]

index 039ecd0d885ad949455ab337b7ad396ee54f1a62..b18d8f9880af034eaa37c2d3747aaa26fe721c9e 100644 (file)
@@ -63,8 +63,10 @@ class RandomPrefix {
             return false;
         }
 
+        // It seems JDK8 is violating the API contract of NamespaceContext by returning null for unbound prefixes,
+        // rather than specified NULL_NS_URI. Work this around by checking explicitly for null.
         final String str = context.getNamespaceURI(prefix);
-        return !XMLConstants.NULL_NS_URI.equals(str);
+        return str != null && !XMLConstants.NULL_NS_URI.equals(str);
     }
 
     @VisibleForTesting
diff --git a/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Bug8803Test.java b/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Bug8803Test.java
new file mode 100644 (file)
index 0000000..d708e17
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies, 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.yangtools.yang.data.codec.xml;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.InputStream;
+import java.io.StringWriter;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+import org.junit.Test;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.QName;
+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.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class Bug8803Test {
+
+    @Test
+    public void test() throws Exception {
+        final SchemaContext schemaContext = YangParserTestUtils.parseYangSources("/bug8803");
+        final SchemaPath topContPath = SchemaPath.create(true, QName.create("foo-ns", "1970-01-01", "top-cont"));
+        final SchemaNode dataSchemaNode = SchemaContextUtil.findDataSchemaNode(schemaContext, topContPath);
+        assertTrue(dataSchemaNode instanceof ContainerSchemaNode);
+        final ContainerSchemaNode topContSchema = (ContainerSchemaNode) dataSchemaNode;
+
+        final InputStream resourceAsStream = Bug8803Test.class.getResourceAsStream("/bug8803/foo.xml");
+
+        // deserialization
+        final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
+
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+        final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, topContSchema);
+        xmlParser.parse(reader);
+        final NormalizedNode<?, ?> transformedInput = result.getResult();
+        assertNotNull(transformedInput);
+
+        // serialization
+        final StringWriter writer = new StringWriter();
+        final XMLOutputFactory outputFactory = XMLOutputFactory.newFactory();
+        // switching NS repairing to false does not help
+        outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE);
+        final XMLStreamWriter xmlStreamWriter = outputFactory.createXMLStreamWriter(writer);
+
+        final NormalizedNodeStreamWriter xmlNormalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(
+                xmlStreamWriter, schemaContext);
+
+        final NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(
+                xmlNormalizedNodeStreamWriter);
+        normalizedNodeWriter.write(transformedInput);
+
+        final String serializedXml = writer.toString();
+        assertFalse(serializedXml.isEmpty());
+    }
+}
diff --git a/yang/yang-data-codec-xml/src/test/resources/bug8803/bar.yang b/yang/yang-data-codec-xml/src/test/resources/bug8803/bar.yang
new file mode 100644 (file)
index 0000000..64adc82
--- /dev/null
@@ -0,0 +1,14 @@
+module bar {
+    namespace bar-ns;
+    prefix bar;
+
+    import foo {
+        prefix foo;
+    }
+
+    augment "/foo:top-cont/foo:keyed-list" {
+        leaf iid-leaf {
+            type instance-identifier;
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-codec-xml/src/test/resources/bug8803/baz.yang b/yang/yang-data-codec-xml/src/test/resources/bug8803/baz.yang
new file mode 100644 (file)
index 0000000..abe4a57
--- /dev/null
@@ -0,0 +1,14 @@
+module baz {
+    namespace baz-ns;
+    prefix baz;
+
+    container top-cont {
+        list keyed-list {
+            key key-leaf;
+
+            leaf key-leaf {
+                type int32;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-codec-xml/src/test/resources/bug8803/foo.xml b/yang/yang-data-codec-xml/src/test/resources/bug8803/foo.xml
new file mode 100644 (file)
index 0000000..8f7bf1c
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<top-cont xmlns="foo-ns">
+    <keyed-list>
+        <key-leaf>150</key-leaf>
+        <iid-leaf xmlns="bar-ns" xmlns:baz="baz-ns">
+            /baz:top-cont/baz:keyed-list[baz:key-leaf='50']</iid-leaf>
+    </keyed-list>
+</top-cont>
\ No newline at end of file
diff --git a/yang/yang-data-codec-xml/src/test/resources/bug8803/foo.yang b/yang/yang-data-codec-xml/src/test/resources/bug8803/foo.yang
new file mode 100644 (file)
index 0000000..7c8bae4
--- /dev/null
@@ -0,0 +1,14 @@
+module foo {
+    namespace foo-ns;
+    prefix foo;
+
+    container top-cont {
+        list keyed-list {
+            key key-leaf;
+
+            leaf key-leaf {
+                type int32;
+            }
+        }
+    }
+}
\ No newline at end of file