JCEA Part 1: Enterprise Java Beans

 

Contents

  1. General
  2. References
  3. Syllabus
    1. Concepts
    2. Common architectures
    3. Legacy connectivity
    4. EJB
    5. EJB Container model
    6. Protocols
    7. Applicability of J2EE
    8. Patterns
    9. Messaging
    10. Internationalisation
    11. Security
  4. Reference
    1. UML
  5. Resources
  6. Further Tips
 
 

Syllabus

  • List the required classes/interfaces that must be provided for an EJB.
  • Distinguish stateful and stateless Session beans
  • Distinguish Session and Entity beans
  • Recognize appropriate uses for Entity, Stateful Session, and Stateless Session beans
  • State benefits and costs of Container Managed Persistence
  • State the transactional behavior in a given scenario for an enterprise bean method with a specified transactional attribute as defined in the deployment descriptor
  • Given a requirement specification detailing security and flexibility needs, identify architectures that would fulfill those requirements
  • Identify costs and benefits of using an intermediate data-access object between an entity bean and the data resource
 

Information

Writing an EJB

For all types of EJBs, you need to provide three Java interfaces/classes to fully describe the EJB to an EJB container:

  1. Home Interface
  2. Remote Interface
  3. Bean Class

Home Interface

The home interface exists for each EJB and allows:

  • The creation of all EJB Objects
  • The removal of all EJB Objects
  • Finding of Entity Beans

It extends the EJBHome interface which provides the following methods:

public interface EJBHome extends Remote                      
{ 
                      
  EJBMetaData getEJBMetaData();
   // Obtain the EJBMetaData interface for the enterprise Bean. 

  HomeHandle getHomeHandle(); 
   // Obtain a handle for the remote home object. 
                      
  void remove(Handle handle); 
   // Remove an EJB object identified by its handle. 

  void remove(java.lang.Object primaryKey); 
   // Remove an EJB object identified by its primary key.

}

The remote home interface is defined by the enterprise Bean provider and implemented by the enterprise Bean container.

import javax.ejb.*;
import java.rmi.RemoteException;
public interface MyHomeInterface extends EJBHome
{
  public MyRemoteInterface create() 
  throws RemoteException;
  ....
}

Remote Interface

The EJBObject interface is extended by all enterprise Beans' remote interfaces. An enterprise Bean's remote interface provides the remote client view of an EJB object. An enterprise Bean's remote interface defines the business methods callable by a remote client.

public interface EJBObject extends Remote                      
{              
                
  EJBHome getEJBHome() 
   // Obtain the enterprise Bean's remote home interface.

  Handle getHandle() 
   // Obtain a handle for the EJB object. 
                        
  java.lang.Object getPrimaryKey()
   // Obtain the primary key of the EJB object.
                        
  boolean isIdentical(EJBObject obj)
   // Test if a given EJB object is identical to the invoked
   // EJB object.
                      
  void remove() 
   // Remove the EJB object.

}

The enterprise Bean's remote interface is defined by the enterprise Bean provider and implemented by the enterprise Bean container.

import javax.ejb.*;
import java.rmi.RemoteException;
public interface MyRemoteInterface extends EJBObject
{
  // business method definitions – all of which throw
  // a RemoteException
} 

Bean Class

The bean class provides implementations for business methods. The bean class does not have to implement the remote interface. If it does then be careful not to export references to this outside fo the class. Some developers will write a business interface that the Bean class implements and the remote interface extends.

Restrictions:

  • The bean class must define a default constructor.
  • The bean class must not define the finalize method.
  • The EJB specification prohibits use of the synchronized keyword.
  • EJB prohibits beans from creating their own threads.
For Session Beans:

The SessionBean interface is implemented by every session enterprise Bean class.

public interface SessionBean extends EnterpriseBean                      
{ 
             
  void ejbActivate() 
   // The activate method is called when the instance is activated 
   // from its "passive" state. 
                    
  void ejbPassivate() 
   // The passivate method is called before the instance enters the 
   // "passive" state. 
                  
  void ejbRemove() 
   // A container invokes this method before it ends the life of the
   // session object. 
                    
  void setSessionContext(SessionContext ctx) 
   // Set the associated session context. 
                  
}

The container uses the SessionBean methods to notify the enterprise Bean instances of the instance's life cycle events.

An enterprise bean must have one or more ejbCreate methods. Typically, it method initializes the state of the enterprise bean. There must be a bean create method corresponding to every create method in the Home,

import javax.ejb.*;
import java.rmi.RemoteException;
public class MyBean implements SessionBean
{
  // required methods

  // used to create Bean isntances
  public void ejbCreate(..) {}

  // from SessionBean interface
  public void ejbRemove() {}
  public void ejbActivate() {}
  public void ejbPassivate() {}
  public void setSessionContext() {}
  // business method implementations
}
For Entity Beans:

The EntityBean interface is implemented by every entity enterprise Bean class.

public interface EntityBean extends EnterpriseBean                      
{ 

  void setEntityContext(EntityContext ctx) 
   // Set the associated entity context. 
                    
  void unsetEntityContext() 
   // Unset the associated entity context. 
             
  void ejbActivate() 
   // A container invokes this method when the instance is taken
   // out of the pool of available instances to become associated 
   // with a specific EJB object. 
                                       
  void ejbPassivate() 
   // A container invokes this method on an instance before the instance 
   // becomes disassociated with a specific EJB object. 
                    
           
  void ejbLoad() 
   // A container invokes this method to instruct the instance to 
   // synchronize its state by loading it state from the underlying 
   // database. 
        
  void ejbStore() 
   // A container invokes this method to instruct the instance to 
   // synchronize its state by storing it to the underlying database.

  void ejbRemove() 
   // A container invokes this method before it removes the EJB object 
   // that is currently associated with the instance.  
                    
                  
}

The container uses the EntityBean methods to notify the enterprise Bean instances of the instance's life cycle events.

import javax.ejb.*;import java.rmi.RemoteException;
public class MyBean implements EntityBean
{  
  // entity bean methods 
}

 

Primary Key Class

The Primary key class is optional, and only used by Entity Beans. There are two ways to specify a primary key class for an entity bean with container-managed persistence:

  1. Primary key that maps to a single field in the entity bean class.
  2. Primary key that maps to multiple fields in the entity bean class.

The second method is necessary for implementing compound keys, and the first method is convenient for single-field keys. Without the first method, simple types such as String would have to be wrapped in a user-defined class.

The first method requires that the the bean provider uses the primkey-field element of the deployment descriptor to specify the container-managed field of the entity bean class that contains the primary key. The field's type must be the primary key type.

The second method requires the use of a primary key class which must be public, and must have a public constructor with no parameters. All fields in the primary key class must be declared as public. The names of the fields in the primary key class must be a subset of the names of the container-managed fields. (This allows the container to extract the primary key fields from an instance’s container-managed fields, and vice versa.)

The Enterprise JavaBeans architecture allows a primary key class to be any class that is a legal Value Type in RMI-IIOP, subject to the some restrictions. The primary key class may be specific to an entity Bean class (i.e., each entity bean class may define a different class for its primary key, but it is possible that multiple entity beans use the same primary key class).

A primary key must implement the Serializable interface. EJB 1.1 requires that the hashCode and equals methods be overridden and allows the PK to be defined by the bean developer or its definition can be deferred until deployment.

import javax.ejb.*;
public class MyBeanPK implements java.io.Serializable
{
  public String someFieldToUseAsPK;
  public MyBeanPK() { someFieldToUseAsPK = null; }
  public MyBeanPK(String s) { someFieldToUseAsPK = s; }
  public int hashCode() { ... }
  public boolean equals(Object obj) { ... }
}

Every entity object has a unique identity within its home. If two entity objects have the same home and the same primary key, they are considered identical.

Types of EJB

Session or Entity Beans

There are two types of beans in the EJB specification, Session and Entity beans.

Session beans represent business logic, rules, and workflow. They perform some sort of work for the client that is calling them. Important features of Session beans:

  • Never used by more than one client at a time
  • Lifetime is roughly the same as the period during which the client interacts with the bean

Entity beans represent data that is stored in a database or some persistent storage. Important features of Entity beans:

  • Persistent across client sessions and the lifetime of the server
  • Have a unique identity used for lookup
  • Multiple clients can access at once – the container manages this concurrency.
  • Persistence of the data the bean represents is either “container” or “bean” - managed

Message Driven Beans

New in the EJB2.0 spec. Probably not in the test, but here for completeness:

When to Use Messaging

  • For better DB performance. Reduce load by putting request onto queue and DB will process later.
  • Quick response. For methods that return void, don’t keep client waiting by blocking.
  • Smooth load balancing. Have servers pull for the message instead of load balancer push to the ones they guess are least burdened.
  • Prioritize requests.
  • Integrate disparate systems because many legacy systems use messaging.
  • Loosely coupled systems so that applications don’t have to know about each other at compile time.
  • Geographically disperse systems
  • Parallel processing by launching a series of messages and continue processing.
  • Reliability by using persistent queues and topics.
  • Many-to-many communications.

When Not to Use Messaging

  • When you’re not sure if the operation will succeed. Synchronous calls can throw exceptions.
  • When you need a return value on the method.
  • When you need an operation to be part of a larger transaction.
  • When you need to propagate the client’s identity to the server.
  • When you are concerned about request performance. Messaging takes a hit because of messaging middleman such as queue or topic.
  • When you need strongly-typed OO system.
  • When you want a tighter, more straightforward system.

Can offer better performance because client does not block waiting for server to process request. However, may take performance hit from messaging middleman.

Can offer better reliability because messages can be stored in persistent queue and you can define quality of service.

Supports multiple sends and receivers.

Publish/Subscribe: Many to many. Uses a topic.

Point-to-Point: One to one???.…many consumers can register with the queue but message is consumed only once.

Session: Stateful or Stateless

Session beans can be either stateless of stateful.

Stateless Session beans do not maintain state across method calls. The Session bean returns to the same state after each successive call to one of its methods from a client. This makes a stateless Session bean more poolable for performance and accessible from multiple clients (one at a time) without fear of conflict. Stateless Session beans are never passivated, but just destroyed (or removed from the pool) when no longer needed. Stateless beans cannot participate in any transaction synchronization (e.g. implement interface SessionSynchronization). A stateless session bean is only dedicated to an EJB object for the duration of the method.

Stateful Session beans maintain a state that can be accessed and changed across multiple client interactions with the bean’s methods. Stateful Session beans are accessed by only a single client and can be passivated by the container.

At deployment time, you indicate to the container whether a Session bean is stateful or stateless with an identifier in the deployment descriptor.

Which to use?

Entity beans do not contain business process logic; they model data. Examples of persistent data include things like “account”, “customer”, “order line”, etc.

Session beans model business processes such as performing a credit card verification, reserving a room, etc. Some processes require a single method call (stateless) to complete, while other processes may require repeated calls that require storing state information across these calls (stateful). An example of a stateful process would be a bean that tracks an on-line shopper’s cart, the contents of which must be maintained across multiple calls to the bean. Code that represents a bank teller interacting with a customer might also need to track account balance or credit limit across multiple banking transactions in a single interaction with the customer.

Recognizing the type of bean to use begins by asking, “is this a process or a persistent thing I’m working with” (session versus entity) and if it is a process, asking “is this a single method call with no need to reference prior state or do I need multiple transactions with a stored state to accomplish this process?” (stateless versus stateful).

Container Managed Persistence

An Entity Bean comes in two forms.

  1. Container Managed Persistence (CMP)
  2. Bean Managed Persistence (BMP)
1. Container Managed Persistence

The term container-managed persistence means that the EJB container handles all database access required by the entity bean. The bean's code contains no database access (SQL) calls. As a result, the bean's code is not tied to a specific persistent storage mechanism (database). Because of this flexibility, even if you redeploy the same entity bean on different J2EE servers that use different databases, you won't need to modify or recompile the bean's code. In short, your entity beans are more portable.

Benefits:

  • Portability: Database Independence - No need to hard code against a specific database API to accomplish these things (although JDBC may give you this anyway)
  • Portability: Container Independence - Although the deployment descriptors will change the code shouldn't need to - although this may also be true with BMP
  • Code Reduction – CMP performs all data access logic without the need to write any JDBC code, reducing the amount of code needed and hence development time for the bean.
  • Enhances Software Quality – JDBC code is not “type-safe” and is frequently buggy because it cannot be verified until runtime. The developer who wrote the container likely writes better data access code than you do and usually provides contained tools that allow detecting of errors at compile time. The better the container, the more your Entity bean code improves in quality.
  • Productivity – don’t have to write/debug tedious database mapping code
  • Performance – the container can implement caching, although the lack of specialism for a particular task may adversely affect performance

Costs:

  • Portability: Databases portability - across databases is not yet perfect. Specifying persistence semantics is not standardized yet and what BEA requires you to do to map your objects to relational fields may be inconsistent with another container vendor. If mapping your objects to relational tables is not 1:1 or you need complicated SQL joins in finder methods, some containers lack the ability to handle this.
  • Portability: Container - not all containers require you to write absolutely zero persistence code. Most containers at least require you to navigate a wizard to specify persistent fields and that you specify the logic for your finder methods. In EJB1.x, deployment of CMP wasn’t portable [to investigate]
  • Lack of Control - if there is a bug, it is hard to see what database operations the container is actually executing in order to troubleshoot the problem.
  • Simplistic Mapping - some containers may not support mapping of complex field types to underlying storage. Example: your entity bean class has a vector as a persistent member field. You may have to convert this vector to some other type that the container can persist for you.
    EJB 1.1 allows the CMP fields to include remote references to EJB objects (remote interface types) and EJB homes (home interface types). EJB 1.0 only allowed Java primitives and serializable types.
  • Legacy support – not every data store is a database but most vendors only support DB mapping

CMP has the following considerations:

  • Data Aliasing - An update of a data item done through a container-managed field of one entity bean may not be visible to another entity bean in the same transaction if the other entity bean maps to the same data item.
  • Eager Loading of State – The container loads the entire object stateinto the container-managed fields before invoking the ejbLoad method.
2. Bean Managed Persistence

Bean Managed Persistence (BMP) required the Application Developer to write logic to persist and restore data to a backing store. This is typically done using JDBC, potentially through the use of Data Access Objects.

Transactions

A transaction is an atomic set of steps which must either all complete (commit) or none of which must complete (rollback). After a rollback everything is as it was before the transaction started.

Transactions are said to have the ACID properties (Atomic, Consistent, Isolation, and Durable) : [taken from nusphere.com]

Atomicity
A transaction allows for the grouping of one or more changes to tables and rows in the database to form an atomic or indivisible operation. That is, either all of the changes occur or none of them do. If for any reason the transaction cannot be completed, everything this transaction changed can be restored to the state it was in prior to the start of the transaction via a rollback operation.
Consistency
Transactions always operate on a consistent view of the data and when they end always leave the data in a consistent state. Data may be said to be consistent as long as it conforms to a set of invariants, such as no two rows in the customer table have the same customer id and all orders have an associated customer row. While a transaction executes these invariants may be violated, but no other transaction will be allowed to see these inconsistencies, and all such inconsistencies will have been eliminated by the time the transaction ends.
Isolation
To a given transaction, it should appear as though it is running all by itself on the database. The effects of concurrently running transactions are invisible to this transaction, and the effects of this transaction are invisible to others until the transaction is committed.
Durability
Once a transaction is committed, its effects are guaranteed to persist even in the event of subsequent system failures. Until the transaction commits, not only are any changes made by that transaction not durable, but are guaranteed not to persist in the face of a system failure, as crash recovery will rollback their effects.

Within a container transactions can either be:

  1. Container Managed Transactions
  2. Bean Managed Transactions
1. Container Managed Transactions

In an enterprise bean with container-managed transactions, the EJB container sets the boundaries of the transactions. You can use container-managed transactions with any type of enterprise bean: session, entity, or message-driven. Container-managed transactions simplify development because the enterprise bean code does not explicitly mark the transaction's boundaries. The code does not include statements that begin and end the transaction.

Typically, the container begins a transaction immediately before an enterprise bean method starts. It commits the transaction just before the method exits. Each method can be associated with a single transaction. Nested or multiple transactions are not allowed within a method.

Container-managed transactions do not require all methods to be associated with transactions. When deploying a bean, you specify which of the bean's methods are associated with transactions by setting the transaction attributes. [from Sun J2EE Tutorial]

In EJB1.0 CMT, it was possible to control transaction further by setting the transaction isolation level in the deployment descriptor on a per method basis. In EJB1.1 CMT, it’s still possible to change the isolation level but it’s container dependent. [need to check EJB2.0]

A transaction attribute controls the scope of a transaction, and so defines which transaction a method called by another method is run in. The options are: [from Sun J2EE Tutorial]

Required
If the client is running within a transaction and invokes the enterprise bean's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container starts a new transaction before running the method.
The Required attribute will work for most transactions. Therefore, you may want to use it as a default, at least in the early phases of development. Because transaction attributes are declarative, you can easily change them at a later time.
RequiresNew
If the client is running within a transaction and invokes the enterprise bean's method, the container takes the following steps:
  1. Suspends the client's transaction
  2. Starts a new transaction
  3. Delegates the call to the method
  4. Resumes the client's transaction after the method completes
If the client is not associated with a transaction, the container starts a new transaction before running the method.
You should use the RequiresNew attribute when you want to ensure that the method always runs within a new transaction.
Mandatory
If the client is running within a transaction and invokes the enterprise bean's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container throws the TransactionRequiredException.
Use the Mandatory attribute if the enterprise bean's method must use the transaction of the client.
NotSupported
If the client is running within a transaction and invokes the enterprise bean's method, the container suspends the client's transaction before invoking the method. After the method has completed, the container resumes the client's transaction.
If the client is not associated with a transaction, the container does not start a new transaction before running the method.
Use the NotSupported attribute for methods that don't need transactions. Because transactions involve overhead, this attribute may improve performance.
Supports
If the client is running within a transaction and invokes the enterprise bean's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container does not start a new transaction before running the method.
Because the transactional behavior of the method may vary, you should use the Supports attribute with caution.
Never
If the client is running within a transaction and invokes the enterprise bean's method, the container throws a RemoteException. If the client is not associated with a transaction, the container does not start a new transaction before running the method.

In summary:

Requires RequiresNew Mandatory NotSupported Supports Never
uses existsing or creates new suspends existing and creates uses existing otherwise throws exception suspends any existing uses if existing throws exception if existing
2. Bean Managed Transactions

In a bean-managed transaction, the code in the session or message-driven bean explicitly marks the boundaries of the transaction. An entity bean cannot have bean-managed transactions; it must use container-managed transactions instead. Although beans with container-managed transactions require less coding, they have one limitation: When a method is executing, it can be associated with either a single transaction or no transaction at all. If this limitation will make coding your bean difficult, you should consider using bean-managed transactions.

When coding a bean-managed transaction for session or message-driven beans, you must decide whether to use JDBC or JTA transactions. The sections that follow discuss both types of transactions.

A JDBC transaction is controlled by the transaction manager of the DBMS. You may want to use JDBC transactions when wrapping legacy code inside a session bean. To code a JDBC transaction, you invoke the commit and rollback methods of the java.sql.Connection interface. The beginning of a transaction is implicit. A transaction begins with the first SQL statement that follows the most recent commit, rollback, or connect statement. (This rule is generally true, but may vary with DBMS vendor.)

JTA is the abbreviation for the Java Transaction API. This API allows you to demarcate transactions in a manner that is independent of the transaction manager implementation. The J2EE SDK implements the transaction manager with the Java Transaction Service ("JTS"). But your code doesn't call the JTS methods directly. Instead, it invokes the JTA methods, which then call the lower-level JTS routines.

A JTA transaction is controlled by the J2EE transaction manager. You may want to use a JTA transaction because it can span updates to multiple databases from different vendors. A particular DBMS's transaction manager may not work with heterogeneous databases. However, the J2EE transaction manager does have one limitation--it does not support nested transactions. In other words, it cannot start a transaction for an instance until the previous transaction has ended.

Entity beans should not use bean-managed transactions because you need to do ejbLoad() before a transaction and an ejbStore() after a transaction but the bean itself can never explicitly call those methods.

Transaction Management

Dirty Read
A dirty read occurs when the first transaction reads uncommitted changes made by a second transaction. If the second transaction is rolled back, the data read by the first transaction becomes invalid because the rollback undoes the changes.
Repeatable Read
A repeatable read is when the data read is guaranteed to look the same if read again during the same transaction.
Phantom Read
Phantom reads occur when new records added to the database are detectable by transactions that started prior to the insert. Queries will include records added by other transactions after their transaction has started.
Isolation levels are commonly used in database systems to describe how locking is applied to data within a transaction.
Read Uncommitted
The transaction can read uncommitted data. Dirty reads, nonrepeatable reads, and phantom reads can occur.
Read Committed
The transaction cannot read uncommitted data. Dirty reads are prevented; nonrepeatable reads and phantom reads can occur. Bean methods with this isolation level cannot read uncommitted data.
Repeatable Read
The tx cannot change data that is being read by a different tx. Dirty reads and nonrepeatable reads are prevented; phantom reads can occur. Bean methods with this isolation level have the same restrictions as Read Committed and can only execute repeatable reads.
Serializable
The transaction has exclusive read and update privileges to data; different transactions can neither read nor write the same data. Dirty reads, nonrepeatable reads, and phantom reads are prevented. Most restrictive isolation level.

Security

The standard Java security features apply (see the Security section). J2EE also had additional security mechanisms.

Within an EJB component security roles are defined - a role is a logical user (e.g. admin, customer). When the component is deployed, the role is mapped to “real” J2EE users/groups (e.g. PJC is able to assume the admin role).

To access secure resources, the Subject (client) must be authenticated and authorized :

Authentication.
To authenticate, the Subject must present their Credentials (e.g. username/password) to the
container. If the authentication is successful, the Subject is associated with one or more Principal objects.
Authentication is not currently part of the EJB specification – e.g. the credentials may be
passed as properties to an InitialContext, JAAS or JNDI may be used, etc.
Authorisation (access control).
Once authenticated, the Principal(s) can be checked against the Role to decide if the client is authorised to access the secure resource.
Role based authorisation is fully supported by J2EE – security constraints in web.xml, method level security in EJB deployment descriptor, “runAs” in deployment descriptor.
Instance based authorisation (e.g. PJC is only allowed access to PJC’s account) isn’t yet
specified

EJB supports declarative security (programmatic security is also supported) by setting the appropriate values in the deployment descriptor :

<method-permission>
<role-name>admin</role-name>
<method>
<ejb-name>Account</ejb-name>
<method-name>*</method-name> </method>
</method-permission>


Not very portable at the moment – authentication and “runAs” are container specific; container to container security propagation is undefined.

J2EE also has other built-in security features :

  • web-tier authentication – via HTTP authentication, forms, client certificates
  • secure communications – SSL; web-tier authentication can use SSL for HTTP/FORM authenticaton
  • security packages – digests, digital signatures, ciphers, certificates, etc.

Data Access Objects

EJBs are remote objects that consume significant system resources and network bandwidth. You can use Data Access Objects to encapsulate the logic required to access databases.

The intent of DAOs is to decouple business logic from data access logic and adapt the resource being accessed, so that the type of resource can change easily and independently.

Advantages.

  • transparency – specifics of data access are hidden from the entity bean
  • modular – the DAO could be swapped for another with little disruption to the entity bean code
  • cleaner code - data access factored out so simplifies entity bean code
  • reusable – DAO could be re-used in a “Fast Lane Reader”
  • future-proof - provide an easier migration path to CMP

Disadvantages.

  • only suitable for BMP
  • extra code - have to write DAO class, DAO wrapper calls in entity bean, maybe some DAO factories
 

Links

  1. Mastering Enterprise Java Beans II by Ed Roman, Scott Ambler, Tyler Jewell, Floyd Marinescu [download for free]
  2. EJB Design Patterns by Floyd Marinescu [download for free]
  3. Enterprise JavaBeans by Richard Monson-Haefal
  4. EJB 2.0 Specification
  5. SCEA nutshell on yahoo groups
  6. Sun J2EE Tutorial
    1. EJB Concepts
    2. Transaction
  7. Data Access Objects as a J2EE pattern
  8. Ian's EJB Test
 

Observations

  • When to use which EJB based on scenarios described
  • Another question covered the passivation and the effect on resources, another change in EJB 1.1
  • Know EJBs really well (no duh, huh?) to a very detailed level. Understand how the different components of a bean react to events and perform their functions. I'd recommend reading all of the Enterprise JavaBeans book (from O'reilly) except for the first and last chapters and chapters 4, 5, 6, 8, and 9 of the EJB 1.1 spec.
  • About 10 questions about ejb including bean life cycle, transaction isolation, security.
  • There is no question specifically to ejb API.

Page created by Leo Crawford
last updated in June 2002