X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=docs%2Fdeveloper-guide%2Fyang-tools.rst;h=fede7d9b1b6abacad97b1ccf0637eee28b81bc29;hb=1cb14399495fca6dba51d0e551d1ab810807629c;hp=b30175a7fb3ed5af88421d8d40d816c0a50683ca;hpb=7263d800d129ea81a1a4fdccdfe40c7b6a4b3fbf;p=docs.git diff --git a/docs/developer-guide/yang-tools.rst b/docs/developer-guide/yang-tools.rst index b30175a7f..fede7d9b1 100644 --- a/docs/developer-guide/yang-tools.rst +++ b/docs/developer-guide/yang-tools.rst @@ -1,5 +1,7 @@ -YANG Tools -========== +.. _yangtools-developer-guide: + +YANG Tools Developer Guide +========================== Overview -------- @@ -20,10 +22,6 @@ YANG Tools provides following features in OpenDaylight: 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 @@ -33,10 +31,10 @@ YANG Tools provides following features in OpenDaylight: - JSON - as defined in `draft-lhotka-netmod-yang-json-01 `__ - - 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: @@ -57,1217 +55,659 @@ 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**. +Concepts +~~~~~~~~ -YANG Java Binding: Mapping rules --------------------------------- +Project defines base concepts and helper classes which are +project-agnostic and could be used outside of YANG Tools project scope. -This chapter covers the details of mapping YANG to Java. +Components +~~~~~~~~~~ -.. note:: +- yang-common - 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. +- yang-data-api -General conversion rules -~~~~~~~~~~~~~~~~~~~~~~~~ +- yang-data-codec-gson -Package names of YANG models -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- yang-data-codec-xml -| The package name consists of the following parts: +- yang-data-impl -- **Opendaylight prefix** - Specifies the opendaylight prefix. Every - package name starts with the prefix ``org.opendaylight.yang.gen.v``. +- yang-data-jaxen -- **Java Binding version** - Specifies the YANG Java Binding version. - Curent Binding version is ``1``. +- yang-data-transform -- **Namespace** - Specified by the value of ``namespace`` substatement. - URI is converted to package name structure. +- yang-data-util -- **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-maven-plugin -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-maven-plugin-it -The following is a list of keywords which are prefixed with underscore: +- yang-maven-plugin-spi -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-model-api -As an example suppose following yang model: +- yang-model-export -.. 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-model-util -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-parser-api -| Java code is generated in the following structure: +- yang-parser-impl -- ``org.opendaylight.yang.gen.v1.urn.module.rev201379`` - package - contains direct substatements of module statement - - - ``Cont.java`` - -- ``org.opendaylight.yang.gen.v1.urn.module.rev201379.cont`` - package - contains substatements of ``cont`` container statement - - - ``ContInner.java`` - interface representing container - ``cont-inner`` - - - ``OutterList.java`` - interface representing list ``outer-list`` - -- ``org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.outter.list`` - - package contains substatements of outter-list list element - - - ``ListInList.java`` - -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: ``.java`` where ```` -is either data or service. +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. -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 -^^^^^^^^^^^^^^^^^^^ - -YANG containers are mapped to Java interfaces which extend the Java -DataObject and Augmentable, 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 { - } - -Leaf statement -^^^^^^^^^^^^^^ + StatementStreamSource yangModuleSource == new YangStatementSourceImpl("/example.yang", false); + StatementStreamSource yangModuleSource2 == new YangStatementSourceImpl("/example2.yang", false); -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. + CrossSourceStatementReactor.BuildAction reactor == YangInferencePipeline.RFC6020_REACTOR.newBuild(); + reactor.addSources(yangModuleSource, yangModuleSource2); -For example, the following YANG: + SchemaContext schemaContext == reactor.buildEffective(); -**YANG model.** +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. -.. code:: yang +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. - 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 { - String getLf(); - } - -- Represents ``leaf lf`` + Set modules == schemaContext.getModules(); + Set dataSchemaNodes == schemaContext.getDataDefinitions(); -leaf-list statement -^^^^^^^^^^^^^^^^^^^ +Usually you want to access specific modules. Getting a concrete module +from SchemaContext is a matter of calling one of these methods: -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. +- findModuleByName(), -For example, the following YANG: +- findModuleByNamespace(), -**YANG model.** +- findModuleByNamespaceAndRevision(). -.. code:: yang - - 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 { - List 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.** + Module exampleModule == schemaContext.findModuleByName("example-module", null); + // or + Date revisionDate == SimpleDateFormatUtil.getRevisionFormat().parse("2015-09-02"); + Module exampleModule == schemaContext.findModuleByName("example-module", revisionDate); -.. 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``. 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: - -**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 { + Module exampleModule == schema.findModuleByNamespace(new URI("opendaylight.org/example-module")); - List getLeafListInList(); +In the third case, you provide both module namespace and revision date +as arguments. - List getListInList(); - - /* - 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; + Set augmentationSchemas == exampleModule.getAugmentations(); + Set moduleImports == exampleModule.getImports(); - import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.OutterListKey; - import Java.math.BigInteger; + ChoiceSchemaNode choiceSchemaNode == (ChoiceSchemaNode) exampleModule.getDataChildByName(QName.create(exampleModule.getQNameModule(), "example-choice")); - public class OutterListKey { + ContainerSchemaNode containerSchemaNode == (ContainerSchemaNode) exampleModule.getDataChildByName(QName.create(exampleModule.getQNameModule(), "example-container")); - private BigInteger _leafInList; +The YANG statement parser can work in three modes: - public OutterListKey(BigInteger _leafInList) { - super(); - this_leafInList = _leafInList; - } - - public BigInteger getLeafInList() { - return _leafInList; - } +- default mode - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((_leafInList == null) ? 0 : _leafInList.hashCode()); - return result; - } +- mode with active resolution of if-feature statements - @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; - } +- mode with active semantic version processing - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("OutterListKey [_leafInList="); - builder.append(_leafInList); - builder.append("]"); - return builder.toString(); - } - } +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. -choice and case statements -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -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. - -For example, the following YANG: - -**YANG model.** - -.. code:: yang - - container cont { - choice example-choice { - case foo-case { - leaf foo { - type string; - } - } - case bar-case { - leaf bar { - type string; - } - } - } - } - -is converted into this Java: - -**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; - import org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.ChoiceTest; - - public interface Cont extends DataObject, Augmentable { - - ExampleChoice getExampleChoice(); - - } - -**ExampleChoice.java.** - -.. code:: java - - package org.opendaylight.yang.gen.v1.urn.module.rev201379.cont; - - import org.opendaylight.yangtools.yang.binding.DataObject; - - public interface ExampleChoice extends DataContainer { - } - -**FooCase.java.** - -.. 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 { - - String getFoo(); - - } - -**BarCase.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.Set object. In the example below, only two +features are supported: example-feature-1 and example-feature-2. The +Set 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.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 { - - String getBar(); - - } + Set supportedFeatures = ImmutableSet.of( + QName.create("example-namespace", "2016-08-31", "example-feature-1"), + QName.create("example-namespace", "2016-08-31", "example-feature-2")); -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: - -**YANG Model.** - -.. code:: yang - - grouping grp { - leaf foo { - type string; - } - } - - container cont { - uses grp; - } + CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(supportedFeatures); -is converted into this Java: - -**Grp.java.** +In case when no features should be supported, you should provide an +empty Set object. .. code:: java - package org.opendaylight.yang.gen.v1.urn.module.rev201379; - - import org.opendaylight.yangtools.yang.binding.DataObject; + Set supportedFeatures = ImmutableSet.of(); - public interface Grp extends DataObject { + CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(supportedFeatures); - String getFoo(); - - } +When this mode is not activated, all features in the processed YANG +sources are supported. -**Cont.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; - - import org.opendaylight.yangtools.yang.binding.DataObject; - import org.opendaylight.yangtools.yang.binding.Augmentable; - - public interface Cont extends DataObject, Augmentable, Grp { - } - -rpc, input and output statements -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + CrossSourceStatementReactor.BuildAction reactor == YangInferencePipeline.RFC6020_REACTOR.newBuild(StatementParserMode.SEMVER_MODE); -An ``rpc`` statement is mapped to Java as method of class -``ModuleService.java``. Any substatements of an ``rpc`` are mapped as -follows: +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. -+--------------------------------------+--------------------------------------+ -| Rpc Substatement | Mapping | -+======================================+======================================+ -| input | presence of input statement triggers | -| | generation of interface | -+--------------------------------------+--------------------------------------+ -| output | presence of output statement | -| | triggers generation of interface | -+--------------------------------------+--------------------------------------+ +.. code:: -For example, the following YANG: + module semantic-version { + namespace "urn:opendaylight:yang:extension:semantic-version"; + prefix sv; + yang-version 1; -**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> rpcTest1(RpcTest1Input input); - - } - -**RpcTest1Input.java.** - -.. code:: java +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. - package org.opendaylight.yang.gen.v1.urn.module.rev201379; +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. - public interface RpcTest1Input { +.. code:: - String getLfInput(); + 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";} -**RpcTest1Output.java.** - -.. code:: java - - package org.opendaylight.yang.gen.v1.urn.module.rev201379; - - public interface RpcTest1Output { - - String getLfOutput(); + revision "2016-02-01" { + description "Initial version"; + } + sv:semantic-version "0.1.1"; + ... } -notification statement -^^^^^^^^^^^^^^^^^^^^^^ - -``notification`` statements are mapped to Java interfaces which extend -the Notification interface. - -For example, the following YANG: +.. code:: -**YANG model.** + module bar { + namespace bar; + prefix bar; + yang-version 1; -.. code:: yang + import semantic-version { prefix sv; revision-date 2016-02-02; sv:semantic-version "0.0.1"; } - notification notif { + revision "2016-01-01" { + description "Initial version"; } + sv:semantic-version "0.1.2"; -is converted into this Java: - -**Notif.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; - import org.opendaylight.yangtools.yang.binding.Notification; - - public interface Notif extends DataObject, Augmentable, Notification { + ... } -augment statement -~~~~~~~~~~~~~~~~~ +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. -``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. +A major version number of 0 indicates that the model is still in +development and is subject to change. -For example, the following YANG: +Following a release of major version 1, all modules will increment major +version number when backwards incompatible changes to the model are +made. -**YANG Model.** +The minor version is changed when features are added to the model that +do not impact current clients use of the model. -.. code:: yang +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. - container cont { - } +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: - augment "/cont" { - leaf additional-value { - type string; - } - } +- 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). -**Cont.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 - - package org.opendaylight.yang.gen.v1.urn.module.rev201379; +Working with YANG Data +~~~~~~~~~~~~~~~~~~~~~~ - import org.opendaylight.yangtools.yang.binding.DataObject; - import org.opendaylight.yangtools.yang.binding.Augmentable; +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. - public interface Cont extends DataObject, Augmentable { +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: - } +- LeafSetNode - leaf-list -**Cont1.java.** +- OrderedLeafSetNode - leaf-list that is ordered-by user -.. code:: java +- LeafSetEntryNode - concrete entry in a leaf-list - package org.opendaylight.yang.gen.v1.urn.module.rev201379; +- MapNode - keyed list - import org.opendaylight.yangtools.yang.binding.DataObject; - import org.opendaylight.yangtools.yang.binding.Augmentation; +- OrderedMapNode - keyed list that is ordered-by user - public interface Cont1 extends DataObject, Augmentation { +- MapEntryNode - concrete entry in a keyed list - } +- UnkeyedListNode - unkeyed list -YANG Type mapping -~~~~~~~~~~~~~~~~~ +- UnkeyedListEntryNode - concrete entry in an unkeyed list -typedef statement -^^^^^^^^^^^^^^^^^ - -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.** - -.. code:: yang - - typedef typedef-enumeration { - type enumeration { - enum enum1 { - description "enum1 description"; - value 18; - } - enum enum2 { - value 16; - } - enum enum3 { - } - } - } - -is converted into this Java: - -**TypedefEnumeration.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 enum TypedefEnumeration { - Enum1(18), - Enum2(16), - Enum3(19); - - int value; + \\ example 1 + ContainerNode containerNode == Builders.containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(moduleQName, "example-container")).build(); - private TypedefEnumeration(int value) { - this.value = value; - } - } + \\ example 2 + ContainerNode containerNode2 == Builders.containerBuilder(containerSchemaNode).build(); -Bits’s Substatement Bit -^^^^^^^^^^^^^^^^^^^^^^^ +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. -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``. - -For example, the following YANG: - -**YANG Model.** - -.. code:: yang - - typedef typedef-bits { - type bits { - bit first-bit { - description "first-bit description"; - position 15; - } - bit second-bit; - } - } - -is converted into this Java: - -**TypedefBits.java.** +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. .. code:: java - public class TypedefBits { + YangInstanceIdentifier.NodeIdentifier contId == new YangInstanceIdentifier.NodeIdentifier(QName.create(moduleQName, "example-container"); - private Boolean firstBit; - private Boolean secondBit; + NormalizedNode contNode == ImmutableNodes.fromInstanceId(schemaContext, YangInstanceIdentifier.create(contId)); - public TypedefBits() { - super(); - } +Let us show a more complex example of creating a NormalizedNode. First, +consider the following YANG module: - public Boolean getFirstBit() { - return firstBit; - } - - public void setFirstBit(Boolean firstBit) { - this.firstBit = firstBit; - } +.. code:: - public Boolean getSecondBit() { - return secondBit; - } + module example-module { + namespace "opendaylight.org/example-module"; + prefix "example"; - public void setSecondBit(Boolean secondBit) { - this.secondBit = secondBit; - } + container parent-container { + container child-container { + list parent-ordered-list { + ordered-by user; - @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; - } + key "parent-key-leaf"; - @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; - } + leaf parent-key-leaf { + type string; + } - @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(); - } - } + leaf parent-ordinary-leaf { + type string; + } -Union’s Substatement Type -^^^^^^^^^^^^^^^^^^^^^^^^^ + list child-ordered-list { + ordered-by user; -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. + key "child-key-leaf"; -For example, the following YANG: + leaf child-key-leaf { + type string; + } -**YANG model.** - -.. code:: yang - - typedef typedef-union { - type union { - type int32; - type string; - } - } - -is converted into this Java: - -**TypdefUnion.java.** - -.. code:: java - - public class TypedefUnion { - - private Integer int32; - private String string; - - public TypedefUnion(Integer int32) { - super(); - this.int32 = int32; - } - - public TypedefUnion(String string) { - super(); - this.string = string; - } - - public Integer getInt32() { - return int32; - } - - public String getString() { - return string; - } - - @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; - } - - @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 patterns = new ArrayList(); - public static final List PATTERN`CONSTANTS = Arrays.asList("[a][.]*"); - - static { - for (String regEx : PATTERN`CONSTANTS) { - patterns.add(Pattern.compile(regEx)); - } - } + 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 builder == ImmutableMap.builder(); + ImmutableMap 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> readNode == snapshotAfterCommits.readNode(path1); + Optional> 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. - 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(); - } - } - -identity statement -~~~~~~~~~~~~~~~~~~ - -The purpose of the ``identity`` statement is to define a new globally -unique, abstract, and untyped value. - -The ``base`` substatement argument is the name of existing identity from -which the new identity is derived. +.. code:: java -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. + InputStream resourceAsStream == ExampleClass.class.getResourceAsStream("/example-module.yang"); -For example, the following YANG: + XMLInputFactory factory == XMLInputFactory.newInstance(); + XMLStreamReader reader == factory.createXMLStreamReader(resourceAsStream); -**YANG Model.** + NormalizedNodeResult result == new NormalizedNodeResult(); + NormalizedNodeStreamWriter streamWriter == ImmutableNormalizedNodeStreamWriter.from(result); -.. code:: yang + XmlParserStream xmlParser == XmlParserStream.create(streamWriter, schemaContext); + xmlParser.parse(reader); - identity toast-type { + 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. - identity white-bread { - base toast-type; - } +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. -is converted into this Java: +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. -**ToastType.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. -.. code:: 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. - public abstract class ToastType extends BaseIdentity { - protected ToastType() { - super(); - } - } +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. -**WhiteBread.java.** +Introducing schema source repositories +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: java +Writing YANG driven generators +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - public abstract class WhiteBread extends ToastType { - protected WhiteBread() { - super(); - } - } +Introducing specific extension support for YANG parser +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Diagnostics +~~~~~~~~~~~