1 = Java Binding Specification 2
2 Tony Tkacik <ttkacik@cisco.com>; Robert Varga <rovarga@cisco.com>; Martin Sunal <msunal@cisco.com>; Martin Ciglan <mciglan@cisco.com>
3 :rfc6020: https://tools.ietf.org/html/rfc6020
12 naming space, in which all identifiers needs to be unique
17 Instantiated Data Node::
18 Instantiated Data Tree::
23 === YANG Identifiers Mapping
25 Every non-Java char in identifier is converted to Java char by its unicode name http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.8
26 JAVA SE SPECIFICATIONS - Identifiers. This mapping solves various issues from Binding Specification v1, which led to compilation issues.
28 There are special types of mapping non-java chars to original identifiers according to specific Java type:
30 * class, enum, interface
32 ** without special separator
33 the first character of identifier, any other first character of identifier part mapped by
34 ** non-Java char name from unicode and char in identifier behind non-java char name are converting to upper case
37 example* - ExampleAsterisk
38 example*example - ExampleAserisksExample
39 \example - ReverseSolidusExample
40 1example - DigitOneExample
42 int - IntReservedKeyword
43 con - ConReservedKeyword
45 * enum value, constant
46 ** used underscore as special separator
47 ** converted identifier to upper case
50 example* - EXAMPLE_ASTERISK
51 example*example - EXAMPLE_ASTERISK_EXAMPLE
52 \example - REVERSE_SOLIDUS_EXAMPLE
53 1example - DIGIT_ONE_EXAMPLE
55 int - INT_RESERVED_KEYWORD
56 con - CON_RESERVED_KEYWORD
59 ** without special separator
60 ** the first character of identifier is converting to lower case
61 ** any other first character of identifier part mapped by non-Java char name from unicode and char in identifier behind non-java char name are converting to upper case
64 example* - exampleAsterisk
65 example*example - exampleAserisksExample
66 \example - reverseSolidusExample
67 1example - digitOneExample
69 int - intReservedKeyword
70 con - conReservedKeyword
72 * package - full package name - https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html
73 ** parts of package name are separated by dots
74 ** parts of package name are converting to lower case
75 ** if parts of package name are reserved Java or Windows keywords, such as 'int' the suggested convention is to add an underscore to keyword
76 ** dash is parsed as underscore according to https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html
79 org.example* - org.exampleasterisk
80 org.example*example - org.exampleasteriskexample
81 org.example - org.reversesolidusexample
82 org.1example - org.digitoneexample
83 org.example1 - org.example1
86 org.foo-cont - org.foo_cont
88 ==== Special case - '-' in identifiers
89 There is special case in CLASS, INTERFACE, ENUM, ENUM VALUE, CONSTANT, METHOD and VARIABLE if
90 identifier contains single dash - then the converter ignores the single dash in the way of the
91 non-java chars. In other way, if dash is the first or the last char in the identifier or there is
92 more dashes in a row in the identifier, then these dashes are converted as non-java chars.
96 * class, enum, interface
99 foo--cont - FooHyphenMinusHyphenMinusCont
100 -foo - HyphenMinusFoo
101 foo- - FooHyphenMinus
103 * enum value, constant
106 foo--cont - FOO_HYPHEN_MINUS_HYPHEN_MINUS_CONT
107 -foo - HYPHEN_MINUS_FOO
108 foo- - FOO_HYPHEN_MINUS
113 foo--cont - fooHyphenMinusHyphenMinusCont
114 -foo - hyphenMinusFoo
115 foo- - fooHyphenMinus
117 ==== Special case - same class (or enum or interface) names with different camel cases
118 Next special case talks about normalizing class name which already exists in package - but with
119 different camel cases (foo, Foo, fOo, ...). To every next classes with same names will by added
120 their actual rank (serial number), except the first one. This working for CLASS, ENUM and
121 INTEFACE java identifiers. If there exist the same ENUM VALUES in ENUM (with different camel
122 cases), then it's parsed with same logic like CLASSES, ENUMS and INTERFACES but according to list
123 of pairs of their ENUM parent. Example:
125 * class, enum, interface
127 package name org.example, class (or interface or enum) Foo - normalized to Foo
128 package name org.example, class (or interface or enum) fOo - normalized to Foo1
136 YANG enum values will be mapped to 'FOO' and 'FOO_1' Java enum values.
139 === Binding Specification v2 Concepts
142 Represent node, which is instantiable by users as a part of notification,
143 rpc, action or data tree.
145 Represents node, which is part of instantiated data tree, this interface
146 is not used directly, but rather via <<TreeChildNode>>. See <<instantiated-data-tree-rules>>
147 for more information.
149 Represents virtual root of instantiated data tree.
151 Represents node, which is part of instantiated data tree and is not root of
154 Represents instantiated node, which is subjectible to be extended / augmented
155 by `augment` statement from external module.
157 Represents extension to instantiated node, which is introduced from different
158 model than instantiated node.
159 <<InstanceIdentifier>>::
160 Unique identifier of node / subtree in data tree, which provides unambiguous
161 information, how to reference node / subtree in Instantiated Data Tree.
166 .2+|Statement .2+| In groupings 3+| Instantiable .2+| Augmentable
167 | In Data | In RPC | In Notification
169 | `grouping` | Yes | No | No | No | No
171 | `container` | Yes | Yes | Yes | Yes | Yes
173 | `leaf` | Yes | Yes | Yes | Yes | No
175 | `leaf-list` | Yes | Yes | Yes | Yes | No
177 | `list` | Yes | Yes | Yes | Yes | Yes
179 | `anydata` | Yes | Yes | Yes | Yes | No
181 | `anyxml` | Yes | Yes | Yes | Yes | No
183 | `choice` | Yes | Yes | Yes | Yes | Yes
185 | `case` | Yes | Yes | Yes | Yes | Yes
187 | `input` | Yes | No | Yes | No | Yes
189 | `output` | Yes | No | Yes | No | Yes
191 | `notification` | Yes | No | No | Yes | Yes
197 YANG defines several namespaces and naming space of YANG is wider then applicable
198 namespace of JAVA language. In order to decrease conflicts between various
199 YANG-defined namespaces and classes introduced by Binding Specification, it
202 * separate namespaces by Java package hierarchy
203 ** each namespace must define rules how to construct package name, which
204 will not conflict with other namespace
205 * if multiple classes are generated for YANG statement they need to be in separate
206 packages to decrease possible conflicts with siblings.
207 * if Binding Specification introduces new concepts, which does not have explicit
208 namespace rules in YANG, these concepts needs to be in their own, separate
209 namespaces, in order to not conflict on valid YANG namespace items.
212 This rules allows to identify two types of namespaces:
214 .Namespace types by source of namespace
216 Naming space explicitly defined in YANG specification, which needs to be
217 explicitly supported in order to prevent naming conflicts.
219 Naming space introduced by Binding Specification for additional properties
220 and functionality of Binding Specification. This namespaces needs to be separate
221 from YANG namespaces in order to not have naming conflict with YANG-derived.
224 Binding Specification v2 uses following namespaces:
226 .Concrete namespaces used in Binding Specification
227 <<module-namespace>>::
228 YANG namespace containing representation for all modules.
229 <<identity-namespace>>::
230 YANG namespace containing representation for all `identity` statements. Identities
231 needs to be separated to prevent naming conflict between Grouping, Data, Type
234 YANG namespace containing representation for all `typedef` statements and
235 annonymous definitions of `union`, `enumeration` and `bits` types. Types needs
236 to be seperated to prevent naming conflict between Identity, Grouping and Data
238 <<grouping-namespace>>::
239 YANG namespace containing representation for all `grouping` statements and their
240 child data node statements. Groupings needs to be separated to prevent naming
241 conflict between Identity, Type, Data namespaces.
243 Binding namespace containing representation for all `key` statements.
244 Representations of key statements needs to be in separate namespace, since it is not defined
245 in YANG specification.
247 YANG namespace containing representation of instantiated data tree.
248 Data needs to be separated to prevent naming conflict between Identity, Type,
251 Binding namespace containing Transfer Objects and Builders representing
252 instantiated data tree items.
254 NOTE: Most of Binding Namespaces were introduced to decrease possibility of name
255 conflict between concepts defined in YANG and additional concepts introduced
256 by Binding Specification.
258 === Package hierarchy
260 .Package hierarchy for model
263 |Namespace | Package | Description
265 | <<identity-namespace, Identity>> | `ident`
266 | flat package containing representation for all `identity`
268 .3+| <<type-namespace, Type>> | `type`
269 | flat package containing representations for all top-level
273 | path-based package hierarchy containing representation
274 for `typedef` statements nested in grouping statements, or anonymous types
275 requiring code generation defined inside groupings
278 | path-based package hierarchy containing representation
279 for `typedef` statements nested in grouping statements, or anonymous types
280 requiring code generation defined inside instantiated data nodes
282 | <<key-namespace, Key>> | `key`
283 | path-based package hierarchy containing representation
284 of key statements for grouping code generation defined inside groupings
286 | <<grouping-namespace, Grouping>> | `grp`
287 | path-based package hierarchy containing representation
288 for `grouping` statements and data node statements nested in these groupings
290 | <<data-namespace, Data>> | `data`
291 | path-based package hierarchy containing representation of instantiated
294 | <<dto-namespace, Builder>> | `dto`
295 | path-based package hierarchy containing Tranfer Objects and their builders
296 for instantiated data nodes
304 [[identity-namespace]]
305 === Identity Namespace
311 [[grouping-namespace]]
312 === Grouping Namespace
321 === Builder Namespace
328 [[subpackage-structure]]
329 === Subpackage Naming
336 === `typedef` statement
338 ==== Globally scoped `typedef`
340 ==== Subtree scoped `typedef`
342 Subtree scoped `typedef` statement is type definition, which is not substatement
343 of `module` or `submodule`, and is only visible to child elements of parent
346 * Representation is generated in Type namespace according to following rules:
351 YANG types does not provide single, simple model of behaviour - some times
352 exhibits special properties to extensibility or limiting scope of valid values
356 .Base types and their behaviours
358 | YANG Type | Description | Java Mapping
361 | `binary` | Any binary data | `Binary`?
362 | `bits` | A set of bits or flags | Custom class
363 | `boolean` | `true` or `false` | `Boolean`
364 | `decimal64` | 64-bit signed decimal number | No
365 | `empty` | A leaf that does not have any value | No
366 | `enumeration` | Enumerated strings | No
367 | `identityref` | A reference to an abstract identity | Yes
368 | `instance-identifier` | References a data tree node | Yes
369 | `int8` | 8-bit signed integer | No
370 | `int16` | 16-bit signed integer | No
371 | `int32` | 32-bit signed integer | No
372 | `int64` | 64-bit signed integer | No
373 | `leafref` | A reference to a leaf instance | Maybe
374 | `string` | Human-readable string | No
375 | `uint8` | 8-bit unsigned integer | No
376 | `uint16` | 16-bit unsigned integer | No
377 | `uint32` | 32-bit unsigned integer | No
378 | `uint64` | 64-bit unsigned integer | No
379 | `union` | Choice of member types | Maybe
382 FIXME: Finalize table
397 ==== `enumeration` type
400 ==== `identityref` type
401 ==== `instance-identifier` type
409 Data nodes could be separated into two distinct groups, based on presence of
413 Node, which according to YANG schema does not have child nodes, is leaf node
414 and carries only simple value.
416 Node, which according to YANG schema may have child nodes, node itself does not
417 carry values, values are stored in descendant leaf nodes.
421 === `leaf-list` Statement
424 === `container` Statement
426 Builders will be located in package "dto"
434 container foo-builder {
438 [uml, file="container-builder.png"]
440 set namespaceSeparator none
445 interface data.FooBuilder {
449 In situations where we have a containing element which has as its child a single container, we should make it easy to autobox it. This should not be implemented in the interfaces themselves, but rather should be a method in the associated builder.
453 container example-outter {
454 container example-inner {
469 key identifier key fookey;
485 [uml, file="list-Keyed.png"]
487 set namespaceSeparator none
492 interface key.foo.FooIdentifier {
495 interface key.foo.FooKey {
498 interface key.foo.FooFooKey {
501 interface type.foo.identifier.IdentifierUnion {
504 data.Foo o- key.foo.FooIdentifier
505 data.Foo o- key.foo.FooKey
506 data.Foo o- key.foo.FooFooKey
507 key.foo.FooIdentifier o- type.foo.identifier.IdentifierUnion
510 ==== List without Key
512 === `choice` Statement
524 leaf bar { type string; }
530 [uml, file="case.png"]
532 set namespaceSeparator none
540 + getBase() : data.top.Base;
542 interface data.top.Base
543 interface data.top.base.Foo {
544 + getFoo() : data.top.base.foo.Foo
546 interface data.top.base.foo.Foo
547 interface data.top.base.Bar {
551 data.top.Base -u-|> Choice
552 data.top.base.Foo -u-|> Case
553 data.top.base.Bar -u-|> Case
555 data.top.base.Foo -u-|> data.top.Base
556 data.top.base.Bar -u-|> data.top.Base
558 data.Top o- data.top.Base
559 data.top.base.Foo o- data.top.base.foo.Foo
564 [[instantiated-data-node-rules]]
565 === Instantiated Data Node Rules
568 FIXME: Do we need section per type, or should just general rules be described.
571 ==== `container` Statement
574 FIXME: Here should be Augmentable & Instantiated
577 ==== `leaf` Statement
579 ==== `leaf-list` Statement
581 ==== `choice` Statement
583 ==== `case` Statement
586 FIXME: Here should be Augmentable & Instantiated
589 ==== `list` Statement
592 FIXME: Here should be Augmentable & Instantiated, List signature uses concrete
596 ==== `input` Statement
599 FIXME: Here should be Augmentable & Instantiated
602 ==== `output` Statement
605 FIXME: Here should be Augmentable & Instantiated
608 ==== `notification` Statement
611 FIXME: Here should be Augmentable & Instantiated
614 [[instantiated-data-tree-rules]]
615 === Instantiated Data Tree Rules
618 ==== `container` Statement
621 FIXME: Here should be Augmentable & Instantied & ChildDataNode
625 ==== `leaf` Statement
627 ==== `leaf-list` Statement
629 ==== `case` Statement
632 FIXME: Here should be Augmentable & Instantied & ChildDataNode
635 ==== `list` Statement
638 FIXME: Here should be Augmentable & Instantied & ChildDataNode
641 === `grouping` Statement
643 * `grouping` statement is represented by `interface`
644 ** interface name is generated according to <<class-naming>> with suffix `Grouping`
645 * Representations of `grouping` statements are generated into <<grouping-namespace>>
646 * schema nodes under grouping are represented by `interface` and are generated
647 into <<grouping-namespace>> + name of grouping
648 ** getters (accessors) from parent nodes are generated according to <<accessor-rules>>
649 ** class name is generated according to <<class-naming>> with suffix `Data`
650 ** schema nodes does not follow <<instantiated-data-tree-rules>>, these interfaces
651 are used only in instantiated data tree.
658 grouping simple { <1>
660 leaf bar { type string;} <3>
663 <1> Is represented by interface `grp.SimpleGrouping`
664 <2> Is represented by interface `grp.simple.FooData` and getter in `grp.SimpleGrouping`
665 with signature `public grp.simple.FooData getFoo();`
666 <3> Is represented by getter in `grp.SimpleGrouping` with signature `public String getBar()`
668 [uml, file="grouping1.png"]
670 interface grp.SimpleGrouping {
672 + getFoo() : grp.simple.FooData
674 interface grp.simple.FooData
675 grp.SimpleGrouping o- grp.simple.FooData
679 ==== Data Node substatements
681 Representations of data node substatements are generated according to rules
682 described in <<data-node-rules>> with following changes:
684 MS: proposed interface names:
685 case - <NodeName>Case
686 choice - <<NodeName>Choice
687 container, list - <NodeName>
690 MC: I would keep Data suffix, but idea about distinguishing cases and choices
693 * Interface names for `case`, `choice`, `container` and `list`, is suffixed by
694 `Data` suffix, in order to not conflict with same named groupings inside same
696 ** Getters in parent node, are still generated without `Data` suffix, so
697 the getter signature is in form `FooData getFoo()`
698 ** If return value of getter is constructed using generics (eg. `list`)
699 instead of signature `List<ListItem>` or `Map<ListKey, ListItem>`, wildcarded
700 `? extends ListItem` generic argument are used to allow for overriding during
701 <<uses-statement,instantation of grouping>>.
704 ==== `list` substatement
707 FIXME: Add reasoning / examples for need to use ? extends, instead of directly
711 ==== `leaf-list` susbstatement
714 FIXME: Add reasoning / examples for need to use ? extends, instead of directly
715 using generics for types, which may need instantiation
721 * `uses` statement triggers interface of parent statement to extend (implement)
722 interface of `grouping` referenced by `uses` argument.
723 * As in YANG `uses` statement triggers instatiation of data children of `grouping`
724 which will result in generation of these children as-if they were direct
725 children of parent statement
726 ** data node children are generated according to rules defined for parent statement.
727 Different rules apply based on parent type (instantiated data tree, `input`,
728 `output` or `grouping`)
729 ** interfaces generated for data children extends (implements) interfaces for
730 same children generated for referenced `grouping`
732 .Simple Grouping and Uses
739 leaf bar { type string;}
746 [uml, file="grouping2.png"]
748 set namespaceSeparator none
750 interface grp.SimpleGrouping {
752 + getFoo() : grp.simple.FooData
754 interface grp.simple.FooData
756 + getFoo() : data.top.Foo
758 interface data.top.Foo
760 grp.SimpleGrouping o-- grp.simple.FooData
762 data.Top o-- data.top.Foo
763 data.Top -|> grp.SimpleGrouping
764 data.top.Foo -|> grp.simple.FooData
767 NOTE: Diagram does not show all details for `data.Top` and `data.top.Foo`, which
768 are based on <<instantiated-data-tree-rules>>
772 .Grouping with Nested Grouping
778 grouping with-inner {
790 [uml, file="grouping3.png"]
792 set namespaceSeparator none
794 interface grp.withinner.inner.ContData
795 interface grp.withinner.InnerGrouping {
796 + getCont() : grp.withinner.inner.ContData
800 interface grp.withinner.ContData
802 interface grp.WithInnerGrouping {
803 + getCont() : grp.withinner.ContData
808 + getCont() : data.top.Cont
811 interface data.top.Cont {
814 data.Top o-- data.top.Cont : contains
816 data.Top -|> grp.WithInnerGrouping
817 data.top.Cont -|> grp.withinner.ContData
819 grp.WithInnerGrouping -|> grp.withinner.InnerGrouping : uses (implements)
820 grp.WithInnerGrouping o-- grp.withinner.ContData : contains
821 grp.withinner.InnerGrouping o-- grp.withinner.inner.ContData : contains
823 grp.withinner.ContData -|> grp.withinner.inner.ContData : is concretization of (implements)
827 NOTE: Diagram does not show all details for `data.Top` and `data.top.Cont`, which
828 are based on <<instantiated-data-tree-rules>>
833 ==== `augment` substatement
835 .Uses & Augment in instantiated Data Tree
858 [uml, file="grouping4.png"]
860 set namespaceSeparator none
863 interface data.top.Nested
864 interface data.top.nested.Bar
866 data.Top o-- data.top.Nested
867 data.top.Nested o-- data.top.nested.Bar
869 interface grp.ExampleGrouping
870 interface grp.example.NestedData
873 grp.ExampleGrouping o-- grp.example.NestedData
875 data.Top -|> grp.ExampleGrouping
876 data.top.Nested -|> grp.example.NestedData
879 NOTE: Diagram does not show all details for `data.Top`, `data.top.Nested` and
880 `data.top.nested.Bar`, which are based on <<instantiated-data-tree-rules>>
886 .Uses & Augment in grouping
909 [uml, file="grouping5.png"]
911 set namespaceSeparator none
913 interface grp.TopGrouping
914 interface grp.top.NestedData
915 interface grp.top.nested.BarData
917 grp.TopGrouping o-- grp.top.NestedData
918 grp.top.NestedData o-- grp.top.nested.BarData
920 interface grp.ExampleGrouping
921 interface grp.example.NestedData
923 grp.ExampleGrouping o-- grp.example.NestedData
925 grp.TopGrouping -|> grp.ExampleGrouping
926 grp.top.NestedData -|> grp.example.NestedData
931 === `augment` statement
933 Representation of `augment` statement depends on module in which target node of
934 augment statement is defined
936 * <<uses-augment, augment is substatement of uses>> - data nodes are represented
937 as-if their statements were inlined in target node.
938 See <<uses-augment, uses Statement: augment Substatement>> section for details.
939 * <<augment-same-module,target node in same module as augment>> - data nodes are
940 represented as-if their statements were inlined in target.
941 See <<augment-same-module>> for details & examples.
942 * <<augment-other-module, target node in other module as augment>> - interface representing
943 augmentation is generated, child data nodes are generated by rules for
944 <<instantiated-data-node-rules>>.
945 See <<augment-other-module>> for details & examples.
946 `augment` statement targets only instantiated data nodes, so child data nodes
947 representation is always generated.
949 [[augment-same-module]]
950 ==== Augmentation target in same module
952 All data node children are generated as-if they were directly defined inside
953 target node. There are no externally observable artefacts in generated
954 representation of these nodes, which would point out that they were defined
955 using `augment` statement instead of directly inlining them in target node.
957 .Why augment of same module is same as inlining
960 This rule may seems counterintuitive at first sight, but YANG defines
961 backwards compatibility in terms of effective model instead of way how model
962 is represented. `augment` statement, when targeting node in same module is not
963 externally observable and could factored out by inlining these statements.
965 Definition of `augment` statement in YANG also defines different behaviour when
966 target is same module and allows all features as-if this statements were
970 .Augment with target in same module
972 .YANG module written using augmentations
985 .Same module written without need to augment
994 .Same module written with grouping
1006 Java representation for all variants
1007 [uml, file="augment1.png"]
1009 set namespaceSeparator none
1012 interface data.top.Foo
1014 data.Top o- data.top.Foo
1019 [[augment-other-module]]
1020 ==== Augmentation target in other module
1022 .Augment with target in other module
1036 import top { prefix top; }
1038 augment "/top:top" {
1047 [uml,file="augment2.png"]
1049 set namespaceSeparator none
1051 interface Augmentable<T>
1052 interface Augmentation<T>
1054 interface top.data.Top
1055 interface foo.data.FooTop {
1059 interface foo.data.top.Bar
1061 top.data.Top -u-|> Augmentable : T = top.data.Top
1062 foo.data.FooTop -u-|> Augmentation : T = top.data.Top
1063 top.data.Top o-- foo.data.FooTop
1064 foo.data.FooTop o-- foo.data.top.Bar
1069 .Multiple augments with same target
1083 import top { prefix top; }
1085 augment "/top:top" {
1091 augment "/top:top" {
1100 [uml,file="augment3.png"]
1102 set namespaceSeparator none
1104 interface Augmentable<T>
1105 interface Augmentation<T>
1107 interface top.data.Top
1108 interface foo.data.FooTop {
1113 interface foo.data.top.Bar
1114 interface foo.data.top.Baz
1116 top.data.Top -u-|> Augmentable : T = top.data.Top
1117 foo.data.FooTop -u-|> Augmentation : T = top.data.Top
1118 top.data.Top o-- foo.data.FooTop
1119 foo.data.FooTop o-- foo.data.top.Bar
1120 foo.data.FooTop o-- foo.data.top.Baz
1125 .Multiple augments with different targets
1143 import target { prefix t; }
1145 augment "/t:first" {
1151 augment "/t:second" {
1160 [uml, file="augment4.png"]
1162 set namespaceSeparator none
1164 interface Augmentable<T>
1165 interface Augmentation<T>
1167 interface target.data.First
1168 interface target.data.Second
1170 interface foo.data.FooFirst {
1173 interface foo.data.FooSecond {
1177 interface foo.data.first.Bar
1178 interface foo.data.second.Baz
1180 target.data.First -u-|> Augmentable : T = target.data.First
1181 target.data.Second -u-|> Augmentable : T = target.data.Second
1183 foo.data.FooFirst -u-|> Augmentation : T = target.data.First
1184 foo.data.FooSecond -u-|> Augmentation : T = target.data.Second
1187 target.data.First o-- foo.data.FooFirst
1188 target.data.Second o-- foo.data.FooSecond
1190 foo.data.FooFirst o-- foo.data.first.Bar
1191 foo.data.FooSecond o-- foo.data.second.Baz
1209 grouping key.grp.nodes.node.<nodeidentifier>
1211 instantiated key.data.nodes.node.<nodeidentifier>