Skip to content

Instantly share code, notes, and snippets.

@tonydamage
Created November 5, 2014 14:31
Show Gist options
  • Save tonydamage/82b15f0cd1f39b729d4e to your computer and use it in GitHub Desktop.
Save tonydamage/82b15f0cd1f39b729d4e to your computer and use it in GitHub Desktop.
Binding Specification v2 Presentation

Binding Specification v2

[TOC]

What is Java Binding Specification

  • Binding specification defines mapping of YANG modeled data to respective Java Objects, structures and DTOs
    • has compile time and runtime aspects, compile time aspects are mostly visible to users of MD-SAL
  • Currently used specification is Binding Specification v1
    • was developed and introduced in Opendaylight Hydrogen release
    • small backwards compatible enhancements in Opendaylight Helium, mostly done for increasing performance of runtime

Requirements for Binding Specification

  • SHOULD model YANG semantics correctly and provide / enforce compile-time safety
    • This prevents bugs at compile time, more allows for assumptions at runtime and performance optimizations
  • Code generation should be isolated. Presence of additional model should not change generation of original model.
  • SHOULD allow for reusing instances of objects at various subtrees

Java Binding Specification v1

  • All YANG structural statements are represented in Java as interfaces describing DTOs
  • Derived value types (typedef) are represented by:
    • Immutable Value object for most simple YANG types
    • Java enum for type enumeration
  • Two major implementations of these DTO interfaces exists:
    • Immutable DTO which is created by user using compile-time generated DTO Builders
    • LazyDataObject Proxy - Immutable Proxy implementation which lazily translates from NormalizedNode representation of data. Only data explicitly accessed by user are translated.

Inheritance vs Composition in Binding Specification v1

augment and choice models mixin concept, where third-party models could introduce additional properties to existing structures. But their semantics are really different:

  • choice - node could have only one case is allowed (0-1)
  • augment - node could have multiple different augmentations present (0-n)

Choice and Case mapping

For modeling choice to case relationship we choosed inheritance because signature of setter / getter clearly says there could be zero or one instance.

 interface ExampleChoice {}
 interface ExampleCase1 extends ExampleChoice { ... }
 interface ExampleCase2 extends ExampleChoice { ... }

 ExampleChoice getExampleChoice();
 ...
 void setExampleChoice(ExampleChoice choice);

As you could see signature clearly says there could be only one instance of ExampleChoice set for parent object. This captures YANG semantics clearly.

Augmentations

When designing mapping of augmentations you need to start thinking of conflicts and compilation isolation.

The requirements for augmenation mapping to properly capture YANG semantics should be always done at least for three modules (to simulate third-party extensions which are developed separatelly).

Also note that YANG allows for augmentations from different models use same identifiers for leaves and containers.

Example Model

Based on this properties we could have following three models:

// Standards model
module switch {
   namespace "urn:example";
   container switch {
   }
}
// Openflow protocol model
module openflow-example {
   namespace "urn:example:openflow";
   import "switch" {prefix s;}
   augment "/s:switch" {
       ext:augment-identifier openflow-switch;
       leaf id { type int64;}
   }
}
// Foo protocol model
module foo-example {
   namespace "urn:example:foo";
   import "switch" {prefix s;}
   augment "/s:switch" {
       ext:augment-identifier foo-switch;
       leaf id { type int32;}
   }
}

Basic Signature

So we should have three interfaces describing DTO from each model. We still did not decide composition over inheritance (augmentations implements target interface).

interface Switch extends DataObject {}
interface OpenflowSwitch extends DataObject {
    Long getId();
}
interface FooSwitch extends DataObject {
    Integer getId();
}
Augmentations modeled via Inheritance
  • Lets assume, there is device which support both data models, so it should have two augmentations present.
  • Object representing Switch should implement interfaces Switch, OpenflowSwitch and FooSwitch
    • Problem is there is conflicting signature for getId method, which prevents any Object implements OpenflowSwitch and FooSwitch interfaces at same time.
  • In this simple case (if we do not assume conflict) this would result in four different implementations of interface needed, since we need to account for all possible combinations.
Augmentations modeled via Composition
  • Lets assume, there is device which support both data models, so it should have two augmentations present.

  • For composition we opted to use ExtensibleObject pattern, which usually have signature

        <T> T getExtension(Class<T> ext);
    
  • Switch interface defines method <T> T getAugmentation(Class<T> ext);, which returns augmentation if present.

    • This allows for only having implementation of Switch interface, which could be used for all possible combinations of augmentations, even if they are using same leaf names.

      class SwitchImpl implements Switch { Map<Class<?>> augmentations;

         <T> T getAugmentation(Class<T> aug) {
         	return (T) augmentations.get(aug);
         }
      }
      
Conclusion

This simple analysis lead us to rule out inheritance between augmentation and augmented objects, since augmentations could be declared issolated and could introduce conflicting return type signatures which is disallowed in Java.

Known problems of Binding Specification v1

These problems could not be addressed without change of API generation and requires new revision of Java Binding Specification.

Java / YANG Namespace collision bugs

This bugs shared common root in Binding Specification v1 and that was caused by not accounting for identifeir namespace differences between Java and YANG.

  • Java has identifier namespace which. Unique identifier in this namespace is Package Name with Class name
  • YANG has 5 namespaces
    • Module and submodule namespace (each module and submodule name must be unique)
    • Extension namespace (extension name must be unique in module context)
    • Type namespace (two types must not share same name in module scope)
    • Grouping namepspace
    • Data tree, rpc and notification namespace

This effectively means that following YANG model is valid:

module example {
    namespace "urn:example";

    extension example {}
	typedef example {type string;}
    grouping example {}
    container example {
       container example {
          leaf example {type example;};
       }
    }
}

Proposed solution

  • Use different packages names for types, groupings and data tree items.

  • If module package name is urn.example:

    • urn.example
    • urn.example.type
    • urn.example.grouping
    • urn.example.data
    • urn.example.rpc
    • urn.example.notify
  • Extension namespace collision is currently non-issue since extensions are used in schema and not in data

Missing mapping of YANG Concepts

Current Binding Specification v1 does not provide following mappings:

  • anyxml statement
  • Instance Identifier which reference leaf node, leaf-list node or list node, which does not have key defined.

anyxml statement

Anyxml definition in RFC6020:

The "anyxml" statement is used to represent an unknown chunk of XML. No restrictions are placed on the XML. This can be useful, for example, in RPC replies.

This effectivelly means that anyxml node could host valid XML document or just string.

Interpretation of anyxml nodes is actually left out to the text of specification and we identified several patterns:

Natural candidates for anyxml representations are:

  • org.w3c.dom.Element
  • javax.xml.transform.Source
  • Own version of Source, which will also provide YANG specific constructs: eg. NormalizedNodeSource, BindingSource)

Leaf, leaf-list Instance Identifiers

Instance Identifier currently are constructed using classes as path arguments

  • is fine and allows for Instance Identifier to capture target type, but works only for container and list

Instance Identifier needs to be extended to allow targeting:

  • leaves
  • choice and case statements
Proposed solution

Introduce LeafPathArgument. LeafPathArguments for leafes will be stored in interface describing parent container as constants. This will allow for use such as:

InstanceIdentifier<Boolean> activePath = InstanceIdentifier.create(Foo.class).leaf(Foo.ACTIVE);
ListenableFuture<Optional<Boolean>> active = tx.read(CONFIGURATION,activePath);

This will require changing signature of MD-SAL to allow Object in its interfaces if we want to read boolean directly. Other approach is to have special DTO which implements DataObject and encapsulates LeafValue, this will allow MD-SAL to still limit input to DataObject.

InstanceIdentifier<LeafValue<Boolean>> activePath = InstanceIdentifier.create(Foo.class).leaf(Foo.ACTIVE);
ListenableFuture<Optional<LeafValue<Boolean>>> active = tx.read(CONFIGURATION,activePath);

Note: Use of Optional is property of MD-SAL and not of Binding Specification

Proposed Enhancements for Bidning Specification v2



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment