Fix XmlStreamUtils writing attributes. 90/9290/3
authorMaros Marsalek <mmarsale@cisco.com>
Thu, 24 Jul 2014 15:06:09 +0000 (17:06 +0200)
committerMaros Marsalek <mmarsale@cisco.com>
Fri, 25 Jul 2014 07:44:33 +0000 (09:44 +0200)
The prefix for attributes was no set.
This would result in an exception when no prefix was available by default.

Using RandomPrefix now.

Change-Id: I6110293b262a77f987534fe98abf51755a066be0
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefix.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtilsTest.java [new file with mode: 0644]

index 223157a223eee681231840c8b0d436dbe2ca0f83..0251678389a8c29cd3d989fc6e9d0a1a227ba78a 100644 (file)
@@ -23,6 +23,10 @@ final class RandomPrefix {
     }
 
     String encodeQName(final QName qname) {
+        return encodePrefix(qname) + ':' + qname.getLocalName();
+    }
+
+    String encodePrefix(final QName qname) {
         String prefix = prefixes.get(qname.getNamespace());
         if (prefix == null) {
             prefix = qname.getPrefix();
@@ -40,7 +44,6 @@ final class RandomPrefix {
 
             prefixes.put(qname.getNamespace(), prefix);
         }
-
-        return prefix + ':' + qname.getLocalName();
+        return prefix;
     }
 }
index 1d319a5acec49db92d0fb909e266ebc85b313508..9471a1be29f81bd075dab2421db5bde71f733840 100644 (file)
@@ -1,9 +1,11 @@
 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 
 import java.net.URI;
+import java.util.Map;
 import java.util.Map.Entry;
 
 import javax.annotation.Nonnull;
@@ -149,8 +151,9 @@ public class XmlStreamUtils {
 
         writer.writeStartElement(pfx, qname.getLocalName(), ns);
         if (data instanceof AttributesContainer && ((AttributesContainer) data).getAttributes() != null) {
+            RandomPrefix randomPrefix = new RandomPrefix();
             for (Entry<QName, String> attribute : ((AttributesContainer) data).getAttributes().entrySet()) {
-                writer.writeAttribute(attribute.getKey().getNamespace().toString(), attribute.getKey().getLocalName(), attribute.getValue());
+                writeAttribute(writer, attribute, randomPrefix);
             }
         }
 
@@ -186,6 +189,15 @@ public class XmlStreamUtils {
         writer.writeEndElement();
     }
 
+    @VisibleForTesting
+    static void writeAttribute(final XMLStreamWriter writer, final Entry<QName, String> attribute, final RandomPrefix randomPrefix)
+            throws XMLStreamException {
+        final QName key = attribute.getKey();
+        final String prefix = randomPrefix.encodePrefix(key);
+        writer.writeAttribute("xmlns:" + prefix, key.getNamespace().toString());
+        writer.writeAttribute(prefix, key.getNamespace().toString(), key.getLocalName(), attribute.getValue());
+    }
+
     /**
      * Write a value into a XML stream writer. This method assumes the start and end of element is
      * emitted by the caller.
diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtilsTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtilsTest.java
new file mode 100644 (file)
index 0000000..1a35875
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. 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.impl.codec.xml;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
+import java.io.ByteArrayOutputStream;
+import java.net.URI;
+import java.util.AbstractMap;
+import java.util.Map;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamWriter;
+import junit.framework.Assert;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.w3c.dom.Document;
+
+public class XmlStreamUtilsTest {
+
+    public static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory();
+
+    @Test
+    public void testWriteAttribute() throws Exception {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        final XMLStreamWriter writer =  XML_OUTPUT_FACTORY.createXMLStreamWriter(out);
+        writer.writeStartElement("element");
+
+        QName name = getAttrQName("namespace", "2012-12-12", "attr", Optional.of("prefix"));
+        final Map.Entry<QName, String> attributeEntry = new AbstractMap.SimpleEntry<>(name, "value");
+
+        name = getAttrQName("namespace2", "2012-12-12", "attr", Optional.<String>absent());
+        final Map.Entry<QName, String> attributeEntryNoPrefix = new AbstractMap.SimpleEntry<>(name, "value");
+
+        final RandomPrefix randomPrefix = new RandomPrefix();
+        XmlStreamUtils.writeAttribute(writer, attributeEntry, randomPrefix);
+        XmlStreamUtils.writeAttribute(writer, attributeEntryNoPrefix, randomPrefix);
+
+        writer.writeEndElement();
+        writer.close();
+        out.close();
+
+        final String xmlAsString = new String(out.toByteArray());
+
+        final Map<String, String> mappedPrefixes = mapPrefixed(randomPrefix.getPrefixes());
+        Assert.assertEquals(2, mappedPrefixes.size());
+        final String randomPrefixValue = mappedPrefixes.get("namespace2");
+
+        final String expectedXmlAsString = "<element xmlns:prefix=\"namespace\" prefix:attr=\"value\" xmlns:" + randomPrefixValue + "=\"namespace2\" " + randomPrefixValue + ":attr=\"value\"></element>";
+
+        XMLUnit.setIgnoreAttributeOrder(true);
+        final Document control = XMLUnit.buildControlDocument(expectedXmlAsString);
+        final Document test = XMLUnit.buildTestDocument(xmlAsString);
+        final Diff diff = XMLUnit.compareXML(control, test);
+
+        final boolean identical = diff.identical();
+        Assert.assertTrue("Xml differs: " + diff.toString(), identical);
+    }
+
+    private Map<String, String> mapPrefixed(final Iterable<Map.Entry<URI, String>> prefixes) {
+        final Map<String, String> mappedPrefixes = Maps.newHashMap();
+        for (final Map.Entry<URI, String> prefix : prefixes) {
+            mappedPrefixes.put(prefix.getKey().toString(), prefix.getValue());
+        }
+        return mappedPrefixes;
+    }
+
+    private QName getAttrQName(final String namespace, final String revision, final String localName, final Optional<String> prefix) {
+
+        if(prefix.isPresent()) {
+            final QName moduleQName = QName.create(namespace, revision, "module");
+            final QNameModule module = QNameModule.create(moduleQName.getNamespace(), moduleQName.getRevision());
+            return QName.create(module, prefix.get(), localName);
+        } else {
+            return QName.create(namespace, revision, localName);
+        }
+    }
+}