-YANG Tools
-==========
+YANG Tools Developer Guide
+==========================
Overview
--------
uses conceptual meta-model more tailored to YANG and OpenDaylight
use-cases than a standard XML DOM model allows for.
- - **Java Binding** - concrete data model and classes generated from
- YANG models, designed to provide compile-time safety when working
- with YANG-modeled data.
-
- serialization / deserialization of YANG-modeled data driven by YANG
models
- JSON - as defined in
`draft-lhotka-netmod-yang-json-01 <https://tools.ietf.org/html/rfc6020>`__
- - Java Binding to Normalized Node and vice-versa
+ - support for third-party generators processing YANG models.
-- Integration of YANG model parsing into Maven build lifecycle and
- support for third-party generators processing YANG models.
+Architecture
+~~~~~~~~~~~~
YANG Tools project consists of following logical subsystems:
components, which wants to generate code or other artefacts based on
YANG model.
-- **YANG Java Binding** - Mapping of YANG model to generated Java APIs.
- Java Binding also references to set of compile-time and runtime
- components which implements this mapping, provides generation of
- classes and APIs based on YANG models and integrate these Java
- Binding objects with **YANG Data** APIs and components.
-
- - **Models** - Set of **IETF** and **YANG Tools** models, with
- generated Java Bindings so they could be simply consumed outside
- of **YANG Tools**.
-
-YANG Java Binding: Mapping rules
---------------------------------
-
-This chapter covers the details of mapping YANG to Java.
-
-.. note::
-
- The following source code examples does not show canonical generated
- code, but rather illustrative example. Generated classes and
- interfaces may differ from this examples, but APIs are preserved.
-
-General conversion rules
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Package names of YANG models
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-| The package name consists of the following parts:
+Concepts
+~~~~~~~~
-- **Opendaylight prefix** - Specifies the opendaylight prefix. Every
- package name starts with the prefix ``org.opendaylight.yang.gen.v``.
+Project defines base concepts and helper classes which are
+project-agnostic and could be used outside of YANG Tools project scope.
-- **Java Binding version** - Specifies the YANG Java Binding version.
- Curent Binding version is ``1``.
+Components
+~~~~~~~~~~
-- **Namespace** - Specified by the value of ``namespace`` substatement.
- URI is converted to package name structure.
+- yang-common
-- **Revision** - Specifies the concatenation of word ``rev`` and value
- of ``module`` substatements ``revision`` argument value without
- leading zeros before month and day. For example: ``rev201379``
+- yang-data-api
-After the package name is generated, we check if it contains any Java
-keywords or starts with a digit. If so, then we add an underscore before
-the offending token.
+- yang-data-codec-gson
-The following is a list of keywords which are prefixed with underscore:
+- yang-data-codec-xml
-abstract, assert, boolean, break, byte, case, catch, char, class, const,
-continue, default, double, do, else, enum, extends, false, final,
-finally, float, for, goto, if, implements, import, instanceof, int,
-interface, long, native, new, null, package, private, protected, public,
-return, short, static, strictfp, super, switch, synchronized, this,
-throw, throws, transient, true, try, void, volatile, while
+- yang-data-impl
-As an example suppose following yang model:
+- yang-data-jaxen
-.. code:: yang
-
- module module {
- namespace "urn:2:case#module";
- prefix "sbd";
- organization "OPEN DAYLIGHT";
- contact "http://www.example.com/";
- revision 2013-07-09 {
- }
- }
-
-After applying rules (replacing digits and Java keywords) the resulting
-package name is
-``org.opendaylight.yang.gen.v1.urn._2._case.module.rev201379``
-
-Additional Packages
-^^^^^^^^^^^^^^^^^^^
-
-In cases when YANG statement contain some of specific YANG statements
-additional packages are generated to designate this containment. Table
-below provides details of parent statement and nested statements, which
-yields additional package generation:
-
-+--------------------------------------+--------------------------------------+
-| Parent statement | Substatement |
-+======================================+======================================+
-| ``list`` | list, container, choice |
-+--------------------------------------+--------------------------------------+
-| ``container`` | list, container, choice |
-+--------------------------------------+--------------------------------------+
-| ``choice`` | leaf, list, leaf-list, container, |
-| | case |
-+--------------------------------------+--------------------------------------+
-| ``case`` | list, container, choice |
-+--------------------------------------+--------------------------------------+
-| rpc ``input`` or ``output`` | list, container, (choice isn’t |
-| | supported) |
-+--------------------------------------+--------------------------------------+
-| ``notification`` | list, container, (choice isn’t |
-| | supported) |
-+--------------------------------------+--------------------------------------+
-| ``augment`` | list, container, choice, case |
-+--------------------------------------+--------------------------------------+
-
-Substatements are not only mapped to Java setter methods in the
-interface representing the parent statement, but they also generate
-packages with names consisting of the parent statement package name with
-the parent statement name appended.
-
-For example, this YANG model considers the container statement ``cont``
-as the direct substatement of the module.
-
-.. code:: yang
-
- container cont {
- container cont-inner {
- }
- list outter-list {
- list list-in-list {
- }
- }
- }
+- yang-data-transform
-Container ``cont`` is the parent statement for the substatements
-``cont-inner`` and ``outter-list``. ``list outter-list`` is the parent
-statement for substatement ``list-in-list``.
+- yang-data-util
-| Java code is generated in the following structure:
+- yang-maven-plugin
-- ``org.opendaylight.yang.gen.v1.urn.module.rev201379`` - package
- contains direct substatements of module statement
+- yang-maven-plugin-it
- - ``Cont.java``
+- yang-maven-plugin-spi
-- ``org.opendaylight.yang.gen.v1.urn.module.rev201379.cont`` - package
- contains substatements of ``cont`` container statement
+- yang-model-api
- - ``ContInner.java`` - interface representing container
- ``cont-inner``
+- yang-model-export
- - ``OutterList.java`` - interface representing list ``outer-list``
+- yang-model-util
-- ``org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.outter.list``
- - package contains substatements of outter-list list element
+- yang-parser-api
- - ``ListInList.java``
+- yang-parser-impl
-Class and interface names
-^^^^^^^^^^^^^^^^^^^^^^^^^
+YANG Model API
+^^^^^^^^^^^^^^
-Some YANG statements are mapped to Java classes and interfaces. The name
-of YANG element may contain various characters which aren’t permitted in
-Java class names. Firstly whitespaces are trimmed from YANG name. Next
-the characters space, -, \` are deleted and the subsequent letter is
-capitalized. At the end, first letter is capitalized.
+Class diagram of yang model API
-For example, ``example-name_ without_capitalization`` would map to
-``ExampleNameWithoutCapitalization``.
+.. figure:: images/yang-model-api.png
-Getter and setter names
-^^^^^^^^^^^^^^^^^^^^^^^
+ YANG Model API
-In some cases, YANG statements are converted to getter and/or setter
-methods. The process for getter is:
+YANG Parser
+^^^^^^^^^^^
-1. the name of YANG statement is converted to Java class name style as
- `explained above <#_class_and_interface_names>`__.
+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). IdentifierNamespace
+represents common superclass for YANG model namespaces.
-2. the word ``get`` is added as prefix, if resulting type is
- ``Boolean``, the name is prefixed with ``is`` prefix instead of
- ``get``.
+Input of the Yang Statement Parser is a collection of
+StatementStreamSource objects. StatementStreamSource interface is used
+for inference of effective model and is required to emit its statements
+using supplied StatementWriter. Each source (e.g. YANG source) has to be
+processed in three steps in order to emit different statements for each
+step. This package provides support for various namespaces used across
+statement parser in order to map relations during declaration phase
+process.
-3. the return type of the getter method is set to Java type representing
- substatement
+Currently, there are two implementations of StatementStreamSource in
+Yangtools:
-The process for setter is:
+- YangStatementSourceImpl - intended for yang sources
-1. the name of YANG statement is converted to Java class name style as
- `explained above <#_class_and_interface_names>`__.
+- YinStatementSourceImpl - intended for yin sources
-2. the word ``set`` is added as prefix
+YANG Data API
+^^^^^^^^^^^^^
-3. the input parameter name is set to element’s name converted to Java
- parameter style
+Class diagram of yang data API
-4. the return parameter is set to builder type
+.. figure:: images/yang-data-api.png
-Statement specific mapping
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+ YANG Data API
-module statement
+YANG Data Codecs
^^^^^^^^^^^^^^^^
-YANG ``module`` statement is converted to Java as two Java classes. Each
-of the classes is in the separate Java file. The names of Java files are
-composed as follows: ``<module name><suffix>.java`` where ``<suffix>``
-is either data or service.
-
-Data Interface
-''''''''''''''
-
-Data Interface has a mapping similar to container, but contains only top
-level nodes defined in module.
-
-Data interface serves only as marker interface for type-safe APIs of
-``InstanceIdentifier``.
-
-Service Interface
-'''''''''''''''''
-
-Service Interface serves to describe RPC contract defined in the module.
-This RPC contract is defined by ``rpc`` statements.
-
-RPC implementation usually implement this interface and users of the
-RPCs use this interface to invoke RPCs.
-
-container statement
-^^^^^^^^^^^^^^^^^^^
+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 containers are mapped to Java interfaces which extend the Java
-DataObject and Augmentable<container-interface>, where
-container-interface is the name of the mapped interface.
+YANG Maven Plugin
+^^^^^^^^^^^^^^^^^
-For example, the following YANG:
+Maven plugin which integrates YANG parser into Maven build lifecycle and
+provides code-generation framework for components, which wants to
+generate code or other artefacts based on YANG model.
-**YANG model.**
+How to / Tutorials
+------------------
-.. code:: yang
+Working with YANG Model
+~~~~~~~~~~~~~~~~~~~~~~~
- container cont {
+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.
-is converted into this Java:
+StatementStreamSource object contains the source file information. It
+has two implementations, one for YANG sources - YangStatementSourceImpl,
+and one for YIN sources - YinStatementSourceImpl.
-**Cont.java.**
+Here is an example of creating StatementStreamSource objects for YANG
+files, providing them to the YANG statement parser and building the
+SchemaContext:
.. code:: java
- public interface Cont extends ChildOf<...>, Augmentable<Cont> {
- }
+ StatementStreamSource yangModuleSource == new YangStatementSourceImpl("/example.yang", false);
+ StatementStreamSource yangModuleSource2 == new YangStatementSourceImpl("/example2.yang", false);
-Leaf statement
-^^^^^^^^^^^^^^
+ CrossSourceStatementReactor.BuildAction reactor == YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSources(yangModuleSource, yangModuleSource2);
-Each leaf has to contain at least one type substatement. The leaf is
-mapped to getter method of parent statement with return type equal to
-type substatement value.
+ SchemaContext schemaContext == reactor.buildEffective();
-For example, the following YANG:
+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.
-**YANG model.**
+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.
-.. code:: yang
-
- container cont {
- leaf lf {
- type string;
- }
- }
+Then you should feed yang sources to it by calling method addSources()
+that takes one or more StatementStreamSource objects as arguments.
-is converted into this Java:
+Finally you call the method buildEffective() on the reactor object which
+returns EffectiveSchemaContext (that is a concrete implementation of
+SchemaContext). Now you are ready to work with contents of the added
+yang sources.
-**Cont.java.**
+Let us explain how to work with models contained in the newly created
+SchemaContext. If you want to get all the modules in the schemaContext,
+you have to call method getModules() which returns a Set of modules. If
+you want to get all the data definitions in schemaContext, you need to
+call method getDataDefinitions, etc.
.. code:: java
- public interface Cont extends DataObject, Augmentable<Cont> {
- String getLf();
- }
-
-- Represents ``leaf lf``
-
-leaf-list statement
-^^^^^^^^^^^^^^^^^^^
+ Set<Module> modules == schemaContext.getModules();
+ Set<DataSchemaNodes> dataSchemaNodes == schemaContext.getDataDefinitions();
-Each leaf-list has to contain one type substatement. The leaf-list is
-mapped to getter method of parent statement with return type equal to
-List of type substatement value.
+Usually you want to access specific modules. Getting a concrete module
+from SchemaContext is a matter of calling one of these methods:
-For example, the following YANG:
+- findModuleByName(),
-**YANG model.**
+- findModuleByNamespace(),
-.. code:: yang
+- findModuleByNamespaceAndRevision().
- container cont {
- leaf-list lf-lst {
- type string;
- }
- }
-
-is converted into this Java:
-
-**Cont.java.**
+In the first case, you need to provide module name as it is defined in
+the yang source file and module revision date if it specified in the
+yang source file (if it is not defined, you can just pass a null value).
+In order to provide the revision date in proper format, you can use a
+utility class named SimpleDateFormatUtil.
.. code:: java
- public interface Cont extends DataObject, Augmentable<Cont> {
- List<String> getLfLst();
- }
-
-list statement
-^^^^^^^^^^^^^^
-
-``list`` statements are mapped to Java interfaces and a getter method is
-generated in the interface associated with it’s parent statement. The
-return type of getter the method is a Java List of objects implementing
-the interface generated corresponding to the ``list statement.
-Mapping of `list`` substatement to Java:
-
-For example, the following YANG:
-
-**YANG model.**
-
-.. code:: yang
-
- container cont {
- list outter-list {
- key "leaf-in-list";
- leaf number {
- type uint64;
- }
- }
- }
-
-The list statement ``example-list`` is mapped to the Java interface
-``ExampleList`` and the ``Cont`` interface (parent of ``ExampleList``)
-contains getter method with return type ``List<ExampleList>``. The
-presence of a ``key`` statement, triggers generation of
-``ExampleListKey``, which may be used to identify item in list.
-
-The end result is this Java:
+ Module exampleModule == schemaContext.findModuleByName("example-module", null);
+ // or
+ Date revisionDate == SimpleDateFormatUtil.getRevisionFormat().parse("2015-09-02");
+ Module exampleModule == schemaContext.findModuleByName("example-module", revisionDate);
-**OutterList.java.**
+In the second case, you have to provide module namespace in form of an
+URI object.
.. code:: java
- package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont;
-
- import org.opendaylight.yangtools.yang.binding.DataObject;
- import org.opendaylight.yangtools.yang.binding.Augmentable;
- import Java.util.List;
- import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.outter.list.ListInList;
-
- public interface OutterList extends DataObject, Augmentable<OutterList> {
-
- List<String> getLeafListInList();
+ Module exampleModule == schema.findModuleByNamespace(new URI("opendaylight.org/example-module"));
- List<ListInList> getListInList();
+In the third case, you provide both module namespace and revision date
+as arguments.
- /*
- Returns Primary Key of Yang List Type
- */
- OutterListKey getOutterListKey();
-
- }
-
-**OutterListKey.java.**
+Once you have a Module object, you can access its contents as they are
+defined in YANG Model API. One way to do this is to use method like
+getIdentities() or getRpcs() which will give you a Set of objects.
+Otherwise you can access a DataSchemaNode directly via the method
+getDataChildByName() which takes a QName object as its only argument.
+Here are a few examples.
.. code:: java
- package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont;
-
- import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.OutterListKey;
- import Java.math.BigInteger;
-
- public class OutterListKey {
-
- private BigInteger _leafInList;
-
- public OutterListKey(BigInteger _leafInList) {
- super();
- this_leafInList = _leafInList;
- }
-
- public BigInteger getLeafInList() {
- return _leafInList;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((_leafInList == null) ? 0 : _leafInList.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- OutterListKey other = (OutterListKey) obj;
- if (_leafInList == null) {
- if (other._LeafInList != null) {
- return false;
- }
- } else if(!_leafInList.equals(other._leafInList)) {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("OutterListKey [_leafInList=");
- builder.append(_leafInList);
- builder.append("]");
- return builder.toString();
- }
- }
+ Set<AugmentationSchema> augmentationSchemas == exampleModule.getAugmentations();
+ Set<ModuleImport> moduleImports == exampleModule.getImports();
-choice and case statements
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ChoiceSchemaNode choiceSchemaNode == (ChoiceSchemaNode) exampleModule.getDataChildByName(QName.create(exampleModule.getQNameModule(), "example-choice"));
-A ``choice`` element is mapped in mostly the same way a ``list`` element
-is. The ``choice`` element is mapped to and interface (marker interface)
-and a new getter method with the return type of a Java ``List`` of this
-marker interfaces is added to the interface corresponding to the parent
-statement. Any ``case`` substatements are mapped to Java interfaces
-which extend the marker interface.
+ ContainerSchemaNode containerSchemaNode == (ContainerSchemaNode) exampleModule.getDataChildByName(QName.create(exampleModule.getQNameModule(), "example-container"));
-For example, the following YANG:
+The YANG statement parser can work in three modes:
-**YANG model.**
+- default mode
-.. code:: yang
+- mode with active resolution of if-feature statements
- container cont {
- choice example-choice {
- case foo-case {
- leaf foo {
- type string;
- }
- }
- case bar-case {
- leaf bar {
- type string;
- }
- }
- }
- }
+- mode with active semantic version processing
-is converted into this Java:
+The default mode is active when you initialize the parsing cycle as
+usual by calling the method newBuild() without passing any arguments to
+it. The second and third mode can be activated by invoking the
+newBuild() with a special argument. You can either activate just one of
+them or both by passing proper arguments. Let us explain how these modes
+work.
-**Cont.java.**
+Mode with active resolution of if-features makes yang statements
+containing an if-feature statement conditional based on the supported
+features. These features are provided in the form of a QName-based
+java.util.function.Predicate object. In the example below, only two
+features are supported: example-feature-1 and example-feature-2. The
+Predicate which contains this information is passed to the method
+newBuild() and the mode is activated.
.. code:: java
- package org.opendaylight.yang.gen.v1.urn.module.rev201379;
-
- import org.opendaylight.yangtools.yang.binding.DataObject;
- import org.opendaylight.yangtools.yang.binding.Augmentable;
- import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.ChoiceTest;
-
- public interface Cont extends DataObject, Augmentable<Cont> {
-
- ExampleChoice getExampleChoice();
-
+ Predicate<QName> isFeatureSupported == qName -> {
+ Set<QName> supportedFeatures == new HashSet<>();
+ supportedFeatures.add(QName.create("example-namespace", "2016-08-31", "example-feature-1"));
+ supportedFeatures.add(QName.create("example-namespace", "2016-08-31", "example-feature-2"));
+ return supportedFeatures.contains(qName);
}
-**ExampleChoice.java.**
-
-.. code:: java
+ CrossSourceStatementReactor.BuildAction reactor == YangInferencePipeline.RFC6020_REACTOR.newBuild(isFeatureSupported);
- package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont;
-
- import org.opendaylight.yangtools.yang.binding.DataObject;
-
- public interface ExampleChoice extends DataContainer {
- }
-
-**FooCase.java.**
+In case when no features should be supported, you should provide a
+Predicate<QName> object whose test() method just returns false.
.. code:: java
- package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.example.choice;
-
- import org.opendaylight.yangtools.yang.binding.DataObject;
- import org.opendaylight.yangtools.yang.binding.Augmentable;
- import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.ChoiceTest;
-
- public interface FooCase extends ExampleChoice, DataObject, Augmentable<FooCase> {
+ Predicate<QName> isFeatureSupported == qName -> false;
- String getFoo();
+ CrossSourceStatementReactor.BuildAction reactor == YangInferencePipeline.RFC6020_REACTOR.newBuild(isFeatureSupported);
- }
+When this mode is not activated, all features in the processed YANG
+sources are supported.
-**BarCase.java.**
+Mode with active semantic version processing changes the way how YANG
+import statements work - each module import is processed based on the
+specified semantic version statement and the revision-date statement is
+ignored. In order to activate this mode, you have to provide
+StatementParserMode.SEMVER\_MODE enum constant as argument to the method
+newBuild().
.. code:: java
- package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.example.choice;
-
- import org.opendaylight.yangtools.yang.binding.DataObject;
- import org.opendaylight.yangtools.yang.binding.Augmentable;
- import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.ChoiceTest;
-
- public interface BarCase extends ExampleChoice, DataObject, Augmentable<BarCase> {
-
- String getBar();
-
- }
-
-grouping and uses statements
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-``grouping`s are mapped to Java interfaces. `uses`` statements in some
-element (using of concrete grouping) are mapped as extension of
-interface for this element with the interface which represents grouping.
-
-For example, the following YANG:
+ CrossSourceStatementReactor.BuildAction reactor == YangInferencePipeline.RFC6020_REACTOR.newBuild(StatementParserMode.SEMVER_MODE);
-**YANG Model.**
+Before you use a semantic version statement in a YANG module, you need
+to define an extension for it so that the YANG statement parser can
+recognize it.
.. code:: yang
- grouping grp {
- leaf foo {
- type string;
- }
- }
-
- container cont {
- uses grp;
- }
-
-is converted into this Java:
-
-**Grp.java.**
-
-.. code:: java
-
- package org.opendaylight.yang.gen.v1.urn.module.rev201379;
-
- import org.opendaylight.yangtools.yang.binding.DataObject;
-
- public interface Grp extends DataObject {
-
- String getFoo();
-
- }
-
-**Cont.java.**
-
-.. code:: java
-
- package org.opendaylight.yang.gen.v1.urn.module.rev201379;
-
- import org.opendaylight.yangtools.yang.binding.DataObject;
- import org.opendaylight.yangtools.yang.binding.Augmentable;
+ module semantic-version {
+ namespace "urn:opendaylight:yang:extension:semantic-version";
+ prefix sv;
+ yang-version 1;
- public interface Cont extends DataObject, Augmentable<Cont>, Grp {
- }
-
-rpc, input and output statements
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-An ``rpc`` statement is mapped to Java as method of class
-``ModuleService.java``. Any substatements of an ``rpc`` are mapped as
-follows:
-
-+--------------------------------------+--------------------------------------+
-| Rpc Substatement | Mapping |
-+======================================+======================================+
-| input | presence of input statement triggers |
-| | generation of interface |
-+--------------------------------------+--------------------------------------+
-| output | presence of output statement |
-| | triggers generation of interface |
-+--------------------------------------+--------------------------------------+
-
-For example, the following YANG:
-
-**YANG model.**
-
-.. code:: yang
-
- rpc rpc-test1 {
- output {
- leaf lf-output {
- type string;
- }
+ revision 2016-02-02 {
+ description "Initial version";
}
- input {
- leaf lf-input {
- type string;
+ sv:semantic-version "0.0.1";
+
+ extension semantic-version {
+ argument "semantic-version" {
+ yin-element false;
}
}
}
-is converted into this Java:
-
-**ModuleService.java.**
-
-.. code:: java
-
- package org.opendaylight.yang.gen.v1.urn.module.rev201379;
-
- import Java.util.concurrent.Future;
- import org.opendaylight.yangtools.yang.common.RpcResult;
-
- public interface ModuleService {
-
- Future<RpcResult<RpcTest1Output>> rpcTest1(RpcTest1Input input);
-
- }
-
-**RpcTest1Input.java.**
-
-.. code:: java
-
- package org.opendaylight.yang.gen.v1.urn.module.rev201379;
-
- public interface RpcTest1Input {
-
- String getLfInput();
-
- }
-
-**RpcTest1Output.java.**
-
-.. code:: java
-
- package org.opendaylight.yang.gen.v1.urn.module.rev201379;
-
- public interface RpcTest1Output {
-
- String getLfOutput();
-
- }
-
-notification statement
-^^^^^^^^^^^^^^^^^^^^^^
-
-``notification`` statements are mapped to Java interfaces which extend
-the Notification interface.
-
-For example, the following YANG:
+In the example above, you see a YANG module which defines semantic
+version as an extension. This extension can be imported to other modules
+in which we want to utilize the semantic versioning concept.
-**YANG model.**
+Below is a simple example of the semantic versioning usage. With
+semantic version processing mode being active, the foo module imports
+the bar module based on its semantic version. Notice how both modules
+import the module with the semantic-version extension.
.. code:: yang
- notification notif {
- }
-
-is converted into this Java:
-
-**Notif.java.**
-
-.. code:: java
-
- package org.opendaylight.yang.gen.v1.urn.module.rev201379;
+ module foo {
+ namespace foo;
+ prefix foo;
+ yang-version 1;
+ import semantic-version { prefix sv; revision-date 2016-02-02; sv:semantic-version "0.0.1"; }
+ import bar { prefix bar; sv:semantic-version "0.1.2";}
- import org.opendaylight.yangtools.yang.binding.DataObject;
- import org.opendaylight.yangtools.yang.binding.Augmentable;
- import org.opendaylight.yangtools.yang.binding.Notification;
+ revision "2016-02-01" {
+ description "Initial version";
+ }
+ sv:semantic-version "0.1.1";
- public interface Notif extends DataObject, Augmentable<Notif>, Notification {
+ ...
}
-augment statement
-~~~~~~~~~~~~~~~~~
-
-``augment`` statements are mapped to Java interfaces. The interface
-starts with the same name as the name of augmented interface with a
-suffix corresponding to the order number of augmenting interface. The
-augmenting interface also extends ``Augmentation<>`` with actual type
-parameter equal to augmented interface.
-
-For example, the following YANG:
-
-**YANG Model.**
-
.. code:: yang
- container cont {
- }
-
- augment "/cont" {
- leaf additional-value {
- type string;
- }
- }
-
-is converted into this Java:
+ module bar {
+ namespace bar;
+ prefix bar;
+ yang-version 1;
-**Cont.java.**
+ import semantic-version { prefix sv; revision-date 2016-02-02; sv:semantic-version "0.0.1"; }
-.. code:: java
-
- package org.opendaylight.yang.gen.v1.urn.module.rev201379;
-
- import org.opendaylight.yangtools.yang.binding.DataObject;
- import org.opendaylight.yangtools.yang.binding.Augmentable;
-
- public interface Cont extends DataObject, Augmentable<Cont> {
+ revision "2016-01-01" {
+ description "Initial version";
+ }
+ sv:semantic-version "0.1.2";
+ ...
}
-**Cont1.java.**
-
-.. code:: java
-
- package org.opendaylight.yang.gen.v1.urn.module.rev201379;
-
- import org.opendaylight.yangtools.yang.binding.DataObject;
- import org.opendaylight.yangtools.yang.binding.Augmentation;
+Every semantic version must have the following form: x.y.z. The x
+corresponds to a major version, the y corresponds to a minor version and
+the z corresponds to a patch version. If no semantic version is
+specified in a module or an import statement, then the default one is
+used - 0.0.0.
- public interface Cont1 extends DataObject, Augmentation<Cont> {
+A major version number of 0 indicates that the model is still in
+development and is subject to change.
- }
+Following a release of major version 1, all modules will increment major
+version number when backwards incompatible changes to the model are
+made.
-YANG Type mapping
-~~~~~~~~~~~~~~~~~
+The minor version is changed when features are added to the model that
+do not impact current clients use of the model.
-typedef statement
-^^^^^^^^^^^^^^^^^
+The patch version is incremented when non-feature changes (such as
+bugfixes or clarifications of human-readable descriptions that do not
+impact model functionality) are made that maintain backwards
+compatibility.
-YANG ``typedef`` statements are mapped to Java classes. A ``typedef``
-may contain following substatements:
-
-+--------------------------------------+--------------------------------------+
-| Substatement | Behaviour |
-+======================================+======================================+
-| type | determines wrapped type and how |
-| | class will be generated |
-+--------------------------------------+--------------------------------------+
-| descripton | Javadoc description |
-+--------------------------------------+--------------------------------------+
-| units | is not mapped |
-+--------------------------------------+--------------------------------------+
-| default | is not mapped |
-+--------------------------------------+--------------------------------------+
-
-Valid Arguments Type
-''''''''''''''''''''
-
-Simple values of type argument are mapped as follows:
-
-+--------------------------------------+--------------------------------------+
-| YANG Type | Java type |
-+======================================+======================================+
-| boolean | Boolean |
-+--------------------------------------+--------------------------------------+
-| empty | Boolean |
-+--------------------------------------+--------------------------------------+
-| int8 | Byte |
-+--------------------------------------+--------------------------------------+
-| int16 | Short |
-+--------------------------------------+--------------------------------------+
-| int32 | Integer |
-+--------------------------------------+--------------------------------------+
-| int64 | Long |
-+--------------------------------------+--------------------------------------+
-| string | String or, wrapper class (if pattern |
-| | substatement is specified) |
-+--------------------------------------+--------------------------------------+
-| decimal64 | Double |
-+--------------------------------------+--------------------------------------+
-| uint8 | Short |
-+--------------------------------------+--------------------------------------+
-| uint16 | Integer |
-+--------------------------------------+--------------------------------------+
-| uint32 | Long |
-+--------------------------------------+--------------------------------------+
-| uint64 | BigInteger |
-+--------------------------------------+--------------------------------------+
-| binary | byte[] |
-+--------------------------------------+--------------------------------------+
-
-Complex values of type argument are mapped as follows:
-
-+--------------------------------------+--------------------------------------+
-| Argument Type | Java type |
-+======================================+======================================+
-| enumeration | generated java enum |
-+--------------------------------------+--------------------------------------+
-| bits | generated class for bits |
-+--------------------------------------+--------------------------------------+
-| leafref | same type as referenced leaf |
-+--------------------------------------+--------------------------------------+
-| identityref | Class |
-+--------------------------------------+--------------------------------------+
-| union | generated java class |
-+--------------------------------------+--------------------------------------+
-| instance-identifier | ``org.opendaylight.yangtools.yang.bi |
-| | nding.InstanceIdentifier`` |
-+--------------------------------------+--------------------------------------+
-
-Enumeration Substatement Enum
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The YANG ``enumeration`` type has to contain some ``enum``
-substatements. An ``enumeration`` is mapped as Java enum type
-(standalone class) and every YANG enum substatements is mapped to Java
-enum’s predefined values.
-
-An ``enum`` statement can have following substatements:
-
-+--------------------------------------+--------------------------------------+
-| Enum’s Substatement | Java mapping |
-+======================================+======================================+
-| description | is not mapped in API |
-+--------------------------------------+--------------------------------------+
-| value | mapped as input parameter for every |
-| | predefined value of enum |
-+--------------------------------------+--------------------------------------+
-
-For example, the following YANG:
-
-**YANG model.**
+When importing a module with activated semantic version processing mode,
+only the module with the newest (highest) compatible semantic version is
+imported. Two semantic versions are compatible when all of the following
+conditions are met:
-.. code:: yang
-
- typedef typedef-enumeration {
- type enumeration {
- enum enum1 {
- description "enum1 description";
- value 18;
- }
- enum enum2 {
- value 16;
- }
- enum enum3 {
- }
- }
- }
+- the major version in the import statement and major version in the
+ imported module are equal. For instance, 1.5.3 is compatible with
+ 1.5.3, 1.5.4, 1.7.2, etc., but it is not compatible with 0.5.2 or
+ 2.4.8, etc.
-is converted into this Java:
+- the combination of minor version and patch version in the import
+ statement is not higher than the one in the imported module. For
+ instance, 1.5.2 is compatible with 1.5.2, 1.5.4, 1.6.8 etc. In fact,
+ 1.5.2 is also compatible with versions like 1.5.1, 1.4.9 or 1.3.7 as
+ they have equal major version. However, they will not be imported
+ because their minor and patch version are lower (older).
-**TypedefEnumeration.java.**
+If the import statement does not specify a semantic version, then the
+default one is chosen - 0.0.0. Thus, the module is imported only if it
+has a semantic version compatible with the default one, for example
+0.0.0, 0.1.3, 0.3.5 and so on.
-.. code:: java
+Working with YANG Data
+~~~~~~~~~~~~~~~~~~~~~~
- public enum TypedefEnumeration {
- Enum1(18),
- Enum2(16),
- Enum3(19);
+If you want to work with YANG Data you are going to need NormalizedNode
+objects that are specified in the YANG Data API. NormalizedNode is an
+interface at the top of the YANG Data hierarchy. It is extended through
+sub-interfaces which define the behaviour of specific NormalizedNode
+types like AnyXmlNode, ChoiceNode, LeafNode, ContainerNode, etc.
+Concrete implemenations of these interfaces are defined in
+yang-data-impl module. Once you have one or more NormalizedNode
+instances, you can perform CRUD operations on YANG data tree which is an
+in-memory database designed to store normalized nodes in a tree-like
+structure.
- int value;
+In some cases it is clear which NormalizedNode type belongs to which
+yang statement (e.g. AnyXmlNode, ChoiceNode, LeafNode). However, there
+are some normalized nodes which are named differently from their yang
+counterparts. They are listed below:
- private TypedefEnumeration(int value) {
- this.value = value;
- }
- }
+- LeafSetNode - leaf-list
-Bits’s Substatement Bit
-^^^^^^^^^^^^^^^^^^^^^^^
+- OrderedLeafSetNode - leaf-list that is ordered-by user
-The YANG ``bits`` type has to contain some bit substatements. YANG
-``bits`` is mapped to a Java class (standalone class) and every YANG
-``bits`` substatements is mapped to a boolean attribute of that class.
-In addition, the class provides overridden versions of the Object
-methods ``hashCode``, ``toString``, and ``equals``.
+- LeafSetEntryNode - concrete entry in a leaf-list
-For example, the following YANG:
+- MapNode - keyed list
-**YANG Model.**
+- OrderedMapNode - keyed list that is ordered-by user
-.. code:: yang
+- MapEntryNode - concrete entry in a keyed list
- typedef typedef-bits {
- type bits {
- bit first-bit {
- description "first-bit description";
- position 15;
- }
- bit second-bit;
- }
- }
+- UnkeyedListNode - unkeyed list
-is converted into this Java:
+- UnkeyedListEntryNode - concrete entry in an unkeyed list
-**TypedefBits.java.**
+In order to create a concrete NormalizedNode object you can use the
+utility class Builders or ImmutableNodes. These classes can be found in
+yang-data-impl module and they provide methods for building each type of
+normalized node. Here is a simple example of building a normalized node:
.. code:: java
- public class TypedefBits {
-
- private Boolean firstBit;
- private Boolean secondBit;
-
- public TypedefBits() {
- super();
- }
-
- public Boolean getFirstBit() {
- return firstBit;
- }
+ \\ example 1
+ ContainerNode containerNode == Builders.containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(moduleQName, "example-container")).build();
- public void setFirstBit(Boolean firstBit) {
- this.firstBit = firstBit;
- }
+ \\ example 2
+ ContainerNode containerNode2 == Builders.containerBuilder(containerSchemaNode).build();
- public Boolean getSecondBit() {
- return secondBit;
- }
-
- public void setSecondBit(Boolean secondBit) {
- this.secondBit = secondBit;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result +
- ((firstBit == null) ? 0 : firstBit.hashCode());
- result = prime * result +
- ((secondBit == null) ? 0 : secondBit.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- TypedefBits other = (TypedefBits) obj;
- if (firstBit == null) {
- if (other.firstBit != null) {
- return false;
- }
- } else if(!firstBit.equals(other.firstBit)) {
- return false;
- }
- if (secondBit == null) {
- if (other.secondBit != null) {
- return false;
- }
- } else if(!secondBit.equals(other.secondBit)) {
- return false;
- }
- return true;
- }
+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.
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("TypedefBits [firstBit=");
- builder.append(firstBit);
- builder.append(", secondBit=");
- builder.append(secondBit);
- builder.append("]");
- return builder.toString();
- }
- }
+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.
-Union’s Substatement Type
-^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code:: java
-If the type of a ``typedef`` is ``union``, it has to contain ``type``
-substatements. The ``union typedef`` is mapped to class and its ``type``
-substatements are mapped to private class members. Every YANG union
-subtype gets its own Java constructor with a parameter which represent
-just that one attribute.
+ YangInstanceIdentifier.NodeIdentifier contId == new YangInstanceIdentifier.NodeIdentifier(QName.create(moduleQName, "example-container");
-For example, the following YANG:
+ NormalizedNode<?, ?> contNode == ImmutableNodes.fromInstanceId(schemaContext, YangInstanceIdentifier.create(contId));
-**YANG model.**
+Let us show a more complex example of creating a NormalizedNode. First,
+consider the following YANG module:
.. code:: yang
- typedef typedef-union {
- type union {
- type int32;
- type string;
- }
- }
+ module example-module {
+ namespace "opendaylight.org/example-module";
+ prefix "example";
-is converted into this Java:
+ container parent-container {
+ container child-container {
+ list parent-ordered-list {
+ ordered-by user;
-**TypdefUnion.java.**
-
-.. code:: java
+ key "parent-key-leaf";
- public class TypedefUnion {
+ leaf parent-key-leaf {
+ type string;
+ }
- private Integer int32;
- private String string;
-
- public TypedefUnion(Integer int32) {
- super();
- this.int32 = int32;
- }
-
- public TypedefUnion(String string) {
- super();
- this.string = string;
- }
+ leaf parent-ordinary-leaf {
+ type string;
+ }
- public Integer getInt32() {
- return int32;
- }
+ list child-ordered-list {
+ ordered-by user;
- public String getString() {
- return string;
- }
+ key "child-key-leaf";
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((int32 == null) ? 0 : int32.hashCode());
- result = prime * result + ((string == null) ? 0 : string.hashCode());
- return result;
- }
+ leaf child-key-leaf {
+ type string;
+ }
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- TypedefUnion other = (TypedefUnion) obj;
- if (int32 == null) {
- if (other.int32 != null) {
- return false;
- }
- } else if(!int32.equals(other.int32)) {
- return false;
- }
- if (string == null) {
- if (other.string != null) {
- return false;
+ leaf child-ordinary-leaf {
+ type string;
+ }
+ }
}
- } else if(!string.equals(other.string)) {
- return false;
}
- return true;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("TypedefUnion [int32=");
- builder.append(int32);
- builder.append(", string=");
- builder.append(string);
- builder.append("]");
- return builder.toString();
- }
- }
-
-String Mapping
-^^^^^^^^^^^^^^
-
-The YANG ``string`` type can contain the substatements ``length`` and
-``pattern`` which are mapped as follows:
-
-+--------------------------------------+--------------------------------------+
-| Type substatements | Mapping to Java |
-+======================================+======================================+
-| length | not mapped |
-+--------------------------------------+--------------------------------------+
-| pattern | | . list of string constants = list |
-| | of patterns |
-| | | . list of Pattern objects |
-| | | . static initialization block |
-| | where list of Patterns is |
-| | initialized from list of string of |
-| | constants |
-+--------------------------------------+--------------------------------------+
-
-For example, the following YANG:
-
-**YANG model.**
-
-.. code:: yang
-
- typedef typedef-string {
- type string {
- length 44;
- pattern "[a][.]*"
}
}
-is converted into this Java:
-
-**TypedefString.java.**
+In the following example, two normalized nodes based on the module above
+are written to and read from the data tree.
.. code:: java
- public class TypedefString {
-
- private static final List<Pattern> patterns = new ArrayList<Pattern>();
- public static final List<String> PATTERN`CONSTANTS = Arrays.asList("[a][.]*");
-
- static {
- for (String regEx : PATTERN`CONSTANTS) {
- patterns.add(Pattern.compile(regEx));
- }
- }
-
- private String typedefString;
-
- public TypedefString(String typedefString) {
- super();
- // Pattern validation
- this.typedefString = typedefString;
- }
-
- public String getTypedefString() {
- return typedefString;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((typedefString == null) ? 0 : typedefString.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- TypedefString other = (TypedefString) obj;
- if (typedefString == null) {
- if (other.typedefString != null) {
- return false;
- }
- } else if(!typedefString.equals(other.typedefString)) {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("TypedefString [typedefString=");
- builder.append(typedefString);
- builder.append("]");
- return builder.toString();
- }
- }
+ TipProducingDataTree inMemoryDataTree == InMemoryDataTreeFactory.getInstance().create(TreeType.OPERATIONAL);
+ inMemoryDataTree.setSchemaContext(schemaContext);
+
+ // first data tree modification
+ MapEntryNode parentOrderedListEntryNode == Builders.mapEntryBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifierWithPredicates(
+ parentOrderedListQName, parentKeyLeafQName, "pkval1"))
+ .withChild(Builders.leafBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifier(parentOrdinaryLeafQName))
+ .withValue("plfval1").build()).build();
+
+ OrderedMapNode parentOrderedListNode == Builders.orderedMapBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifier(parentOrderedListQName))
+ .withChild(parentOrderedListEntryNode).build();
+
+ ContainerNode parentContainerNode == Builders.containerBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifier(parentContainerQName))
+ .withChild(Builders.containerBuilder().withNodeIdentifier(
+ new NodeIdentifier(childContainerQName)).withChild(parentOrderedListNode).build()).build();
+
+ YangInstanceIdentifier path1 == YangInstanceIdentifier.of(parentContainerQName);
+
+ DataTreeModification treeModification == inMemoryDataTree.takeSnapshot().newModification();
+ treeModification.write(path1, parentContainerNode);
+
+ // second data tree modification
+ MapEntryNode childOrderedListEntryNode == Builders.mapEntryBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifierWithPredicates(
+ childOrderedListQName, childKeyLeafQName, "chkval1"))
+ .withChild(Builders.leafBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifier(childOrdinaryLeafQName))
+ .withValue("chlfval1").build()).build();
+
+ OrderedMapNode childOrderedListNode == Builders.orderedMapBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifier(childOrderedListQName))
+ .withChild(childOrderedListEntryNode).build();
+
+ ImmutableMap.Builder<QName, Object> builder == ImmutableMap.builder();
+ ImmutableMap<QName, Object> keys == builder.put(parentKeyLeafQName, "pkval1").build();
+
+ YangInstanceIdentifier path2 == YangInstanceIdentifier.of(parentContainerQName).node(childContainerQName)
+ .node(parentOrderedListQName).node(new NodeIdentifierWithPredicates(parentOrderedListQName, keys)).node(childOrderedListQName);
+
+ treeModification.write(path2, childOrderedListNode);
+ treeModification.ready();
+ inMemoryDataTree.validate(treeModification);
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(treeModification));
+
+ DataTreeSnapshot snapshotAfterCommits == inMemoryDataTree.takeSnapshot();
+ Optional<NormalizedNode<?, ?>> readNode == snapshotAfterCommits.readNode(path1);
+ Optional<NormalizedNode<?, ?>> readNode2 == snapshotAfterCommits.readNode(path2);
+
+First comes the creation of in-memory data tree instance. The schema
+context (containing the model mentioned above) of this tree is set.
+After that, two normalized nodes are built. The first one consists of a
+parent container, a child container and a parent ordered list which
+contains a key leaf and an ordinary leaf. The second normalized node is
+a child ordered list that also contains a key leaf and an ordinary leaf.
+
+In order to add a child node to a node, method withChild() is used. It
+takes a NormalizedNode as argument. When creating a list entry,
+YangInstanceIdentifier.NodeIdentifierWithPredicates should be used as
+its identifier. Its arguments are the QName of the list, QName of the
+list key and the value of the key. Method withValue() specifies a value
+for the ordinary leaf in the list.
+
+Before writing a node to the data tree, a path (YangInstanceIdentifier)
+which determines its place in the data tree needs to be defined. The
+path of the first normalized node starts at the parent container. The
+path of the second normalized node points to the child ordered list
+contained in the parent ordered list entry specified by the key value
+"pkval1".
+
+Write operation is performed with both normalized nodes mentioned
+earlier. It consist of several steps. The first step is to instantiate a
+DataTreeModification object based on a DataTreeSnapshot.
+DataTreeSnapshot gives you the current state of the data tree. Then
+comes the write operation which writes a normalized node at the provided
+path in the data tree. After doing both write operations, method ready()
+has to be called, marking the modification as ready for application to
+the data tree. No further operations within the modification are
+allowed. The modification is then validated - checked whether it can be
+applied to the data tree. Finally we commit it to the data tree.
+
+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.
-identity statement
-~~~~~~~~~~~~~~~~~~
-
-The purpose of the ``identity`` statement is to define a new globally
-unique, abstract, and untyped value.
+.. code:: java
-The ``base`` substatement argument is the name of existing identity from
-which the new identity is derived.
+ InputStream resourceAsStream == ExampleClass.class.getResourceAsStream("/example-module.yang");
-Given that, an ``identity`` statement is mapped to Java abstract class
-and any ``base`` substatements are mapped as ``extends`` Java keyword.
-The identity name is translated to class name.
+ XMLInputFactory factory == XMLInputFactory.newInstance();
+ XMLStreamReader reader == factory.createXMLStreamReader(resourceAsStream);
-For example, the following YANG:
+ NormalizedNodeResult result == new NormalizedNodeResult();
+ NormalizedNodeStreamWriter streamWriter == ImmutableNormalizedNodeStreamWriter.from(result);
-**YANG Model.**
+ XmlParserStream xmlParser == XmlParserStream.create(streamWriter, schemaContext);
+ xmlParser.parse(reader);
-.. code:: yang
+ NormalizedNode<?, ?> transformedInput == result.getResult();
- identity toast-type {
+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.
- identity white-bread {
- base toast-type;
- }
+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.
-is converted into this Java:
+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.
-**ToastType.java.**
+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.
-.. code:: java
+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.
- public abstract class ToastType extends BaseIdentity {
- protected ToastType() {
- super();
- }
- }
+Introducing schema source repositories
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-**WhiteBread.java.**
+Writing YANG driven generators
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. code:: java
+Introducing specific extension support for YANG parser
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- public abstract class WhiteBread extends ToastType {
- protected WhiteBread() {
- super();
- }
- }
+Diagnostics
+~~~~~~~~~~~