X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=docs%2Fdeveloper-guide%2Fyang-tools.rst;h=8f5f4bde2e73e41c072b5dbda784932c741aedbc;hb=65a2e18246a32cc50fac93d6860eaa27d0d2bbf1;hp=b30175a7fb3ed5af88421d8d40d816c0a50683ca;hpb=581dd9938c73e6e25d6e70ce5a014349a2d774af;p=docs.git diff --git a/docs/developer-guide/yang-tools.rst b/docs/developer-guide/yang-tools.rst index b30175a7f..8f5f4bde2 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,660 @@ 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. +Concepts +~~~~~~~~ -.. note:: +Project defines base concepts and helper classes which are +project-agnostic and could be used outside of YANG Tools project scope. - 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. +Components +~~~~~~~~~~ -General conversion rules -~~~~~~~~~~~~~~~~~~~~~~~~ +- yang-common -Package names of YANG models -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- yang-data-api -| The package name consists of the following parts: +- yang-data-codec-gson -- **Opendaylight prefix** - Specifies the opendaylight prefix. Every - package name starts with the prefix ``org.opendaylight.yang.gen.v``. +- yang-data-codec-xml -- **Java Binding version** - Specifies the YANG Java Binding version. - Curent Binding version is ``1``. +- yang-data-impl -- **Namespace** - Specified by the value of ``namespace`` substatement. - URI is converted to package name structure. +- yang-data-jaxen -- **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-transform -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. - -The following is a list of keywords which are prefixed with underscore: - -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 - -As an example suppose following yang model: - -.. 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-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-maven-plugin -| Java code is generated in the following structure: +- yang-maven-plugin-it -- ``org.opendaylight.yang.gen.v1.urn.module.rev201379`` - package - contains direct substatements of module statement +- yang-maven-plugin-spi - - ``Cont.java`` +- yang-model-api -- ``org.opendaylight.yang.gen.v1.urn.module.rev201379.cont`` - package - contains substatements of ``cont`` container statement +- yang-model-export - - ``ContInner.java`` - interface representing container - ``cont-inner`` +- yang-model-util - - ``OutterList.java`` - interface representing list ``outer-list`` +- yang-parser-api -- ``org.opendaylight.yang.gen.v1.urn.module.rev201379.cont.outter.list`` - - package contains substatements of outter-list list element +- yang-parser-impl - - ``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. - -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, 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 { - } + 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 { - String getLf(); - } + Set modules == schemaContext.getModules(); + Set dataSchemaNodes == schemaContext.getDataDefinitions(); -- Represents ``leaf lf`` +Usually you want to access specific modules. Getting a concrete module +from SchemaContext is a matter of calling one of these methods: -leaf-list statement -^^^^^^^^^^^^^^^^^^^ +- findModuleByName(), -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. +- findModuleByNamespace(), -For example, the following YANG: +- findModuleByNamespaceAndRevision(). -**YANG model.** - -.. 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.** - -.. 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: + 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 { - - List getLeafListInList(); + Module exampleModule == schema.findModuleByNamespace(new URI("opendaylight.org/example-module")); - List 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; + 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; - } +- default mode - public BigInteger getLeafInList() { - return _leafInList; - } +- mode with active resolution of if-feature statements - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((_leafInList == null) ? 0 : _leafInList.hashCode()); - return result; - } +- mode with active semantic version processing - @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; - } +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. - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("OutterListKey [_leafInList="); - builder.append(_leafInList); - builder.append("]"); - return builder.toString(); - } - } - -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.** +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; - - import org.opendaylight.yangtools.yang.binding.DataObject; + Set supportedFeatures = ImmutableSet.of( + QName.create("example-namespace", "2016-08-31", "example-feature-1"), + QName.create("example-namespace", "2016-08-31", "example-feature-2")); - public interface ExampleChoice extends DataContainer { - } + CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(supportedFeatures); -**FooCase.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.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; + Set supportedFeatures = ImmutableSet.of(); - public interface FooCase extends ExampleChoice, DataObject, Augmentable { + 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. - } - -**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 { - - 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. + CrossSourceStatementReactor.BuildAction reactor == YangInferencePipeline.RFC6020_REACTOR.newBuild(StatementParserMode.SEMVER_MODE); -For example, the following YANG: - -**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; + module semantic-version { + namespace "urn:opendaylight:yang:extension:semantic-version"; + prefix sv; + yang-version 1; - 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 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -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> 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(); - - } +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. -notification statement -^^^^^^^^^^^^^^^^^^^^^^ - -``notification`` statements are mapped to Java interfaces which extend -the Notification interface. - -For example, the following YANG: - -**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, 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 { + 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 { +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; - } +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. - public void setSecondBit(Boolean secondBit) { - this.secondBit = secondBit; - } +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. - @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; - } - - @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(); - } - } - -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 patterns = new ArrayList(); - public static final List 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 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. -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 +~~~~~~~~~~~