The APIs used by RAD are defined by using an XML-based IDL. The normative schema for this language can be found in /usr/share/lib/xml/rng/radadr.rng.1. The namespace name is http://xmlns.oracle.com/radadr.
The top-level element in an ADR definition document is an api. The api element has one mandatory attribute, name, which is used to name the output files. The element contains one or more derived type or interface definitions. Because there is no requirement that an interface must use derived types, it is not necessary to specify any derived types in an API document. To enable consumers to use the data typing defined by ADR for non-interface purposes, there is no requirement that an interface must be defined. However, note that either a derived type or an interface must be defined.
Three derived types are available for definition and use by interfaces: a structured type that can be defined with a struct element, an enumeration type that can be defined with an enum element, and a dictionary type that can be defined with a dictionary element. Interfaces are defined using interface elements. The derived types defined in an API document are available for use by all interfaces defined in that document.
The following is an example of an API.
Example 46 Skeleton API document<api xmlns="http://xmlns.oracle.com/radadr" name="com.oracle.solaris.rad.example" register="true"> <version/> <struct>...</struct> <struct>...</struct> <enum>...</enum> <dictionary>...</dictionary> <interface>...</interface> <interface>...</interface> </api>
The xmlns is required to indicate the type of the XML document. The name attribute is identifying the name of the API, the namespace within which all subsidiary interfaces are to be found. There are additional attributes to assist in the generation of server module code.
The register attribute is a boolean, which is optional and true by default. If true, then radadrgen automatically generates a _rad_reg() function when generating server implementation code. If false, the function is not generated and the module author will need to provide a _rad_reg() function. This option is primarily provided for the creation of special types of modules, such as protocol or transport modules, in general it does not need to be specified, since the default generated function is enough for most purposes.
The documentation elements allow you to document the RAD module APIs and are defined by the schema specification in /usr/share/lib/xml/rng/radadr-doc.rng.1.
The two main documentation elements are:
Container for inline elements.
Container for block elements.
The <summary /> element is a mandatory element, which represents a short text synopsis of the parent element. The <summary /> element can only text data annotated with the inline elements <code />, <emphasis />, <strong />, and <link />. The output of a <summary /> element is running text with possible typographic modifications and the available inline elements are as follows:
Indicates small fragments of code.
Emphasizes a phrase or word in italics.
Emphasizes a phrase or word in bold.
Displays hypertext based on the following values for the hyperlink:
An external URL.
An interface, method, property, or an event defined within the ADR document.
An enum data type or an enum value defined within the ADR document.
A struct data type or a struct field defined within the ADR document.
Use the <doc /> element to define larger blocks of content. The <doc /> element might contain inline elements, block elements or text data. The <doc /> element is displayed as separate blocks of data and the available block elements are:
Defines a section heading.
Defines a paragraph.
Defines a list of items. Items in the list are defined by an <item /> element. The <list /> element takes an optional attribute that defines the type of list to display using the ordered attribute for a numbered list or unordered attribute for a bullet list. The default list type is an unordered list.
Defines an item in a list. It might contain block or inline elements.
Displays a program listing. Available attributes are:
A mandatory attribute which defines the programming language. It can have any one of c, python, java, rest, or curl. The value must be in lowercase.
An optional attribute, which provides a label for the example.
An optional attribute. Displays line numbers. Default is to omit line numbers.
Defines a block of text in which line breaks and whitespace are to be preserved and displayed as is.
For more information about how to use the documentation definitions, see ADR API Example.
A version element is required for all APIs.
The initial version of an API must always be defined as follows:
<version major="1" minor="0"/>
This indicates that the module is starting at version 1.0.
The enum element has a single mandatory attribute, name. The name is used when referring to the enumeration from other derived type or interface definitions. An enum contains one or more value elements, one for each user-defined enumerated value. A value element has a mandatory name attribute that gives the enumerated value a symbolic name. The symbolic name is not used elsewhere in the API definition, only in the server and various client environments. The symbolic name that is exposed in these environments are environment-dependent. An environment offering an explicit interface to RAD must provide an interface that accepts the exact string values defined by the value elements' name attributes.
Some language environments support associating scalar values with enumerated type values, for example C. To provide richer support for these environments, ADR supports this concept as well. By default, an enumerated value has an associated scalar value 1 greater than the preceding enumerated value's associated scalar value. The first enumerated value is assigned a scalar value of 0. Any enumerated value element may override this policy by defining a value attribute with the desired value. A value attribute must not specify a scalar value already assigned, implicitly or explicitly, to an earlier value in the enumeration and value elements contain no other elements.
Example 47 Enumeration Definition<enum name="Colors"> <value name="RED" /> <!-- scalar value: 0 --> <value name="ORANGE" /> <!-- scalar value: 1 --> <value name="YELLOW" /> <!-- scalar value: 2 --> <value name="GREEN" /> <!-- scalar value: 3 --> <value name="BLUE" /> <!-- scalar value: 4 --> <value name="VIOLET" value="6" /> <!-- indigo was EOLed --> </enum>
Similar to the enum element, the struct element has a single mandatory attribute, name. The name is used when referring to the structure from other derived type or interface definitions. A struct contains one or more field elements, one for each field of the structure. A field element has a mandatory name attribute that gives the field a symbolic name. The symbolic name isn't used elsewhere in the API definition, only in the server and various client environments. In addition to a name, each field must specify a type.
You can define the type of a field in multiple ways. If a field is a plain base type or a derived type defined elsewhere in the API document, that type is defined with a type attribute. If a field is an array of some type (base or derived), that type is defined with a nested list element. The type of the array is defined in the same fashion as the type of the field: either with a type attribute, or another nested list element.
A field's value might be declared nullable by setting the field element's nullable attribute to true.
<struct name="Name"> <field name="familyName" type="string" /> <field name="givenNames"> <list type="string" /> </field> </struct> <struct name="Person"> <field name="name" typeref="Name" /> <field name="title" type="string" nullable="true" /> <field name="shoeSize" type="int" /> </struct>
You can use dictionaries to add a data structure in which the key-value pair mappings can be stored and retrieved. The following example shows how to use the dictionary tag.
<dictionary> <key type="<key type>"> <value type="<value type>"> </dictionary>
You can use the dictionary type similar to any other RAD type such as a field in a structure, a method argument or a return value, a property, an error payload, or as an event payload.
Example 49 Defining a DictionaryThis example shows how to define a dictionary with a key type of integer and value type of string as a read-write property.
... <property name="DictProp" access="rw" > <dictionary> <key type="integer" /> <value type="string" /> </dictionary> </property> ...
Values can be of any type except for list and dictionary. The value can be a derived type or a reference in which case you must use the "typeref" tag instead of the "type" tag. However, the key must belong to any one of the following basic types:
boolean
integer
unsigned integer
long
unsigned long
float
double
time
string
name
An interface definition has a name, and one or more attributes, methods, or events. An interface's name is defined with the interface element's mandatory name attribute. This name is used when referring to the inherited interface from other interface definitions, as well as in the server and various client environments. The other characteristics of an interface are defined using child elements of the interface element.
Each method in an interface is defined by a method element. The name of a method is defined by this element's mandatory name attribute. The other properties of a method are defined by child elements of the method.
If a method has a return value, it is defined using a single result element. The type of the return value is specified in the same way the type is specified for a structure field. If no result element is present, the method has no return value.
If a method can fail for an API-specific reason, it is defined using a single error element. The type of an error is specified the same way the type is specified for a structure field. Unlike a structure field, an error need not specify a type. Such a situation is indicated by an error element with no attributes or child elements. If no error element is present, the method will only fail if there is a connectivity problem between the client and the server.
A method's arguments are defined, in order, with zero or more argument elements. Each argument element has a mandatory name attribute. The type of an argument is specified in the same way the type is specified for a structure field.
Example 50 Method Definition<struct name="Meal">...</struct> <struct name="Ingredient">...</struct> <method name="cook"> <result typeref="Meal" /> <error /> <argument type="string" name="name" nullable="true" /> <argument name="ingredients"> <list typeref="Ingredient" /> </argument> </method>
Each attribute in an interface is defined by a property element. The name of an attribute is defined by this element's mandatory name attribute. The types of access permitted are defined by the mandatory access attribute, which takes a value of ro, wo, or rw, corresponding to read-only access, write-only access, or read-write access, respectively.
The type of an attribute is specified in the same way the type is specified for a structure field.
If access to an attribute can fail for an API-specific reason, it is defined using one or more error elements. An error element in a property may specify a for attribute, which takes a value of ro, wo, or rw, corresponding to the types of access the error return definition applies to. An error element with no for attribute is equivalent to one with a for attribute set to the access level defined on the property. Two error elements may not specify overlapping access types. For example, on a read-write property it is invalid for one error to have no for attribute (implying rw) and one to have a for attribute of wo they both specify an error for writing.
The type of an error is specified the same way the type is specified for a method. It is identical to defining the type of a structure, with the exception that a type need not be defined.
Example 51 Attribute Definition<struct name="PrivilegeError">...</struct> <property name="guestList" access="rw"> <list type="string" /> <error for="wo" typeref="PrivilegeError" /> <!-- Reads cannot fail --> </property>
Each event in an interface is defined by a event element. The name of an event is defined by this element's mandatory name attribute. The type of an event is specified in the same way the type is specified for a structure field.
Example 52 Event Definition<struct name="TremorInfo">...</struct> <event name="earthquakes" typeref="TremorInfo" />
ADR include feature allows you to include an XML-based IDL file within the parent IDL file. The following example shows how to include the fragment.xml file within the parent.adr file.
/*fragment.xml*/ <?xml version="1.0" encoding="UTF-8"?> <fragment xmlns="http://xmlns.oracle.com/radadr"> <version major="1" minor="0"/> <para> Paragraph 1 </para> <para> Paragraph 2 </para> </fragment> /*parent.adr*/ <?xml version="1.0" encoding="UTF-8"?> . . . . <?include href="fragment.xml" major="1" minor="0"?>
The <?include ?> processing instruction has the following mandatory attributes:
Path to the included file.
Expected major version of the included fragment.
Expected minor version of the included fragment
Version checking provides a warning in case of minor version mismatch and fail with an error in case of major version mismatch.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <api xmlns="http://xmlns.oracle.com/radadr" name="com.oracle.solaris.rad.example"> <version major="1" minor="0"/> <struct name="StringInfo"> <field type="integer" name="length" /> <field name="substrings"> <list type="string" /> </field> </struct> <struct name="SqrtError"> <field type="float" name="real" /> <field type="float" name="imaginary" /> </struct> <enum name="Mood"> <value name="IRREVERENT" /> <value name="MAUDLIN" /> </enum> <struct name="MoodStatus"> <field typeref="Mood" name="mood" /> <field type="boolean" name="changed" /> </struct> <interface name="GrabBag" stability="private"> <method name="sqrt"> <result type="integer" /> <error typeref="SqrtError" /> <argument type="integer" name="x" /> </method> <method name="parseString"> <result typeref="StringInfo" nullable="true" /> <argument type="string" name="str" nullable="true" /> </method> <property typeref="Mood" name="mood" access="rw"> <error for="wo" /> </property> <event typeref="MoodStatus" name="moodswings" /> </interface> </api>