<artifactId>yang-data-codec-gson</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-codec-xml</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-model-api</artifactId>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-codec-gson</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-codec-xml</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-model-api</artifactId>
<!-- GSON-based JSON codec. Can be split out -->
<bundle>mvn:com.google.code.gson/gson/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.yangtools/yang-data-codec-gson/{{VERSION}}</bundle>
+
+ <bundle>mvn:org.opendaylight.yangtools/yang-data-codec-xml/{{VERSION}}</bundle>
</feature>
<feature name='odl-yangtools-common' version='${project.version}' description='OpenDaylight :: Yangtools :: Common'>
wants to generate code or other artefacts based on YANG model.
=== Concepts
-Project defines base concepts and helper classes which are project-agnostic and could be used outside of YANG Tools project scope.
+Project defines base concepts and helper classes which are project-agnostic and could be used outside of YANG Tools project scope.
=== Components
- yang-common
- yang-data-api
- yang-data-codec-gson
+- yang-data-codec-xml
- yang-data-impl
- yang-data-jaxen
- yang-data-transform
Yang Statement Parser works on the idea of statement concepts as defined in RFC6020, section 6.3. We come up here with basic ModelStatement and StatementDefinition, following RFC6020 idea of having sequence of statements, where
every statement contains keyword and zero or one argument. ModelStatement is extended by DeclaredStatement (as it comes from source, e.g. YANG source)
-and EffectiveStatement, which contains other substatements and tends to represent result of semantic processing of other statements (uses, augment for YANG).
+and EffectiveStatement, which contains other substatements and tends to represent result of semantic processing of other statements (uses, augment for YANG).
IdentifierNamespace represents common superclass for YANG model namespaces.
Input of the Yang Statement Parser is a collection of StatementStreamSource objects.
image:models/yang-data-api.png[]
==== YANG Data Codecs
+Codecs which enable serialization of NormalizedNodes into YANG-modeled data in XML or JSON format and deserialization of YANG-modeled data in XML or JSON format into NormalizedNodes.
==== YANG Maven Plugin
Maven plugin which integrates YANG parser into Maven
== How to / Tutorials
=== Working with YANG Model
-First thing you need to do if you want to work with YANG models is to instantiate a SchemaContext object. This object type describes one or more parsed YANG modules.
+First thing you need to do if you want to work with YANG models is to instantiate a SchemaContext object. This object type describes one or more parsed YANG modules.
-In order to create it you need to utilize YANG statement parser which takes one or more StatementStreamSource objects as input and then produces the SchemaContext object.
+In order to create it you need to utilize YANG statement parser which takes one or more StatementStreamSource objects as input and then produces the SchemaContext object.
-StatementStreamSource object contains the source file information. It has two implementations, one for YANG sources - YangStatementSourceImpl, and one for YIN sources - YinStatementSourceImpl.
+StatementStreamSource object contains the source file information. It has two implementations, one for YANG sources - YangStatementSourceImpl, and one for YIN sources - YinStatementSourceImpl.
Here is an example of creating StatementStreamSource objects for YANG files, providing them to the YANG statement parser and building the SchemaContext:
SchemaContext schemaContext = reactor.buildEffective();
----
-First, StatementStreamSource objects with two constructor arguments should be instantiated: path to the yang source file (which is a regular String object) and a boolean which determines if the path is absolute or relative.
+First, StatementStreamSource objects with two constructor arguments should be instantiated: path to the yang source file (which is a regular String object) and a boolean which determines if the path is absolute or relative.
-Next comes the initiation of new yang parsing cycle - which is represented by CrossSourceStatementReactor.BuildAction object. You can get it by calling method newBuild() on CrossSourceStatementReactor object (RFC6020_REACTOR) in YangInferencePipeline class.
+Next comes the initiation of new yang parsing cycle - which is represented by CrossSourceStatementReactor.BuildAction object. You can get it by calling method newBuild() on CrossSourceStatementReactor object (RFC6020_REACTOR) in YangInferencePipeline class.
Then you should feed yang sources to it by calling method addSources() that takes one or more StatementStreamSource objects as arguments.
Set<Module> modules = schemaContext.getModules();
Set<DataSchemaNodes> dataSchemaNodes = schemaContext.getDataDefinitions();
-Usually you want to access specific modules. Getting a concrete module from SchemaContext is a matter of calling one of these methods:
+Usually you want to access specific modules. Getting a concrete module from SchemaContext is a matter of calling one of these methods:
* findModuleByName(),
* findModuleByNamespace(),
\\ example 2
ContainerNode containerNode2 = Builders.containerBuilder(containerSchemaNode).build();
----
-Both examples produce the same result. NodeIdentifier is one of the four types of YangInstanceIdentifier (these types are described in the javadoc of YangInstanceIdentifier). The purpose of YangInstanceIdentifier is to uniquely identify a particular node in the data tree. In the first example, you have to add NodeIdentifier before building the resulting node. In the second example it is also added using the provided ContainerSchemaNode object.
+Both examples produce the same result. NodeIdentifier is one of the four types of YangInstanceIdentifier (these types are described in the javadoc of YangInstanceIdentifier). The purpose of YangInstanceIdentifier is to uniquely identify a particular node in the data tree. In the first example, you have to add NodeIdentifier before building the resulting node. In the second example it is also added using the provided ContainerSchemaNode object.
ImmutableNodes class offers similar builder methods and also adds an overloaded method called fromInstanceId() which allows you to create a NormalizedNode object based on YangInstanceIdentifier and SchemaContext. Below is an example which shows the use of this method.
Now you can access the written nodes. In order to do this, you have to create a new DataTreeSnapshot instance and call the method readNode() with path argument pointing to a particular node in the tree.
=== Serialization / deserialization of YANG Data
+If you want to deserialize YANG-modeled data which have the form of an XML document, you can use the XML parser found in the module yang-data-codec-xml. The parser walks through the XML document containing YANG-modeled data based on the provided SchemaContext and emits node events into a NormalizedNodeStreamWriter. The parser disallows multiple instances of the same element except for leaf-list and list entries. The parser also expects that the YANG-modeled data in the XML source are wrapped in a root element. Otherwise it will not work correctly.
+
+Here is an example of using the XML parser.
+[source, java]
+----
+InputStream resourceAsStream = ExampleClass.class.getResourceAsStream("/example-module.yang");
+
+XMLInputFactory factory = XMLInputFactory.newInstance();
+XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
+
+NormalizedNodeResult result = new NormalizedNodeResult();
+NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
+xmlParser.parse(reader);
+
+NormalizedNode<?, ?> transformedInput = result.getResult();
+----
+The XML parser utilizes the javax.xml.stream.XMLStreamReader for parsing an XML document. First, you should create an instance of this reader using XMLInputFactory and then load an XML document (in the form of InputStream object) into it.
+
+In order to emit node events while parsing the data you need to instantiate a NormalizedNodeStreamWriter. This writer is actually an interface and therefore you need to use a concrete implementation of it. In this example it is the ImmutableNormalizedNodeStreamWriter, which constructs immutable instances of NormalizedNodes.
+
+There are two ways how to create an instance of this writer using the static overloaded method from(). One version of this method takes a NormalizedNodeResult as argument. This object type is a result holder in which the resulting NormalizedNode will be stored. The other version takes a
+NormalizedNodeContainerBuilder as argument. All created nodes will be written to this builder.
+
+Next step is to create an instance of the XML parser. The parser itself is represented by a class named XmlParserStream. You can use one of two versions of the static overloaded method create() to construct this object. One version accepts a NormalizedNodeStreamWriter and a SchemaContext as arguments, the other version takes the same arguments plus a SchemaNode. Node events are emitted to the writer. The SchemaContext is used to check if the YANG data in the XML source comply with the provided YANG model(s). The last argument, a SchemaNode object, describes the node that is the parent of nodes defined in the XML data. If you do not provide this argument, the parser sets the SchemaContext as the parent node.
+
+The parser is now ready to walk through the XML. Parsing is initiated by calling the method parse() on the XmlParserStream object with XMLStreamReader as its argument.
+
+Finally you can access the result of parsing - a tree of NormalizedNodes containg the data as they are defined in the parsed XML document - by calling the method getResult() on the NormalizedNodeResult object.
=== Introducing schema source repositories
<module>yang-data-impl</module>
<module>yang-data-transform</module>
<module>yang-data-codec-gson</module>
+ <module>yang-data-codec-xml</module>
<module>yang-model-api</module>
<module>yang-maven-plugin</module>
<module>yang-maven-plugin-it</module>
import java.io.IOException;
import java.net.URI;
import java.util.ArrayDeque;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
-import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.schema.stream.DataSchemaNodeAwareAdaptor;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.util.AbstractNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.AnyXmlNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.CompositeNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.LeafListEntryNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.LeafListNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.LeafNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.ListEntryNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.ListNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.ParserStreamUtils;
+import org.opendaylight.yangtools.yang.data.util.RpcAsContainer;
+import org.opendaylight.yangtools.yang.data.util.SimpleNodeDataWithSchema;
import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
}
namesakes.add(jsonElementName);
- final Deque<DataSchemaNode> childDataSchemaNodes = findSchemaNodeByNameAndNamespace(parentSchema,
- localName, getCurrentNamespace());
+ final Deque<DataSchemaNode> childDataSchemaNodes =
+ ParserStreamUtils.findSchemaNodeByNameAndNamespace(parentSchema, localName, getCurrentNamespace());
if (childDataSchemaNodes.isEmpty()) {
throw new IllegalStateException("Schema for node with name " + localName + " and namespace "
+ getCurrentNamespace() + " doesn't exist.");
return namespaces.peek();
}
- /**
- * Returns stack of schema nodes via which it was necessary to pass to get schema node with specified
- * {@code childName} and {@code namespace}
- *
- * @param dataSchemaNode
- * @param childName
- * @param namespace
- * @return stack of schema nodes via which it was passed through. If found schema node is direct child then stack
- * contains only one node. If it is found under choice and case then stack should contains 2*n+1 element
- * (where n is number of choices through it was passed)
- */
- private Deque<DataSchemaNode> findSchemaNodeByNameAndNamespace(final DataSchemaNode dataSchemaNode,
- final String childName, final URI namespace) {
- final Deque<DataSchemaNode> result = new ArrayDeque<>();
- final List<ChoiceSchemaNode> childChoices = new ArrayList<>();
- DataSchemaNode potentialChildNode = null;
- if (dataSchemaNode instanceof DataNodeContainer) {
- for (final DataSchemaNode childNode : ((DataNodeContainer) dataSchemaNode).getChildNodes()) {
- if (childNode instanceof ChoiceSchemaNode) {
- childChoices.add((ChoiceSchemaNode) childNode);
- } else {
- final QName childQName = childNode.getQName();
-
- if (childQName.getLocalName().equals(childName) && childQName.getNamespace().equals(namespace)) {
- if (potentialChildNode == null ||
- childQName.getRevision().after(potentialChildNode.getQName().getRevision())) {
- potentialChildNode = childNode;
- }
- }
- }
- }
- }
- if (potentialChildNode != null) {
- result.push(potentialChildNode);
- return result;
- }
- // try to find data schema node in choice (looking for first match)
- for (final ChoiceSchemaNode choiceNode : childChoices) {
- for (final ChoiceCaseNode concreteCase : choiceNode.getCases()) {
- final Deque<DataSchemaNode> resultFromRecursion = findSchemaNodeByNameAndNamespace(concreteCase, childName,
- namespace);
- if (!resultFromRecursion.isEmpty()) {
- resultFromRecursion.push(concreteCase);
- resultFromRecursion.push(choiceNode);
- return resultFromRecursion;
- }
- }
- }
- return result;
- }
private static class NamespaceAndName {
private final URI uri;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2016 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yangtools-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>/../../common/parent/pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>yang-data-codec-xml</artifactId>
+ <name>${project.artifactId}</name>
+ <description>${project.artifactId}</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <!--
+ Maven Site Configuration
+
+ The following configuration is necessary for maven-site-plugin to
+ correctly identify the correct deployment path for OpenDaylight Maven
+ sites.
+ -->
+ <url>${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/</url>
+
+ <distributionManagement>
+ <site>
+ <id>opendaylight-site</id>
+ <url>${nexus.site.url}/${project.artifactId}/</url>
+ </site>
+ </distributionManagement>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.data.api.codec.BooleanCodec;
+import org.opendaylight.yangtools.yang.data.api.codec.DecimalCodec;
+import org.opendaylight.yangtools.yang.data.api.codec.Int16Codec;
+import org.opendaylight.yangtools.yang.data.api.codec.Int32Codec;
+import org.opendaylight.yangtools.yang.data.api.codec.Int64Codec;
+import org.opendaylight.yangtools.yang.data.api.codec.Int8Codec;
+import org.opendaylight.yangtools.yang.data.api.codec.Uint16Codec;
+import org.opendaylight.yangtools.yang.data.api.codec.Uint32Codec;
+import org.opendaylight.yangtools.yang.data.api.codec.Uint64Codec;
+import org.opendaylight.yangtools.yang.data.api.codec.Uint8Codec;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+
+/**
+ * Abstract base implementation of {@link XmlCodec}, which wraps a {@link TypeDefinitionAwareCodec}.
+ *
+ * @param <T> Deserialized object type
+ */
+abstract class AbstractXmlCodec<T> implements XmlCodec<T> {
+
+ private final Codec<String, T> codec;
+
+ protected AbstractXmlCodec(final Codec<String, T> codec) {
+ this.codec = Preconditions.checkNotNull(codec);
+ }
+
+ /**
+ * Create a proper XmlCodec based on the underlying codec type
+ * @param codec underlying codec
+ * @return An XmlCodec instance
+ */
+ public static XmlCodec<?> create(final Codec<String, ?> codec) {
+ if (codec instanceof BooleanCodec) {
+ return new BooleanXmlCodec((BooleanCodec<String>) codec);
+ } else if (codec instanceof DecimalCodec || codec instanceof Int8Codec
+ || codec instanceof Int16Codec || codec instanceof Int32Codec
+ || codec instanceof Int64Codec || codec instanceof Uint8Codec
+ || codec instanceof Uint16Codec || codec instanceof Uint32Codec
+ || codec instanceof Uint64Codec) {
+ return new NumberXmlCodec(codec);
+ } else {
+ return new QuotedXmlCodec(codec);
+ }
+ }
+
+ @Override
+ public final T deserialize(final String input) {
+ return codec.deserialize(input);
+ }
+
+ @Override
+ public final String serialize(final T input) {
+ return codec.serialize(input);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.yangtools.concepts.Codec;
+
+final class BooleanXmlCodec extends AbstractXmlCodec<Boolean> {
+
+ BooleanXmlCodec(final Codec<String, Boolean> codec) {
+ super(codec);
+ }
+
+ /**
+ * Serialize specified value with specified XMLStreamWriter.
+ *
+ * @param writer XMLStreamWriter
+ * @param value value which will be serialized to the writer
+ */
+ @Override
+ public void serializeToWriter(XMLStreamWriter writer, Boolean value) throws XMLStreamException {
+ writer.writeCharacters(String.valueOf(value));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.yangtools.concepts.Codec;
+
+final class NumberXmlCodec<T extends Number> extends AbstractXmlCodec<T>{
+
+ NumberXmlCodec(final Codec<String, T> codec) {
+ super(codec);
+ }
+
+ /**
+ * Serialize specified value with specified XMLStreamWriter.
+ *
+ * @param writer XMLStreamWriter
+ * @param value value which will be serialized to the writer
+ */
+ @Override
+ public void serializeToWriter(XMLStreamWriter writer, T value) throws XMLStreamException {
+ writer.writeCharacters(String.valueOf(value));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.yangtools.concepts.Codec;
+
+final class QuotedXmlCodec<T> extends AbstractXmlCodec<T> {
+
+ QuotedXmlCodec(final Codec<String, T> codec) {
+ super(codec);
+ }
+
+ /**
+ * Serialize specified value with specified XMLStreamWriter.
+ *
+ * @param writer XMLStreamWriter
+ * @param value value which will be serialized to the writer
+ */
+ @Override
+ public void serializeToWriter(XMLStreamWriter writer, T value) throws XMLStreamException {
+ writer.writeCharacters(serialize(value));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.yangtools.concepts.Codec;
+
+interface XmlCodec<T> extends Codec<String, T> {
+
+ /**
+ * Serialize specified value with specified XMLStreamWriter.
+ *
+ * @param writer XMLStreamWriter
+ * @param value value which will be serialized to the writer
+ */
+ void serializeToWriter(XMLStreamWriter writer, T value) throws XMLStreamException;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Verify;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+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.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
+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.opendaylight.yangtools.yang.model.util.type.DerivedTypes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class XmlCodecFactory {
+
+ private static final Logger LOG = LoggerFactory.getLogger(XmlCodecFactory.class);
+ private static final XmlCodec<Object> NULL_CODEC = new XmlCodec<Object>() {
+ @Override
+ public Object deserialize(final String input) {
+ return null;
+ }
+
+ @Override
+ public String serialize(final Object input) {
+ return null;
+ }
+
+ @Override
+ public void serializeToWriter(final XMLStreamWriter writer, final Object value) throws XMLStreamException {
+ // NOOP since codec is unkwown.
+ LOG.warn("Call of the serializeToWriter method on XmlCodecFactory.NULL_CODEC object. No operation " +
+ "performed.");
+ }
+ };
+
+ private final LoadingCache<DataSchemaNode, XmlCodec<Object>> codecs =
+ CacheBuilder.newBuilder().softValues().build(new CacheLoader<DataSchemaNode, XmlCodec<Object>>() {
+ @Override
+ public XmlCodec<Object> load(final DataSchemaNode key) throws Exception {
+ final TypeDefinition<?> type;
+ if (key instanceof LeafSchemaNode) {
+ type = ((LeafSchemaNode) key).getType();
+ } else if (key instanceof LeafListSchemaNode) {
+ type = ((LeafListSchemaNode) key).getType();
+ } else {
+ throw new IllegalArgumentException("Not supported node type " + key.getClass().getName());
+ }
+ return createCodec(key,type);
+ }
+ });
+
+ private final SchemaContext schemaContext;
+ private final XmlCodec<?> iidCodec;
+
+ private XmlCodecFactory(final SchemaContext context) {
+ this.schemaContext = Preconditions.checkNotNull(context);
+ iidCodec = new XmlStringInstanceIdentifierCodec(context, this);
+ }
+
+ /**
+ * Instantiate a new codec factory attached to a particular context.
+ *
+ * @param context SchemaContext to which the factory should be bound
+ * @return A codec factory instance.
+ */
+ public static XmlCodecFactory create(final SchemaContext context) {
+ return new XmlCodecFactory(context);
+ }
+
+ @SuppressWarnings("unchecked")
+ private XmlCodec<Object> createCodec(final DataSchemaNode key, final TypeDefinition<?> type) {
+ final TypeDefinition<?> normalizedType = DerivedTypes.derivedTypeBuilder(type, type.getPath()).build();
+ if (normalizedType instanceof LeafrefTypeDefinition) {
+ return createReferencedTypeCodec(key, (LeafrefTypeDefinition) normalizedType);
+ } else if (normalizedType instanceof IdentityrefTypeDefinition) {
+ final XmlCodec<?> xmlStringIdentityrefCodec =
+ new XmlStringIdentityrefCodec(schemaContext, key.getQName().getModule());
+ return (XmlCodec<Object>) xmlStringIdentityrefCodec;
+ }
+ return createFromSimpleType(normalizedType);
+ }
+
+ private XmlCodec<Object> createReferencedTypeCodec(final DataSchemaNode schema, final LeafrefTypeDefinition type) {
+ // FIXME: Verify if this does indeed support leafref of leafref
+ final TypeDefinition<?> referencedType =
+ SchemaContextUtil.getBaseTypeForLeafRef(type, getSchemaContext(), schema);
+ Verify.verifyNotNull(referencedType, "Unable to find base type for leafref node '%s'.", schema.getPath());
+ return createCodec(schema, referencedType);
+ }
+
+ @SuppressWarnings("unchecked")
+ private XmlCodec<Object> createFromSimpleType(final TypeDefinition<?> type) {
+ if (type instanceof InstanceIdentifierTypeDefinition) {
+ return (XmlCodec<Object>) iidCodec;
+ }
+ if (type instanceof EmptyTypeDefinition) {
+ return XmlEmptyCodec.INSTANCE;
+ }
+
+ final TypeDefinitionAwareCodec<Object, ?> codec = TypeDefinitionAwareCodec.from(type);
+ if (codec == null) {
+ LOG.debug("Codec for type \"{}\" is not implemented yet.", type.getQName()
+ .getLocalName());
+ return NULL_CODEC;
+ }
+ return (XmlCodec<Object>) AbstractXmlCodec.create(codec);
+ }
+
+ SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+
+ XmlCodec<Object> codecFor(final DataSchemaNode schema) {
+ return codecs.getUnchecked(schema);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+final class XmlEmptyCodec implements XmlCodec<Object> {
+
+ static final XmlEmptyCodec INSTANCE = new XmlEmptyCodec();
+
+ private XmlEmptyCodec() {
+
+ }
+
+ @Override
+ public Object deserialize(final String input) {
+ return null;
+ }
+
+ @Override
+ public String serialize(final Object input) {
+ return null;
+ }
+
+ @Override
+ public void serializeToWriter(final XMLStreamWriter writer, final Object value) throws XMLStreamException {
+ writer.writeCharacters("");
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import com.google.common.base.Preconditions;
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.Set;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.DataSchemaNodeAwareAdaptor;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.util.AbstractNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.AnyXmlNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.CompositeNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.LeafListEntryNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.LeafListNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.LeafNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.ListEntryNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.ListNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.data.util.ParserStreamUtils;
+import org.opendaylight.yangtools.yang.data.util.RpcAsContainer;
+import org.opendaylight.yangtools.yang.data.util.SimpleNodeDataWithSchema;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * This class provides functionality for parsing an XML source containing YANG-modeled data. It disallows multiple
+ * instances of the same element except for leaf-list and list entries. It also expects that the YANG-modeled data in
+ * the XML source are wrapped in a root element.
+ */
+public final class XmlParserStream implements Closeable, Flushable {
+
+ private String rootElement = null;
+ private final SchemaAwareNormalizedNodeStreamWriter writer;
+ private final XmlCodecFactory codecs;
+ private final SchemaContext schema;
+ private final DataSchemaNode parentNode;
+
+ private XmlParserStream(final NormalizedNodeStreamWriter writer, final SchemaContext schemaContext,
+ final DataSchemaNode parentNode) {
+ this.schema = Preconditions.checkNotNull(schemaContext);
+ this.writer = DataSchemaNodeAwareAdaptor.forWriter(writer);
+ this.codecs = XmlCodecFactory.create(schemaContext);
+ this.parentNode = parentNode;
+ }
+
+ public static XmlParserStream create(final NormalizedNodeStreamWriter writer, final SchemaContext schemaContext,
+ final SchemaNode parentNode ) {
+ if (parentNode instanceof RpcDefinition) {
+ return new XmlParserStream(writer, schemaContext, new RpcAsContainer((RpcDefinition) parentNode));
+ }
+ Preconditions.checkArgument(parentNode instanceof DataSchemaNode, "Instance of DataSchemaNode class awaited.");
+ return new XmlParserStream(writer, schemaContext, (DataSchemaNode) parentNode);
+ }
+
+ public static XmlParserStream create(final NormalizedNodeStreamWriter writer, final SchemaContext schemaContext) {
+ return new XmlParserStream(writer, schemaContext, schemaContext);
+ }
+
+ /**
+ * This method parses the XML source and emits node events into a NormalizedNodeStreamWriter based on the
+ * YANG-modeled data contained in the XML source.
+ *
+ * @param reader
+ * StAX reader which is to used to walk through the XML source
+ * @return
+ * instance of XmlParserStream
+ * @throws XMLStreamException
+ * if a well-formedness error or an unexpected processing condition occurs while parsing the XML
+ * @throws URISyntaxException
+ * if the namespace URI of an XML element contains a syntax error
+ * @throws IOException
+ * if an error occurs while parsing the value of an anyxml node
+ * @throws ParserConfigurationException
+ * if an error occurs while parsing the value of an anyxml node
+ * @throws SAXException
+ * if an error occurs while parsing the value of an anyxml node
+ */
+ public XmlParserStream parse(final XMLStreamReader reader) throws XMLStreamException, URISyntaxException,
+ IOException, ParserConfigurationException, SAXException {
+ if (reader.hasNext()) {
+ final CompositeNodeDataWithSchema compositeNodeDataWithSchema = new CompositeNodeDataWithSchema(parentNode);
+ reader.nextTag();
+ rootElement = reader.getLocalName();
+ read(reader, compositeNodeDataWithSchema);
+ compositeNodeDataWithSchema.write(writer);
+ }
+
+ return this;
+ }
+
+ private String readAnyXmlValue(XMLStreamReader in) throws XMLStreamException {
+ String result = "";
+ String anyXmlElementName = in.getLocalName();
+
+ while (in.hasNext()) {
+ int eventType = in.next();
+
+ if (eventType == XMLStreamConstants.START_ELEMENT) {
+ result += "<" + in.getLocalName() + ">";
+ } else if (eventType == XMLStreamConstants.END_ELEMENT) {
+ if (in.getLocalName().equals(anyXmlElementName)) {
+ break;
+ }
+
+ result += "</" + in.getLocalName() + ">";
+ } else if (eventType == XMLStreamConstants.CHARACTERS) {
+ result += in.getText();
+ }
+ }
+
+ return result;
+ }
+
+ private void read(final XMLStreamReader in, AbstractNodeDataWithSchema parent) throws XMLStreamException,
+ URISyntaxException, ParserConfigurationException, SAXException, IOException {
+ if (in.hasNext()) {
+ if (parent instanceof LeafNodeDataWithSchema || parent instanceof LeafListEntryNodeDataWithSchema) {
+ setValue(parent, in.getElementText().trim());
+ in.nextTag();
+ return;
+ } else if (parent instanceof LeafListNodeDataWithSchema || parent instanceof ListNodeDataWithSchema) {
+ String parentSchemaName = parent.getSchema().getQName().getLocalName();
+ String xmlElementName = in.getLocalName();
+ while (xmlElementName.equals(parentSchemaName)) {
+ AbstractNodeDataWithSchema newChild = newEntryNode(parent);
+ read(in, newChild);
+ xmlElementName = in.getLocalName();
+ }
+
+ return;
+ } else if (parent instanceof AnyXmlNodeDataWithSchema) {
+ setValue(parent, readAnyXmlValue(in));
+ in.nextTag();
+ return;
+ }
+
+ switch (in.nextTag()) {
+ case XMLStreamConstants.START_ELEMENT:
+ final Set<String> namesakes = new HashSet<>();
+ while (in.hasNext()) {
+ String xmlElementName = in.getLocalName();
+ String xmlElementNamespace = in.getNamespaceURI();
+
+ if (xmlElementName.equals(rootElement)) {
+ break;
+ }
+
+ DataSchemaNode parentSchema = parent.getSchema();
+ if (parentSchema instanceof YangModeledAnyXmlSchemaNode) {
+ parentSchema = ((YangModeledAnyXmlSchemaNode) parentSchema).getSchemaOfAnyXmlData();
+ }
+
+ String parentSchemaName = parentSchema.getQName().getLocalName();
+ if (parentSchemaName.equals(xmlElementName)
+ && in.getEventType() == XMLStreamConstants.END_ELEMENT) {
+ in.nextTag();
+ break;
+ }
+
+ if (namesakes.contains(xmlElementName)) {
+ int lineNumber = in.getLocation().getLineNumber();
+ int columnNumber = in.getLocation().getColumnNumber();
+ throw new IllegalStateException("Duplicate element \"" + xmlElementName + "\" in XML " +
+ "input at: line " + lineNumber + " column " + columnNumber);
+ }
+ namesakes.add(xmlElementName);
+
+ Deque<DataSchemaNode> childDataSchemaNodes = ParserStreamUtils.findSchemaNodeByNameAndNamespace(
+ parentSchema, xmlElementName, new URI(xmlElementNamespace));
+
+ if (childDataSchemaNodes.isEmpty()) {
+ throw new IllegalStateException("Schema for node with name " + xmlElementName +
+ " and namespace " + xmlElementNamespace + " doesn't exist.");
+ }
+
+ AbstractNodeDataWithSchema newChild =
+ ((CompositeNodeDataWithSchema) parent).addChild(childDataSchemaNodes);
+
+ read(in, newChild);
+ }
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ in.nextTag();
+ break;
+ }
+ }
+ }
+
+ private void setValue(final AbstractNodeDataWithSchema parent, final String value) throws
+ ParserConfigurationException, SAXException, IOException {
+ Preconditions.checkArgument(parent instanceof SimpleNodeDataWithSchema, "Node %s is not a simple type",
+ parent.getSchema().getQName());
+ final SimpleNodeDataWithSchema parentSimpleNode = (SimpleNodeDataWithSchema) parent;
+ Preconditions.checkArgument(parentSimpleNode.getValue() == null, "Node '%s' has already set its value to '%s'",
+ parentSimpleNode.getSchema().getQName(), parentSimpleNode.getValue());
+
+ final Object translatedValue = translateValueByType(value, parentSimpleNode.getSchema());
+ parentSimpleNode.setValue(translatedValue);
+ }
+
+ private Object translateValueByType(final String value, final DataSchemaNode node) throws IOException,
+ SAXException, ParserConfigurationException {
+ if (node instanceof AnyXmlSchemaNode) {
+ /*
+ * FIXME: Figure out some YANG extension dispatch, which will
+ * reuse JSON parsing or XML parsing - anyxml is not well-defined in
+ * JSON.
+ */
+ DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ Document doc = db.parse( new InputSource(new StringReader(value)));
+ doc.normalize();
+ DOMSource anyXmlValueSource = new DOMSource(doc);
+
+ return anyXmlValueSource;
+ }
+ return codecs.codecFor(node).deserialize(value);
+ }
+
+ private AbstractNodeDataWithSchema newEntryNode(final AbstractNodeDataWithSchema parent) {
+ AbstractNodeDataWithSchema newChild;
+ if (parent instanceof ListNodeDataWithSchema) {
+ newChild = new ListEntryNodeDataWithSchema(parent.getSchema());
+ } else {
+ newChild = new LeafListEntryNodeDataWithSchema(parent.getSchema());
+ }
+ ((CompositeNodeDataWithSchema) parent).addChild(newChild);
+ return newChild;
+ }
+
+ @Override
+ public void close() throws IOException {
+ writer.flush();
+ writer.close();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ writer.flush();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import com.google.common.base.Preconditions;
+import java.net.URI;
+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.util.AbstractModuleStringIdentityrefCodec;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+final class XmlStringIdentityrefCodec extends AbstractModuleStringIdentityrefCodec implements XmlCodec<QName> {
+
+ private final SchemaContext context;
+ private final QNameModule parentModuleQname;
+
+ XmlStringIdentityrefCodec(final SchemaContext context, final QNameModule parentModule) {
+ this.context = Preconditions.checkNotNull(context);
+ this.parentModuleQname = Preconditions.checkNotNull(parentModule);
+ }
+
+ @Override
+ protected Module moduleForPrefix(final String prefix) {
+ if (prefix.isEmpty()) {
+ return context.findModuleByNamespaceAndRevision(parentModuleQname.getNamespace(),
+ parentModuleQname.getRevision());
+ } else {
+ return context.findModuleByName(prefix, null);
+ }
+ }
+
+ @Override
+ protected String prefixForNamespace(final URI namespace) {
+ final Module module = context.findModuleByNamespaceAndRevision(namespace, null);
+ return module == null ? null : module.getName();
+ }
+
+ /**
+ * Serialize QName with specified XMLStreamWriter.
+ *
+ * @param writer XMLStreamWriter
+ * @param value QName
+ */
+ @Override
+ public void serializeToWriter(XMLStreamWriter writer, QName value) throws XMLStreamException {
+ writer.writeCharacters(serialize(value));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import com.google.common.base.Preconditions;
+import java.net.URI;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+final class XmlStringInstanceIdentifierCodec extends AbstractModuleStringInstanceIdentifierCodec
+ implements XmlCodec<YangInstanceIdentifier> {
+
+ private final DataSchemaContextTree dataContextTree;
+ private final XmlCodecFactory codecFactory;
+ private final SchemaContext context;
+
+ XmlStringInstanceIdentifierCodec(final SchemaContext context, final XmlCodecFactory jsonCodecFactory) {
+ this.context = Preconditions.checkNotNull(context);
+ this.dataContextTree = DataSchemaContextTree.from(context);
+ this.codecFactory = Preconditions.checkNotNull(jsonCodecFactory);
+ }
+
+ @Override
+ protected Module moduleForPrefix(final String prefix) {
+ return context.findModuleByName(prefix, null);
+ }
+
+ @Override
+ protected String prefixForNamespace(final URI namespace) {
+ final Module module = context.findModuleByNamespaceAndRevision(namespace, null);
+ return module == null ? null : module.getName();
+ }
+
+ @Override
+ protected DataSchemaContextTree getDataContextTree() {
+ return dataContextTree;
+ }
+
+ @Override
+ protected Object deserializeKeyValue(final DataSchemaNode schemaNode, final String value) {
+ Preconditions.checkNotNull(schemaNode, "schemaNode cannot be null");
+ Preconditions.checkArgument(schemaNode instanceof LeafSchemaNode, "schemaNode must be of type LeafSchemaNode");
+ final XmlCodec<Object> objectXmlCodec = codecFactory.codecFor(schemaNode);
+ return objectXmlCodec.deserialize(value);
+ }
+
+ /**
+ * Serialize YangInstanceIdentifier with specified XMLStreamWriter.
+ *
+ * @param writer XMLStreamWriter
+ * @param value YangInstanceIdentifier
+ */
+ @Override
+ public void serializeToWriter(final XMLStreamWriter writer, final YangInstanceIdentifier value)
+ throws XMLStreamException {
+ writer.writeCharacters(serialize(value));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.codec.xml;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+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.impl.schema.Builders;
+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.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+import org.xml.sax.SAXException;
+
+public class XmlToNormalizedNodesTest {
+
+ private QNameModule bazModule;
+
+ private QName outerContainer;
+
+ private QName myContainer1;
+ private QName myKeyedList;
+ private QName myKeyLeaf;
+ private QName myLeafInList1;
+ private QName myLeafInList2;
+ private QName myLeaf1;
+ private QName myLeafList;
+
+ private QName myContainer2;
+ private QName innerContainer;
+ private QName myLeaf2;
+ private QName myLeaf3;
+ private QName myChoice;
+ private QName myLeafInCase2;
+
+ private QName myContainer3;
+ private QName myDoublyKeyedList;
+ private QName myFirstKeyLeaf;
+ private QName mySecondKeyLeaf;
+ private QName myLeafInList3;
+
+ @Before
+ public void setup() throws URISyntaxException, ParseException {
+ bazModule = QNameModule.create(new URI("baz-namespace"), SimpleDateFormatUtil.getRevisionFormat().parse
+ ("1970-01-01"));
+
+ outerContainer = QName.create(bazModule, "outer-container");
+
+ myContainer1 = QName.create(bazModule, "my-container-1");
+ myKeyedList = QName.create(bazModule, "my-keyed-list");
+ myKeyLeaf = QName.create(bazModule, "my-key-leaf");
+ myLeafInList1 = QName.create(bazModule, "my-leaf-in-list-1");
+ myLeafInList2 = QName.create(bazModule, "my-leaf-in-list-2");
+ myLeaf1 = QName.create(bazModule, "my-leaf-1");
+ myLeafList = QName.create(bazModule, "my-leaf-list");
+
+ myContainer2 = QName.create(bazModule, "my-container-2");
+ innerContainer = QName.create(bazModule, "inner-container");
+ myLeaf2 = QName.create(bazModule, "my-leaf-2");
+ myLeaf3 = QName.create(bazModule, "my-leaf-3");
+ myChoice = QName.create(bazModule, "my-choice");
+ myLeafInCase2 = QName.create(bazModule, "my-leaf-in-case-2");
+
+ myContainer3 = QName.create(bazModule, "my-container-3");
+ myDoublyKeyedList = QName.create(bazModule, "my-doubly-keyed-list");
+ myFirstKeyLeaf = QName.create(bazModule, "my-first-key-leaf");
+ mySecondKeyLeaf = QName.create(bazModule, "my-second-key-leaf");
+ myLeafInList3 = QName.create(bazModule, "my-leaf-in-list-3");
+ }
+
+ @Test
+ public void testComplexXmlParsing() throws IOException, URISyntaxException, ReactorException, XMLStreamException,
+ ParserConfigurationException, SAXException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl("/baz.yang", false));
+
+ SchemaContext schemaContext = reactor.buildEffective();
+
+ final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/baz.xml");
+
+ final XMLInputFactory factory = XMLInputFactory.newInstance();
+ final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
+ xmlParser.parse(reader);
+
+ final NormalizedNode<?, ?> transformedInput = result.getResult();
+ assertNotNull(transformedInput);
+
+ final NormalizedNode<?, ?> expectedNormalizedNode = buildOuterContainerNode();
+ assertNotNull(expectedNormalizedNode);
+
+ assertEquals(expectedNormalizedNode, transformedInput);
+ }
+
+ @Test
+ public void testSimpleXmlParsing() throws IOException, URISyntaxException, ReactorException, XMLStreamException,
+ ParserConfigurationException, SAXException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl("/foo.yang", false));
+
+ SchemaContext schemaContext = reactor.buildEffective();
+
+ final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/foo.xml");
+
+ final XMLInputFactory factory = XMLInputFactory.newInstance();
+ final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
+ xmlParser.parse(reader);
+
+ final NormalizedNode<?, ?> transformedInput = result.getResult();
+ assertNotNull(transformedInput);
+ }
+
+ @Test
+ public void shouldFailOnDuplicateLeaf() throws ReactorException, XMLStreamException, IOException,
+ ParserConfigurationException, SAXException, URISyntaxException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl("/foo.yang", false));
+
+ SchemaContext schemaContext = reactor.buildEffective();
+
+ final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo.xml");
+
+ final XMLInputFactory factory = XMLInputFactory.newInstance();
+ final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
+ try {
+ xmlParser.parse(reader);
+ fail("IllegalStateException should have been thrown because of duplicate leaf.");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("Duplicate element \"decimal64-leaf\" in XML input"));
+ }
+
+ }
+
+ @Test
+ public void shouldFailOnDuplicateAnyXml() throws ReactorException, XMLStreamException, IOException,
+ ParserConfigurationException, SAXException, URISyntaxException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl("/foo.yang", false));
+
+ SchemaContext schemaContext = reactor.buildEffective();
+
+ final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-2.xml");
+
+ final XMLInputFactory factory = XMLInputFactory.newInstance();
+ final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
+ try {
+ xmlParser.parse(reader);
+ fail("IllegalStateException should have been thrown because of duplicate anyxml");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("Duplicate element \"my-anyxml\" in XML input"));
+ }
+ }
+
+ @Test
+ public void shouldFailOnDuplicateContainer() throws ReactorException, XMLStreamException, IOException,
+ ParserConfigurationException, SAXException, URISyntaxException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl("/foo.yang", false));
+
+ SchemaContext schemaContext = reactor.buildEffective();
+
+ final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-3.xml");
+
+ final XMLInputFactory factory = XMLInputFactory.newInstance();
+ final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
+ try {
+ xmlParser.parse(reader);
+ fail("IllegalStateException should have been thrown because of duplicate container");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("Duplicate element \"leaf-container\" in XML input"));
+ }
+ }
+
+ @Test
+ public void shouldFailOnUnterminatedLeafElement() throws ReactorException, XMLStreamException, IOException,
+ ParserConfigurationException, SAXException, URISyntaxException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl("/baz.yang", false));
+
+ SchemaContext schemaContext = reactor.buildEffective();
+
+ final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz.xml");
+
+ final XMLInputFactory factory = XMLInputFactory.newInstance();
+ final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
+ try {
+ xmlParser.parse(reader);
+ fail("XMLStreamException should have been thrown because of unterminated leaf element.");
+ } catch (XMLStreamException ex) {
+ assertTrue(ex.getMessage().contains("elementGetText() function expects text only elment but " +
+ "START_ELEMENT was encountered."));
+ }
+ }
+
+ @Test
+ public void shouldFailOnUnterminatedLeafElement2() throws ReactorException, XMLStreamException, IOException,
+ ParserConfigurationException, SAXException, URISyntaxException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl("/baz.yang", false));
+
+ SchemaContext schemaContext = reactor.buildEffective();
+
+ final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-2.xml");
+
+ final XMLInputFactory factory = XMLInputFactory.newInstance();
+ final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
+ try {
+ xmlParser.parse(reader);
+ fail("XMLStreamException should have been thrown because of unterminated leaf element.");
+ } catch (XMLStreamException ex) {
+ assertTrue(ex.getMessage().contains("The element type \"my-leaf-1\" must be terminated by the matching " +
+ "end-tag \"</my-leaf-1>\"."));
+ }
+ }
+
+ @Test
+ public void shouldFailOnUnterminatedContainerElement() throws ReactorException, XMLStreamException, IOException,
+ ParserConfigurationException, SAXException, URISyntaxException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl("/baz.yang", false));
+
+ SchemaContext schemaContext = reactor.buildEffective();
+
+ final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-4.xml");
+
+ final XMLInputFactory factory = XMLInputFactory.newInstance();
+ final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
+ try {
+ xmlParser.parse(reader);
+ fail("XMLStreamException should have been thrown because of unterminated container element.");
+ } catch (XMLStreamException ex) {
+ assertTrue(ex.getMessage().contains("The element type \"my-container-1\" must be terminated by the " +
+ "matching end-tag \"</my-container-1>\"."));
+ }
+ }
+
+ @Test
+ public void shouldFailOnUnexistingContainerElement() throws ReactorException, XMLStreamException, IOException,
+ ParserConfigurationException, SAXException, URISyntaxException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl("/baz.yang", false));
+
+ SchemaContext schemaContext = reactor.buildEffective();
+
+ final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-3.xml");
+
+ final XMLInputFactory factory = XMLInputFactory.newInstance();
+ final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
+ try {
+ xmlParser.parse(reader);
+ fail("IllegalStateException should have been thrown because of an unexisting container element.");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("Schema for node with name my-container-1 and namespace baz-namespace" +
+ " doesn't exist."));
+ }
+ }
+
+ private NormalizedNode<?, ?> buildOuterContainerNode() {
+ // my-container-1
+ MapNode myKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myKeyedList))
+ .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
+ new NodeIdentifierWithPredicates(myKeyedList, myKeyLeaf, "listkeyvalue1"))
+ .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList1))
+ .withValue("listleafvalue1").build())
+ .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList2))
+ .withValue("listleafvalue2").build()).build())
+ .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
+ new NodeIdentifierWithPredicates(myKeyedList, myKeyLeaf, "listkeyvalue2"))
+ .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList1))
+ .withValue("listleafvalue12").build())
+ .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList2))
+ .withValue("listleafvalue22").build()).build()).build();
+
+ LeafNode<?> myLeaf1Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf1))
+ .withValue("value1").build();
+
+ LeafSetNode<?> myLeafListNode = Builders.leafSetBuilder().withNodeIdentifier(new NodeIdentifier(myLeafList))
+ .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
+ new NodeWithValue<>(myLeafList, "lflvalue1")).withValue("lflvalue1").build())
+ .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
+ new NodeWithValue<>(myLeafList, "lflvalue2")).withValue("lflvalue2").build()).build();
+
+ ContainerNode myContainer1Node = Builders.containerBuilder().withNodeIdentifier(
+ new NodeIdentifier(myContainer1))
+ .withChild(myKeyedListNode)
+ .withChild(myLeaf1Node)
+ .withChild(myLeafListNode).build();
+
+ // my-container-2
+ ContainerNode innerContainerNode = Builders.containerBuilder().withNodeIdentifier(
+ new NodeIdentifier(innerContainer))
+ .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf2))
+ .withValue("value2").build()).build();
+
+ LeafNode<?> myLeaf3Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf3))
+ .withValue("value3").build();
+
+ ChoiceNode myChoiceNode = Builders.choiceBuilder().withNodeIdentifier(new NodeIdentifier(myChoice))
+ .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInCase2))
+ .withValue("case2value").build()).build();
+
+ ContainerNode myContainer2Node = Builders.containerBuilder().withNodeIdentifier(
+ new NodeIdentifier(myContainer2))
+ .withChild(innerContainerNode)
+ .withChild(myLeaf3Node)
+ .withChild(myChoiceNode).build();
+
+ // my-container-3
+ Map<QName, Object> keys = new HashMap<>();
+ keys.put(myFirstKeyLeaf, "listkeyvalue1");
+ keys.put(mySecondKeyLeaf, "listkeyvalue2");
+
+ MapNode myDoublyKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myDoublyKeyedList))
+ .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
+ new NodeIdentifierWithPredicates(myDoublyKeyedList, keys))
+ .withChild(Builders.leafBuilder().withNodeIdentifier(
+ new NodeIdentifier(myLeafInList3)).withValue("listleafvalue1").build()).build())
+ .build();
+
+ AugmentationNode myDoublyKeyedListAugNode = Builders.augmentationBuilder().withNodeIdentifier(
+ new AugmentationIdentifier(Sets.newHashSet(myDoublyKeyedList)))
+ .withChild(myDoublyKeyedListNode).build();
+
+ ContainerNode myContainer3Node = Builders.containerBuilder().withNodeIdentifier(
+ new NodeIdentifier(myContainer3))
+ .withChild(myDoublyKeyedListAugNode).build();
+
+ AugmentationNode myContainer3AugNode = Builders.augmentationBuilder().withNodeIdentifier(
+ new AugmentationIdentifier(Sets.newHashSet(myContainer3)))
+ .withChild(myContainer3Node).build();
+
+ ContainerNode outerContainerNode = Builders.containerBuilder().withNodeIdentifier(
+ new NodeIdentifier(outerContainer))
+ .withChild(myContainer1Node)
+ .withChild(myContainer2Node)
+ .withChild(myContainer3AugNode).build();
+
+ return outerContainerNode;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<root xmlns="baz-namespace">
+ <outer-container>
+ <my-container-1>
+ <my-keyed-list>
+ <my-key-leaf>listkeyvalue1</my-key-leaf>
+ <my-leaf-in-list-1>listleafvalue1</my-leaf-in-list-1>
+ <my-leaf-in-list-2>listleafvalue2</my-leaf-in-list-2>
+ </my-keyed-list>
+
+ <my-keyed-list>
+ <my-key-leaf>listkeyvalue2</my-key-leaf>
+ <my-leaf-in-list-1>listleafvalue12</my-leaf-in-list-1>
+ <my-leaf-in-list-2>listleafvalue22</my-leaf-in-list-2>
+ </my-keyed-list>
+
+ <my-leaf-1>value1</my-leaf-1>
+
+ <my-leaf-list>lflvalue1</my-leaf-list>
+ <my-leaf-list>lflvalue2</my-leaf-list>
+ </my-container-1>
+
+ <my-container-2>
+ <inner-container>
+ <my-leaf-2>value2</my-leaf-2>
+ </inner-container>
+ <my-leaf-3>value3</my-leaf-3>
+ <my-leaf-in-case-2>case2value</my-leaf-in-case-2>
+ </my-container-2>
+
+ <my-container-3>
+ <my-doubly-keyed-list>
+ <my-first-key-leaf>listkeyvalue1</my-first-key-leaf>
+ <my-second-key-leaf>listkeyvalue2</my-second-key-leaf>
+ <my-leaf-in-list-3>listleafvalue1</my-leaf-in-list-3>
+ </my-doubly-keyed-list>
+ </my-container-3>
+ </outer-container>
+</root>
--- /dev/null
+module baz {
+ namespace "baz-namespace";
+ prefix bz;
+
+ container outer-container {
+ container my-container-1 {
+ list my-keyed-list {
+ key "my-key-leaf";
+
+ leaf my-key-leaf {
+ type string;
+ }
+
+ leaf my-leaf-in-list-1 {
+ type string;
+ }
+
+ leaf my-leaf-in-list-2 {
+ type string;
+ }
+ }
+
+ leaf my-leaf-1 {
+ type string;
+ }
+
+ leaf-list my-leaf-list {
+ type string;
+ }
+ }
+
+ container my-container-2 {
+ container inner-container {
+ leaf my-leaf-2 {
+ type string;
+ }
+ }
+
+ leaf my-leaf-3 {
+ type string;
+ }
+
+ choice my-choice {
+ case my-case-1 {
+ leaf my-leaf-in-case-1 {
+ type string;
+ }
+ }
+
+ case my-case-2 {
+ leaf my-leaf-in-case-2 {
+ type string;
+ }
+ }
+ }
+ }
+ }
+
+ augment "/outer-container" {
+ container my-container-3 {
+
+ }
+ }
+
+ augment "/outer-container/my-container-3" {
+ list my-doubly-keyed-list {
+ key "my-first-key-leaf my-second-key-leaf";
+
+ leaf "my-first-key-leaf" {
+ type string;
+ }
+
+ leaf my-second-key-leaf {
+ type string;
+ }
+
+ leaf my-leaf-in-list-3 {
+ type string;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<root xmlns="foo-namespace">
+ <parent-container>
+ <leaf-container>
+ <int32-leaf>1500</int32-leaf>
+ <decimal64-leaf>150.45</decimal64-leaf>
+ <string-leaf>hello world</string-leaf>
+ <leafref-leaf>hello world</leafref-leaf>
+ <empty-leaf/>
+ <boolean-leaf>true</boolean-leaf>
+ <enum-leaf>five</enum-leaf>
+ </leaf-container>
+ <anyxml-container>
+ <my-anyxml><my-element><my-sub-element>sub-element value</my-sub-element></my-element></my-anyxml>
+ </anyxml-container>
+ </parent-container>
+</root>
--- /dev/null
+module foo {
+ namespace "foo-namespace";
+ prefix "f";
+
+ container parent-container {
+
+ container leaf-container {
+
+ leaf int32-leaf {
+ type int32;
+ }
+
+ leaf decimal64-leaf {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+ leaf string-leaf {
+ type string;
+ }
+
+ leaf leafref-leaf {
+ type leafref {
+ path "../string-leaf";
+ }
+ }
+
+ leaf empty-leaf {
+ type empty;
+ }
+
+ leaf boolean-leaf {
+ type boolean;
+ }
+
+ leaf enum-leaf {
+ type enumeration {
+ enum zero;
+ enum one;
+ enum five {
+ value 5;
+ }
+ }
+ }
+ }
+
+ container anyxml-container {
+ anyxml my-anyxml;
+ }
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<root xmlns="baz-namespace">
+ <outer-container>
+ <my-container-1>
+ <my-keyed-list>
+ <my-key-leaf>listkeyvalue1</my-key-leaf>
+ <my-leaf-in-list-1>listleafvalue1</my-leaf-in-list-1>
+ <my-leaf-in-list-2>listleafvalue2</my-leaf-in-list-2>
+ </my-keyed-list>
+
+ <my-keyed-list>
+ <my-key-leaf>listkeyvalue2</my-key-leaf>
+ <my-leaf-in-list-1>listleafvalue12</my-leaf-in-list-1>
+ <my-leaf-in-list-2>listleafvalue22</my-leaf-in-list-2>
+ </my-keyed-list>
+
+ <my-leaf-1>value1</invalid-my-leaf-1>
+
+ <my-leaf-list>lflvalue1</my-leaf-list>
+ <my-leaf-list>lflvalue2</my-leaf-list>
+ </my-container-1>
+
+ <my-container-2>
+ <inner-container>
+ <my-leaf-2>value2</my-leaf-2>
+ </inner-container>
+ <my-leaf-3>value3</my-leaf-3>
+ <my-leaf-in-case-2>case2value</my-leaf-in-case-2>
+ </my-container-2>
+
+ <my-container-3>
+ <my-doubly-keyed-list>
+ <my-first-key-leaf>listkeyvalue1</my-first-key-leaf>
+ <my-second-key-leaf>listkeyvalue2</my-second-key-leaf>
+ <my-leaf-in-list-3>listleafvalue3</my-leaf-in-list-3>
+ </my-doubly-keyed-list>
+ </my-container-3>
+ </outer-container>
+</root>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<root xmlns="baz-namespace">
+ <outer-container>
+ <my-container-1>
+ <my-keyed-list>
+ <my-key-leaf>listkeyvalue1</my-key-leaf>
+ <my-leaf-in-list-1>listleafvalue1</my-leaf-in-list-1>
+ <my-leaf-in-list-2>listleafvalue2</my-leaf-in-list-2>
+ </my-keyed-list>
+
+ <my-keyed-list>
+ <my-key-leaf>listkeyvalue2</my-key-leaf>
+ <my-leaf-in-list-1>listleafvalue12</my-leaf-in-list-1>
+ <my-leaf-in-list-2>listleafvalue22</my-leaf-in-list-2>
+ </my-keyed-list>
+
+ <my-leaf-1>value1</my-leaf-1>
+
+ <my-leaf-list>lflvalue1</my-leaf-list>
+ <my-leaf-list>lflvalue2</my-leaf-list>
+ <my-container-1>
+
+ <my-container-2>
+ <inner-container>
+ <my-leaf-2>value2</my-leaf-2>
+ </inner-container>
+ <my-leaf-3>value3</my-leaf-3>
+ <my-leaf-in-case-2>case2value</my-leaf-in-case-2>
+ </my-container-2>
+
+ <my-container-3>
+ <my-doubly-keyed-list>
+ <my-first-key-leaf>listkeyvalue1</my-first-key-leaf>
+ <my-second-key-leaf>listkeyvalue2</my-second-key-leaf>
+ <my-leaf-in-list-3>listleafvalue3</my-leaf-in-list-3>
+ </my-doubly-keyed-list>
+ </my-container-3>
+ </outer-container>
+</root>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<root xmlns="baz-namespace">
+ <outer-container>
+ <my-container-1>
+ <my-keyed-list>
+ <my-key-leaf>listkeyvalue1</my-key-leaf>
+ <my-leaf-in-list-1>listleafvalue1</my-leaf-in-list-1>
+ <my-leaf-in-list-2>listleafvalue2</my-leaf-in-list-2>
+ </my-keyed-list>
+
+ <my-keyed-list>
+ <my-key-leaf>listkeyvalue2</my-key-leaf>
+ <my-leaf-in-list-1>listleafvalue12</my-leaf-in-list-1>
+ <my-leaf-in-list-2>listleafvalue22</my-leaf-in-list-2>
+ </my-keyed-list>
+
+ <my-leaf-1>value1</my-leaf-1>
+
+ <my-leaf-list>lflvalue1</my-leaf-list>
+ <my-leaf-list>lflvalue2</my-leaf-list>
+ </invalid-my-container-1>
+
+ <my-container-2>
+ <inner-container>
+ <my-leaf-2>value2</my-leaf-2>
+ </inner-container>
+ <my-leaf-3>value3</my-leaf-3>
+ <my-leaf-in-case-2>case2value</my-leaf-in-case-2>
+ </my-container-2>
+
+ <my-container-3>
+ <my-doubly-keyed-list>
+ <my-first-key-leaf>listkeyvalue1</my-first-key-leaf>
+ <my-second-key-leaf>listkeyvalue2</my-second-key-leaf>
+ <my-leaf-in-list-3>listleafvalue3</my-leaf-in-list-3>
+ </my-doubly-keyed-list>
+ </my-container-3>
+ </outer-container>
+</root>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<root xmlns="baz-namespace">
+ <outer-container>
+ <my-container-1>
+ <my-keyed-list>
+ <my-key-leaf>listkeyvalue1</my-key-leaf>
+ <my-leaf-in-list-1>listleafvalue1</my-leaf-in-list-1>
+ <my-leaf-in-list-2>listleafvalue2</my-leaf-in-list-2>
+ </my-keyed-list>
+
+ <my-keyed-list>
+ <my-key-leaf>listkeyvalue2</my-key-leaf>
+ <my-leaf-in-list-1>listleafvalue12</my-leaf-in-list-1>
+ <my-leaf-in-list-2>listleafvalue22</my-leaf-in-list-2>
+ </my-keyed-list>
+
+ <my-leaf-1>value1<my-leaf-1>
+
+ <my-leaf-list>lflvalue1</my-leaf-list>
+ <my-leaf-list>lflvalue2</my-leaf-list>
+ </my-container-1>
+
+ <my-container-2>
+ <inner-container>
+ <my-leaf-2>value2</my-leaf-2>
+ </inner-container>
+ <my-leaf-3>value3</my-leaf-3>
+ <my-leaf-in-case-2>case2value</my-leaf-in-case-2>
+ </my-container-2>
+
+ <my-container-3>
+ <my-doubly-keyed-list>
+ <my-first-key-leaf>listkeyvalue1</my-first-key-leaf>
+ <my-second-key-leaf>listkeyvalue2</my-second-key-leaf>
+ <my-leaf-in-list-3>listleafvalue3</my-leaf-in-list-3>
+ </my-doubly-keyed-list>
+ </my-container-3>
+ </outer-container>
+</root>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<root xmlns="foo-namespace">
+ <parent-container>
+ <leaf-container>
+ <int32-leaf>1500</int32-leaf>
+ <decimal64-leaf>150.45</decimal64-leaf>
+ <string-leaf>hello world</string-leaf>
+ <leafref-leaf>hello world</leafref-leaf>
+ <empty-leaf/>
+ <boolean-leaf>true</boolean-leaf>
+ <enum-leaf>five</enum-leaf>
+ </leaf-container>
+ <anyxml-container>
+ <my-anyxml>
+ <my-element>
+ <my-sub-element>sub-element value</my-sub-element>
+ </my-element>
+ </my-anyxml>
+ <my-anyxml>
+ <my-element-2>
+ <my-sub-element-2>sub-element value 2</my-sub-element-2>
+ </my-element-2>
+ </my-anyxml>
+ </anyxml-container>
+ </parent-container>
+</root>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<root xmlns="foo-namespace">
+ <parent-container>
+ <leaf-container>
+ <int32-leaf>1500</int32-leaf>
+ <decimal64-leaf>150.45</decimal64-leaf>
+ <string-leaf>hello world</string-leaf>
+ <leafref-leaf>hello world</leafref-leaf>
+ <empty-leaf/>
+ <boolean-leaf>true</boolean-leaf>
+ <enum-leaf>five</enum-leaf>
+ </leaf-container>
+ <leaf-container>
+ <int32-leaf>2500</int32-leaf>
+ <decimal64-leaf>250.45</decimal64-leaf>
+ <string-leaf>goodbye world</string-leaf>
+ </leaf-container>
+ <anyxml-container>
+ <my-anyxml>
+ <my-element>
+ <my-sub-element>sub-element value</my-sub-element>
+ </my-element>
+ </my-anyxml>
+ </anyxml-container>
+ </parent-container>
+</root>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<root xmlns="foo-namespace">
+ <parent-container>
+ <leaf-container>
+ <int32-leaf>1500</int32-leaf>
+ <decimal64-leaf>150.45</decimal64-leaf>
+ <decimal64-leaf>240.35</decimal64-leaf>
+ <string-leaf>hello world</string-leaf>
+ <leafref-leaf>hello world</leafref-leaf>
+ <empty-leaf/>
+ <boolean-leaf>true</boolean-leaf>
+ <enum-leaf>five</enum-leaf>
+ </leaf-container>
+ <anyxml-container>
+ <my-anyxml>
+ <my-element>
+ <my-sub-element>sub-element value</my-sub-element>
+ </my-element>
+ </my-anyxml>
+ </anyxml-container>
+ </parent-container>
+</root>
\ No newline at end of file
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
* Utility abstract class for tracking parser state, as needed by StAX-like parser.
*/
@Beta
-abstract class AbstractNodeDataWithSchema {
+public abstract class AbstractNodeDataWithSchema {
private final DataSchemaNode schema;
- protected AbstractNodeDataWithSchema(final DataSchemaNode schema) {
+ public AbstractNodeDataWithSchema(final DataSchemaNode schema) {
this.schema = Preconditions.checkNotNull(schema);
}
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-class AnyXmlNodeDataWithSchema extends SimpleNodeDataWithSchema {
+public class AnyXmlNodeDataWithSchema extends SimpleNodeDataWithSchema {
public AnyXmlNodeDataWithSchema(final DataSchemaNode dataSchemaNode) {
super(dataSchemaNode);
@Override
public void write(final SchemaAwareNormalizedNodeStreamWriter writer) throws IOException {
writer.nextDataSchemaNode(getSchema());
- // FIXME: should be changed according to format of value
- writer.anyxmlNode(provideNodeIdentifier(), getValue());
+ writer.leafNode(provideNodeIdentifier(), getValue());
}
}
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
+
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
class CaseNodeDataWithSchema extends CompositeNodeDataWithSchema {
- public CaseNodeDataWithSchema(final ChoiceCaseNode schema) {
+ CaseNodeDataWithSchema(final ChoiceCaseNode schema) {
super(schema);
}
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
private CaseNodeDataWithSchema caseNodeDataWithSchema;
- public ChoiceNodeDataWithSchema(final ChoiceSchemaNode schema) {
+ ChoiceNodeDataWithSchema(final ChoiceSchemaNode schema) {
super(schema);
}
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
+import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.Map.Entry;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils;
import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
/**
* A node which is composed of multiple simpler nodes.
*/
-class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
+public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
/**
* nodes which were added to schema via augmentation and are present in data input
AugmentationSchema augSchema = null;
if (choiceCandidate.isAugmenting()) {
- augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), choiceCandidate);
+ augSchema = findCorrespondingAugment(getSchema(), choiceCandidate);
}
// looking for existing choice
AugmentationSchema augSchema = null;
if (schema.isAugmenting()) {
- augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), schema);
+ augSchema = findCorrespondingAugment(getSchema(), schema);
}
if (augSchema != null) {
augmentationsToChild.put(augSchema, newChild);
}
void addCompositeChild(final CompositeNodeDataWithSchema newChild) {
- AugmentationSchema augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), newChild.getSchema());
+ AugmentationSchema augSchema = findCorrespondingAugment(getSchema(), newChild.getSchema());
if (augSchema != null) {
augmentationsToChild.put(augSchema, newChild);
} else {
final Collection<AbstractNodeDataWithSchema> childsFromAgumentation = augmentationToChild.getValue();
if (!childsFromAgumentation.isEmpty()) {
// FIXME: can we get the augmentation schema?
- writer.startAugmentationNode(SchemaUtils.getNodeIdentifierForAugmentation(augmentationToChild.getKey()));
+ writer.startAugmentationNode(getNodeIdentifierForAugmentation(augmentationToChild.getKey()));
for (AbstractNodeDataWithSchema nodeDataWithSchema : childsFromAgumentation) {
nodeDataWithSchema.write(writer);
}
}
}
+
+ /**
+ * Tries to find in {@code parent} which is dealed as augmentation target node with QName as {@code child}. If such
+ * node is found then it is returned, else null.
+ *
+ * @param parent parent node
+ * @param child child node
+ * @return augmentation schema
+ */
+ private AugmentationSchema findCorrespondingAugment(final DataSchemaNode parent, final DataSchemaNode child) {
+ if (parent instanceof AugmentationTarget && !(parent instanceof ChoiceSchemaNode)) {
+ for (AugmentationSchema augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) {
+ DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName());
+ if (childInAugmentation != null) {
+ return augmentation;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static YangInstanceIdentifier.AugmentationIdentifier getNodeIdentifierForAugmentation(final AugmentationSchema schema) {
+ final Collection<QName> qnames = Collections2.transform(schema.getChildNodes(), QNAME_FUNCTION);
+ return new YangInstanceIdentifier.AugmentationIdentifier(ImmutableSet.copyOf(qnames));
+ }
+
+ private static final Function<DataSchemaNode, QName> QNAME_FUNCTION = new Function<DataSchemaNode, QName>() {
+ @Override
+ public QName apply(@Nonnull final DataSchemaNode input) {
+ return input.getQName();
+ }
+ };
}
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
class ContainerNodeDataWithSchema extends CompositeNodeDataWithSchema {
- public ContainerNodeDataWithSchema(final DataSchemaNode schema) {
+ ContainerNodeDataWithSchema(final DataSchemaNode schema) {
super(schema);
}
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-class LeafListEntryNodeDataWithSchema extends SimpleNodeDataWithSchema {
+public class LeafListEntryNodeDataWithSchema extends SimpleNodeDataWithSchema {
public LeafListEntryNodeDataWithSchema(final DataSchemaNode dataSchemaNode) {
super(dataSchemaNode);
}
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-class LeafListNodeDataWithSchema extends CompositeNodeDataWithSchema {
+public class LeafListNodeDataWithSchema extends CompositeNodeDataWithSchema {
public LeafListNodeDataWithSchema(final DataSchemaNode schema) {
super(schema);
}
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-class LeafNodeDataWithSchema extends SimpleNodeDataWithSchema {
+public class LeafNodeDataWithSchema extends SimpleNodeDataWithSchema {
public LeafNodeDataWithSchema(final DataSchemaNode schema) {
super(schema);
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import com.google.common.base.Preconditions;
import java.io.IOException;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-class ListEntryNodeDataWithSchema extends CompositeNodeDataWithSchema {
+public class ListEntryNodeDataWithSchema extends CompositeNodeDataWithSchema {
private final Map<QName, SimpleNodeDataWithSchema> qNameToKeys = new HashMap<>();
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-class ListNodeDataWithSchema extends CompositeNodeDataWithSchema {
+public class ListNodeDataWithSchema extends CompositeNodeDataWithSchema {
public ListNodeDataWithSchema(final DataSchemaNode schema) {
super(schema);
--- /dev/null
+/*
+ * Copyright (c) 2016 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.util;
+
+import java.net.URI;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+public final class ParserStreamUtils {
+
+ private ParserStreamUtils() {
+ throw new UnsupportedOperationException("Utility class should not be instantiated.");
+ }
+
+ /**
+ * Returns stack of schema nodes via which it was necessary to pass to get schema node with specified
+ * {@code childName} and {@code namespace}
+ *
+ * @param dataSchemaNode
+ * @param childName
+ * @param namespace
+ * @return stack of schema nodes via which it was passed through. If found schema node is direct child then stack
+ * contains only one node. If it is found under choice and case then stack should contains 2*n+1 element
+ * (where n is number of choices through it was passed)
+ */
+ public static Deque<DataSchemaNode> findSchemaNodeByNameAndNamespace(final DataSchemaNode dataSchemaNode,
+ final String childName, final URI namespace) {
+ final Deque<DataSchemaNode> result = new ArrayDeque<>();
+ final List<ChoiceSchemaNode> childChoices = new ArrayList<>();
+ DataSchemaNode potentialChildNode = null;
+ if (dataSchemaNode instanceof DataNodeContainer) {
+ for (final DataSchemaNode childNode : ((DataNodeContainer) dataSchemaNode).getChildNodes()) {
+ if (childNode instanceof ChoiceSchemaNode) {
+ childChoices.add((ChoiceSchemaNode) childNode);
+ } else {
+ final QName childQName = childNode.getQName();
+
+ if (childQName.getLocalName().equals(childName) && childQName.getNamespace().equals(namespace)) {
+ if (potentialChildNode == null ||
+ childQName.getRevision().after(potentialChildNode.getQName().getRevision())) {
+ potentialChildNode = childNode;
+ }
+ }
+ }
+ }
+ }
+ if (potentialChildNode != null) {
+ result.push(potentialChildNode);
+ return result;
+ }
+
+ // try to find data schema node in choice (looking for first match)
+ for (final ChoiceSchemaNode choiceNode : childChoices) {
+ for (final ChoiceCaseNode concreteCase : choiceNode.getCases()) {
+ final Deque<DataSchemaNode> resultFromRecursion = findSchemaNodeByNameAndNamespace(concreteCase, childName,
+ namespace);
+ if (!resultFromRecursion.isEmpty()) {
+ resultFromRecursion.push(concreteCase);
+ resultFromRecursion.push(choiceNode);
+ return resultFromRecursion;
+ }
+ }
+ }
+ return result;
+ }
+}
/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import java.util.ArrayList;
import java.util.Collection;
import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
import org.opendaylight.yangtools.yang.model.api.UsesNode;
-final class RpcAsContainer implements ContainerSchemaNode {
+public final class RpcAsContainer implements ContainerSchemaNode {
private final RpcDefinition delegate;
return delegate.getOutput();
}
- RpcAsContainer(final RpcDefinition parentNode) {
+ public RpcAsContainer(final RpcDefinition parentNode) {
delegate = parentNode;
}
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-abstract class SimpleNodeDataWithSchema extends AbstractNodeDataWithSchema {
+public abstract class SimpleNodeDataWithSchema extends AbstractNodeDataWithSchema {
private Object value;
super(dataSchemaNode);
}
- void setValue(final Object value) {
+ public void setValue(final Object value) {
this.value = value;
}
/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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.codec.gson;
+package org.opendaylight.yangtools.yang.data.util;
import java.io.IOException;
import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;