Previous     Contents     Index     DocHome     Next     
iPlanet Application Server Programmer's Guide (Java)



Chapter 6   Building Entity EJBs


This chapter describes what an entity EJB is and what entity beans must contain. It also provides additional guidelines for creating entity beans and for determining the entity beans needs of an application.

This chapter contains the following sections:

All specifications are accessible from installdir/ias/docs/index.htm, where installdir is the location where the iPlanet Application Server is installed.



Introducing Entity EJBs



The heart of a distributed, multi-user application involves interactions with datasources which are often transactional, such as to a database or an existing legacy application. In most cases, the external datasource or business object is transparent to the user, or is shielded or buffered from direct user interaction. These protected, transactional, and persistent interactions with databases, documents, and other business objects, are candidates for entity EJB encapsulation.

Business EJBs are self-contained, reusable components—with data members, properties, and methods—that represent generic instances, transactionally aware, persistent data objects that are shared among clients. Persistence refers to the creation and bean maintenance throughout the application's lifetime.

There are two persistence management types and the iPlanet Application Server supports both types as listed below.

  • Container managed persistence - this is when the container is responsible for the bean persistence.

  • Bean managed persistence - this is when the bean is responsible for their own persistence.

A developer, codes a bean managed entity bean by providing database access calls—via JDBC or SQL—directly in the bean class methods. Database access calls must be in the ejbCreate(), ejbRemove(), ejbFindXXX(), ejbLoad(), and ejbStore() methods. The bean managed persistence advantage is these beans can be in any container without requiring the container to generate database calls.

Entity beans rely on the container to manage security, concurrency, transactions, and other, container specific services for the entity objects it manages. Multiple clients can access an entity object at the same time and the container transparently handles simultaneous accesses through transactions.

As an application developer, you cannot access the container's entity bean services directly, nor do you ever need to. Instead, the container is there to take care of low level implementation details so that you focus on the larger role the entity bean plays in an application picture.

Clients access an entity bean through the bean's remote interface. The object that implements the remote interface is called the EJB object. Usually, an entity EJB is shared among multiple clients and represents a single entry point to a data resource or business object, such as a database. Regardless of which client accesses an entity object at a given time, each client's object view is both location independent and transparent to other clients.

Finally, any number of entity beans can be installed in a container. The container implements a home interface for each entity bean. The home interface enables a client to create, look up, and remove entity objects. A client can look up an entity bean's home interface through Java Naming and Directory Interface (JNDI).

An entity bean includes the following attributes:

  • Represents data in a database.

  • Supports transactions.

  • Executes for multiple clients.

  • Persists for as long as needed by all clients.

  • Transparently survives server crashes.

Generally, an entity bean represents shared data in a database and is transaction aware. Their operations always take place in the context of transactions managed by the bean's container.


How an Entity Bean is Accessed

A client, such as a browser or servlet, accesses an entity bean through the bean's remote interface, EJBObject. An EJB object is a remote Java programming language object accessible from the client through standard Java APIs for remote object calls. The EJB lives in the container from its creation to its destruction, and the container manages the EJB's life cycle and support services.

A client never accesses an entity bean instance directly. Instead, a client uses the entity bean's remote interface to access a bean instance. The EJB object class that implements an entity bean's remote interface is provided by the container. At a minimum, an EJB object supports all methods of the java.ejb.EJBObject interface. This includes methods to obtain the entity bean's home interface, to get the object's handle, to retrieve the entity's primary key, to test if the object is identical to another object, and to remove the object. These methods are stipulated by the EJB specification. In addition, the remote interface for most EJB objects also support specific business logic methods. These are the methods at the heart of your specific application.

All specifications are accessible from installdir/ias/docs/index.htm, where installdir is the location where the iPlanet Application Server is installed.



Entity Bean Components



When creating an entity bean you must provide the following class files:

  • Enterprise bean class

  • Enterprise bean home interface, javax.ejb.EJBHome

  • Enterprise bean remote interface, javax.ejb.EJBObject


Creating the Class Definition

For an entity bean, the bean class must be defined as public and cannot be abstract. The bean class must implement the javax.ejb.EntityBean interface. For example:

import java.rmi.*;
import java.util.*;
import javax.ejb.*;
public class MyEntityBean implements EntityBean {
// Entity Bean implementation. These methods must always included.
public void ejbActivate() throws RemoteException {
}
public void ejbLoad() throws Remote Exception {
}
public void ejbPassivate() throws RemoteException {
}
public void ejbRemove() throws RemoteException{
}
public void ejbStore() throws RemoteException{
}
public void setEntityContext(EntityContext ctx) throws RemoteException {
}
public void unsetEntityContext() throuws RemoteException {
}
// other code omitted here....
}

In addition to these methods, the entity bean class must also define one or more ejbCreate() methods and the ejbFindByPrimaryKey() finder method. Optionally, it may also define one ejbPostCreate() method for each ejbCreate() method. It may optionally provide additional, developer defined finder methods that take the form ejbFindXXX, where XXX represents a unique method name continuation (for example, ejbFindApplesAndOranges) that does not duplicate any other method names.

Finally, most useful entity beans also implement one or more business methods. These methods are usually unique to each bean and represent its particular functionality. Business method names can be anything you want, but must not conflict with the method names used in the EJB architecture. Business methods must be declared as public. Method arguments and return value types must be Java RMI legal. The throws clause may define application specific exceptions and may include java.rmi.RemoteException.

There are two business method types to implement in an entity bean: internal ones, are used by other business methods in the bean, but never accessed outside the bean itself; and external ones, are referenced by the entity bean's remote interface.

The following sections describe the various methods in an entity bean's class definition in more detail.

The examples in these sections assume the following member variable definitions:

private transient javax.ejb.EntityContext m_ctx = null;

// These define the state of our bean
private int m_quantity;
private int m_totalSold;


Using ejbActivate and ejbPassivate

When an entity bean instance is needed by a server application, the bean's container invokes ejbActivate() to ready a bean instance for use. Similarly, when an instance is no longer needed, the bean's container invokes ejbPassivate() to disassociate the bean from the application.

If, specific application tasks need to be performed when a bean is first made ready for an application or needs to be performed when a bean is no longer needed, program those operations within these methods.

Activation is not the same as creating a bean. You can only activate a bean that has already been created. Similarly, passivation is not the same as removing a bean. Passivation merely returns a bean instance to the container pool for later use. ejbRemove() is required to actually terminate a bean instance.

The container passivates session beans after they are inactive for a specified (or default) time. This timeout value is set in the bean's property file. For more information, see "EJB XML DTD".

For more information about ejbCreate() and ejbRemove(), see Using ejbCreate Methods.

For more information about ejbActivate() and ejbPassivate(), see the EJB specification. All specifications are accessible from installdir/ias/docs/index.htm, where installdir is the location where the iPlanet Application Server is installed.


Using ejbLoad and ejbStore

An entity bean should permit its container to store the bean state information in a database for synchronization purposes. Use your implementation of ejbStore() to store state information in the database and use your implementation of ejbLoad() to retrieve state information from the database. When the container calls ejbLoad(), it synchronizes the bean state by loading state information from the database.

The following example shows ejbLoad() and ejbStore() method definitions that store and retrieve active data.

public void ejbLoad()
      throws java.rmi.RemoteException
{
   String itemId;
   DatabaseConnection dc = null;
   java.sql.Statement stmt = null;
   java.sql.ResultSet rs = null;

   itemId = (String) m_ctx.getPrimaryKey();

   System.out.println("myBean: Loading state for item " + itemId);

   String query =
      "SELECT s.totalSold, s.quantity " +
      " FROM Item s " +
      " WHERE s.item_id = " + itemId;

   dc = new DatabaseConnection();
   dc.createConnection(DatabaseConnection.GLOBALTX);
   stmt = dc.createStatement();
   rs = stmt.executeQuery(query);

   if (rs != null) {
      rs.next();
      m_totalSold = rs.getInt(1);
      m_quantity = rs.getInt(2);
   }
}

public void ejbStore()
      throws java.rmi.RemoteException
{
   String itemId;
   itemId = (String) m_ctx.getPrimaryKey();
   DatabaseConnection dc = null;
   java.sql.Statement stmt1 = null;
   java.sql.Statement stmt2 = null;

   System.out.println("myBean: Saving state for item = " + itemId);

   String upd1 =
      "UPDATE Item " +
      " SET quantity = " + m_quantity +
      " WHERE item_id = " + itemId;

   String upd2 =
      "UPDATE Item " +
      " SET totalSold = " + m_totalSold +
      " WHERE item_id = " + itemId;

   dc = new DatabaseConnection();
   dc.createConnection(DatabaseConnection.GLOBALTX);
   stmt1 = dc.createStatement();
   stmt1.executeUpdate(upd1);
   stmt1.close();
   stmt2 = dc.createStatement();

   stmt2.executeUpdate(upd2);
   stmt2.close();
}



Note For related information about bean isolation levels that access transactions concurrently with other beans, see Handling Concurrent Access.




Using setEntityContext and unsetEntityContext

A container calls setEntityContext() after it creates an entity bean instance to provide the bean's interface to the container. Implement this method, to store the container reference in an instance variable.

public void setEntityContext(javax.ejb.EntityContext ctx)
{
m_ctx = ctx;
}

Similarly, a container calls unsetEntityContext() to remove the container reference from the instance. This is the last bean class method a container calls. After this call, the Java garbage collection mechanism eventually calls finalize() on the instance to clean it up and dispose it.

public void unsetEntityContext()
{
m_ctx = null;
}


Using ejbCreate Methods

The entity bean must also implement one or more ejbCreate(...) methods. There is one method for each way a client is allowed to invoke the bean. For example:

public int ejbCreate() {
   string[] userinfo = {"User Name", "Encrypted Password"};
}

Each ejbCreate() method must be declared as public, return either the entity's primary key type or a collection, and be named ejbCreate. The return type can be any legal Java RMI type that can convert to a number for key purposes. Any arguments must be legal Java RMI types. The throws clause, may define application specific exceptions, and may include java.rmi.RemoteException and/or java.ejb.CreateException.

For each ejbCreate() method, the entity bean class may also define an ejbPostCreate() method to handle entity services immediately following creation. Each ejbPostCreate() method must be declared as public, must return void, and be named ejbPostCreate. The method arguments, if any, must match in number and argument type of its corresponding ejbCreate method. The throws clause, may define application specific exceptions, and may include java.rmi.RemoteException and/or java.ejb.CreateException.

Finally, an entity bean also implements one or more ejbRemove() methods to free a bean when it is no longer needed.


Using Finder Methods

Because entity beans are persistent, are shared among clients, and may have more than one instance instantiated at the same time, an entity bean must implement at least one method, FindByPrimaryKey(), that enables the client and the bean's container to locate a specific bean instance. All entity beans must provide a unique primary key as an identifying signature. You can implement the FindByPrimaryKey() method in the bean's class to enable a bean to return its primary key to the container.

The following example shows a definition for FindByPrimaryKey():

public String ejbFindByPrimaryKey(String key)
      throws java.rmi.RemoteException,
         javax.ejb.FinderException
{
   //System.out.println("@@@ myBean.ejbFindByPrimaryKey key = " + key);
   return key;
}

In some cases, you may want to find a specific entity bean instance based on what the bean does, based on certain values the instance is working with, or based on other criteria. These implementation specific finder method names take the form ejbFindXXX, where XXX represents a unique continuation of a method name (for example, ejbFindApplesAndOranges) that does not duplicate any other method names.

Finder methods must be declared as public, and their arguments and return values must be legal Java RMI types. Each finder method return type must be the entity bean's primary key type or a collection of objects of the same primary key type. If the return type is a collection, the return type must be java.util.Enumeration.

The throws clause of a finder method is an application specific exception, and may include java.rmi.RemoteException and/or java.ejb.FinderException.


Declaring vs. Implementing the Remote Interface

A bean class definition must include one matching method definition including matching method names, arguments, and return types, for each method defined in the bean's remote interface. The EJB specification also permits the bean class to implement the remote interface's methods, but recommends against this practice to avoid inadvertently passing a direct reference (via this) to a client in violation of the client-container-EJB protocol intended by the specification.


Creating the Home Interface

The home interface defines the methods that enables a client accessing your application to create and remove entity objects. A home interface always extends javax.ejb.EJBHome. For example:

import javax.ejb.*;
import java.rmi.*;

public interface MyEntityBeanHome extends EJBHome {
   MyEntityBean create() throws CreateException, RemoteException;
}

As this example illustrates, an entity bean's home interface defines one or more create methods. Usually the home interface also defines one or more find methods corresponding to the finder methods in the bean class.


Defining Create Methods

Each method must be named create, and must correspond in number and argument types to an ejbCreate method defined in the entity bean class. The return type for each create method, however, does not match the corresponding ejbCreate method's return type. Instead, it must return the entity bean's remote interface type.

All exceptions defined in the throws clause of an ejbCreate method must be defined in the throws clause of the matching create method in the home interface. In addition, the throws clause in the home interface must always include javax.ejb.CreateException.


Defining Find Methods

A home interface can define one or more find methods. Each method must be named findXXX (e.g., findApplesAndOranges), where XXX is a unique method name continuation. Each finder method must correspond to one of the finder methods defined in the entity bean class definition. The number and argument types must also correspond to the finder method definitions in the bean class. The return type, however, may be different. The finder method's return type in the home interface must be the entity bean's remote interface type or a collection of interfaces.

Finally, all home interfaces automatically define two remove methods for destroying an EJB when it is no longer needed.



Note Do not override these methods.




Creating the Remote Interface

An entity bean's remote interface defines a user's access to a bean's methods. All remote interfaces extend javax.ejb.EJBObject. For example:

import javax.ejb.*;
import java.rmi.*;
public interface MyEntityBean extends EJBObject {
// define business method methods here....
}

The remote interface defines the entity bean's business methods that a client calls. The business methods defined in the remote interface are implemented by the bean's container at runtime. For each method you define in the remote interface, you must supply a corresponding method in the bean class. The corresponding method in the bean class must have the same signature.

Besides the business methods you define in the remote interface, the EJBObject interface defines several abstract methods that enables you to retrieve the bean's home interface, to retrieve the bean's handle, to retrieve the bean's primary key which uniquely identifies the bean's instance, to compare the bean to another bean to see if it is identical, and to remove the bean when it is no longer needed.

For more information about these built-in methods and how they are used, see the EJB specification. All specifications are accessible from installdir/ias/docs/index.htm, where installdir is the location where the iPlanet Application Server is installed.



Additional Entity Bean Guidelines



Before you decide what application parts you can represent as entity beans, you should consider a few more guidelines. A couple of these are related to the EJB specification for entity beans, and a couple are specific to the iPlanet Application Server and its support for entity beans.


Accessing iPlanet Application Server Functionality

You can develop entity beans that adhere strictly to the EJB specification, you can develop entity beans that take advantage of both the specification and additional, value-added iPlanet Application Server features, and you can develop entity beans that adhere to the specifications in non-iPlanet Application Server environments but take advantage of the iPlanet Application Server features if they are available. Make the choice that is best for your intended deployment scenario.

The iPlanet Application Server offers several features through the iPlanet Application Server container and the iPlanet Application Server APIs that enables your applications to take programmatic advantage of specific iPlanet Application Server environment features. You can embed API calls in your entity beans if you plan on using those beans only in an iPlanet Application Server environment.


Serializing Handles and References

The EJB specification indicates that to guarantee serializable bean references, you should use handles rather than direct references to EJBs.

The iPlanet Application Server direct references are also serializable. You may wish to take advantage of this extension, but be aware not all vendors support it.


Managing Transactions

Most entity beans interact with databases. You can control transactions in beans using settings in the bean's property file. This permits you to specify transaction attributes at bean deployment time. By having a bean handle transaction management you are freed from having to explicitly start, rollback, or commit transactions in the bean's database access methods.

By moving transaction management to the bean level, you gain the ability to place all bean activities—even those not directly tied to database access—under the same transaction control as your database calls. This guarantees that all application parts controlled by an entity bean run as part of the same transaction, and either everything the bean undertakes is committed, or is rolled back because of a failure. In effect, bean managed transactional state permits you to synchronize your application without having to code any synchronization routines.


Committing a Transaction

When a commit occurs, it signals the container that the entity bean has completed its useful work and should synchronize its state with the underlying datasource. The container permits the transaction to complete and then returns the bean to the pool for later reuse. Result sets associated with a committed transaction are no longer valid. Subsequent requests for the same bean cause the container to issue a load to synchronize state with the underlying datasource.

Note that transactions begun in the container are implicitly committed. Also, any participant can rollback a transaction. For details about transactions, see Chapter 7 "Handling Transactions with EJBs."


Commit Options B and C

Commit options B and C are supported by the iPlanet Application Server CMP.

  • Commit option B caches the entity bean instance between method invocations. The instance retains it's association with a particular primary key and is not yet returned to the free pool of unassociated instances. When the instance's stay in the ready cache exceeds the ready cache timeout value, the container transitions the instance back to the free pool.

  • Commit option C gets an bean instance from the free pool at the start of a transaction and transitions the instance back to the free pool at the end of the transaction.



    Note If the entity bean has the TX_NOT_SUPPORTED attribute set and the commit option B defined, the bean performs read only data caching.



The operation rules for commit option B are a little more complex than for commit option C. The following examples help explain the differences.


Example 1
This is the lifecyle for several business method invocations by a single transactional client.

On the first invocation (no ready instance has been cached):

ejbActivate -> ejbLoad -> business method-> ejbStore-> (instance is put in ready cache)

On subsequent invocations:

(retrieve ready instance)-> ejbLoad -> business method -> ejbStore-> (instance is returned to ready cache)

In comparison, the lifecycle for every business method invocation under commit option C looks like this:

ejbActivate-> ejbLoad -> business method -> ejbStore -> ejbPassivate

If there is more than one transactional client concurrently accessing the same entity EJBObject, the first client gets the ready instance and subsequent concurrent clients get new instances from the pool. The lifecycle for these new instances are the same as if they were operating under commit option C.


Example 2
This is the lifecyle for several business method invocations by a single non-transactional client.

On the first invocation (no ready instance has been cached):

ejbActivate -> ejbLoad -> (instance is put in ready cache)-> business method

On subsequent invocations:

(get reference to ready instance) -> business method

Multiple non-transactional clients can access the ready instance concurrently. The bean, therefore, must be declared as reentrant.

If a transactional client is using the ready instance, non-transactional clients are blocked until the transaction completes.


Handling Concurrent Access

As an entity bean developer, you do not have to be concerned about concurrent access to an entity bean from multiple transactions. The bean's container automatically provides synchronization in these cases. In an iPlanet Application Server, the iPlanet Application Server container activates one entity bean instance for each simultaneously occurring transaction that uses the bean. Transaction synchronization is performed automatically by the underlying database during database access calls.

The iPlanet Application Server EJB container implementation does not provide its own synchronization mechanism when multiple transactions try to access an entity bean. It creates a new entity bean instance for every new transaction. The iPlanet Application Server container delegates the responsibility of the application synchronization.

You typically perform this synchronization in conjunction with the underlying database or resource. One approach would be to acquire the corresponding database locks in the ejbLoad() method, for example by choosing an appropriate isolation level or by using a select for update clause. The specifics depend on the database being used. For more information, see the EJB specification as it relates to concurrent access.

The following example ejbLoad() snippet illustrates the select for update syntax to obtain database locks. This prevents other instances from being loaded at the same time.

public void ejbLoad() throws java.rmi.RemoteException
{
....
// Get the lock on the corresponding DB table
   try {
      java.sql.Connection dbConn = ds.getConnection();
      String query = "SELECT accountNum, balance FROM accounts "
         + "WHERE customerId = ? FOR UPDATE";
      prepStmt = dbConn.prepareStatement(query);
      prepStmt.setString(1, m_customerId);
      resultSet = prepStmt.executeQuery();
      if ((resultSet != null) && resultSet.next()) {
         acctNum = resultSet.getInt(1);
         acctBalance = resultSet.getInt(2);
      } else {
         throw new RemoteException("Database error. "
               + "Couldn't find accout");
      }
   } catch (java.sql.SQLException e) {
      throw new RemoteException("Database error. "
            + "Couldn't load account");
   } finally {
      try {
         if (resultSet != null)
            resultSet.close();
         if (prepStmt != null)
            prepStmt.close();
         if (dbConn != null)
            dbConn.disconnect();
         } catch (java.sql.SQLException e) {
         System.out.println("Unexpected exception while "
            + "closing resources"); }
   }
}


Accessing Databases

Most entity beans work with databases, and always use the transaction and security management methods in javax.ejb.deployment.ControlDescriptor to manage transaction requirements. For details about creating and managing transactions with beans, see Chapter 7 "Handling Transactions with EJBs."

To work with data in the context of a bean managed transaction, use JDBC. For details about using JDBC to work with data, see Chapter 8 "Using JDBC for Database Access."


Container Managed Persistence

If the container manages the entity bean's state storage to an underlying resource manager, you can use Container Managed Persistence (CMP) entity beans.

The iPlanet Application Server CMP provides:

  • Support for the J2EE v 1.2 specification CMP model.

  • Support multiple pluggable persistence managers in the server.

  • Provides the user with the iASDT to perform the object relational (O/R) mapping and creates the separate CMP DD XML files.

  • Support for sophisticated custom finder methods


How Container Managed Persistence Works

The EJB container needs two things to support CMP entity beans. First, it needs information on how to map an entity bean into a resource such as a table in a relational database. Second, it needs a CMP runtime environment that uses the mapping information to perform persistence operations on each bean.

The iPlanet Application Server supports multiple CMP solutions via an architecture known as Pluggable CMP (PCMP). A CMP solution consists of a mapping tool and a runtime environment. The mapping tool is used to generate mapping information for CMP entity beans. Typically this information is stored in an XML file. The CMP runtime environment is responsible for performing persistence operations.

The iPlanet Application Server ships with a mapping tool embedded in the Deployment Tool (iASDT). See the iASDT Online Help for information on how to generate mapping information. The iPlanet Application Server also provides CMP runtime environment reference implementation that utilizes the mapping information generated by the iASDT to perform persistence operations.


Pluggable Container Managed Persistence

The iPlanet Application Server supports CMP entity beans via the PCMP architecture. The primary architecture benefit is it separates the EJB container from the CMP runtime environment (also known as the persistence manager). The EJB container communicates with the persistence manager through a well defined open API. Using the API, the container is able to ask the persistence manager to perform various persistence operations throughout the entity bean's lifecycle. The persistence manager is responsible for performing the persistence operations, and may use caching and other techniques to improve performance.

PCMP is an open and well defined API. It is possible to write your own persistence manager to support legacy systems.


How to Use Persistence Managers in the iPlanet Application Server

Pluggable persistence managers allow users to set the persistence policies for a bean at deployment time. In order to use PCMP with a particular bean, you need to set a persistence manager factory class in the XML DD. The EJB container uses this factory class to create persistence managers during runtime.

The iASDT should be used to set the persistence manager factory class for a particular bean. See the Deployment Tool Online Help for information on how to modify the DD.

If you are using the iPlanet Application Server persistence manager reference implementation the factory class tag should have the value: com.netscape.server.ejb.SQLPersistenceManagerFactory


iPlanet Application Server Persistence Manager Reference Implementation

The iPlanet Application Server has a simple persistence manager reference implementation. The reference implementation uses mapping information generated by the iASDT. Users may also hand modify the mapping information file produced by iASDT to access additional features. For example, custom finder methods are not supported by the iASDT but may be added to the mapping information file by hand.


Previous     Contents     Index     DocHome     Next     
Copyright © 2000 Sun Microsystems, Inc. Some preexisting portions Copyright © 2000 Netscape Communications Corp. All rights reserved.

Last Updated January 25, 2001