Bondi logo

The BONDI API Design Patterns - Version 1.1

9 February 2010

Authors

Abstract

BONDI API Design Patterns specify the common rules governing all the APIs defined in BONDI Interfaces documents.

Table of Contents


1. Introduction

The BONDI initiative defines a set of Application Programming Interfaces (APIs). All the interfaces are defined in WebIDL, combined with documentation formatted using doxygen-like syntax. BONDI Interfaces are grouped into modules, where each module defines a set of related WebIDL interfaces. Each BONDI module is defined in a single file with the extension ".widl". Both WebIDL and doxygen-like documentation are combined in the same file.

Since the number of BONDI modules is considerable and is likely to grow in the future, it is necessary to specify common rules that will govern how both the WebIDL content and doxygen-like documentation are structured. This will ensure consistency throughout all BONDI APIs. This document specifies those rules and guidelines.

The WebIDL patterns section defines the rules that are applicable to the WebIDL parts of .widl files, whereas the Documentation patterns section defines the rules that are applicable to the doxygen-like parts of .widl files.

2. WebIDL patterns

BONDI APIs are specified in W3C's interface definition language, WebIDL. The detailed syntax is based on WebIDL rev. 1.181.

2.1. Error Handling

Motivation and problem statement

WebIDL allows methods, getters and setters to raise not only exceptions, but also objects that expose given interfaces. WebIDL exceptions cannot be inherited and therefore no hierarchy of exceptions can be built. However, within BONDI each module is able to define its own error interface. Thus, to support hierarchy of errors within BONDI, we are going to use only error interfaces for which a specific inheritance hierarchy has been built.

Solution

The following rules apply to WebIDL parts of .widl files for the error-related conventions:

WebIDL definition

interface Error {

        readonly attribute DOMString name;

        readonly attribute DOMString message;
};

interface GenericError : Error {

        readonly attribute unsigned short code;
};
        
interface DeviceAPIError : GenericError {

        const unsigned short UNKNOWN_ERROR           = 10000;

        const unsigned short INVALID_ARGUMENT_ERROR  = 10001;

        const unsigned short NOT_FOUND_ERROR         = 10002;

        const unsigned short PENDING_OPERATION_ERROR = 10003;

        const unsigned short IO_ERROR                = 10004;

        const unsigned short NOT_SUPPORTED_ERROR     = 10005;
};

interface SecurityError : GenericError {
        const unsigned short PERMISSION_DENIED_ERROR = 20000;
};

2.2. Asynchronicity

Motivation and problem statement

ECMAScript methods can be either synchronous or asynchronous. Methods using the synchronous mode of operation do not return control to the caller until the operation is complete. Asynchronous methods return immediately and notify the caller at some point in the future of the results via callback method(s). The callback methods are specified as parameters to the asynchronous method. The following rules describe how to specify asynchronous methods in BONDI WebIDL.

Solution

The following rules specify the signature and the way of operation of the asynchronous method call.

WebIDL definition

[Callback] interface SuccessCallback {

        void onSuccess(in Object ob);

};

[Callback] interface ErrorCallback {

        void onError(in Error error);

};

interface PendingOperation {

        boolean cancel();

};

2.2.1. How to combine APIs with architecture and security principles?

Motivation and problem statement

The design of BONDI APIs MUST satisfy the principles resulting from the BONDI Architecture & Security.

Solution

The BONDI Architecture & Security rules are specifically defining:

2.3. Namespaces and interface structure

Motivation and problem statement

BONDI APIs comprise a set of interfaces grouped into modules. It shall be clearly stated where an object that instantiates an interface is placed in the object hierarchy, i.e. property of which object it becomes.

Solution

The grouping of interfaces into modules is purely for organizational purposes. The "module" keyword does not have any semantics related to the execution of the API. The WebIDL's "implements" keyword is used to specify as property of what object the given interface is instantiated. The statement

	Window implements bondiObject;
specifies that bondi interface is instantiated as the property of the Window object of the browsing context's active document.
module bondi {
	interface bondi {
		...
        PendingOperation requestFeature (in RequestFeatureSuccessCallback successCallback,
                in ErrorCallback errorCallback,
                in DOMString name)
            raises (DeviceAPIError, SecurityError);
		...
	};

	interface bondiObject {
		readonly attribute bondi bondi; 
	};

	Window implements bondiObject;
};


module calendar {
	interface CalendarManager {
	...
	...
	};
	
	interface Calendar {
	...
	...
	};

	interface CalendarManagerObject {
		readonly attribute CalendarManager calendarManager;
	};
	bondi implements CalendarManagerObject;

};

2.4. Data records, supported property keys and filters

Motivation and problem statement

BONDI APIs operate on data collections that MAY potentially be large. Very often there arises a need to filter the collection's data records and search for records with specific values of the properties. BONDI modules and interfaces shall provide a unified way of expressing the filter syntax used in search operations. In ECMAScript the properties of objects MAY be added dynamically. Whereas it is a very useful extensibility mechanism, it MAY be difficult to handle for objects that are to be persistently stored. This is because some platforms MAY be able to store only predefined properties and their values. On the other hand, the interoperability reasons require that the minimum set of properties is specified. This results in the following categorization of properties:

Solution

The properties regarded as storable information-carriers MUST be grouped into interfaces whose name is postfixed with "Properties" string. For example, in case of a contact record we MAY start with the following basic interfaces:

    interface Address {
        attribute DOMString country;
        attribute DOMString postalCode;
    };

    interface Contact {
        readonly attribute DOMString id;
        attribute DOMString name;
        attribute DOMString email;
        attribute Address address;
	};
We note that the properties name, email and address carry useful contact information, whereas the administrative property id results from need to store the contact information and it is readonly, since it is to be assigned by the implementation. When searching for the contact in the contacts' collection, we assume that the filter would be based on the primitive properties name and email as well as on the properties of the Address interface that would refer to the address property. The result of the above considerations are:
    interface ContactProperties {
        attribute DOMString name;
        attribute DOMString email;
        attribute Address address;
	};
    interface Contact : ContactProperties {
        readonly attribute DOMString id;
	};
The interoperable data-carrying properties, i.e. those specified on the XXXProperties interfaces, MUST be available and storable in all implementations. Additionally to them, the underlying implementation MAY provide platform-specific data-carrying properties. E.g. in case of the ContactProperties interface this could be the phoneNumber property. Such a property MUST be set to null when the ContactProperties interface is instantiated. Furthermore, the script MAY try to add new properties; those are called here application-specific data-carrying properties. E.g. the following code:
    contact.name = "Marcin Hanclik";
    contact.email = "marcin.hanclik@access-company.com";
    contact.web-colorofeyes = "blue";
tries to add the property colorofeyes to the contact object. Such a property MAY always be added to the object (design of ECMAScript language), but it is BONDI implementation specific whether this property will persist when storing the contact object. The XXX (to distinguish from XXXProperties) interfaces are to be used when creating filter objects. The usage of only those properties in the filter objects SHALL guarantee the interoperability of the filter object. The implementations MUST ignore properties requested in the filter objects that are not actually present in the matching objects. The names of the application-specific and platform-specific data-carrying properties MUST be prefixed in a way that will enable adding of the new properties in the BONDI API without any conflicts. See below example about "x-colorofeyes" property.
Type of property Example Is storable? Is interoperable (works on all platforms)?
interoperable data-carrying ContactProperties.email yes yes
platform-specific data-carrying contact.phone yes no (no guarantee for interoperability, although it could happen)
application-specific data-carrying contact.web-colorofeyes user-agent dependent n/a
administrative Contact.id yes (but it is irrelevant, since the administrative properties are readonly and cannot be set by the widget/application) yes

The following is the rule for creating the filter object:

Examples

3. Architectural patterns

3.1. Versioning

Motivation and problem statement

It is assumed that the BONDI interfaces will evolve over time. The interfaces defined within a given BONDI Release MAY be modified in future releases of the BONDI specifications. They MAY add new methods or attributes, they MAY remove them or modify the way they operate. Therefore a versioning model is defined that will enable widgets to be installable and to function properly on WUAs that are equipped with the appropriate implementation of the APIs.

Solution

The BONDI API versioning is based on the IRI of the API features. If the functionality behind an existing feature is changed, a new IRI for that extended feature MUST be assigned. If the functionality behind an existing feature-set is changed (e.g. the API owner wants to incorporate new feature into a feature-set), a new IRI for that extended feature-set MUST be assigned. Between BONDI Releases vendors MAY add experimental APIs under the already provided IRI, but MUST take special care in order not to compromise the security provided by the API design in the official BONDI Release. It is out of the scope of this specification to specify how those additional APIs are discoverable.

3.2. API coverage by features

Motivation and problem statement

From the security perspective all APIs (methods, attributes and constants) expressed in BONDI WebIDL are to some extent related to the user's privacy. Some APIs MAY not be accessible due to security restrictions, other APIs MAY be not available on the given platform or exposed by a given User Agent. When requesting access to some APIs by means of a feature within the configuration document or programmatically, the list of methods, attributes, and constants to which access is requested and later granted, shall be made clear.

Solution

Every method, attribute and constant MUST belong to at least one feature.

3.3. Feature-sets

Motivation and problem statement

Rich Web Applications need to use many BONDI APIs. Thus, to satisfy the BONDI security model, many features MUST be declared within the configuration document or MUST be requested programmatically. This need MAY result in unnecessary performance impact on the application or excessive burden for the developer of the configuration document.

Solution

Features are grouped into feature-sets. Feature-set comprises one or more features from a single module. Each module MUST have at least one feature-set declared. The feature-set MAY comprise all the features declared within a module.

4. Documentation patterns

4.1. General format

Motivation and problem statement

Each BONDI 1.0 module is specified by widl files. WebIDL does not have a mechanism for inclusion of the comments.

Solution

The format for widl file combines doxygen-like syntax with WebIDL syntax. Each WebIDL statement in widl file MUST be prefixed with the comments in doxygen format as follows.
        /**
         * \brief Messaging specific error callback.
         *
         * This callback error interface is specific to this messaging API. It
         * specifies a error callback with a function taking an MessagingError object
         * input argument.
         */
        [Callback] interface MessagingErrorCallback {
                void onError(in MessagingError error);
        };

The documentation syntax MUST begin with the line that includes only "/**" and white-space characters (space, tab or new line). Each of the subsequent documentation lines MUST begin with "*" and the final documentation line MUST consist of only "*/" and white-space characters. Each line of the documentation MAY include up to one keyword, i.e. a token prefixed with the backslash ("\") character. The following keywords are available for BONDI widl documentation:

The detailed description of the syntax follows in the next sections of this document.

4.2. Common types, errors and interfaces

Motivation and problem statement

BONDI APIs share a few type definitions, errors and interfaces. For consistency reasons the common types, errors and interfaces MUST be specified in one file.

Solution

The file bondi.widl MUST include all the common BONDI type, error and interface definitions. Those definitions include:

The PendingOperation interface MUST also be specified in bondi.widl.

4.3. Documentation syntax

Motivation and problem statement

The following WebIDL statements are used in widls:

Solution

The following subsections provide the detailed information about syntaxes used for each of the relevant WebIDL definitions.

4.3.1. Documentation format for WebIDL module

The comment for a module definition SHOULD include the following doxygen-like keywords:
    /**
     * \brief 
     *
     * 'module description'
     *
     * \def-api-feature 'API Feature Identifier'
     * \brief 'API Feature brief description'
     *
     * \def-feature-set 'Feature-Set Identifier'
     * \api-feature 'Identifier of the API feature belonging to the feature-set above'
     * \api-feature 'Identifier of the API feature belonging to the feature-set above'
     *
     * 'API Feature detailed description (optional, blank line above not needed if absent)'
     * \device-cap 'Identifier of related Device Capability'
     * 'optional brief description of circumstance in which that device cap is used'
     *
     * ...
     * \def-device-cap 'Device Capability Identifier'
     * \brief 'Device capability brief description'
     *
     * 'Device Capability detailed description (optional, blank line above not needed if absent)'
     * \param 'security parameter name' 'brief description'
     * ...
     *
     * \author 'Name' 'e-mail'
     * \version 'API version'
     *
     */
     module foo {
      ...
      aaa implements bbb; 
     };

4.3.2. Documentation format for WebIDL interface

The comment for a interface definition SHOULD include the following doxygen-like keywords:
    /**
     * \brief 'Brief interface description'
     *
     * 'Detailed description of the interface'
     *
     * \code
     * 'Code Example'
     * \endcode
     */
    interface fooInterface {
    ...
    };

For instance, in the case of the FileSystemManager Interface

    /**
     * \brief FileSystemManager API.
     *
     * This file system API provides basic filesystem access.
     *
     * \def-instantiated
     * \api-feature 'Identifier of the API feature that instantiates the interface object'
     * \api-feature 'Identifier of the API feature that instantiates the interface object'
     *
     * \code
     *    var dir = bondi.filesystem.mount(fs.getDefaultLocation("app:public"));
     *    var files = dir.listFiles();
     *    for(var i = 0; i < files.length; i++) {
     *      alert(files[i].name); // displays name of each file in directory
     *    }
     *    var file = dir.createFile("test.txt");
     *    var out  = file.open("w", "UTF-8");
     *    // writes Hello World to test.txt
     *    out.write("Hello World");
     *    out.close();
     * \endcode
     */
    interface FileSystemManager {

4.3.3. Documentation format for WebIDL attribute

The comment for a read-only attribute definition SHOULD include the following doxygen-like keywords:

Additionally, read-write attributes MUST include a description of the possible errors and the conditions in which they are raised when setting or getting the value of the attribute based on the setraises or getraises WebIDL keywords.

 /**
  * \brief 'brief attribute description'
  *
  * 'detailed attribute description'. 
  * This attribute is read-only
  *
  * \api-feature 'API Feature ID' 'optional brief description'
  *
  * \code
  *   'example code'
  * \endcode  
  */
  readonly attribute 'type' 'name'

 /**
  * \brief Contains the implementation dependent maximum path length.
  *
  * This attribute is read-only.
  *
  * \code
  *    alert(bondi.filesystem.maxPathLength);
  * \endcode
  */
  readonly attribute long maxPathLength;

 /**
  * \brief 'brief attribute description'
  *
  * 'detailed attribute description'. 
  * This attribute is read-only
  *
  * \code
  *   'example code'
  * \endcode  
  * \throw 'error object and code to be thrown' 'conditions in which is thrown'
  */
  attribute 'type' 'name'
       setraises('errorobject');

  /**
    * \brief Get/set current position in this stream.
    *
    * The position of this stream is an offset of bytes from the start
    * of the file stream.  When invoking an operation that reads or writes
    * from the stream, the operation will take place from the position
    * in the position attribute.
    *
    * \code
    *   alert(stream.position); // displays current stream position
    *   // alters current stream position to the begin of the file,
    *   // like seek() in C
    *   stream.position = 0;
    * \endcode
    * \throw FileSystemError IO_ERROR if invalid position was given.
    */
    attribute long position
              setraises(FileSystemError);

4.3.4. Documentation format for WebIDL method

The comment for a method definition SHOULD include the following doxygen-like keywords:
 /**
   * \brief 'Method's brief description'
   *
   * 'Method's long description'
   *
   * \api-feature 'API Feature ID' 'optional brief description'
   *
   * \code
   * 'example code'   
   * \endcode
   *
   * \param 'name' - 'description'
   * \return 'description of the return value'
   * \throw 'errorobject' 'error code' if 'error condition'
   */

4.3.5. Documentation format for WebIDL constant

The comment for a constant definition SHOULD include the following doxygen-like keywords:
 /**
   * \brief 'Constant's brief description'
   *
   * 'Constant's long description'
   *
   * \api-feature 'API Feature ID' 'optional brief description'
   *
   * \code
   * 'example code'   
   * \endcode
   *
   */

4.3.6. Documentation format for WebIDL type

The comment for a type definition SHOULD include the following doxygen-like keywords:
 /**
   * \brief 'Type's brief description'
   *
   * 'Type's long description'
   *
   * \code
   * 'example code'   
   * \endcode
   *
   */