SA Forum - Java AIS API (R2 A.01.01)

Service Availability Forum - Java AIS API

This set of packages (published under the Service Availability Forum Specification License Agreement) defines a Java language binding that provides access to high availability middleware implementations compliant with the Application Interface Specification defined by Service Availability Forum.

See:
          Description

Packages
org.saforum.ais This package contains common types and constants for the AIS service APIs.
org.saforum.ais.amf This package contains common types and constants of the Java language binding for the AIS Availability Management Framework defined by Service Availability Forum.
org.saforum.ais.clm This package contains common types and constants of the Java language binding for the AIS Cluster Membership Service defined by Service Availability Forum.

 

This set of packages (published under the Service Availability Forum Specification License Agreement) defines a Java language binding that provides access to high availability middleware implementations compliant with the Application Interface Specification defined by Service Availability Forum.

Copyright statement is specified here.

Java Mapping for AIS APIs: Overview

Introduction

This set of packages defines a Java API that provides access to high availability middleware implementations compliant with the Application Interface Specification defined by Service Availability Forum (also referred to as SA Forum or SAF). If you are not familiar with the terms SA Forum and AIS, the next two sections give you a very brief overview. Otherwise you can jump to the Design principles section.

Background

The Service Availability Forum (SAF or SA Forum) is a consortium of industry-leading communications and computing companies working together to foster an ecosystem that enables the use of commercial off-the-shelf building blocks in the creation of high availability network infrastructure products, systems and services. The SA Forum develops and publishes high availability and management software interface specifications.

The Application Interface Specification (AIS) defined by SA Forum standardizes the interface between a SAF-compliant High Availability (HA) middleware and service applications. AIS defines a set of AIS Services, which are services designed to support highly available applications in a cluster. Furthermore, AIS Frameworks are AIS Services that in addition to providing service for their clients also define an information model that these clients must use.

The current AIS release (B.01.01, i.e. Release 2) defines the following services and frameworks: Availability Management Framework (AMF), Cluster Membership Service (CLM), Checkpoint Service (CKPT), Message Service (MSG), Event Service (EVT) and Lock Service (LCK). Further AIS services may be specified in future releases by SA Forum.

The following AIS services and frameworks are supported in this release of Java APIs:

In the future SA Forum will publish Java API mappings according to the following guidelines:

  1. It is expected that additional Java API mappings for most of the AIS services will be provided in future releases.
  2. Already existing Java API mappings will be updated in future AIS releases.
  3. Java API mappings for earlier releases (i.e. before Release 5) will only be specified upon request. If someone would like to see a Java API for an earlier version for some of the services, then that person/organization must first create a candidate proposal. In order to enforce the 2nd rule above, the candidate proposal must also provide missing mappings for all subsequent releases. SA Forum will review and eventually publish these candidate proposals. (This Java API mapping - intended for Release 2 - is an example of this guideline.)

Related AIS Specification documents for B.01.01 (Release 2, November 22, 2004)

SA Forum provides a general AIS overview document and separate specification documents for each AIS service. These documents are available from www.saforum.org:

The above specification documents define the semantics of the services and also describe the APIs provided for applications using the services (the APIs are defined in the C programming language). If you are not familiar with these specification documents, you are strongly advised to study them: this javadoc can be used as a programming reference, but it does not explain the underlying AIS services. Furthermore, the knowledge of the C API will help understand the Java API as certain patterns are "imported" from the C API.

The specification for the Java mapping contains two documents:

Design principles

The AIS service API definitions in Java are based very closely on the corresponding C language APIs for AIS. They are designed so that:

Java API Design

Package structure

There are presently two levels of packages:

org.saforum.ais
This package factors out definitions common to all AIS services. It roughly corresponds to the "ais.h" header file. Additionally, it contains library handle interfaces providing lifecycle control and the infrastructure for asynchronous communication between the AIS services and the client code. Finally, it adds a generic factory class to provide the entry point for the client code.
org.saforum.ais.<service>
There is a package for each service: e.g. "amf", "clm" and so on. These contain the definitions common to the service. The service specific library handle interface (<Area>Handle and its factory <Area>HandleFactory are located in this package.

Interface oriented design

The functionality of the AIS services is presented to the client code by Java methods. These methods are declared in interfaces rather than in classes. Interfaces preserve the separation between implementation and specification as well as keeping the class hierarchy flexible.

Programming model

The AIS library life cycle is based upon the following model:

  1. The client code (i.e. the AIS component) initializing a dynamic entity representing the association between the client and the AIS area server.
  2. The client code communicating with the area server via the entity.
  3. The client code shutting down the association when it is not needed any more.
In the Java API this generic model is translated to the following steps:
  1. The client code obtaining an <Area>Handle object (the library handle).
  2. The client code communicating with the area server by invoking methods on the library handle or on other closely associated objects.
  3. The client code shutting down the library handle by invoking its finalizeHandle() method, which makes its further use invalid.

Thus, the core object of each service is the <Area>Handle, representing the dynamic association between the AIS component and the AIS area server. This object:

The client usually is free to use more than one <Area>Handle objects to communicate with the area server (the only restriction applies to AMF, which allows only a single library handle to carry out operations that require registration).

The two AIS library life cycle operations are the initialization and the finalization of the library handle. Initialization is done by invoking the initializeHandle() method of the appropriate service factory object (i.e. <Area>HandleFactory). The client code must specify the Version of the requested AIS service and pass a <Area>Callbacks object containing the set of implemented callback interfaces used by the library for asynchronous communication.

The factory framework is specified in the following manner:

The finalization is done by invoking the finalizeHandle() method on the <Area>Handle object. This makes it invalid for further use, but note that the references of <Area>Handle and the related objects still need to be dropped to give the garbage collector a chance to clean up.

The library handle provides the infrastructure for asynchronous communication between the client and the AIS area server. This infrastructure has three elements:

Finally, the library handle provides a gateway for service specific API functionality. In order to avoid the creation of a potentially huge spaghetti class, <Area>Handle objects do not declare methods offering service specific API functionality directly. Instead, service specific methods are implemented by closely associated objects and the library handle provides methods returning references to these associated objects. These library handle methods (and consequently the associated objects) come in two different flavours:

Threading model

Sa Forum mandates that the service libraries implementing the C APIs do not have hidden threads, thus allowing a truly single-threaded process to utilize these libraries. This rule may seem obsolete in Java at first sight, as Java has built-in language support for multiple threads. Nevertheless, there are Java application frameworks that rely on a single-threaded application model, i.e. the framework itself may consist of multiple threads but the applications executed by the framework are assigned a single thread and prohibited from creating multiple threads. Consequently, the Java AIS API libraries must be implemented according to the following rules:

Comparison of Java and C APIs

This section is primarily intended to readers who are familiar with the C AIS API and would like to know what are the differences and the similarities between the Java API and C API.

Naming conventions

As a general rule, the Java API uses commonly accepted naming conventions. These conventions dictate using uppercase letters to begin type names, lowercase letters for methods, all caps for constants, and all lower case letters for packages. Also note that method names start with a verb, followed by the subject of the action.

The C AIS API uses naming conventions that heavily rely on the usage of service specific prefixes (sa, saAmf, saCkpt, etc.). These prefixes reflect the lack of namespaces in C language. Since Java packages do provide namespaces, the Java API does not generally use these prefixes. This rule applies to all public names, i.e. classes, methods, formal parameters, fields, constants. There are a few exceptions, though:

The result of these rules is that most names of the Java API are shorter than the corresponding C API name. Nevertheless, it is still very easy to "find" corresponding names of the two APIs. For example, saAmfComponentRegister() becomes registerComponent() (see ComponentRegistry).

Backward Compatibility rules in Java

As a general rule, the Java APIs follow the same principle concerning backward compatibility as the C APIs: the Java APIs are defined in such a way that they must not prevent implementations from supporting older versions of the API if they decide so (although implementations are not mandated to do that). However, due to the differences between the two languages, there are some differences in the actual guidelines on backward compatibility as well:

Constants

Constants are defined in the Java API using two typical flavours:

Enumerated types (Enum classes) are used to define most constant values. The basic form of Java Enums defines a set of symbolic identifiers without explicitly assigning a numeric value to the identifiers. In the Java AIS API enums are extended so that each symbolic identifier is tied to the numeric value defined by the corresponding C API definition. The reason for this extension is that the Java client may have to forward the numeric value to a non-Java entity within the SA Forum cluster (e.g. embed the value into a message or a log).

The Java API uses public static final fields of the appropriate primitive type for constants that cannot be Enums. Enumerated types are in general more favourable, but they cannot always be used to define constants, mostly because the set of legal values of an enumeration type is strictly limited to those listed in its definition. As a consequence:

Types

The C API defines a fairly high number of special data types that are used primarily to pass information between the underlying middleware and the client code. These data types are converted "directly" in the Java API. The following guidelines are used when converting the types of the C API:

Primitive data types are usually converted to their Java counterparts of the same bit-size. E.g. a type defined in the C API as SaInt16T (directly or via typedef) is mapped to a short type in the Java API. However, there are a few exceptions. Certain unsigned values in the C API represent identifiers/handles that are converted into full-scale Java objects. Another frequent example is the size information for C buffers: these are typically presented as arrays in the Java API, where the length information is a built-in language construct.

Note that unsigned integer types are also usually converted to the signed Java primitive type of the same bit-size: thus, an SaUint32T becomes (a signed) int in the Java API. Although this could in theory cause interpretation problems if e.g. arithmetic or relational operations were used carelessly, in practice most unsigned integer types of the C API are used for special purposes, so this is not a problem:

However, there are a few exceptions, e.g. the majorVersion and minorVersion fields of Version are expected to be used in comparison operations, therefore they are declared as short instead of byte, so that the whole 8-bit unsigned range is included in their type.

There are several ways strings are represented in the C API (e.g null-terminated strings, character arrays, SaNameT). All of these types are represented by the String class in the Java API. It is the responsibility of the Java API implementation to carry out any conversion, if necessary.

There are C structs that encapsulate a buffer pointer and its length: these are represented as Java arrays. Otherwise, C structs are defined in Java as public classes with public fields. For the sake of simplicity and effectiveness, no code is added to them, not even setters or getters. The reasons for this arguable decision are the following:

C unions are replaced by a hierarchy of classes, the root class representing the union as a type, subclasses representing particular union components.

C arrays are defined as Java arrays.

Function pointers -- callbacks -- are defined as interfaces with a single method defining the signature of the callback

Methods, Parameters, Return Values, and Exceptions

The functions of the C API are mapped to methods of the Java API. In most cases there is one-to-one correspondence in functionality between the C function and the Java method. In such cases, as explained above, typically the naming has been simplified in the Java API in such a manner that the equivalent C function name is obvious. Noteworthy exceptions to the naming of such Java methods is the initialization and finalization of handles:

There are cases where a single C API function is refactored to several Java methods with different parameter lists. These C functions use certain parameters to govern what the function actually should do. These functions are decomposed into several Java methods. Below you can find some examples:

The documentation of the Java methods contains a reference to the equivalent C functions, including information on the specific parameter values that belong to a "refactored" Java method.

In Java, memory is never freed explicitly. Instead, the garbage collector reclaims unused memory. Therefore, C API functions freeing up memory (typically named as sa<Area><SomeEntity>Free() do not have their counterparts in Java.

In the C API, a "handle" is often passed to a function. In Java, this is not the case. The "handle" is the object on which the method is invoked. Within the method, this can be used to explicitly refer to this implicit parameter.

The C AIS API follows a typical C error handling convention: the return value of each API functions invoked by the AIS Component is an integer value (enum type SaAisErrorT) representing the error status of the executed function. SA_AIS_OK represents a successful execution, whereas SA_AIS_ERR_<SOME_ERROR> values represent possible errors.

Errors are handled using exceptions in Java, therefore the Java AIS API declares appropriate exceptions for the possible AIS errors. For each SA_AIS_ERR_<SOME_ERROR> value there is an Ais<SomeError>Exception class declared in the org.saforum.ais package. So, Java AIS API methods throw one of these exceptions instead of returning an error value. (If no exception is thrown, the method executed successfully i.e. this is the equivalent behaviour with the C function returning SA_AIS_OK). There is a superclass AisException for all the exception classes: it is never thrown by the API but can be used by the applications for error handling, especially if the error handling code is generic and applies to all possible exceptions thrown by the API method. (However, note that many argue that catching individual exceptions is the best ? and preferred - programming style in Java...) The AisException is a checked exception (i.e. Exception subclass), which means that the clients of AIS API methods are forced to handle the Ais<SomeError>Exceptions either by catching the exceptions or by explicitly declaring them in the enclosing methods. As usual in Java, extra status information is embedded in an exception when it is thrown: e.g. a stack trace, a possible nested exception, a message string.

There is an enumerated type AisStatus that corresponds to the C SaAisErrorT values (including SA_AIS_OK). It is used to indicate the status of operations executed asynchronously, i.e. the status of an operation other than the one initiated by the actual method call. Some examples are as follows:

Often in the C API, the parameters being passed must be accompanied by descriptive data. For example, often a pointer to an array is passed along with a second parameter giving the number of (valid) elements. In the Java API, this is not done. Instead, Java's type checking/safety and ability to interrogate objects is used. For example, to get the number of elements in an array, the ".length" attribute is used, etc.

The replacement of handles with object references, the use of exceptions instead of a status return, and the elimination of descriptive parameters means that the Java methods have far fewer parameters (approximately one half, on average) compared to the C functions. So the signatures are quite different. Also, the elimination of the status return frees up this usage for other return values. Hence, there are very few "out" parameters in the Java API.

Generic Types

Java generic types are used to create a uniform factory framework. The C API "factories" (i.e. the sa<Area>Initialize() functions) provide the same initialization scheme, but still have to be declared separately in the C API for each service because of the differences in the formal parameter list. By using a generic interface, the Java API can capture the uniformity of library handle initialization in a more elegant way. Thus, the Java API declares a generic initializeHandle() method (see Factory). There are two actual differences between the initializers for the different services: the set of callbacks supported by the service and the actual library handle implementation returned by the factory. Hence, in the interface you will find two type variables: S" for Service (i.e. the library handle) and "C" for Callbacks.


OWNERSHIP OF SPECIFICATION AND COPYRIGHTS.

Copyright 2008 by the Service Availability Forum. All rights reserved.

Permission to use, copy, and distribute this mapping specification for any purpose without fee is hereby granted, provided that this entire notice is included in all copies. No permission is granted for, and users are prohibited from, modifying or making derivative works of the mapping specification.


SAIM-AIS-R2-JD-A.01.01

Created by Service Availability Forum, 2008