X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-data-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Fimpl%2Fcodec%2Fxml%2FXmlStreamUtils.java;h=541253d09f0434de6cb77e2c799382640173ed56;hb=052bd27d118a2addb3eae2253515890369a60182;hp=b60cf2bc19e878fda63c1cc57d372b75087a3fc9;hpb=8fbeb37b37d38ce783712c370f63edafe5bc8d7b;p=yangtools.git 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 b60cf2bc19..541253d09f 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 @@ -2,17 +2,17 @@ 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.Optional; import com.google.common.base.Preconditions; - import java.net.URI; +import java.util.Collection; +import java.util.Collections; import java.util.Map; import java.util.Map.Entry; - import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; - import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.AttributesContainer; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -25,10 +25,14 @@ import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; +import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,9 +44,15 @@ import org.slf4j.LoggerFactory; public class XmlStreamUtils { private static final Logger LOG = LoggerFactory.getLogger(XmlStreamUtils.class); private final XmlCodecProvider codecProvider; + private final Optional schemaContext; protected XmlStreamUtils(final XmlCodecProvider codecProvider) { + this(codecProvider, null); + } + + private XmlStreamUtils(final XmlCodecProvider codecProvider, final SchemaContext schemaContext) { this.codecProvider = Preconditions.checkNotNull(codecProvider); + this.schemaContext = Optional.fromNullable(schemaContext); } /** @@ -85,17 +95,17 @@ public class XmlStreamUtils { * @param writer XML Stream writer * @param id InstanceIdentifier * @throws XMLStreamException + * + * @deprecated Use {@link #writeInstanceIdentifier(XMLStreamWriter, YangInstanceIdentifier)} instead. */ + @Deprecated public static void write(final @Nonnull XMLStreamWriter writer, final @Nonnull YangInstanceIdentifier id) throws XMLStreamException { Preconditions.checkNotNull(writer, "Writer may not be null"); Preconditions.checkNotNull(id, "Variable should contain instance of instance identifier and can't be null"); final RandomPrefix prefixes = new RandomPrefix(); final String str = XmlUtils.encodeIdentifier(prefixes, id); - - for (Entry e: prefixes.getPrefixes()) { - writer.writeNamespace(e.getValue(), e.getKey().toString()); - } + writeNamespaceDeclarations(writer,prefixes.getPrefixes()); writer.writeCharacters(str); } @@ -118,12 +128,11 @@ public class XmlStreamUtils { } /** - * Short-hand for {@link #writeDataDocument(XMLStreamWriter, CompositeNode, SchemaNode, XmlCodecProvider)} with + * Short-hand for {@link #writeDocument(XMLStreamWriter, CompositeNode, SchemaNode)})} with * null SchemaNode. * * @param writer XML Stream writer * @param data data node - * @param schema corresponding schema node, may be null * @throws XMLStreamException if an encoding problem occurs */ public void writeDocument(final XMLStreamWriter writer, final CompositeNode data) throws XMLStreamException { @@ -141,8 +150,8 @@ public class XmlStreamUtils { */ public void writeElement(final XMLStreamWriter writer, final @Nonnull Node data, final SchemaNode schema) throws XMLStreamException { final QName qname = data.getNodeType(); - final String pfx = qname.getPrefix() != null ? qname.getPrefix() : ""; final String ns = qname.getNamespace() != null ? qname.getNamespace().toString() : ""; + final String pfx = ""; if (isEmptyElement(data)) { if (hasAttributes(data)) { @@ -178,10 +187,8 @@ public class XmlStreamUtils { if (data instanceof SimpleNode) { // Simple node - if (schema instanceof LeafListSchemaNode) { - writeValue(writer, ((LeafListSchemaNode) schema).getType(), data.getValue()); - } else if (schema instanceof LeafSchemaNode) { - writeValue(writer, ((LeafSchemaNode) schema).getType(), data.getValue()); + if (schema instanceof LeafListSchemaNode || schema instanceof LeafSchemaNode) { + writeValue(writer, schema, data.getValue()); } else { Object value = data.getValue(); if (value != null) { @@ -190,22 +197,49 @@ public class XmlStreamUtils { } } else { // CompositeNode - for (Node child : ((CompositeNode) data).getValue()) { - DataSchemaNode childSchema = null; - if (schema instanceof DataNodeContainer) { - childSchema = SchemaUtils.findFirstSchema(child.getNodeType(), ((DataNodeContainer) schema).getChildNodes()).orNull(); - if (LOG.isDebugEnabled()) { - if (childSchema == null) { - LOG.debug("Probably the data node \"{}\" does not conform to schema", child == null ? "" : child.getNodeType().getLocalName()); - } - } + final CompositeNode castedData = ((CompositeNode) data); + final DataNodeContainer castedSchema; + if (schema instanceof DataNodeContainer) { + castedSchema = (DataNodeContainer) schema; + } else { + castedSchema = null; + } + final Collection keyLeaves; + if (schema instanceof ListSchemaNode) { + keyLeaves = ((ListSchemaNode) schema).getKeyDefinition(); + + } else { + keyLeaves = Collections.emptyList(); + + } + for (QName key : keyLeaves) { + SimpleNode keyLeaf = castedData.getFirstSimpleByName(key); + if(keyLeaf != null) { + writeChildElement(writer,keyLeaf,castedSchema); } + } - writeElement(writer, child, childSchema); + for (Node child : castedData.getValue()) { + if(keyLeaves.contains(child.getNodeType())) { + // Skip key leaf which was written by previous for loop. + continue; + } + writeChildElement(writer,child,castedSchema); } } } + private void writeChildElement(final XMLStreamWriter writer, final Node child, final DataNodeContainer parentSchema) throws XMLStreamException { + DataSchemaNode childSchema = null; + if (parentSchema != null) { + childSchema = SchemaUtils.findFirstSchema(child.getNodeType(), parentSchema.getChildNodes()).orNull(); + if ((childSchema == null) && LOG.isDebugEnabled()) { + LOG.debug("Probably the data node \"{}\" does not conform to schema", child == null ? "" : child.getNodeType().getLocalName()); + } + } + writeElement(writer, child, childSchema); + } + private static void writeAttributes(final XMLStreamWriter writer, final AttributesContainer data, final RandomPrefix randomPrefix) throws XMLStreamException { for (Entry attribute : data.getAttributes().entrySet()) { writeAttribute(writer, attribute, randomPrefix); @@ -235,7 +269,39 @@ public class XmlStreamUtils { * emitted by the caller. * * @param writer XML Stream writer - * @param type data type + * @param schemaNode Schema node that describes the value + * @param value data value + * @throws XMLStreamException if an encoding problem occurs + */ + public void writeValue(final @Nonnull XMLStreamWriter writer, final @Nonnull SchemaNode schemaNode, final Object value) throws XMLStreamException { + if (value == null) { + LOG.debug("Value of {}:{} is null, not encoding it", schemaNode.getQName().getNamespace(), schemaNode.getQName().getLocalName()); + return; + } + + Preconditions.checkArgument(schemaNode instanceof LeafSchemaNode || schemaNode instanceof LeafListSchemaNode, + "Unable to write value for node %s, only nodes of type: leaf and leaf-list can be written at this point", schemaNode.getQName()); + + TypeDefinition type = schemaNode instanceof LeafSchemaNode ? + ((LeafSchemaNode) schemaNode).getType(): + ((LeafListSchemaNode) schemaNode).getType(); + + TypeDefinition baseType = XmlUtils.resolveBaseTypeFrom(type); + + if (schemaContext.isPresent() && baseType instanceof LeafrefTypeDefinition) { + LeafrefTypeDefinition leafrefTypeDefinition = (LeafrefTypeDefinition) baseType; + baseType = SchemaContextUtil.getBaseTypeForLeafRef(leafrefTypeDefinition, schemaContext.get(), schemaNode); + } + + writeValue(writer, baseType, value); + } + + /** + * Write a value into a XML stream writer. This method assumes the start and end of element is + * emitted by the caller. + * + * @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 * @throws XMLStreamException if an encoding problem occurs */ @@ -244,8 +310,8 @@ public class XmlStreamUtils { LOG.debug("Value of {}:{} is null, not encoding it", type.getQName().getNamespace(), type.getQName().getLocalName()); return; } + TypeDefinition baseType = XmlUtils.resolveBaseTypeFrom(type); - final TypeDefinition baseType = XmlUtils.resolveBaseTypeFrom(type); if (baseType instanceof IdentityrefTypeDefinition) { write(writer, (IdentityrefTypeDefinition) baseType, value); } else if (baseType instanceof InstanceIdentifierTypeDefinition) { @@ -271,14 +337,10 @@ public class XmlStreamUtils { private static void write(final @Nonnull XMLStreamWriter writer, final @Nonnull IdentityrefTypeDefinition type, final @Nonnull Object value) throws XMLStreamException { if (value instanceof QName) { final QName qname = (QName) value; - final String prefix; - if (qname.getPrefix() != null && !qname.getPrefix().isEmpty()) { - prefix = qname.getPrefix(); - } else { - prefix = "x"; - } + final String prefix = "x"; - writer.writeNamespace(prefix, qname.getNamespace().toString()); + 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()); @@ -286,12 +348,36 @@ public class XmlStreamUtils { } } - private static void write(final @Nonnull XMLStreamWriter writer, final @Nonnull InstanceIdentifierTypeDefinition type, final @Nonnull Object value) throws XMLStreamException { + private void write(final @Nonnull XMLStreamWriter writer, final @Nonnull InstanceIdentifierTypeDefinition type, final @Nonnull Object value) throws XMLStreamException { if (value instanceof YangInstanceIdentifier) { - write(writer, (YangInstanceIdentifier)value); + writeInstanceIdentifier(writer, (YangInstanceIdentifier)value); } else { LOG.warn("Value of {}:{} is not an InstanceIdentifier but {}", type.getQName().getNamespace(), type.getQName().getLocalName(), value.getClass()); writer.writeCharacters(String.valueOf(value)); } } + + public void writeInstanceIdentifier(XMLStreamWriter writer, YangInstanceIdentifier value) throws XMLStreamException { + if(schemaContext.isPresent()) { + RandomPrefixInstanceIdentifierSerializer iiCodec = new RandomPrefixInstanceIdentifierSerializer(schemaContext.get()); + String serializedValue = iiCodec.serialize(value); + writeNamespaceDeclarations(writer,iiCodec.getPrefixes()); + writer.writeCharacters(serializedValue); + } else { + LOG.warn("Schema context not present in {}, serializing {} without schema.",this,value); + write(writer,value); + } + } + + private static void writeNamespaceDeclarations(XMLStreamWriter writer, Iterable> prefixes) throws XMLStreamException { + for (Entry e: prefixes) { + final String ns = e.getKey().toString(); + final String p = e.getValue(); + writer.writeNamespace(p, ns); + } + } + + public static XmlStreamUtils create(final XmlCodecProvider codecProvider, final SchemaContext schemaContext) { + return new XmlStreamUtils(codecProvider, schemaContext); + } }