|
| 1 | +== API design principles and patterns contributed by southbound plugins |
| 2 | + |
| 3 | +This section is intended to define common design patterns supporting extensions contributed by southbound plugins, which could be used in the SAL or or used in modelling any abstract extensible APIs. |
| 4 | + |
| 5 | +NOTE: Wire protocol specific information (serialization, serialization constants , TLV identifiers, bit masks, field ordering) should not be part of the SAL. Also, APIs (interfaces, classes) should support extensibility using subclassing or other extension patterns. This allows for abstract APIs and also for concrete APIs to coexist in the SAL and to use common infrastructure. |
| 6 | + |
| 7 | +=== Extensible enumeration pattern |
| 8 | + |
| 9 | +This pattern is suitable for modelling or defining APIs for the enumeration of immutable data or types, which for example could represent ether type, protocol type, and others. The workflow for API definition is simple: |
| 10 | + |
| 11 | +. Define a simple interface with the needed functionality. |
| 12 | + |
| 13 | +. Declare an enum implementing the interface where the enum constants represent the known values. |
| 14 | + |
| 15 | +. (optional) Include a factory method mapping from names to objects implementing the interface. |
| 16 | + |
| 17 | +For more information, see the following links: |
| 18 | + |
| 19 | +** http://jtechies.blogspot.com/2012/07/item-34-emulate-extensible-enums-with.html |
| 20 | + |
| 21 | +** http://blogs.oracle.com/darcy/entry/enums_and_mixins |
| 22 | + |
| 23 | +=== Type-value pairs pattern |
| 24 | + |
| 25 | +This pattern is suitable for modelling or defining APIs for extensible set of fields, where the values could be of different types. The requirements for type-value pairs are: Extensible and Type safety. |
| 26 | + |
| 27 | +==== Common antipatterns |
| 28 | + |
| 29 | +This pattern is to replace the following constructs: |
| 30 | + |
| 31 | + |
| 32 | +* Simple untyped approach to properties (pros: extensible, cons: does not provide semantics and type safety): |
| 33 | + |
| 34 | +[literal] |
| 35 | +// Ommited for clarity... |
| 36 | +HashMap<String,Object> properties; |
| 37 | + |
| 38 | + |
| 39 | +* More refined approach using the enumeration to define a set of supported field types (pros: provides semantics, cons: not extensible). |
| 40 | + |
| 41 | +[literal] |
| 42 | +enum Type { |
| 43 | + TYPE1(String.class), |
| 44 | + TYPE2(Boolean.class), |
| 45 | + private Class<?> valueType; // This line is optional. |
| 46 | + // ommited for clarity... |
| 47 | +} |
| 48 | +class Field { |
| 49 | + Type type; |
| 50 | + Object value; |
| 51 | + // ommited for clarity... |
| 52 | +} |
| 53 | + |
| 54 | + |
| 55 | +=== Actual pattern |
| 56 | + |
| 57 | +We can model this by using the abstract class and the generics to define value type and set of subclasses representing various types of fields. The instances of this class represents actual type-value pair, where class represents type and value is represented by object in the instance. |
| 58 | + |
| 59 | +[literal] |
| 60 | +abstract class Field<V> { |
| 61 | + private V value; |
| 62 | + public Field(V value) { |
| 63 | + this.value = value; |
| 64 | + } |
| 65 | + ... |
| 66 | +} |
| 67 | + class Type1Field extends Field<String> { |
| 68 | + public Type1Field(String value){super(value);} |
| 69 | +} |
| 70 | + class Type2Field extends Field<Boolean> { |
| 71 | + public Type2Field(Boolean value){super(value);} |
| 72 | +} |
| 73 | + |
| 74 | +The abstract class does not have to only define fields or values, but could also define additional methods (concrete or abstract) which could provide additional semantic about the field type. This example shows only one value field, but it is possible to have multiple fields. It is possible to model common part of API also as an interface and leave all the implementation to the super types. Map, which should store one instance of the field is: Map<Class<? extends Field<?>>,Field<?>>. It is possible to provide simpler facade on top of this map. |
| 75 | + |
| 76 | +=== Extension interface pattern |
| 77 | + |
| 78 | +The following Java design allows an object to be extended without changing its interface to clients. The object can implement additional extension interfaces. Clients can ask the object for extension interfaces that it implements. |
| 79 | + |
| 80 | + |
| 81 | +In the interface present in the SAL models general approach or abstraction, the client code (applications) could ask for extension interface (which could be used to model protocol specific functionality, interfaces, data) by querying for the extension. Extension is identified by Java interface (the client code using extension must be compiled against this interface). |
| 82 | + |
| 83 | + |
| 84 | +This pattern could be also used as an replacement for the field pattern. We have defined a set of fields provided by extension as separate class or interface, the values could be queried by using the extension class. |
| 85 | +The strong point of this pattern is that the client code needs to be aware of the extension and its contract (be compiled against the base interface and also extension) in order to use the extension. The code which was not compiled against extension is not affected by introducing new extensions. |
| 86 | + |
| 87 | +*Synopsis: Original pattern* |
| 88 | + |
| 89 | +[literal] |
| 90 | +public interface A { |
| 91 | + // Ommited for clarity... |
| 92 | + <T> T getExtension(Class<T> extensionType) |
| 93 | +} |
| 94 | + |
| 95 | +*Synopsis: Updated pattern* |
| 96 | +[literal] |
| 97 | +public interface Extensible<P> { |
| 98 | + // Ommited for clarity... |
| 99 | + <T extends Extension<P>> T getExtension(Class<T> extensionType) |
| 100 | +} |
| 101 | +public interface Extension<T> { |
| 102 | +} |
| 103 | + |
| 104 | +Where: |
| 105 | + |
| 106 | +* Extensible is interface which is to be implemented by classes which provides extension support |
| 107 | + |
| 108 | +* P - generic argument, usually interface / class which implements |
| 109 | + |
| 110 | +* Extension is marker interface (for type-safety reasons) which marks interfaces / classes which are extensions |
| 111 | + |
| 112 | +* T - generic argument, pointing to the class / interface to which this extension is associated. |
| 113 | + |
| 114 | +=== Usage example |
| 115 | + |
| 116 | +[literal] |
| 117 | +ublic class Node extends Extensible<Node> { |
| 118 | + // contents ommited |
| 119 | + // the instatiated version of extension interface isExtension method is |
| 120 | + @Override |
| 121 | + <T extends Extension<Node> T getExtension(Class<T> extensionType) { |
| 122 | + // contents ommited |
| 123 | + } |
| 124 | +} |
| 125 | +public class OpenflowNode extends Extension<Node> { |
| 126 | + // contents ommited |
| 127 | +} |
| 128 | +Node node = provider.getNode(); // sample call returning node |
| 129 | +OpenflowNode ofNode = node.getExtension(OpenflowNode.class); |
| 130 | +if(ofNode != null) { |
| 131 | + // do openflow specific stuff |
| 132 | +} |
0 commit comments