OpenOffice-API - Design-Guidelines

(by Michael Hönnig <mi@sun.com>)

The following rules apply to all external programming interface specifications for OpenOffice. The API consists of the following stereotypes (design elements):

Structures
are used to specify simple composed data elements.
(Structures do only consist of data, not methods.)
Exceptions
are used for error handling.
(Exceptions can be thrown or transported using an any.)
Interfaces
are used to specify a single aspect in behavior.
(Interfaces only consist of methods, not data.)
Services
are used to specify abstract objects.
(Services specify the properties and the interaction of the supported interfaces.)
Typedefs
are used to define basic types for specific purposes.
(This stereotype should be used carefully.)

General Design Rules

Universality

It is preferable to design and use universal interfaces instead of specialised ones. Whenever a new interface is created, one should think about the possibility of similar requirements in other application domains. If it is not possible to re-use an existing interface, the interfaces should be based along the same idea.

Orthogonality

The functionality of interfaces should extend each other. Redundancy should generally be avoided, but is allowable if it leads to a major simplification for application programmers. In general, functionality which can be built upon the basic interfaces should not be added directly. If necessary, external tool services should be used.

Inheritance

All interfaces are derived from XInterface, other superclasses are only allowed if the following terms are true:

Uniformity

All identifiers have to follow uniform rules for semantics, lexical names, order of arguments etc. Anybody who is familiar with any portion of the API should be able to work with other any part intuitively.

Correct English

Whoever designs API elements is responsible for the correctness in spelling and meaning of the applied English terms, especially for lexical names of interfaces, methods, structures and exceptions as well as members of structures and exceptions. If not absolutely certain, ask Merriam-Webster's Dictionary (http://www.m-w.com). We use US-English, not British-English.

Mixed capitalization or underscores (the latter only for lexical constants and enumeration values) are used to separate words within single identifiers. The word separation has to be applied appropriately. English generally doesn't have compound words, unlike (for example) German.

2 Definition of API Elements

In this chapter we define several API elements, how they are used and which rules apply.

Attributes

Definition

Attributes are used to access data members of object through an interface.

Naming

Attributes are defined in interfaces as getter and (optional) setter methods. Although the UNO-IDL knows attributes for compatibility reasons, we don't use this feature. The attribute identifier itself begins with a capital letter. The mixed upper/lower case method is used to separate single words. Only letters and numbers are allowed, no underscores. Example: getParent(), setParent().

Usage

Attributes are used to express structural relationships (both with and without lifetime coupling). For scripting languages the attributes can be accessed as properties.

Methods

Definition

Methods are functions which are defined within an interface. Technically an interface only consists of methods. There is a syntax for attributes, but these just map to methods.

Naming

Method identifiers begin with a verb in lower case (for example, close) and continue with studly caps (first letter of each word capitalized, otherwise lower case, no underscores). Example: getFormat.

Method names just with a verb without any additional terms must only be used if they refer to the object itself as a whole and do not just operate on parts of the objects which are specified with arguments of this method. On the one hand this makes names semantically more precise and on the other hand we avoid the risk of two method names of two different interfaces at the same object folding into each other, which makes a problem for scripting languages.

Special attention should be paid to uniformity within semantically related interfaces. This means, if a method is named destroyRecord, an insert method should be called insertRecord.

If a method refers to a part of the object and an argument specifies this part, the type or role of the part is appended to the verbal part of the method: removeFrame( [in] XFrame xFrame ). If the name of the part or its position is specified as an argument, ByName or ByIndex has to be appended additionally: removeFrameByName( [in] string aName ) or removeFrameByIndex( [in] long nIndex ).

The following method prefixes have special meanings:

Usage

Non-structural attributes should be represented by the property concept, not by getter and setter methods or attributes of interfaces.

If there are multiple options for interfaces to put methods in, keep possible implementations in mind. For example: a file cannot really destroy itself, just the container directory could.

Don't use const as an attribute for methods, future versions of UNO-IDL will not support this feature.

Interfaces

Definition

Interfaces are collections of methods which belong to a single aspect of behavior. Methods themselves have neither data nor implementation.

Once an interface gets into an official release of the API, it may no longer be changed. This means no methods or attributes can be added, removed or modified, not even arguments of methods. This rule covers syntax as well as semantics.

Interfaces are identified by their name and additionally by a UIK (Universal Interface Key), a unique 128 bit number.

Naming

Identifiers of interfaces begin with the prefix 'X' followed by the name itself in studly caps, capitalizing even the first letter after the 'X' (for example, XFrameListener). Avoid abbrevations.

We apply the prefix 'X' because interfaces have to get treated differently then pointers in C/C++ and also differently then normal interfaces in Java. It is also very likely that the main interface of a service should get the same name as the service, which could cause confusion or ambiguity in documentation.

It is mostly a sign of bad design if the name or abbrevation of a specific component appears within the name of an interface (for example, XSfxFrame or XVclComponent).

Usage

Interfaces are used to represent stable aspects of design objects. A single interface should only contain methods which belong to exactly one aspect of object behavior, never collections of arbitrary methods. Both aspects of usage, client and server, should be considered in design. Keep the role of the object in mind. If some methods of your new interface are only used in one role and others in a different another role, your design is probably flawed.

Properties

Definition

Properties are descriptive attributes of an objects which can normally queried and changed at runtime using the XPropertySet interface.

Naming

In non-scripting languages, like Java or C/C, property identifiers are simply strings. These identifiers begin always with a capital letter and use studly caps (for example, BackgroundColor). Avoid abbrevations.

Usage

Properties are used for non-structural attributes of an object. For structural attributes (composition) use getter and setter methods in an interface instead.

Events

Definition

Events are notifications for which you can register listeners. This concept is actually expressed by registration/unregistration methods for the broadcaster, listener interfaces for the listener and event structures for the event itself.

Naming

If an object broadcasts a certain event, it offers a pair of methods like addEventNameListener and removeEventNameListener. This scheme conforms JavaBeans and does not mean that the implementation has to keep track of a separate list for each event.

The event methods of the listener interface use the past tense form of the verb which specifies the event, usually in combination with the subject to which it applies (for example, mouseDragged). For events which are notified before the event actually happens, the method should begin with notify (for example, notifyTermination). Event methods for vetoable-events normally start with the prefix approve (for example, approveTermination).

Usage

Use events if a set of other, unknown, objects has to be notified about changes in state of your object.

Normally the methods addEventNameListener and removeEventNameListener have a single argument. The type of this argument is an interface which is derived from XEventListener.

The event itself is normally a struct which is derived from EventObject. EventObject contains the source of the event.

Services

Definition

Services are collections of related interfaces and properties. They specify the behavior of implementation objects at an abstract level by specifying the relationship and interaction between these interfaces and properties. Like interfaces, services don't have an implementation.

Naming

Service identifier begin with a capital letter and are put in studly caps (for example, TextDocument). Avoid abbrevations.

Usage

Services are used by a factory to create objects which fulfill certain requirements. Another usage is documentation: you can specify in great detail what methods expect as arguments or what they return.

Exceptions

Definition

Exceptions are special classes which describe exceptional states.

Naming

Exception identifiers begin with a capital letter, are put in studly caps and always end with Exception (for example, UnknownArgumentException). Avoid abbrevations.

Usage

The OpenOffice API uses exceptions as the general error handling concept, however, the API should be designed in such a way that it is possible to avoid exceptions in typical error situations like opening non-existent files etc.

Enums

Definition

Enums are non-arbitrary sets of identifying values. If an interface uses an enum type, it means that all implementations have to implement all specified enum values. It is possible to specify exceptions at the interface. Extending enums is incompatible .

Naming

Enum types begin with a capital letter and are put in studly caps. Avoid abbrevations. If there is a possible name-conflict with structs which use the same name, add Type or Style to the enum identifier.

Enum values are completely capitalized and words are seperated by underscores. Do not use a version of the enum type as a prefix for the values, some language bindings will do that anyway.

Example

enum FooBarType
{
  NONE,
  READ,
  WRITE,
  USER_DEFINED = 255
};

struct FooBar
{
  FooBarType Type;
  string FileName
};

Three typical endings of special enum values are _NONE, _ALL and _USER_DEFINED.

Usage

If by general fact an enum represents the most common values within an open set, add an value for USER_DEFINED and specify the actual meaning of this by a string in the same object or argument list where the enum is used. In this case, offer a method which returns a sequence of all possible values of this string.

Typedefs

Definition

Typedefs specify new names for existing types.

Naming

Typedefs begin with a capital letter and are put in studly caps. Avoid abbrevations.

Usage

Do not use typedefs in the OpenOffice API.

Structs

Definition

Structs are static collections of multiple values which belong to a single aspect and could be considered as a single, complex value.

Naming

Structs begin with a capital letter and are put in studly caps. Avoid abbrevations.

If the actual name for the struct does not sound correct by itself, you should not add Attributes, Properties or the suffixes suggested for enums. These two words refer to different concepts within the OpenOffice API. Instead use words like Format or Descriptor.

Usage

Use structs as data containers. Data other than interfaces is always copied by value. This is a big efficiency gain, especially in distributed systems.

Counting inherited members as wenn, structs with just a single member are wrong by definition.

Parameter

Definition

Parameters are names for arguments of methods.

Naming

Argument identifiers begin with a special lower-case letter as a prefix and are put in studly caps further on (for example, nItemCount).

Use the following prefixes:

Usage

The order of parameters is defined by the following rule: Where, What, How. Within these groups, order by importance. Example: insertContent( USHORT nPos, XContent xContent, boolean bAllowMultiInsert).

Special Cases

Error Handling (Exceptions/Error-Codes)

Runtime errors which are caused by wrong usage of interfaces or which at least do not happen regularly , raise exceptions. Runtime errors which happen regularly without a programming mistake (like non-existence of a file for a file opening method), should be handled by using error codes as return values.

Collection-Interfaces (Interface-Ableitung plus Typisierung plus insert/remove)

Collection-Services werden üblicherweise von einem der X...Access-Interfaces abgeleitet und typisieren dessn Zugriffsfunktionen. Aus XInterface XIndexAccess::getElementByIndex(unsigned short) wird so z.B. XField XFields::getFieldByIndex(unsigned short).

...Document for components which are document-like

Components, whose instances normally would be called a document, get the postfix Document to their name (for example, service TextDocument).

...Start/...End vs. ...Begin/...End

...Start/...End is to be preferred over...Begin/...End.

Abbrevations

Avoid abbrevations in identifiers of interfaces, services, enums, structs, exceptions and constant groups as well as identifiers of constants and enum values. Use the following open list of abbrevations if your identifier is otherwise longer than 20 characters. Remain consistent in parallel constructions, like addSomething/removeSomething.

Abs: Absolute
Back: Background
Char: Character
Doc: Document
Ext: Extended, Extension
Desc: Description, Descriptor
Ref: Reference
Hori: Horizontal
Orient: Orientation
Para: Paragraph
Var: Variable
Rel: Relative
Vert: Vertical

Source Files and Types

For each type, create a separate IDL file with the same base name.