INTRODUCTION TO OBJECT DEFINITION LANGUAGE (ODL).
odl file contains the class definitions and the relationships between classes in the system.
using odl primitives system designer can define the classes and the relationships between
classes in the system. Odl is similar to C++ in look and feel. Odl provides facilities to
inline C/C++ code along with the class and relationship definitions. This section will
explain the primitives of the odl file and how to use them
extern block allows us to write code and definitions in C/C++ language. The code and definitions
defined in the "extern" block go in to generated files as is with out any modification.
main (int ac, char **av)
printf("I will go unmodified");
let us define a class "xyz" which contains some primitive data types and user data types as well
class xyz can use primitive data types or complex user data types as its data members. user should
include proper header files in the extern block for the definitions of the complex data types used
in the class definition. class definition cannot use pointers or references since they dont have
any meaning in data store.
NOTE: A class definition is expanded at run time to accomodate more fields which are generated. A
C++ equivalent with the same name is generated out of an odl class and can be referred with its
name in the application code.
unsigned int x;
struct complex c; ---> struct complex is defined in the header complex.h included in the extern block.
Comments are similar to c/c++ comments. ex:
//I am a C++ comment
/* I am a C comment and i can be multiline */
A relation is used to define the relationship between 2 classes. A relation primitive is similar to
C++ template instantiation. lets look at an example
relation primitive is of the form
relation < An odl class already defined,
Another or same odl class already defined,
Container to hold the elements of the class of 2nd argument type,
key to index in to the container which should be one of the fields of
the class of 2nd argument
> Name of the relation;
ClassA ------relates to ---> ClassB , here ClassA is called lhs of the relation and ClassB as rhs.
relation < ClassA, ClassB, list, ClassB.key> RelationClassAClassB;
ClassA - is an odl class.
ClassB - is an odl class.
list - All the relatives should be ordered in a list fashion.
ClassB.key - key to index in to the set of relatives.
Constraint methods are called to evaluate when 2 objects are composed in to a relationship. These methods
are executed in the context of data store and should be carefully coded so that they take less number of
cycles and are fast. Methods are defined using the keyword "constraint". Each constraint method should
return bool as their return type and should take references to arguments of an lhs object and an rhs object.
The syntax of the constraint method is like below,
RelationClassAClassB::check_a_compatible_with_b (const ClassADsRef a, const ClassBDsRef b)
/* write regular c/C++ code here using the input arguments */
ClassADsRef , ClassBDsRef ------> are type definitions emitted by the odl compiler.
The logic of the constraint method can be written using normal c/c++ code.
A more real life example from an atm configuration is below
The below definition will create a structure some thing like below
[ port ]
[ vpi ] <---------> [ vpi ] <-----------> [ vpi
/ \ / \
vci vci x x
#define DEVICE_ATM 0x1
printf ("I will stay unmodified");
#include "dsTypes.h" //defines types which are used in the class definitions
* There can be at the max 32 vpis in our example system so we define the container
* type as list in the 3rd argument.
relation <port, vpi, list, vpi::vpi_id> ResidenceRelationPortVpi;
* vpis can be configured only on atm devices if any other devices return false.
* portDsRef and vpiDsRef are pointers to the objects in the data store and can be used
* as like regular c,c++ pointers.
ResidenceRelationPortVpi::check_port_vpi_compat (const portDsRef port, const vpiDsRef vpi)
return port->dev_type == DEVICE_ATM;
* There can be at the max of 32767 vcis on each of vpi in our example system so we
* define the container type as rbtree with the key vci_id.
relation <vpi, vci, rbtree, vci::vci_id> ResidenceRelationVpiVci;
* Define constraint such that the id of the vci being configured is not greater than
* the max_vci limit configured on the vpi.
ResidenceRelationVpiVci::check_vpi_vci_compat (const vpiDsRef vpi, const vciDsRef vci)
return vci->vci_id < vpi->vci_max;