Binding2: Added WIP text of Specification. 13/38013/2
authorTony Tkacik <ttkacik@cisco.com>
Fri, 22 Apr 2016 12:02:54 +0000 (14:02 +0200)
committerRobert Varga <nite@hq.sk>
Tue, 26 Apr 2016 14:55:41 +0000 (14:55 +0000)
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 <ttkacik@cisco.com>
binding2/mdsal-binding2-spec/src/site/asciidoc/binding-2.adoc [new file with mode: 0644]

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 (file)
index 0000000..257801c
--- /dev/null
@@ -0,0 +1,950 @@
+= Java Binding Specification 2
+Tony Tkacik <ttkacik@cisco.com>; Robert Varga <rovarga@cisco.com>; Martin Sunal <msunal@cisco.com>; Martin Ciglan <mciglan@cisco.com>
+: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
+
+<<Instantiated>>::
+  Represent node, which is instantiated
+<<TreeNode>>::
+  Represents node, which is part of instantiated data tree, this interface
+  is not used directly, but rather via <<TreeChildNode>>. See <<instantiated-data-tree-rules>>
+  for more information.
+<<TreeRoot>>::
+  Represents virtual root of instantiated data tree node.
+<<TreeChildNode>>::
+  Represents node, which is part of instantiated data tree and is not root of
+  data tree.
+<<Augmentable>>::
+  Represents instantiated node, which is subjectible to be extended / augmented
+  by `augment` statement from external module.
+<<Augmentation>>::
+  Represents extension to instantiated node, which is introduced from different
+  model than instantiated node.
+<<InstanceIdentifier>>::
+  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
+<<module-namespace>>::
+  YANG namespace containing representation for all modules.
+<<identity-namespace>>::
+  YANG namespace containing representation for all `identity` statements. Identities
+  needs to be separated to prevent naming conflict between Grouping, Data, Type
+  namespaces.
+<<type-namespace>>::
+  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.
+<<grouping-namespace>>::
+  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.
+<<key-namespace>>::
+  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.
+<<data-namespace>>::
+  YANG namespace containing representation of instantiated data tree.
+  Data needs to be separated to prevent naming conflict between Identity, Type,
+  Grouping namespaces.
+<<dto-namespace>>::
+  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
+
+| <<identity-namespace, Identity>> | `ident`
+| flat package containing representation for all `identity`
+
+.3+| <<type-namespace, Type>> | `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-namespace, Key>> | `key`
+| path-based package hierarchy containing representation
+  of key statements for grouping code generation defined inside groupings
+
+| <<grouping-namespace, Grouping>> | `grp`
+| path-based package hierarchy containing representation
+  for `grouping` statements and data node statements nested in these groupings
+
+| <<data-namespace, Data>> | `data`
+| path-based package hierarchy containing representation of instantiated
+  data nodes
+
+| <<dto-namespace, Builder>> | `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 <<class-naming>> with suffix `Grouping`
+* Representations of `grouping` statements are generated into <<grouping-namespace>>
+* data schema nodes under grouping are represented by `interface` and are generated
+  into <<grouping-namespace>>
+** getters (accessors) from parent nodes are generated according to <<accessor-rules>>
+** class name is generated according to <<class-naming>> with suffix `Data`
+** data schema nodes does not follow <<instantiated-data-tree-rules>>, 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 <<data-node-rules>> 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<ListItem>` or `Map<ListKey, ListItem>`, wildcarded
+    `? extends ListItem` generic argument are used to allow for overriding during
+    <<uses-statement,instantation of grouping>>.
+
+
+==== `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 <<instantiated-data-tree-rules>>
+
+====
+
+.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 <<instantiated-data-tree-rules>>
+
+====
+
+[[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 <<instantiated-data-tree-rules>>
+
+
+====
+
+
+.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
+
+* <<uses-augment, augment is substatement of uses>> - data nodes are represented
+  as-if their statements were inlined in target node.
+  See <<uses-augment, uses Statement: augment Substatement>> section for details.
+* <<augment-same-module,target node in same module as augment>> - data nodes are
+  represented as-if their statements were inlined in target.
+  See <<augment-same-module>> for details & examples.
+* <<augment-other-module, target node in other module as augment>> - interface representing
+  augmentation is generated, child data nodes are generated by rules for
+  <<instantiated-data-node-rules>>.
+  See <<augment-other-module>> 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<T>
+interface Augmentation<T>
+
+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<T>
+interface Augmentation<T>
+
+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<T>
+interface Augmentation<T>
+
+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
+
+....
+====