From: Tony Tkacik Date: Fri, 22 Apr 2016 12:02:54 +0000 (+0200) Subject: Binding2: Added WIP text of Specification. X-Git-Tag: release/boron~154 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=17217cf89fd498b77b664ca665cc8d7d45161226;p=mdsal.git Binding2: Added WIP text of Specification. Bug 157: Described namespace problem and solution by having separate packages for identities,types, keys groupings and data Bug 4625: Described groupings and instantiation of data Change-Id: I61f84ae7ca7b2ee62e4e49a7ce155e4c20813a97 Signed-off-by: Tony Tkacik --- diff --git a/binding2/mdsal-binding2-spec/src/site/asciidoc/binding-2.adoc b/binding2/mdsal-binding2-spec/src/site/asciidoc/binding-2.adoc new file mode 100644 index 0000000000..257801cb6c --- /dev/null +++ b/binding2/mdsal-binding2-spec/src/site/asciidoc/binding-2.adoc @@ -0,0 +1,950 @@ += Java Binding Specification 2 +Tony Tkacik ; Robert Varga ; Martin Sunal ; Martin Ciglan +:rfc6020: https://tools.ietf.org/html/rfc6020 +:toc: +:toclevels: 4 + +== Introduction + +=== Terminology + +Namespace:: + naming space, in which all identifiers needs to be unique +identifiers. +Data Node:: +Data Tree:: +Instance Identifier:: +Instantiated Data Node:: +Instantiated Data Tree:: +Transfer Object:: +Builder:: + builder + +=== Binding Specification v2 Concepts + +<>:: + Represent node, which is instantiated +<>:: + Represents node, which is part of instantiated data tree, this interface + is not used directly, but rather via <>. See <> + for more information. +<>:: + Represents virtual root of instantiated data tree node. +<>:: + Represents node, which is part of instantiated data tree and is not root of + data tree. +<>:: + Represents instantiated node, which is subjectible to be extended / augmented + by `augment` statement from external module. +<>:: + Represents extension to instantiated node, which is introduced from different + model than instantiated node. +<>:: + Unique identifier of node / subtree in data tree, which provides unambiguous + information, how to reference node / subtree in Instantiated Data Tree. + +== Namespaces + +YANG defines several namespaces and naming space of YANG is wider then applicable +namespace of JAVA language. In order to decrease conflicts between various +YANG-defined namespaces and classes introduced by Binding Specification, it +is needed to: + +* separate namespaces by Java package hierarchy +** each namespace must define rules how to construct package name, which + will not conflict with other namespace +* if multiple classes are generated for YANG statement they need to be in separate + packages to decrease possible conflicts with siblings. +* if Binding Specification introduces new concepts, which does not have explicit + namespace rules in YANG, these concepts needs to be in their own, separate + namespaces, in order to not conflict on valid YANG namespace items. + + +This rules allows to identify two types of namespaces: + +.Namespace types by source of namespace +YANG namespace:: + Naming space explicitly defined in YANG specification, which needs to be + explicitly supported in order to prevent naming conflicts. +Binding namespace:: + Naming space introduced by Binding Specification for additional properties + and functionality of Binding Specification. This namespaces needs to be separate + from YANG namespaces in order to not have naming conflict with YANG-derived + names. + + +Binding Specification v2 uses following namespaces: + +.Concrete namespaces used in Binding Specification +<>:: + YANG namespace containing representation for all modules. +<>:: + YANG namespace containing representation for all `identity` statements. Identities + needs to be separated to prevent naming conflict between Grouping, Data, Type + namespaces. +<>:: + YANG namespace containing representation for all `typedef` statements and + annonymous definitions of `union`, `enumeration` and `bits` types. Types needs + to be seperated to prevent naming conflict between Identity, Grouping and Data + namespaces. +<>:: + YANG namespace containing representation for all `grouping` statements and their + child data node statements. Groupings needs to be separated to prevent naming + conflict between Identity, Type, Data namespaces. +<>:: + Binding namespace containing representation for all `key` statements. + Representations of key statements needs to be in separate namespace, since it is not defined + in YANG specification. +<>:: + YANG namespace containing representation of instantiated data tree. + Data needs to be separated to prevent naming conflict between Identity, Type, + Grouping namespaces. +<>:: + Binding namespace containing Transfer Objects and Builders representing + instantiated data tree items. + +NOTE: Most of Binding Namespaces were introduced to decrease possibility of name +conflict between concepts defined in YANG and additional concepts introduced +by Binding Specification. + +=== Package hierarchy + +.Package hierarchy for model +[cols="1,1,4"] +|=== +|Namespace | Package | Description + +| <> | `ident` +| flat package containing representation for all `identity` + +.3+| <> | `type` +| flat package containing representations for all top-level + `typedef` statements + +| `type.grp` +| path-based package hierarchy containing representation + for `typedef` statements nested in grouping statements, or anonymous types + requiring code generation defined inside groupings + +| `type.data` +| path-based package hierarchy containing representation + for `typedef` statements nested in grouping statements, or anonymous types + requiring code generation defined inside instantiated data nodes + +| <> | `key` +| path-based package hierarchy containing representation + of key statements for grouping code generation defined inside groupings + +| <> | `grp` +| path-based package hierarchy containing representation + for `grouping` statements and data node statements nested in these groupings + +| <> | `data` +| path-based package hierarchy containing representation of instantiated + data nodes + +| <> | `dto` +| path-based package hierarchy containing Tranfer Objects and their builders + for instantiated data nodes +|=== + +[[module-namespace]] +=== Module Namespace + + + +[[identity-namespace]] +=== Identity Namespace + + +[[type-namespace]] +=== Type Namespace + +[[grouping-namespace]] +=== Grouping Namespace + +[[key-namespace]] +=== Key Namespace + +[[data-namespace]] +=== Data Namespace + +[[dto-namespace]] +=== Builder Namespace + +== Generic rules + +[[class-naming]] +=== Class Naming + +[[subpackage-structure]] +=== Subpackage Naming + +[[accessor-rules]] +=== Accessor rules + +== Type rules + +=== `typedef` statement + +==== Globally scoped `typedef` + +==== Subtree scoped `typedef` + +Subtree scoped `typedef` statement is type definition, which is not substatement +of `module` or `submodule`, and is only visible to child elements of parent +statement. + +* Representation is generated in Type namespace according to following rules: + + +=== Type mapping + +YANG types does not provide single, simple model of behaviour - some times +exhibits special properties to extensibility or limiting scope of valid values +when type is derived + +//// +.Base types and their behaviours +|=== +| YANG Type | Description | Java Mapping + + +| `binary` | Any binary data | `Binary`? +| `bits` | A set of bits or flags | Custom class +| `boolean` | `true` or `false` | `Boolean` +| `decimal64` | 64-bit signed decimal number | No +| `empty` | A leaf that does not have any value | No +| `enumeration` | Enumerated strings | No +| `identityref` | A reference to an abstract identity | Yes +| `instance-identifier` | References a data tree node | Yes +| `int8` | 8-bit signed integer | No +| `int16` | 16-bit signed integer | No +| `int32` | 32-bit signed integer | No +| `int64` | 64-bit signed integer | No +| `leafref` | A reference to a leaf instance | Maybe +| `string` | Human-readable string | No +| `uint8` | 8-bit unsigned integer | No +| `uint16` | 16-bit unsigned integer | No +| `uint32` | 32-bit unsigned integer | No +| `uint64` | 64-bit unsigned integer | No +| `union` | Choice of member types | Maybe + +|=== +FIXME: Finalize table +//// + +==== `boolean` type +==== `empty` type +==== `int8` type +==== `int16` type +==== `int32` type +==== `int64` type +==== `uint8` type +==== `uint16` type +==== `uint32` type +==== `uint64` type +==== `string` type +==== `binary` type +==== `enumeration` type +==== `bits` type + +==== `identityref` type +==== `instance-identifier` type + +==== `leafref` type +==== `union` type + +[[data-node-rules]] +== Data Node rules + +Data nodes could be separated into two distinct groups, based on presence of +child nodes: + +Leaf node:: + Node, which according to YANG schema does not have child nodes, is leaf node + and carries only simple value. +Interior node:: + Node, which according to YANG schema may have child nodes, node itself does not + carry values, values are stored in descendant leaf nodes. + +=== `leaf` Statement + +=== `leaf-list` Statement + + +=== `container` Statement + +=== `list` Statement + +==== Keyed List + +==== List without Key + +=== `choice` Statement + +=== `case` Statement + +[source,yang] +---- +container top { + choice base { + case foo { + container foo; + } + case bar { + leaf bar { type string; } + } + } +} +---- + +[plantuml] +.... +set namespaceSeparator none + +package spec { + interface Choice + interface Case +} + +interface data.Top { + + getBase() : data.top.Base; +} +interface data.top.Base +interface data.top.base.Foo { + + getFoo() : data.top.base.foo.Foo +} +interface data.top.base.foo.Foo +interface data.top.base.Bar { + + getBar() : String +} + +data.top.Base -u-|> Choice +data.top.base.Foo -u-|> Case +data.top.base.Bar -u-|> Case + +data.top.base.Foo -u-|> data.top.Base +data.top.base.Bar -u-|> data.top.base.Foo + +data.Top o- data.top.Base +data.top.base.Foo o- data.top.base.foo.Foo +.... + +== Specific rules + +[[instantiated-data-node-rules]] +=== Instantiated Data Node Rules + +//// +FIXME: Do we need section per type, or should just general rules be described. +//// + +==== `container` Statement + +//// +FIXME: Here should be Augmentable & Instantiated +//// + +==== `leaf` Statement + +==== `leaf-list` Statement + +==== `choice` Statement + +==== `case` Statement + +//// +FIXME: Here should be Augmentable & Instantiated +//// + +==== `list` Statement + +//// +FIXME: Here should be Augmentable & Instantiated, List signature uses concrete +interfaces +//// + +==== `input` Statement + +//// +FIXME: Here should be Augmentable & Instantiated +//// + +==== `output` Statement + +//// +FIXME: Here should be Augmentable & Instantiated +//// + +==== `notification` Statement + +//// +FIXME: Here should be Augmentable & Instantiated +//// + +[[instantiated-data-tree-rules]] +=== Instantiated Data Tree Rules + + +==== `container` Statement + +//// +FIXME: Here should be Augmentable & Instantied & ChildDataNode +//// + + +==== `leaf` Statement + +==== `leaf-list` Statement + +==== `case` Statement + +//// +FIXME: Here should be Augmentable & Instantied & ChildDataNode +//// + +==== `list` Statement + +//// +FIXME: Here should be Augmentable & Instantied & ChildDataNode +//// + +=== `grouping` Statement + +* `grouping` statement is represented by `interface` +** class name is generated according to <> with suffix `Grouping` +* Representations of `grouping` statements are generated into <> +* data schema nodes under grouping are represented by `interface` and are generated + into <> +** getters (accessors) from parent nodes are generated according to <> +** class name is generated according to <> with suffix `Data` +** data schema nodes does not follow <>, these interfaces + are used only in instantiated data tree. + +.Simple Grouping +==== +.YANG Snippet +[source, yang] +---- +grouping simple { <1> + container foo; <2> + leaf bar { type string;} <3> +} +---- +<1> Is represented by interface `grp.SimpleGrouping` +<2> Is represented by interface `grp.simple.FooData` and getter in `grp.SimpleGrouping` + with signature `public grp.simple.FooData getFoo();` +<3> Is represented by getter in `grp.SimpleGrouping` with signature `public String getBar()` + +[plantuml] +.... +interface grp.SimpleGrouping { + + getBar() : String + + getFoo() : grp.simple.FooData +} +interface grp.simple.FooData +grp.SimpleGrouping o- grp.simple.FooData +.... +==== + +==== Data Node substatements + +Representations of data node substatements are generated according to rules +described in <> with following changes: + +* Interface names for `case`, `choice`, `container` and `list`, is suffixed by + `Data` suffix, in order to not conflict with same named groupings inside same + package +** Getters in parent node, are still generated without `Data` suffix, so + the getter signature is in form `FooData getFoo()` +** If return value of getter is constructed using generics (eg. `list`) + instead of signature `List` or `Map`, wildcarded + `? extends ListItem` generic argument are used to allow for overriding during + <>. + + +==== `list` substatement + +//// +FIXME: Add reasoning / examples for need to use ? extends, instead of directly +using generics. +//// + +==== `leaf-list` susbstatement + +//// +FIXME: Add reasoning / examples for need to use ? extends, instead of directly +using generics for types, which may need instantiation +//// + +[[uses-statement]] +=== `uses` Statement + +* `uses` statement triggers interface of parent statement to extend (implement) + interface of `grouping` referenced by `uses` argument. +* As in YANG `uses` statement triggers instatiation of data children of `grouping` + which will result in generation of these children as-if they were direct + children of parent statement +** data node children are generated according to rules defined for parent statement. + Different rules apply based on parent type (instantiated data tree, `input`, + `output` or `grouping`) +** interfaces generated for data children extends (implements) interfaces for + same children generated for referenced `grouping` + +.Simple Grouping and Uses +==== +.YANG Snippet +[source, yang] +---- +grouping simple { + container foo; + leaf bar { type string;} +} + +container top { + uses simple; +} +---- + +[plantuml] +.... +set namespaceSeparator none + +interface grp.SimpleGrouping { + + getBar() : String + + getFoo() : grp.simple.FooData +} +interface grp.simple.FooData +interface data.Top { + + getFoo() : data.top.Foo +} +interface data.top.Foo + +grp.SimpleGrouping o-- grp.simple.FooData + +data.Top o-- data.top.Foo +data.Top -|> grp.SimpleGrouping +data.top.Foo -|> grp.simple.FooData +.... + +NOTE: Diagram does not show all details for `data.Top` and `data.top.Foo`, which +are based on <> + +==== + +.Grouping with Nested Grouping +==== + +.YANG Snippet +[source, yang] +---- +set namespaceSeparator none +grouping with-inner { + + grouping inner { + container cont; + } + uses inner; +} + +container top { + uses with-inner; +} +---- + +[plantuml] +.... +set namespaceSeparator none + +interface grp.withinner.inner.ContData +interface grp.withinner.InnerGrouping { + + getCont() : grp.withinner.inner.ContData +} + + +interface grp.withinner.ContData + +interface grp.WithInnerGrouping { + + getCont() : grp.withinner.ContData +} + + +interface data.Top { + + getCont() : data.top.Cont +} + +interface data.top.Cont { + +} +data.Top o-- data.top.Cont : contains + +data.Top -|> grp.WithInnerGrouping +data.top.Cont -|> grp.withinner.ContData + +grp.WithInnerGrouping -|> grp.withinner.InnerGrouping : uses (implements) +grp.WithInnerGrouping o-- grp.withinner.ContData : contains +grp.withinner.InnerGrouping o-- grp.withinner.inner.ContData : contains + +grp.withinner.ContData -|> grp.withinner.inner.ContData : is concretization of (implements) + +.... + +NOTE: Diagram does not show all details for `data.Top` and `data.top.Cont`, which +are based on <> + +==== + +[[uses-augment]] +==== `augment` substatement + +.Uses & Augment in instantiated Data Tree +==== +[source,yang] +---- +grouping example { + container nested { + leaf foo { + type string; + } + } +} + +container top { + uses example { + augment nested { + container bar { + } + } + } +} + +---- + +[plantuml] +.... +set namespaceSeparator none + +interface data.Top +interface data.top.Nested +interface data.top.nested.Bar + +data.Top o-- data.top.Nested +data.top.Nested o-- data.top.nested.Bar + +interface grp.ExampleGrouping +interface grp.example.NestedData + + +grp.ExampleGrouping o-- grp.example.NestedData + +data.Top -|> grp.ExampleGrouping +data.top.Nested -|> grp.example.NestedData +.... + +NOTE: Diagram does not show all details for `data.Top`, `data.top.Nested` and +`data.top.nested.Bar`, which are based on <> + + +==== + + +.Uses & Augment in grouping +==== +[source,yang] +---- +grouping example { + container nested { + leaf foo { + type string; + } + } +} + +grouping top { + uses example { + augment nested { + container bar { + } + } + } +} + +---- + +[plantuml] +.... +set namespaceSeparator none + +interface grp.TopGrouping +interface grp.top.NestedData +interface grp.top.nested.BarData + +grp.TopGrouping o-- grp.top.NestedData +grp.top.NestedData o-- grp.top.nested.BarData + +interface grp.ExampleGrouping +interface grp.example.NestedData + +grp.ExampleGrouping o-- grp.example.NestedData + +grp.TopGrouping -|> grp.ExampleGrouping +grp.top.NestedData -|> grp.example.NestedData +.... + +==== + +=== `augment` statement + +Representation of `augment` statement depends on module in which target node of +augment statement is defined + +* <> - data nodes are represented + as-if their statements were inlined in target node. + See <> section for details. +* <> - data nodes are + represented as-if their statements were inlined in target. + See <> for details & examples. +* <> - interface representing + augmentation is generated, child data nodes are generated by rules for + <>. + See <> for details & examples. + +`augment` statement targets only instantiated data nodes, so child data node +representation are always ge + +[[augment-same-module]] +==== Augmentation target in same module + +All data node children are generated as-if they were directly defined inside +target node. There are no externally observable artefacts in generated +representation of these nodes, which would point out that they were defined +using `augment` statement instead of directly inlining them in target node. + +.Why augment of same module is same as inlining +[IMPORTANT] +==== +This rule may seems counterintuitive at first sight, but YANG defines +backwards compatibility in terms of effective model instead of way how model +is represented. `augment` statement, when targeting node in same module is not +externally observable and could factored out by inlining these statements. + +Definition of `augment` statement in YANG also defines different behaviour when +target is same module and allows all features as-if this statements were +directly inlined. +==== + +.Augment with target in same module +==== +.YANG module written using augmentations +[source,yang] +---- +container top { + +} + +augment "/top" { + container foo { + + } +} +---- +.Same module written without need to augment +---- +container top { + container foo { + + } +} + +.Java representation for both variants +---- +[plantuml] +.... +set namespaceSeparator none + +interface data.Top +interface data.top.Foo + +data.Top o- data.top.Foo +.... + +==== + +[[augment-other-module]] +==== Augmentation target in other module + +.Augment with target in other module +==== +[source,yang] +---- +module top { + ... + + container top { + + } +} + +module foo { + ... + import top { prefix top; } + ... + augment "/top:top" { + container bar { + + } + } +} + +---- + +[plantuml] +.... +set namespaceSeparator none + +interface Augmentable +interface Augmentation + +interface top.data.Top +interface foo.data.FooTop { + + getBar() : Bar +} + +interface foo.data.top.Bar + +top.data.Top -u-|> Augmentable : T = top.data.Top +foo.data.FooTop -u-|> Augmentation : T = top.data.Top +top.data.Top o-- foo.data.FooTop +foo.data.FooTop o-- foo.data.top.Bar +.... + +==== + +.Multiple augments with same target +==== +[source,yang] +---- +module top { + ... + + container top { + + } +} + +module foo { + ... + import top { prefix top; } + ... + augment "/top:top" { + container bar { + + } + } + + augment "/top:top" { + container baz { + + } + } +} + +---- + +[plantuml] +.... +set namespaceSeparator none + +interface Augmentable +interface Augmentation + +interface top.data.Top +interface foo.data.FooTop { + + getBar() : Bar + + getBaz() : Baz +} + +interface foo.data.top.Bar +interface foo.data.top.Baz + +top.data.Top -u-|> Augmentable : T = top.data.Top +foo.data.FooTop -u-|> Augmentation : T = top.data.Top +top.data.Top o-- foo.data.FooTop +foo.data.FooTop o-- foo.data.top.Bar +foo.data.FooTop o-- foo.data.top.Baz + +.... + +==== + +.Multiple augments with different targets +==== +[source,yang] +---- +module target { + ... + + container first { + + } + + container second { + + } +} + +module foo { + ... + import target { prefix t; } + ... + augment "/t:first" { + container bar { + + } + } + + augment "/t:second" { + container baz { + + } + } +} + +---- + +[plantuml] +.... +set namespaceSeparator none + +interface Augmentable +interface Augmentation + +interface target.data.First +interface target.data.Second + +interface foo.data.FooFirst { + + getBar() : Bar +} +interface foo.data.FooSecond { + + getBaz() : Baz +} + +interface foo.data.first.Bar +interface foo.data.second.Baz + +target.data.First -u-|> Augmentable : T = target.data.First +target.data.Second -u-|> Augmentable : T = target.data.Second + +foo.data.FooFirst -u-|> Augmentation : T = target.data.First +foo.data.FooSecond -u-|> Augmentation : T = target.data.Second + + +target.data.First o-- foo.data.FooFirst +target.data.Second o-- foo.data.FooSecond + +foo.data.FooFirst o-- foo.data.first.Bar +foo.data.FooSecond o-- foo.data.second.Baz + +.... +====