Bug 1441: Implement XML Stream Reader to Normalized Node Writer 31/37031/5
authorIgor Foltin <ifoltin@cisco.com>
Sat, 2 Apr 2016 11:06:34 +0000 (13:06 +0200)
committerRobert Varga <nite@hq.sk>
Mon, 2 May 2016 08:39:41 +0000 (08:39 +0000)
This patch introduces new XML Parser which walks the DOM tree
and emits events into a NormalizedNodeStreamWriter.

The parser is found in the newly created module yang-data-codec-xml.

Classes which are shared by XML and JSON Parser were moved to module yang-data-util.

Added documentation for the XML parser.

Change-Id: I5b7de341333f94ad75bc2ff93b0f47f2c007e793
Signed-off-by: Igor Foltin <ifoltin@cisco.com>
44 files changed:
common/artifacts/pom.xml
common/features/pom.xml
common/features/src/main/features/features.xml
docs/src/main/asciidoc/developer/introduction.adoc
yang/pom.xml
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java
yang/yang-data-codec-xml/pom.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/AbstractXmlCodec.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/BooleanXmlCodec.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NumberXmlCodec.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/QuotedXmlCodec.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodec.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodecFactory.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlEmptyCodec.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringIdentityrefCodec.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringInstanceIdentifierCodec.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlToNormalizedNodesTest.java [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/baz.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/baz.yang [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/foo.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/foo.yang [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/invalid-baz-2.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/invalid-baz-3.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/invalid-baz-4.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/invalid-baz.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/invalid-foo-2.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/invalid-foo-3.xml [new file with mode: 0644]
yang/yang-data-codec-xml/src/test/resources/invalid-foo.xml [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AbstractNodeDataWithSchema.java with 89% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AnyXmlNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlNodeDataWithSchema.java with 69% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/CaseNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CaseNodeDataWithSchema.java with 68% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ChoiceNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ChoiceNodeDataWithSchema.java with 88% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/CompositeNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CompositeNodeDataWithSchema.java with 77% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ContainerNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ContainerNodeDataWithSchema.java with 81% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafListEntryNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafListEntryNodeDataWithSchema.java with 80% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafListNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafListNodeDataWithSchema.java with 85% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafNodeDataWithSchema.java with 80% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ListEntryNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListEntryNodeDataWithSchema.java with 93% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ListNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListNodeDataWithSchema.java with 86% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ParserStreamUtils.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/RpcAsContainer.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/RpcAsContainer.java with 93% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/SimpleNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/SimpleNodeDataWithSchema.java with 69% similarity]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/YangModeledAnyXmlNodeDataWithSchema.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/YangModeledAnyXmlNodeDataWithSchema.java with 89% similarity]

index 023785f9b52fe15e2ec2136f05d9cb6f6a5a0605..d25f0fcb43e169fe3a2fab70c6ba2e6ba711fb33 100644 (file)
                 <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>
index cbc6b24323e9351cd104e7345a8627c001799f1b..82fb08fed060c22bc1e41144e4041c6b30e83597 100644 (file)
             <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>
index b984c6b1d91739b4b449a2d73be9e580455908bf..631a2e60fae244d7c4fa7c2b47620cae7f0fece9 100644 (file)
@@ -20,6 +20,8 @@
         <!-- 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'>
index 4e2a96a0c919f4b7d4dcd31272ef5d7f33edbc4a..7542f3c8622a31c34a6f2a6758a44b03c05a0828 100644 (file)
@@ -37,13 +37,14 @@ YANG Tools project consists of following logical subsystems:
   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
@@ -66,7 +67,7 @@ image:models/yang-model-api.png[]
 
 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.
@@ -88,6 +89,7 @@ Class diagram of yang data API
 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
@@ -97,11 +99,11 @@ 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:
 
@@ -116,9 +118,9 @@ reactor.addSources(yangModuleSource, yangModuleSource2);
 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.
 
@@ -130,7 +132,7 @@ Let us explain how to work with models contained in the newly created SchemaCont
 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(),
@@ -187,7 +189,7 @@ ContainerNode containerNode = Builders.containerBuilder().withNodeIdentifier(new
 \\ 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.
 
@@ -307,6 +309,36 @@ Write operation is performed with both normalized nodes mentioned earlier. It co
 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
 
index 335af8721a932418d391981f93b6c452a7bc386f..b8d2a7a95d7f717cb3720703f8042620fcd18dc0 100644 (file)
@@ -27,6 +27,7 @@
         <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>
index f184ce7b5e87d2595766d30c97ac94f4307109d4..99ac2809bde3135a21508b87a873a4db68b3933b 100644 (file)
@@ -20,16 +20,24 @@ import java.io.Flushable;
 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;
@@ -168,8 +176,8 @@ public final class JsonParserStream implements Closeable, Flushable {
                 }
                 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.");
@@ -302,57 +310,7 @@ public final class JsonParserStream implements Closeable, Flushable {
         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;
diff --git a/yang/yang-data-codec-xml/pom.xml b/yang/yang-data-codec-xml/pom.xml
new file mode 100644 (file)
index 0000000..750e497
--- /dev/null
@@ -0,0 +1,63 @@
+<?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>
diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/AbstractXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/AbstractXmlCodec.java
new file mode 100644 (file)
index 0000000..2568cf6
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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);
+    }
+}
diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/BooleanXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/BooleanXmlCodec.java
new file mode 100644 (file)
index 0000000..b83df13
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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));
+    }
+}
diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NumberXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/NumberXmlCodec.java
new file mode 100644 (file)
index 0000000..3343832
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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));
+    }
+}
diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/QuotedXmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/QuotedXmlCodec.java
new file mode 100644 (file)
index 0000000..200094b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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));
+    }
+
+}
diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodec.java
new file mode 100644 (file)
index 0000000..fe59135
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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;
+}
diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodecFactory.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodecFactory.java
new file mode 100644 (file)
index 0000000..6cdb638
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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);
+    }
+}
diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlEmptyCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlEmptyCodec.java
new file mode 100644 (file)
index 0000000..1d7abc6
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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("");
+    }
+}
diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java
new file mode 100644 (file)
index 0000000..f9e491b
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * 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();
+    }
+}
diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringIdentityrefCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringIdentityrefCodec.java
new file mode 100644 (file)
index 0000000..2ea1860
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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));
+    }
+}
diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringInstanceIdentifierCodec.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringInstanceIdentifierCodec.java
new file mode 100644 (file)
index 0000000..b3d0578
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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));
+    }
+
+}
diff --git a/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlToNormalizedNodesTest.java b/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlToNormalizedNodesTest.java
new file mode 100644 (file)
index 0000000..c57228e
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * 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;
+    }
+}
diff --git a/yang/yang-data-codec-xml/src/test/resources/baz.xml b/yang/yang-data-codec-xml/src/test/resources/baz.xml
new file mode 100644 (file)
index 0000000..48f4510
--- /dev/null
@@ -0,0 +1,40 @@
+<?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>
diff --git a/yang/yang-data-codec-xml/src/test/resources/baz.yang b/yang/yang-data-codec-xml/src/test/resources/baz.yang
new file mode 100644 (file)
index 0000000..d61077e
--- /dev/null
@@ -0,0 +1,82 @@
+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
diff --git a/yang/yang-data-codec-xml/src/test/resources/foo.xml b/yang/yang-data-codec-xml/src/test/resources/foo.xml
new file mode 100644 (file)
index 0000000..9af808e
--- /dev/null
@@ -0,0 +1,18 @@
+<?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>
diff --git a/yang/yang-data-codec-xml/src/test/resources/foo.yang b/yang/yang-data-codec-xml/src/test/resources/foo.yang
new file mode 100644 (file)
index 0000000..d089245
--- /dev/null
@@ -0,0 +1,54 @@
+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
diff --git a/yang/yang-data-codec-xml/src/test/resources/invalid-baz-2.xml b/yang/yang-data-codec-xml/src/test/resources/invalid-baz-2.xml
new file mode 100644 (file)
index 0000000..ef9fc35
--- /dev/null
@@ -0,0 +1,40 @@
+<?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
diff --git a/yang/yang-data-codec-xml/src/test/resources/invalid-baz-3.xml b/yang/yang-data-codec-xml/src/test/resources/invalid-baz-3.xml
new file mode 100644 (file)
index 0000000..2219b1b
--- /dev/null
@@ -0,0 +1,40 @@
+<?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
diff --git a/yang/yang-data-codec-xml/src/test/resources/invalid-baz-4.xml b/yang/yang-data-codec-xml/src/test/resources/invalid-baz-4.xml
new file mode 100644 (file)
index 0000000..f4eae6f
--- /dev/null
@@ -0,0 +1,40 @@
+<?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
diff --git a/yang/yang-data-codec-xml/src/test/resources/invalid-baz.xml b/yang/yang-data-codec-xml/src/test/resources/invalid-baz.xml
new file mode 100644 (file)
index 0000000..51da202
--- /dev/null
@@ -0,0 +1,40 @@
+<?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
diff --git a/yang/yang-data-codec-xml/src/test/resources/invalid-foo-2.xml b/yang/yang-data-codec-xml/src/test/resources/invalid-foo-2.xml
new file mode 100644 (file)
index 0000000..69deaae
--- /dev/null
@@ -0,0 +1,27 @@
+<?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
diff --git a/yang/yang-data-codec-xml/src/test/resources/invalid-foo-3.xml b/yang/yang-data-codec-xml/src/test/resources/invalid-foo-3.xml
new file mode 100644 (file)
index 0000000..b043f49
--- /dev/null
@@ -0,0 +1,27 @@
+<?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
diff --git a/yang/yang-data-codec-xml/src/test/resources/invalid-foo.xml b/yang/yang-data-codec-xml/src/test/resources/invalid-foo.xml
new file mode 100644 (file)
index 0000000..3f18dcf
--- /dev/null
@@ -0,0 +1,23 @@
+<?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
@@ -1,11 +1,11 @@
 /*
- * 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;
@@ -19,10 +19,10 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
  * 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);
     }
 
similarity index 69%
rename from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlNodeDataWithSchema.java
rename to yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AnyXmlNodeDataWithSchema.java
index 76a960bfd80cb27e259c82dfaf8f793cba52b06c..873e280574a74c6d2429f5a2aed94d397160159c 100644 (file)
@@ -1,17 +1,17 @@
 /*
- * 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);
@@ -20,7 +20,6 @@ class AnyXmlNodeDataWithSchema extends SimpleNodeDataWithSchema {
     @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());
     }
 }
similarity index 68%
rename from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CaseNodeDataWithSchema.java
rename to yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/CaseNodeDataWithSchema.java
index 67e3c59389719edae7701e6a20c04700f58a1b85..b04d387588d55772332a7dec7ac9745a9d796d88 100644 (file)
@@ -1,16 +1,17 @@
 /*
- * 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);
     }
 
similarity index 88%
rename from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ChoiceNodeDataWithSchema.java
rename to yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ChoiceNodeDataWithSchema.java
index b246959835cc93c214f5c63cf05353c84f99f718..e4813a9a5549ae34375c44eb9fc69c15aba3050d 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * 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;
@@ -22,7 +22,7 @@ class ChoiceNodeDataWithSchema extends CompositeNodeDataWithSchema {
 
     private CaseNodeDataWithSchema caseNodeDataWithSchema;
 
-    public ChoiceNodeDataWithSchema(final ChoiceSchemaNode schema) {
+    ChoiceNodeDataWithSchema(final ChoiceSchemaNode schema) {
         super(schema);
     }
 
@@ -1,14 +1,17 @@
 /*
- * 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;
@@ -16,10 +19,13 @@ import java.util.Collection;
 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;
@@ -32,7 +38,7 @@ import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode;
 /**
  * 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
@@ -71,7 +77,7 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
 
         AugmentationSchema augSchema = null;
         if (choiceCandidate.isAugmenting()) {
-            augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), choiceCandidate);
+            augSchema = findCorrespondingAugment(getSchema(), choiceCandidate);
         }
 
         // looking for existing choice
@@ -108,7 +114,7 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
 
         AugmentationSchema augSchema = null;
         if (schema.isAugmenting()) {
-            augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), schema);
+            augSchema = findCorrespondingAugment(getSchema(), schema);
         }
         if (augSchema != null) {
             augmentationsToChild.put(augSchema, newChild);
@@ -157,7 +163,7 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
     }
 
     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 {
@@ -191,7 +197,7 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
             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);
@@ -201,4 +207,36 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
             }
         }
     }
+
+    /**
+     * 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();
+        }
+    };
 }
@@ -1,11 +1,11 @@
 /*
- * 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;
@@ -13,7 +13,7 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 
 class ContainerNodeDataWithSchema extends CompositeNodeDataWithSchema {
 
-    public ContainerNodeDataWithSchema(final DataSchemaNode schema) {
+    ContainerNodeDataWithSchema(final DataSchemaNode schema) {
         super(schema);
     }
 
@@ -1,17 +1,17 @@
 /*
- * 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);
     }
@@ -1,18 +1,18 @@
 /*
- * 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);
     }
similarity index 80%
rename from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafNodeDataWithSchema.java
rename to yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafNodeDataWithSchema.java
index 32263d68dccd8ac8bd8a97faa5de25393ac72a25..6f241cb7b5b7f899060392db3648a42cef531cf1 100644 (file)
@@ -1,17 +1,17 @@
 /*
- * 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);
@@ -1,11 +1,11 @@
 /*
- * 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;
@@ -21,7 +21,7 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 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<>();
 
similarity index 86%
rename from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListNodeDataWithSchema.java
rename to yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ListNodeDataWithSchema.java
index abbf1eaec48dd67cf90c4a6e455e8c1271e4cab2..36690e45229ec92550306c5f336e790cd1ad3baa 100644 (file)
@@ -1,18 +1,18 @@
 /*
- * 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);
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ParserStreamUtils.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ParserStreamUtils.java
new file mode 100644 (file)
index 0000000..bc3228a
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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;
+    }
+}
similarity index 93%
rename from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/RpcAsContainer.java
rename to yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/RpcAsContainer.java
index b9fddf3ecf5a063c86ddeab1a93b958f7f07641a..da1c5a8d4d042c5505f0c150f2b6a1208befa6f5 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * 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;
@@ -25,7 +25,7 @@ import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 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;
 
@@ -62,7 +62,7 @@ final class RpcAsContainer implements ContainerSchemaNode {
         return delegate.getOutput();
     }
 
-    RpcAsContainer(final RpcDefinition parentNode) {
+    public RpcAsContainer(final RpcDefinition parentNode) {
         delegate = parentNode;
     }
 
similarity index 69%
rename from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/SimpleNodeDataWithSchema.java
rename to yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/SimpleNodeDataWithSchema.java
index 26d774cde2d33f9c97aefa524e8dc67f906ce82e..fd0b0e2baa781c62124a892bea834a6bead81b4d 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * 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;
 
@@ -17,7 +17,7 @@ abstract class SimpleNodeDataWithSchema extends AbstractNodeDataWithSchema {
         super(dataSchemaNode);
     }
 
-    void setValue(final Object value) {
+    public void setValue(final Object value) {
         this.value = value;
     }
 
@@ -1,11 +1,11 @@
 /*
- * 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;