From f350c4f23d1a431c1086abb90f7d0fd7861faee9 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Tue, 9 Jun 2015 16:16:30 +0200 Subject: [PATCH] Bug 3191: Optimisation of serialisation of IdentityrefTypeDefinition Workaround for the case when prefix and namespace within element and its value is same as parent namespace. Change-Id: I1c8f8b503dc38385aa8cd23a517e067531081661 Signed-off-by: Marian Dubai Signed-off-by: Tomas Cere Signed-off-by: Maros Marsalek --- .../XMLStreamNormalizedNodeStreamWriter.java | 8 +-- .../data/impl/codec/xml/XmlStreamUtils.java | 54 ++++++++++++++----- .../impl/codec/xml/XmlStreamUtilsTest.java | 30 +++++++++++ 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XMLStreamNormalizedNodeStreamWriter.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XMLStreamNormalizedNodeStreamWriter.java index ddef032d92..ee464ce6fc 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XMLStreamNormalizedNodeStreamWriter.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XMLStreamNormalizedNodeStreamWriter.java @@ -101,7 +101,7 @@ public final class XMLStreamNormalizedNodeStreamWriter implements NormalizedNode try { writeStartElement(qname); if (value != null) { - streamUtils.writeValue(writer, type, value); + streamUtils.writeValue(writer, type, value, qname.getModule()); } writer.writeEndElement(); } catch (XMLStreamException e) { @@ -113,7 +113,7 @@ public final class XMLStreamNormalizedNodeStreamWriter implements NormalizedNode try { writeStartElement(qname); if (value != null) { - streamUtils.writeValue(writer, schemaNode, value); + streamUtils.writeValue(writer, schemaNode, value, qname.getModule()); } writer.writeEndElement(); } catch (XMLStreamException e) { @@ -124,9 +124,10 @@ public final class XMLStreamNormalizedNodeStreamWriter implements NormalizedNode private void writeElement(final QName qname, final SchemaNode schemaNode, final Object value, final Map attributes) throws IOException { try { writeStartElement(qname); + writeAttributes(attributes); if (value != null) { - streamUtils.writeValue(writer, schemaNode, value); + streamUtils.writeValue(writer, schemaNode, value, qname.getModule()); } writer.writeEndElement(); } catch (XMLStreamException e) { @@ -191,6 +192,7 @@ public final class XMLStreamNormalizedNodeStreamWriter implements NormalizedNode for (final Map.Entry qNameStringEntry : attributes.entrySet()) { try { final String namespace = qNameStringEntry.getKey().getNamespace().toString(); + if(Strings.isNullOrEmpty(namespace)) { writer.writeAttribute(qNameStringEntry.getKey().getLocalName(), qNameStringEntry.getValue()); } else { diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java index 89a4cea565..e26c144fbf 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java @@ -10,6 +10,7 @@ import javax.annotation.Nonnull; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; @@ -70,7 +71,7 @@ public class XmlStreamUtils { final RandomPrefix prefixes = new RandomPrefix(); final String str = XmlUtils.encodeIdentifier(prefixes, id); - writeNamespaceDeclarations(writer,prefixes.getPrefixes()); + writeNamespaceDeclarations(writer, prefixes.getPrefixes()); writer.writeCharacters(str); } @@ -90,9 +91,10 @@ public class XmlStreamUtils { * @param writer XML Stream writer * @param schemaNode Schema node that describes the value * @param value data value + * @param parent optional parameter of a module QName owning the leaf definition * @throws XMLStreamException if an encoding problem occurs */ - public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final SchemaNode schemaNode, final Object value) throws XMLStreamException { + public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final SchemaNode schemaNode, final Object value, final Optional parent) throws XMLStreamException { if (value == null) { LOG.debug("Value of {}:{} is null, not encoding it", schemaNode.getQName().getNamespace(), schemaNode.getQName().getLocalName()); return; @@ -112,7 +114,15 @@ public class XmlStreamUtils { baseType = SchemaContextUtil.getBaseTypeForLeafRef(leafrefTypeDefinition, schemaContext.get(), schemaNode); } - writeValue(writer, baseType, value); + writeValue(writer, baseType, value, parent); + } + + public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final SchemaNode schemaNode, final Object value) throws XMLStreamException { + writeValue(writer, schemaNode, value, Optional.absent()); + } + + public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final SchemaNode schemaNode, final Object value, final QNameModule parent) throws XMLStreamException { + writeValue(writer, schemaNode, value, Optional.of(parent)); } /** @@ -122,9 +132,10 @@ public class XmlStreamUtils { * @param writer XML Stream writer * @param type data type. In case of leaf ref this should be the type of leaf being referenced * @param value data value + * @param parent optional parameter of a module QName owning the leaf definition * @throws XMLStreamException if an encoding problem occurs */ - public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final TypeDefinition type, final Object value) throws XMLStreamException { + public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final TypeDefinition type, final Object value, final Optional parent) throws XMLStreamException { if (value == null) { LOG.debug("Value of {}:{} is null, not encoding it", type.getQName().getNamespace(), type.getQName().getLocalName()); return; @@ -132,35 +143,54 @@ public class XmlStreamUtils { TypeDefinition baseType = XmlUtils.resolveBaseTypeFrom(type); if (baseType instanceof IdentityrefTypeDefinition) { - write(writer, (IdentityrefTypeDefinition) baseType, value); + if (parent.isPresent()) { + write(writer, (IdentityrefTypeDefinition) baseType, value, parent); + } else { + write(writer, (IdentityrefTypeDefinition) baseType, value, Optional.absent()); + } } else if (baseType instanceof InstanceIdentifierTypeDefinition) { write(writer, (InstanceIdentifierTypeDefinition) baseType, value); } else { - final TypeDefinitionAwareCodec codec = codecProvider.codecFor(baseType); + final TypeDefinitionAwareCodec codec = codecProvider.codecFor(type); String text; if (codec != null) { try { text = codec.serialize(value); } catch (ClassCastException e) { - LOG.error("Provided node value {} did not have type {} required by mapping. Using stream instead.", value, baseType, e); + LOG.error("Provided node value {} did not have type {} required by mapping. Using stream instead.", value, type, e); text = String.valueOf(value); } } else { - LOG.error("Failed to find codec for {}, falling back to using stream", baseType); + LOG.error("Failed to find codec for {}, falling back to using stream", type); text = String.valueOf(value); } writer.writeCharacters(text); } } - private static void write(@Nonnull final XMLStreamWriter writer, @Nonnull final IdentityrefTypeDefinition type, @Nonnull final Object value) throws XMLStreamException { + public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final TypeDefinition type, final Object value, final QNameModule parent) throws XMLStreamException { + writeValue(writer, type, value, Optional.of(parent)); + } + + public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final TypeDefinition type, final Object value) throws XMLStreamException { + writeValue(writer, type, value, Optional.absent()); + } + + @VisibleForTesting + static void write(@Nonnull final XMLStreamWriter writer, @Nonnull final IdentityrefTypeDefinition type, @Nonnull final Object value, final Optional parent) throws XMLStreamException { if (value instanceof QName) { final QName qname = (QName) value; final String prefix = "x"; - final String ns = qname.getNamespace().toString(); - writer.writeNamespace(prefix, ns); - writer.writeCharacters(prefix + ':' + qname.getLocalName()); + //in case parent is present and same as element namespace write value without namespace + if (parent.isPresent() && qname.getNamespace().equals(parent.get().getNamespace())){ + writer.writeCharacters(qname.getLocalName()); + } else { + final String ns = qname.getNamespace().toString(); + writer.writeNamespace(prefix, ns); + writer.writeCharacters(prefix + ':' + qname.getLocalName()); + } + } else { LOG.debug("Value of {}:{} is not a QName but {}", type.getQName().getNamespace(), type.getQName().getLocalName(), value.getClass()); writer.writeCharacters(String.valueOf(value)); 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 index a95366ae15..c66b159220 100644 --- 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 @@ -8,8 +8,10 @@ package org.opendaylight.yangtools.yang.data.impl.codec.xml; +import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import com.google.common.base.Optional; import com.google.common.collect.Maps; @@ -19,7 +21,10 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.AbstractMap; import java.util.Arrays; +import java.util.Date; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamWriter; import org.custommonkey.xmlunit.Diff; @@ -98,6 +103,31 @@ public class XmlStreamUtilsTest { assertTrue("Xml differs: " + diff.toString(), identical); } + @Test + public void testWriteIdentityRef() throws Exception { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final XMLStreamWriter writer = XML_OUTPUT_FACTORY.createXMLStreamWriter(out); + + writer.writeStartElement("element"); + final QNameModule parent = QNameModule.create(URI.create("parent:uri"), new Date()); + XmlStreamUtils.write(writer, null, QName.create(parent, "identity"), Optional.of(parent)); + writer.writeEndElement(); + + writer.writeStartElement("elementDifferent"); + XmlStreamUtils.write(writer, null, QName.create("different:namespace", "identity"), Optional.of(parent)); + writer.writeEndElement(); + + writer.close(); + out.close(); + + final String xmlAsString = new String(out.toByteArray()).replaceAll("\\s*", ""); + assertThat(xmlAsString, containsString("element>identity")); + + final Pattern prefixedIdentityPattern = Pattern.compile(".*\"different:namespace\">(.*):identity.*"); + final Matcher matcher = prefixedIdentityPattern.matcher(xmlAsString); + assertTrue("Xml: " + xmlAsString + " should match: " + prefixedIdentityPattern, matcher.matches()); + } + /** * One leafref reference to other leafref via relative references */ -- 2.36.6