Skip Headers
Oracle® Containers for J2EE Enterprise JavaBeans Developer's Guide
10g Release 3 (10.1.3)
B14428-02
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

15 Using EJB 2.1 BMP Entity Bean API

This chapter describes the various options that you must configure in order to use an EJB 2.1 BMP entity bean.

Table 15-1 lists these options and indicates which are basic (applicable to most applications) and which are advanced (applicable to more specialized applications).

For more information, see:

Table 15-1 Configurable Options for an EJB 2.1 BMP Entity Bean

Options Type

"Configuring a Read-Only BMP Entity Bean"


Advanced

"Configuring BMP Commit Options"


Advanced

"Configuring an EJB 2.1 BMP Entity Bean Query"


Basic

"Configuring a Lifecycle Callback Method for an EJB 2.1 BMP Entity Bean"


Basic


Configuring a Read-Only BMP Entity Bean

You can configure a BMP entity bean as read-only. By doing so, you enter into a contract with OC4J by which you guarantee not to change the BMP entity bean's state after it is activated. Unlike CMP read-only, no exception will be thrown if you do update a read-only BMP bean.

When you configure a BMP entity bean as read-only, OC4J uses a special case of commit option A (see "Configuring BMP Commit Options") to improve performance by:

As Figure 15-1 shows, multiple clients accessing the same read-only BMP entity bean by primary key are allocated a single instance. Both Client 1 and Client 2 are satisfied by the same cached read-only BMP entity bean instance. Because the BMP entity bean is read-only, both transactions can proceed in parallel.

Without this optimization, each client is allocated a separate instance and each instance requires the execution of all lifecycle methods.

Figure 15-1 Read-Only BMP Entity Beans and Commit Option A

Description of Figure 15-1 follows
Description of "Figure 15-1 Read-Only BMP Entity Beans and Commit Option A"

Using Deployment XML

Example 15-1 shows the orion-ejb-jar.xml file entity-deployment element locking-mode attribute mode configured to specify a BMP entity bean as read-only.

Example 15-1 orion-ejb-jar.xml For Read-Only

<entity-deployment
    name=EmployeeBean"
    location="bmpapp/EmployeeBean" 
    locking-mode="read-only"
>
...
</entity-deployment>

Configuring BMP Commit Options

For a BMP entity bean, you can choose between commit options A and C.

Commit option A offers a performance improvement by postponing a call to ejbLoad.

If you configure a read-only BMP entity bean to use commit option A (see "Configuring a Read-Only BMP Entity Bean"), you can further improve performance by taking advantage of read-only BMP entity bean caching (see "Commit Options and BMP Applications".

Commit option C is the default.

For more information, see "What are Entity Bean Commit Options?".

Using Deployment XML

Example 15-2 shows the orion-ejb-jar.xml file entity-deployment element commit-option sub-element attribute mode. Valid settings are A and C. The number-of-buckets attribute is the maximum number of cached instances allowed and is applicable only for commit option A.

Example 15-2 orion-ejb-jar.xml For Commit Options

<entity-deployment name=EmployeeBean" location="bmpapp/EmployeeBean" >
   <resource-ref-mapping name="jdbc/OracleDS" />
   <commit-option mode="A" number-of-buckets="10" />
</entity-deployment>

Configuring an EJB 2.1 BMP Entity Bean Query

You must implement an ejbFindByPrimaryKey method for a BMP entity bean (see "Implementing an EJB 2.1 BMP the ejbFindByPrimaryKey Method"). Optionally, you may configure other finders (see "Implementing Other EJB 2.1 BMP Finder Methods").

For more information, see "Using EJB 2.1 Query API".

Implementing an EJB 2.1 BMP the ejbFindByPrimaryKey Method

The ejbFindByPrimaryKey implementation is a requirement for all BMP entity beans. Its primary responsibility is to ensure that the primary key corresponds to a valid bean. Once it is validated, it returns the primary key to the container, which uses the key to return the bean reference to the user.

This sample verifies that the employee number is valid and returns the primary key, which is the employee number, to the container. A more complex verification would be necessary if the primary key was a class.

    public EmployeePK ejbFindByPrimaryKey(EmployeePK pk)
        throws FinderException
    {
        if (pk == null || pk.empNo == null) {
            throw new FinderException("Primary key cannot be null");
        }
        try {
            conn = getConnection(dsName);
            ps = conn.prepareStatement(findByPKStatement);
            ps.setInt(1, pk.empNo.intValue());
            ps.executeQuery();
            ResultSet rs = ps.getResultSet();
            if (rs.next()) {
                pk.empNo = new Integer(rs.getInt(1));
                pk.empName = new String(rs.getString(2));
                pk.salary = new Float(rs.getFloat(3));
            } else {
                throw new FinderException("Failed to select this PK");
            }
        } catch (SQLException e) {
            throw new FinderException(e.getMessage());
        } catch (NamingException e) {
            System.out.println("Caught an exception 1 " + e.getMessage() );
            throw new EJBException(e.getMessage());
        } finally {
            try {
                ps.close();
                conn.close();
            } catch (SQLException e) {
                throw new EJBException(e.getMessage());
            }
        }
        return pk;
    }

Implementing Other EJB 2.1 BMP Finder Methods

Optionally, you can create other finder methods in addition to the single ejbFindByPrimaryKey.

To create other finder methods, do the following:

  1. Add the finder method to the home interface.

  2. Implement the finder method in the BMP bean implementation.

Finders can retrieve one or more beans according to the WHERE clause. If more than a single bean is returned, then a Collection of primary keys must be returned by the BMP finder method. These finder methods need only to gather the primary keys for all of the entity beans that should be returned to the user. The container maps the primary keys to references to each entity bean within either a Collection (if multiple references are returned) or to the single class type.

The following example shows the implementation of a finder method that returns all employee records.

public Collection ejbFindAll() throws FinderException
{
  ArrayList recs = new ArrayList();

  ps = conn.prepareStatement("SELECT EMPNO FROM EMPLOYEEBEAN");
  ps.executeQuery();
  ResultSet rs = ps.getResultSet();

  int i = 0;

  while (rs.next()) 
  {
   retEmpNo = new Integer(rs.getInt(1));
   recs.add(retEmpNo);
  }

 ps.close();
 return recs;
}

Configuring a Lifecycle Callback Method for an EJB 2.1 BMP Entity Bean

In a BMP entity bean, you are responsible for implementing all of the EJB 2.1 BMP entity bean lifecycle callback methods:

Implementing an EJB 2.1 BMP ejbStore Method

The ejbStore method is called by the container before the object is passivated or whenever a transaction is about to end. Its purpose is to save the persistent data to an outside resource, such as a database

The container invokes the ejbStore method when the persistent data should be saved to the database. This synchronizes the state of the instance to the entity in the underlying database. For example, the container invokes before the container passivates the bean instance or removes the instance. The BMP bean is responsible for ensuring that all data is stored to some resource, such as a database, within this method.

    public void ejbStore() throws EJBException
    {
        //Container invokes this method to instruct the instance to
        //synchronize its state by storing it to the underlying database
        //System.out.println("EmployeeBean.ejbStore(): begin");
        try {
            pk = (EmployeePK) ctx.getPrimaryKey();
            conn = getConnection(dsName);
            ps = conn.prepareStatement(updateStatement);
            ps.setString(1, pk.empName);
            ps.setFloat(2, pk.salary.floatValue());
            ps.setInt(3, pk.empNo.intValue());
            if (ps.executeUpdate() != 1) {
                throw new EJBException("Failed to update record");
            }
        } catch (SQLException e) {
            throw new EJBException(e.getMessage());
        } catch (NamingException e) {
            System.out.println("Caught an exception 1 " + e.getMessage() );
            throw new EJBException(e.getMessage());
        } finally {
            try {
                ps.close();
                conn.close();
            } catch (SQLException e) {
                throw new EJBException(e.getMessage());
            }
        }
    }

Implementing an EJB 2.1 BMP ejbLoad Method

The ejbLoad method is called by the container before the object is activated or whenever a transaction has begun, or when an entity bean is instantiated. Its purpose is to restore any persistent data that exists for this particular bean instance

The container invokes the ejbLoad method whenever it needs to synchronize the state of the bean with what exists in the database. This method is invoked after activating the bean instance to refresh it with the state that is in the database. The purpose of this method is to repopulate the persistent data with the saved state. For most ejbLoad methods, this implies reading the data from a database into the instance data variables.

    public void ejbLoad() throws EJBException 
    {
        //Container invokes this method to instruct the instance to
        //synchronize its state by loading it from the underlying database
        //System.out.println("EmployeeBean.ejbLoad(): begin");
        try {
            pk = (EmployeePK) ctx.getPrimaryKey();
            ejbFindByPrimaryKey(pk);
        } catch (FinderException e) {
            throw new EJBException (e.getMessage());
        }
    }

Implementing an EJB 2.1 BMP ejbPassivate Method

The ejbPassivate method is invoked directly before the bean instance is serialized for future use. It will be re-activated, through the ejbActivate method, the next time the user invokes a method on this instance.

Before the bean is passivated, you should release all resources and release any static information that would be too large to be serialized. Any large, static information that can be easily regenerated within the ejbActivate method should be released in this method.

In our example, the only resource that cannot be serialized is the open database connection. It is closed in this method and reopened in the ejbActivate method.

public void ejbPassivate()
{
    // Container invokes this method on an instance before the instance
    // becomes disassociated with a specific EJB object
    conn.close();
}

Implementing an EJB 2.1 BMP ejbActivate Method

The container invokes this method when the bean instance is reactivated. That is, the user has asked to invoke a method on this instance. This method is used to open resources and rebuild static information that was released in the ejbPassivate method.

In addition, the container invokes this method after the start of any transaction.

Our employee example opens the database connection where the employee information is stored.

public void ejbActivate()
{
    // Container invokes this method when the instance is taken out
    // of the pool of available instances to become associated with
    // a specific EJB object
    conn = getConnection(dsName);
}

Implementing an EJB 2.1 BMP ejbRemove Method

The container invokes the ejbRemove method before removing the bean instance itself or by placing the instance back into the bean pool. This means that the information that was represented by this entity bean should be removed from within persistent storage. The employee example removes the employee and all associated information from the database before the instance is destroyed. Close the database connection.

    public void ejbRemove() throws RemoveException
    {
        //Container invokes this method befor it removes the EJB object
        //that is currently associated with the instance
        //System.out.println("EmployeeBean.ejbRemove(): begin");
        try {
            pk = (EmployeePK) ctx.getPrimaryKey();
            conn = getConnection(dsName);
            ps = conn.prepareStatement(deleteStatement);
            ps.setInt(1, pk.empNo.intValue());
            if (ps.executeUpdate() != 1) {
                throw new RemoveException("Failed to delete record");
            }
        } catch (SQLException e) {
            throw new RemoveException(e.getMessage());
        } catch (NamingException e) {
            System.out.println("Caught an exception 1 " + e.getMessage() );
            throw new EJBException(e.getMessage());
        } finally {
            try {
                ps.close();
                conn.close();
            } catch (SQLException e) {
                throw new EJBException(e.getMessage());
            }
        }
    }