Oracle9i Enterprise JavaBeans Developer's Guide and Reference
Release 1 (9.0.1)

Part Number A90188-01
Go To Documentation Library
Home
Go To Product List
Book List
Go To Table Of Contents
Contents
Go To Index
Index

Master Index

Feedback

Go to previous page Go to next page

4
Entity Beans

This chapter discusses what an entity bean is, how to create one, and how it is different from a session bean.

Definition of an Entity Bean

An entity bean is a remote object that manages persistent data, performs complex business logic, potentially uses several dependent Java objects, and can be uniquely identified by a primary key. Entity beans are normally coarse-grained persistent objects, in that they utilize persistent data stored within several fine-grained persistent Java objects.


Note:

Fine-grained persistent Java objects typically manage persistent data that has a one-to-one mapping between the data and a table column. Coarse-grained persistent Java objects use or manage persistent data stored in several fine-grained persistent objects. 


Managing Persistent Data

An entity bean manages its data persistentcy through callback methods, which are defined in the javax.ejb.EntityBean interface. When you implement the EntityBean interface in your bean class, you develop each of the callback functions as designated by the type of persistence that you choose: bean-managed persistence or container-managed persistence. The container invokes the callback functions at designated times. That is, the contract between the container and the entity bean designates the order that the callback methods are invoked and who manages the bean's persistent data.

Uniquely Identified by a Primary Key

Each entity bean has a persistent identity associated with it. That is, the entity bean contains a unique identity that can be retrieved if you have the primary key. Given the primary key, a client can retrieve the entity bean. If the bean is not available, the container instantiates the bean and repopulates the persistent data for you.

The type for the unique key is defined by the bean provider.

Performing Complex Logic Involving Dependent Objects

When designing your EJB application, you need to keep in mind the aspects of each type of object.

Enterprise JavaBeans are remote objects and are used for interacting with clients over a network. Remote objects have a higher overhead for verifying security and transaction information. Thus, when you design your application, you may have an entity or session bean interacting with the client, but also have the Enterprise JavaBean invoke other dependent Java objects to perform tasks or manage persistent data.

Entity beans are normally used to manage complex, coarse-grained persistent data for a remote client. Be careful to separate the difference between an entity bean and a persistent object. Your entity bean should be more than just a persistent object; it should manage and return complex data to justify using a remote object for managing data.

You can have an entity bean that calls one or more dependent objects within the application. The entity bean is a remote object and thus its primary function is interacting with the client over the network. You should not have an entity bean invoking another entity bean within the same node on the network. If you need to design multiple objects within your application, design your application so that the entity bean facilitates the communication and data management between the client and other Java objects.

Figure 4-1 demonstrates how the client interacts with either a session or an entity bean, which then manages the application for the client with other Java objects within the application. The Java objects that make up the backend of the application can be persistent objects. The figure also shows how both the entity bean and a persistent Java object can be persistent and store data within the database.

Figure 4-1 Relationship of Enterprise JavaBeans to Java objects


Text description of entitya.gif follows
Text description of the illustration entitya.gif

For example, if you are managing a shopping cart for an online bookstore, you would have the following requirements:

In this scenario, the entity bean could do the following:

Thus, this entity bean not only retrieves persistent information from other objects, but would also maintain its own persistent data and perform complex calculations.

Difference Between Session and Entity Beans

The major differences between session and entity beans is that entity beans involve a framework for persistent data management, a persistent identity, and complex business logic. The interface requirements on entity beans provides callback functions that the container calls when persistent data should be managed or when a bean should be retrieved based upon its identity.

With an entity bean, the interfaces have been designed so that each callback method is called at the appropriate time. For example, right before the transaction is committed, the ejbStore method is always invoked. This enables the entity bean to save all of its persistent data before the transaction is completed. Each of these callback methods are discussed further in "Implementing Callback Methods".

The following table illustrates the different interfaces for session and entity beans. Notice that the difference between the two types of EJBs exists within the bean class and the primary key. All of the persistent data management is done within the bean class methods.

  Entity Bean  Session Bean 

Remote interface 

Extends javax.ejb.EJBObject 

Extends javax.ejb.EJBObject 

Home interface 

Extends javax.ejb.EJBHome 

Extends javax.ejb.EJBHome 

Bean class 

Extends javax.ejb.EntityBean 

Extends javax.ejb.SessionBean 

Primary key 

Used to identify and retrieve specific bean instances 

Not used for session beans 

Implementing Callback Methods

An entity bean is a remote object that manages its data persistently through callback methods, which are defined in the javax.ejb.EntityBean interface. When you implement the EntityBean interface in your bean class, you develop each of the callback functions as designated by the type of persistence that you choose: bean-managed persistence or container-managed persistence. The container invokes the callback functions at designated times, to manage the bean and its persistent data. That is, the contract between the container and the entity bean involves in what order the callback methods are invoked and who manages the bean's persistent data.

Your bean class implements the methods of the EntityBean interface. The javax.ejb.EntityBean interface has the following definition:

public interface javax.ejb.EntityBean extends javax.ejb.EnterpriseBean {
   public abstract void ejbActivate(); 
   public abstract void ejbLoad();
   public abstract void ejbPassivate();
   public abstract void ejbRemove();
   public abstract void ejbStore();
   public abstract void setEntityContext(EntityContext ctx);
   public abstract voic unsetEntityContext();
}

The container expects these methods to have the following functionality:

  • ejbCreate

You must implement an ejbCreate method corresponding to one create method declared in the home interface. When the client invokes the create method, the container first invokes the constructor to instantiate the object, then it invokes the corresponding ejbCreate method. The ejbCreate method performs the following:

  • creates any persistent storage for its data, such as database rows

  • intializes a unique primary key and returns it

  • ejbPostCreate

The container invokes this method after the environment is set. For each ejbCreate method, an ejbPostCreate method must exist with the same arguments. This method can be used to initialize parameters within or from the entity context.

  • ejbRemove

The container invokes this method before it ends the life of the session object. This method may perform any required clean-up, for example closing external resources such as file handles.

  • ejbStore

The container invokes this method right before a transaction commits. It saves the persistent data to an outside resource, such as a database.

  • ejbLoad

The container invokes this method within a transaction when the data should be reinitialized from the database. This normally occurs after the transaction begins.

  • setEntityContext

Associates the bean instance with context information. The container calls this method after the bean creation. The enterprise bean can store the reference to the context object in an instance variable, for use in transaction management. Beans that manage their own transactions can use the session context to get the transaction context.

You can also allocate any resources that will exist for the lifetime of the bean within this method. You should release these resources in unsetEntityContext.

  • unsetEntityContext

Unset the associated entity context and release any resources allocated in setEntityContext.

  • ejbActivate

Implement this as a null method, because it is never called in this release of the server.

  • ejbPassivate

Implement this as a null method, because it is never called in this release of the server.

Using ejbCreate and ejbPostCreate

An entity bean is similar to a session bean in that certain callback methods, such as ejbCreate, are invoked at specified times. Entity beans use callback functions for managing its persistent data, primary key, and context information. The following diagram shows what methods are called when an entity bean is created.

Figure 4-2 Creating the Entity Bean


Text description of create.gif follows
Text description of the illustration create.gif

Using setEntityContext

This method is used by an entity bean instance to retain a reference to its context. Entity beans have contexts that the container maintains and makes available to the beans. The bean may use the methods in the entity context to retrieve information about the bean, such as security, and transactional role. Refer to the Enterprise JavaBeans 1.1 specification for the full range of information that you can retrieve about the bean from the context.

The container invokes setEntityContext method, after it first instantiates the bean, to enable the bean to retrieve the context. The container will never call this method from within a transaction context. If the bean does not save the context at this point, the bean will never gain access to the context.


Note:

You can also use the setEntityContext and unsetEntityContext methods to allocate and destroy any resources that will exist for the lifetime of the instance. 


When the container calls this method, it passes the reference of the EntityContext object to the bean. The bean can then store the reference for later use. The following example shows the bean saving the context in the this.ctx variable.

public void setEntityContext(EntityContext ctx) { this.ctx = ctx; }

Using ejbRemove

When the client invokes the remove method, the container invokes the following methods.

Figure 4-3 Removing the Entity Bean


Text description of remove.gif follows
Text description of the illustration remove.gif

Using ejbStore and ejbLoad

In addition, the ejbStore and ejbLoad methods are called for managing your persistent data. These are the most important callback methods--for bean-managed persistent beans.

Creating Entity Beans

The steps for creating an entity bean are the same as for a session bean. The difference is contained in the methods and data within the bean class. There are two types of entity beans: bean-managed persistent and container-managed persistent. This section discusses a bean-managed persistent bean. The "Container-Managed Persistence" gives an example of a container-managed persistent bean.

To create an entity bean, you perform the following steps:

  1. Create a remote interface for the bean. The remote interface declares the methods that a client can invoke. It must extend javax.ejb.EJBObject.

  2. Create a home interface for the bean. The home interface must extend javax.ejb.EJBHome. It defines the create and finder methods, including findByPrimaryKey, for your bean.

  3. Define the primary key for the bean. The primary key identifies each entity bean instance. The primary key must either be a well-known class, such as java.lang.String, or be defined within its own class.

  4. Implement the bean. This includes the following:

    1. The implementation for the methods declared in your remote interface.

    2. An empty constructor for the bean.

    3. The methods defined in the javax.ejb.EntityBean interface.

    4. The methods that match the methods declared in your home interface. This includes the following:

      • The ejbCreate and ejbPostCreate methods with parameters matching those of the create method defined of the home interface.

      • An ejbFindByPrimary key method which corresponds to the findByPrimaryKey method of the home interface.

      • Any other finder methods that were defined in the home interface.

  5. If the persistent data is saved to or restored from a database, you must ensure that the correct tables exist for the bean.

  6. Create the bean deployment descriptor. The deployment descriptor specifies properties for the bean through XML properties. See "Deploying an EJB" for more details.

  7. Create an ejb-jar file containing the bean, the remote and home interfaces, and the deployment descriptor. The ejb-jar file must define all beans within your application. Refer to "Create a JAR File" for more details.

Home Interface

Similar to session beans, the entity bean's home interface must contain a create method, which the client invokes to create the bean instance. Each create method can have a different signature.

For an entity bean, you must develop a findByPrimaryKey method. Because of the persistent data associated with the instance, each entity bean instance is uniquely identified by a primary key. The type for the unique key is defined by the developer. For example, the customer bean's primary key is the customer number. The purchase order's primary key is a purchase order number. The primary key can be anything--as long as it is unique.

When the entity bean is first created, the ejbCreate method creates a primary key to identify the bean. A unique primary key is created and initialized within the ejbCreate method in the bean class. From this time onward, this bean is associated with this primary key. Thus, you can retrieve the bean by providing the primary key object to the findByPrimaryKey method.

Optionally, you can develop other finder methods to find the bean. These methods are named find<name>.


Note:

The return type for all finder methods within the home interface must be either the entity bean's remote interface or an Enumeration of objects that implement the entity bean's remote interface. Returning a Collection is not supported.

The return type for all finder methods implemented within the bean class returns the primary key or an Enumeration of primary keys. The container retrieves the appropriate entity bean remote interface for each primary key returned on any ejbFind<name> method. 


Example 4-1 Purchase Order Home Interface

To demonstrate an entity bean, we are creating a bean that manages a purchase order. The entity bean contains a list of items ordered by the customer.

The home interface extends javax.ejb.EJBHome and defines the create and findByPrimaryKey methods.

package common;

import java.rmi.RemoteException;
import java.sql.SQLException;
import javax.ejb.*;

public interface PurchaseOrderHome extends EJBHome
{
  // Create a new PO
  public PurchaseOrderRemote create() throws CreateException, RemoteException;

  // Find an existing one
  public PurchaseOrderRemote findByPrimaryKey (String POnumber)
    throws FinderException, RemoteException;
}

Remote Interface

The entity bean remote interface is the interface that the customer sees and invokes methods upon. It extends javax.ejb.EJBObject and defines the business logic methods. For our purchase order entity bean, the remote interface contains methods for adding items to the purchase order, for retrieving a list of all items within the purchase order, and computing the full price for the purchase order.

package common;

import java.rmi.RemoteException;
import java.sql.SQLException;
import java.util.Vector;
import javax.ejb.EJBObject;

public interface PurchaseOrderRemote extends EJBObject
{
  // Price the PO
  public float price() throws RemoteException;

  // Manage contents

  // getContents returns a Vector of LineItem objects
  public Vector getContents() throws RemoteException;

  public void addItem(int sku, int count) throws RemoteException;
}

Primary Key

Each entity bean instance has a primary key that uniquely identifies it from other instances. You can define your primary key in one of two ways:

Defining Primary Key as Well-known Type

Define your primary key to be a well-known type by defining the data type of the primary key within the deployment descriptor.

The purchase example defines its primary key as a java.lang.String.

<enterprise-beans>
      <entity>
         <ejb-name>PurchaseOrderBean</ejb-name>
         <home>common.PurchaseOrderHome</home>
         <remote>common.PurchaseOrderRemote</remote>
         <ejb-class>server.PurchaseOrderBean</ejb-class>
         <persistence-type>Bean</persistence-type>
         <prim-key-class>java.lang.String</prim-key-class>
         <reentrant>False</reentrant>
      </entity>
...
</enterprise-beans>

Defining the Primary Key in a Class

If your primary key is more complex than a simple data type, your primary key must be a class that is serializable of the name <name>PK. Within this class, you should implement the equals and hashCode methods to provide for an implementation specific to this primary key.

The customer example declares its primary key--a customer identifier--within the PurchaseOrderPK.java.

package common;

public class PurchaseOrderPK implements java.io.Serializable
{
  public int orderid;

  public boolean equals(Object obj) {
    if ((obj instanceof PurchaseOrderPK) &&
        (((PurchaseOrderPK)obj).orderid == this.orderid))
      return true;
    return false;
  }

  public int hashCode() {
    return orderid;
  }
}

The class that defines the primary key is declared within the deployment descriptor, as follows:

<enterprise-beans>
      <entity>
         <ejb-name>PurchaseOrderBean</ejb-name>
         <home>common.PurchaseOrderHome</home>
         <remote>common.PurchaseOrderRemote</remote>
         <ejb-class>server.PurchaseOrderBean</ejb-class>
         <persistence-type>Bean</persistence-type>
         <prim-key-class>common.PurchaseOrderPK</prim-key-class>
         <reentrant>False</reentrant>
      </entity>
...
</enterprise-beans>

Manage the Primary Key

The ejbCreate method is responsible primarily for the creation of the primary key. This involves creating the primary key, creating the persistent data representation for the key, initializing the key to a unique value, and returning this key to the invoker. The ejbFindByPrimaryKey method is responsible for verifying that the primary key is still unique and returns it again to the container.

In the purchase order example, these methods perform the following:

Entity Bean Class

The entity bean class implements the following methods:

The following code implements methods of an entity bean called PurchaseOrderBean.

1. Declaring Variables

The purchase order bean declares a vector to store all of the items within the customer's shopping cart. In addition, to retrieve environment information for the entity bean, an entity context is defined.

#sql iterator ItemsIter (int skunumber, int count, String description,
                         float price);

public class PurchaseOrderBean implements EntityBean {
  EntityContext ctx;
  Vector items;         // The items in the PO (instances of LineItem)

2. Implementing Remote Interface Methods

The following is the implementation for the bean methods that were declared in the remote interface: price, getContents, and addItem.

  public float price() throws RemoteException {
    float price = 0;
    Enumeration e = items.elements ();
    while (e.hasMoreElements ()) {
      LineItem item = (LineItem)e.nextElement ();
      price += item.quantity * item.price;
    }

    // 5% discount if buying more than 10 items
    if (items.size () > 10)
      price -= price * 0.05;

    // Shipping is a constant plus function of the number of items
    price += 10 + (items.size () * 2);

    return price;
  }

  // The getContents methods has to load the descriptions
  public Vector getContents() throws RemoteException {
    return items;
  }

  // The add Item method gets the price and description
  public void addItem (int sku, int count) throws RemoteException {
    try {
      String description;
      float price;
      #sql { select price, description into :price, :description
             from skus where skunumber = :sku };
      items.addElement (new LineItem (sku, count, description, price));
    } catch (SQLException e) {
      throw new PurchaseException (this, "addItem", e);
    }
  }

3. Implementing EntityBean Interface Methods

Once you have implemented the business logic methods, you also must provide the following:

Public Constructor

The public constructor is called by the container to create the bean instance. The ejbCreate and ejbPostCreate methods are invoked to intialize this instance. The following is the purchase order constructor.

//provide an empty constructor for the creating the instance
public void PurchaseOrderBean() {}
The Create Methods: ejbCreate and ejbPostCreate

As shown in Figure 4-2, the ejbCreate and ejbPostCreate methods are invoked when the corresponding create method--the methods all have the same arguments--is invoked. Typically, the ejbCreate method initializes all of the persistent data; the ejbPostCreate does any initialization that involves the entity's context. The context information is not available at ejbCreate time, but is available at ejbPostCreate time.

The following example shows the ejbCreate and ejbPostCreate for the purchase order example. The ejbCreate method initializes the primary key, which is the purchase order number, and returns this key to the invoker. The purchase order line item vector is initialized within the ejbPostCreate.

// The create methods takes care of generating a new PO and returns
// its primary key
public String ejbCreate () throws CreateException, RemoteException
{
  String ponumber = null;
  try {
    //retrieve the next available purchase order number
    #sql { select ponumber.nextval into :ponumber from dual };
    //assign this number as this instance's identification number
    #sql { insert into pos (ponumber, status) values (:ponumber, 'OPEN') };
  } catch (SQLException e) {
    throw new PurchaseException (this, "create", e);
  }
  return ponumber;
}

// create a vector to contain the purchase order line items. since this
// is performed only once and needed for the lifetime of the object, it is 
// appropriate to create the vector in either ejbCreate or ejbPostCreate.
public void ejbPostCreate () {
    items = new Vector ();
}
The Finder Methods

All entity beans must provide an ejbFindByPrimaryKey method. You can also have other types of finder methods. Since the developer must implement any finder method declared within the home interface, there is no limitation on how many of these types of methods you can have. The only restrictions is that any finder method, other than the ejbFindByPrimaryKey method, must return either a reference to the remote interface or an Enumeration containing multiple references to remote interfaces. The ejbFindByPrimaryKey method must return the primary key.


Note:

The return type cannot be a Collection, as it is not currently supported. 


In order to provide other finder methods, you must do the following:

  1. Declare the method as find<name> in the home interface.

  2. Implement the method as ejbFind<name> in the bean class.

The following is the ejbFindByPrimaryKey method for the purchase order example. It verifies that the primary key is valid. If so, it returns the key to the container. The container retrieves the correct bean instance for this key and returns the reference to the client.

// The findByPrimaryKey method verifies that the POnumber exists. This
// method must return the primary key to the container.. which in turn
// retrieves the instance based on the primary key. So.. this method must
// only verify that the primary key is valid.
public String ejbFindByPrimaryKey (String ponumber)
    throws FinderException, RemoteException
{
    try {
      int count;
      #sql { select count (ponumber) into :count from pos
               where ponumber = :ponumber };

      // There has to be one
      if (count != 1)
        throw new FinderException ("Inexistent PO: " + ponumber);
    } catch (SQLException e) {
      throw new PurchaseException (this, "findByPrimaryKey", e);
    }
    // The ponumber is the primary key
    return ponumber;
}
The EntityBean Methods: Load and Store

The main difference between entity and session beans is that entity beans possess persistent data that must be managed. When data is defined as persistent, it must be continually saved to or restored from a resource, such as a database or file. If the bean is destroyed, the persistent data can be restored without any loss.

The EntityBean interface, which all entity beans implement, defines the following callback methods for managing the persistent data:

Figure 4-4 shows how the persistent data within an entity bean can be saved to a database using ejbStore. In addition, the data is restored from the database through ejbLoad.

Figure 4-4 Persistent Data Management


Text description of persiste.gif follows
Text description of the illustration persiste.gif

The following are the methods from the purchase order example. The ejbStore method saves the purchase order items to the database. The ejbLoad method restores the purchase order items from the database.

// The store method replaces all entries in the lineitems table with the
// new entries from the bean
public void ejbStore() throws RemoteException {
  // Get the purchase order number
  String ponumber = (String)ctx.getPrimaryKey();

  try {
    // Delete old entries in the database
    #sql { delete from lineitems where ponumber = :ponumber };

    // Insert new entries from the vector in the bean. Crude, but effective.
    Enumeration e = items.elements ();
    while (e.hasMoreElements ()) {
      LineItem item = (LineItem)e.nextElement ();
      #sql { insert into lineitems (ponumber, skunumber, count)
               values (:ponumber, :(item.sku), :(item.quantity))
      };
    }
  } catch (SQLException e) {
    throw new PurchaseException (this, "store", e);
  }
} 

// The load method populates the items array with all the saved
// line items
public void ejbLoad() throws RemoteException {
  // Get the purchase order number
  String ponumber = (String)ctx.getPrimaryKey();

  // Load all line items into a new vector.
  try {
    items = new Vector ();
    ItemsIter iter = null;
    try {
      #sql iter = {
        select lineitems.skunumber, lineitems.count,
               skus.description, skus.price
          from lineitems, skus
          where ponumber = :ponumber and lineitems.skunumber = skus.skunumber
      };

      while (iter.next ()) {
        LineItem item =
          new LineItem (iter.skunumber(), iter.count(), iter.description(),
                        iter.price());
        items.addElement (item);
      }
    } finally {
      if (iter != null) iter.close ();
    }
   } catch (SQLException e) {
    throw new PurchaseException (this, "load", e);
  }
}
The EntityBean Methods: Remove

The ejbRemove method is invoked when the client invokes the remove method. For a bean-managed persistent bean, you must remove the data from the database that is associated with the bean within this method.

The following example shows how the purchase order line items are removed from the database.

// The remove method deletes all line items belonging to the purchase order
public void ejbRemove() throws RemoteException {
  // Get the purchase order number from the session context
  String ponumber = (String)ctx.getPrimaryKey();
  try {
    //delete the line item vector for the purchase order
    #sql { delete from lineitems where ponumber = :ponumber };
    //delete the row associated with the purchase order
    #sql { delete from pos where ponumber = :ponumber };
  } catch (SQLException e) {
    throw new PurchaseException (this, "remove", e);
  }
}
The EntityBean Methods: Setting the Context

If you want to access any information within the context during the lifetime of your application, you must save the context within the setEntityContext.

public void setEntityContext(EntityContext ctx) { this.ctx = ctx; }
public void unsetEntityContext() {}
The Entity Bean Methods: Activate and Passivate

Oracle does not currently support activation and passivation. However, you still must provide an empty implementation for these methods. ,

//There are no requirements for ejbActivate for this bean
public void ejbActivate() {}

//There are no requirements for ejbPassivate for this bean
public void ejbPassivate() {}

4. LineItem Class

The purchase order application persistently stores the individual orders within the purchase using a persistent Java object, called LineItem. That is, the entity bean delegates management of each item in the purchase order to a non-EJB Java object.

package common;

public class LineItem implements java.io.Serializable {
  public int sku;
  public int quantity;
  public String description;
  public float price;

  //Persistently manage each line item within the purchase order. 
  public LineItem (int sku, int quantity, String description, float price) {
    //Each line item has the following information: SKU number, quantity,
    // description, and price.
    this.sku = sku;
    this.quantity = quantity;
    this.description = description;
    this.price = price;
  }
}

Create Database Table and Columns for Entity Data

If your entity bean stores its persistent data within a database, you need to create the appropriate table with the proper columns for the entity bean. This table must be created before the bean is loaded into the database.

In our purchase order example, you must create the following tables:

Table  Columns  Description 

SKUS 

  • skunumber: item number

  • description: item description

  • price: price of item

 

Each item in the warehouse is described in this table. 

POS 

  • ponumber:purchase order number

  • status: open, executed, or shipped

 

The table that manages the state of the purchase order for a customer. Contains the state of the order. 

LINEITEMS 

  • ponumber: purchase order number

  • skunumber: item number

  • count: number of items ordered.

 

The table that contains all of the individual items ordered by a customer.  

The following shows the SQL commands that create these fields.

-- This sql scripts create the SQL tables used by the PurchaseOrder bean

-- The sku table lists all the items available for purchase
create table skus (skunumber number constraint pk_skus primary key,
                   description varchar2(2000),
                   price number);

-- The pos table stores information about purchase orders
-- The status column is 'OPEN', 'EXECUTED' or 'SHIPPED'
create table pos (ponumber number constraint pk_pos primary key,
                  status varchar2(30));

-- The ponumber sequence is used to generate PO ids
create sequence ponumber;

-- The lineitems table stores the contents of a po
-- The skunumber is a reference into the skus table
-- The ponumber is a reference into the pos table 
create table lineitems (ponumber number constraint fk_pos references pos,
                        skunumber number constraint fk_skus references skus,
                        count number);

commit;

exit;

Deploying the Entity Bean

You deploy the entity bean the same way as the session bean, which is detailed in "Deploying an EJB". In the same manner, you must create the XML deployment descriptors for the bean, create a JAR file containing all of the bean's files, and use deployejb tool to load and publish the bean in the database.

The XML deployment descriptors are explained fully in Appendix A, "XML Deployment Descriptors". See the appendix for a full description on defining persistence for entity beans.

The following example demonstrates how the purchase order example deployment descriptors are organized. The features that this descriptor describes are as follows:

Example 4-2 Purchase Order EJB Deployment Descriptor

<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems Inc.//DTD Enterprise JavaBeans 1.1
//EN" "ejb-jar.dtd">
<ejb-jar>
   <enterprise-beans>
      <entity>
         <description>no description</description>
         <ejb-name>PurchaseOrderBean</ejb-name>
         <home>common.PurchaseOrderHome</home>
         <remote>common.PurchaseOrderRemote</remote>
         <ejb-class>server.PurchaseOrderBean</ejb-class>
         <persistence-type>Bean</persistence-type>
         <prim-key-class>java.lang.String</prim-key-class>
         <reentrant>False</reentrant>
      </entity>
   </enterprise-beans>
   <assembly-descriptor>
      <security-role>
         <description>no description</description>
         <role-name>PUBLIC</role-name>
      </security-role>
      <method-permission>
         <description>no description</description>
         <role-name>PUBLIC</role-name>
         <method>
            <ejb-name>PurchaseOrderBean</ejb-name>
            <method-name>*</method-name>
         </method>
      </method-permission>
      <container-transaction>
         <description>no description</description>
         <method>
            <ejb-name>PurchaseOrderBean</ejb-name>
            <method-name>*</method-name>
         </method>
         <trans-attribute>Required</trans-attribute>
      </container-transaction>
   </assembly-descriptor>
</ejb-jar>

Example 4-3 Oracle-Specific Deployment Descriptor

<?xml version="1.0"?>
<!DOCTYPE oracle-descriptor PUBLIC "-//Oracle Corporation.//DTD Oracle 1.1//EN" 
"oracle-ejb-jar.dtd">
<oracle-descriptor>
<mappings>
  <ejb-mapping>
     <ejb-name>PurchaseOrderBean</ejb-name>
     <jndi-name>test/PurchaseOrderBean</jndi-name>
  </ejb-mapping>
  <transaction-manager>
    <default-enlist>TRUE</default-enlist>
  </transaction-manager>
</mappings>
</oracle-descriptor>

Client Accessing Deployed Entity Bean

To access a deployed entity bean, the client does one of the following:

Create a New Entity Bean

When you access an entity bean, you must first locate the bean's home interface. You retrieve the home interface from the name space through JNDI. The URL must be of the following syntax:

<service_name>://<hostname>:<iiop_listener_port>:<SID>/<published_obj_name>


This syntax is described more in "Getting the Home Interface Object".

Example 4-4 Retrieving the Home Interface from the JNDI Name Space

The following example retrieves the home interface of the EJB located published in /test/purchase. The host, port, and SID are localhost, 2471, and ORCL respectively.

String serviceURL = "sess_iiop://localhost:2471:ORCL";
String objectName = "/test/purchase";

Hashtable env = new Hashtable();
env.put(Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
env.put(Context.SECURITY_PRINCIPAL, user);
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN);
Context ic = new InitialContext (env);

CustomerHome ch = (CustomerHome)ic.lookup (serviceURL + objectName);
Customer myCust = (Customer) ch.create();


Note:

Notice how the type casting on the lookup does not require the narrow method. The Oracle9i lookup method automatically performs the proper narrowing function for you. Although you still must provide the type that the returned object is cast to. 


Access an Existing Entity Bean

A client can access an existing entity bean through one of the following methods:

Difference Between Bean-Managed and Container-Managed Beans

There are two methods for managing the persistent data within an entity bean: bean-managed and container-managed persistence. The main difference between bean-managed and container-managed persistent beans is defined by who manages the persistence of the entity bean's data.

In practical terms, the following table provides a definition for both types and a summary of the programmatic and declarative differences between them:

  Bean-Managed Persistence  Container-Managed Persistence 

Persistence management 

You are required to implement the persistence management within the ejbStore and ejbLoad EntityBean methods. These methods must contain logic for saving and restoring the persistent data.

For example, the ejbStore method must have logic in it to store the entity bean's data to the appropriate database. If it does not, the data can be lost. See "3. Implementing EntityBean Interface Methods" for an example of implementing bean-managed persistence. 

The management of the persistent data is done for you. That is, the container invokes a persistence manager on behalf of your bean.

You use ejbStore and ejbLoad for preparing the data before the commit or for manipulating the data after it is refreshed from the database. The container always invokes the ejbStore method right before the commit. In addition, it always invokes the ejbLoad method right after reinstating CMP data from the database. 

Finder methods allowed 

The findByPrimaryKey method and any other finder method you wish to implement are allowed. 

Only the findByPrimaryKey method and a finder method for the where clause are allowed. 

Defining CMP fields 

N/A 

Required within the EJB deployment descriptor. The primary key must also be declared as a CMP field. 

Mapping CMP fields to resource destination. 

N/A 

Required. Dependent on persistence manager. 

Definition of persistence manager. 

N/A 

Required within the Oracle-specific deployment descriptor. See the next section for a description of a persistence manager. 

Container-Managed Persistence

You can choose to have the container manage your persistent data for the bean. You have less to develop and manage, as the container stores and reloads your persistent data to and from the database.

When you use container-managed persistence, the container invokes a persistence manager class that provides the persistence management business logic. You can use either BC4J for your persistence management or the Oracle Persistence Service Interface Reference Implementation (PSI-RI). This document only discusses the PSI-RI implementation. See the BC4J documentation for information on their CMP manager.

To enable the container to manage your persistent data, you need to perform the following:

  1. Modify the appropriate bean class callback methods

  2. Define the primary key

  3. Declare the container-managed persistent fields within the deployment descriptor

  4. Declare the persistence manager class

  5. Map container-managed persistent fields to a database

Modify Bean Class Callback Methods

If you do not want to manage your persistent data, choose to have your bean managed by the container. This means that you do not have to implement some of the callback methods as the container and the persistence manager performs the persistence and primary key management for you. The container will still call these methods--so you can add logic for other purposes. You still must provide at least an empty implementation for all callback methods.

The following table details the implementation requirements for the bean class' callback functions:

Callback Method  Functionality Required 

ejbCreate 

The same functionality as bean-managed persistent beans. You must initialize all container-managed persistent fields, including the primary key. 

ejbPostCreate 

The same functionality as bean-managed persistent beans. You have the option to provide any other initialization, which can involve the entity context.  

ejbRemove 

No functionality for removing the persistent data from the outside resource is required. The persistent manager removes all persistent data associated with the entity bean from the database. You must at least provide an empty implementation for the callback, which means that you can add logic for performing any cleanup functionality you require. 

ejbFindByPrimaryKey 

No functionality is required for returning the primary key to the container. The container manages the primary key--after it is initialized by the ejbCreate method. Thus, the container performs the functionality normally required of this method. You still must provide an empty implementation for this method. 

ejbStore 

No functionaltiy is required for saving persistent data within this method. The persistent manager saves all persistent data to the database for you. However, you must provide at least an empty implementation as the container invokes the ejbStore method before invoking the persistent manager. This enables you to perform any data management or cleanup before the persistent data is saved. 

ejbLoad 

No functionality is required for restoring persistent data within this method. The persistence manager restores all persistent data for you. However, you must provide at least an empty implementation as the container invokes the ejbLoad method after invoking the persistent manager. This enables you to perform any logic to manipulate the persistent data after it is restored to the bean. 

setEntityContext 

Associates the bean instance with context information. The container calls this method after the bean creation. The enterprise bean can store the reference to the context object in an instance variable, for use in transaction management. Beans that manage their own transactions can use the session context to get the transaction context.

You can also allocate any resources that will exist for the lifetime of the bean within this method. You should release these resources in unsetEntityContext

unsetEntityContext 

Unset the associated entity context and release any resources allocated in setEntityContext

A Finder Method for the Where Clause

PSI-RI enables you to perform a SQL query against the persistent data table through a CMP-only finder method with a find<name> naming syntax. This method takes a String that denotes the "where" clause of a SQL query. Thus, the String would include the entire statement except for the "select * from <table". If you supply an empty string, all values are selected from this table.

You must define any such finder method within the Home interface. The container will provide the implementation for satisfying the where clause for the finder method.

For example, the following defines finder methods within the home interface, where one retrieves all customers and the other retrieves a single customer. Notice how the findAllCustomers method, which retrieves all customers in the table, returns an Enumeration.


Note:

Normally, the return type for multiple items in a finder method would be a Collection. However, Collection is not supported in this release. You must use the Enumeration type to receive multiple items from any finder method. 


public Customer findByWhere(String whereString) 
throws RemoteException, FinderException;

public java.util.Enumeration findMultipleCustomers(String whereString)
throws RemoteException, FinderException;

If you want to retrieve a single customer, provide the name, the SQL would be constructed as follows:

select * from customer where name = "Smith, John";

The findbyWhere finder method would include the entire statement except for the "select * from customer". It assumes that you want to select against the persistence table, as follows:

Customer find_customer = findByWhere ("where name = ", + custname);

If you want to select a few rows from employee based upon a certain condition, the SQL would be constructed as follows:

select * from customer where item_bought = treadmill order by name;

The find<name> method, which in this example is findByWhere, would include the entire statement except for the "select * from employee". It assumes that you want to select all matches against the persistence table. This is demonstrated below:

Enumeration customer_list = findMultipleCustomers(
"where item_bought = treadmill order by name");

Or, if you wanted a full customer listing, provide an empty string. The container will invoke a "select * from customer" and retrieve all records.

Enumeration customer_list = findMultipleCustomers();

Define Your Primary Key

The main difference between defining a bean-managed and container-managed persistent primary key is that the fields within the key must be declared as container-managed persistent fields in the deployment descriptor. All fields within the primary key are restricted to be either primitive, serializable, and types that can be mapped to SQL types. See "Persistence Fields" for more information.

You can define your primary key in one of two ways:

Defining A Single Object as your Primary Key

Define your primary key as a container-managed persistent field and its type within the deployment descriptor. The following shows the primary key, custid, declared as a <cmp-field> and <primkey-field> and its type declared within the <prim-key-class>:

<enterprise-beans> 
  <entity>
      <description>customer bean</description>
      <ejb-name>/test/customer</ejb-name>
      <home>customer.CustomerHome</home>
      <remote>customer.Customer</remote>
      <ejb-class>customerServer.CustomerBean</ejb-class>
      <persistence-type>Container</persistence-type>
      <prim-key-class>java.lang.String</prim-key-class>
      <reentrant>False</reentrant>
      <cmp-field><field-name>custid</field-name></cmp-field>
      <cmp-field><field-name>name</field-name></cmp-field>
      <cmp-field><field-name>addr</field-name></cmp-field>
      <primkey-field>custid</primkey-field>
  </entity>
</enterprise-beans>

The primary key variable declared within the bean class must be declared as public.

This should be a Java type that can be mapped to a SQL type through SQLJ. Also, this object must be serializable. See "Entity Bean Elements" for a full description.

Defining a Complex Primary Key Class

If your primary key is more complex than a simple data type, you define the fields that make up the primary key as container-managed fields within the deployment descriptor. Then, you declare these fields as the primary key within a class. This class must be serializable. Also, all primary key variables declared within the bean class must be types that can be mapped to SQL types.

Within the bean class, the primary key variables must be declared as public. Also, you must provide a constructor with no arguments for creating an empty primary key instance.

Within the serializable primary key class, you implement the equals and hashCode methods to provide for an implementation specific to this primary key.

The following example is a cruise ship cabin bean primary key that identifies each cabin with ship name, deck name, and cabin number.

package cruise;

public class CabinPK implements java.io.Serializable
{
//Ship names { Castaway, LightFantastic, FantasyRide }
  public String ship;

//Deck names { Upper Promendade, Promenade, Lower Promenade, Main Deck, 
                 Lower Deck }
  public String deck;

  //Cabin numbers A100-N300
  public String cabin;

  //empty constructor
  public CabinPK ( ) { }

  public boolean equals(Object obj) {
    if ((obj instanceof CabinPK) &&
        (((CabinPK)obj).ship == this.ship) &&
         (((CabinPK)obj).deck == this.deck) &&
         (((CabinPK)obj).cabin == this.cabin))
      return true;
    return false;
  }

  public int hashCode() {
    return ((ship + deck + cabin).hash);
  }

The class that defines the primary key is declared within the XML deployment descriptor, as follows:

<enterprise-beans>
      <entity>
         <ejb-name>CabinBean</ejb-name>
         <home>cruise.CabinHome</home>
         <remote>cruise.Cabin</remote>
         <ejb-class>cruiseServer.CabinBean</ejb-class>
         <persistence-type>Container</persistence-type>
         <reentrant>False</reentrant>
         <cmp-field><field-name>deck</field-name></cmp-field>
         <cmp-field><field-name>cabin</field-name></cmp-field>
         <prim-key-class>cruise.CabinPK</prim-key-class>
...
</enterprise-beans>

See "Entity Bean Elements" for a full description of the deployment descriptor definition.

Manage the Primary Key

You must initialize all CMP fields, including the primary key, within the ejbCreate method. The ejbCreate method for the purchase order example initializes the primary key, ponumber, to the next available number in the purchase order number sequence.

// The create methods takes care of generating a new PO and returns
// its primary key
public String ejbCreate () throws CreateException, RemoteException
{
  String ponumber = null;
  try {
    //retrieve the next available purchase order number
    #sql { select ponumber.nextval into :ponumber from dual };
    //assign this number as this instance's identification number
    #sql { insert into pos (ponumber, status) values (:ponumber, 'OPEN') };
  } catch (SQLException e) {
    throw new PurchaseException (this, "create", e);
  }
  return ponumber;
}

Declare Persistence Fields

All container-managed persistent fields must be declared as public within your bean class. They cannot be transient. In addition, these fields are restricted to be either primitive, serializable, and types that can be mapped to SQL types. See Table A-2, "Unsupported Java Types for Persistent Variables" for more information.

Declare Persistence Provider

The container invokes a persistence provider for managing your CMP bean. This release supports Oracle Persistence Service Interface Reference Implementation (PSI-RI). For more information on defining the provider, see "Defining Container-Managed Persistence" for a full description.


Note:

Make sure that the class that contains the persistence manager is loaded within the database. 


The following shows the portion of the Oracle-specific deployment descriptor that defines the persistence manager:

...
 <persistence-provider>
  <description> specifies a type of persistence manager </description>
  <persistence-name>psi-ri</persistence-name>
  <persistence-deployer>oracle.aurora.ejb.persistence.ocmp.OcmpEntityDeployer</p
ersistence-deployer>
 </persistence-provider>

 <persistence-descriptor>
  <description> This specifies a particular type of persistence manager to be us
ed for a bean.  param is where you would put bean specific persistence info in t
he format of params.  The deployment process just passes what's in the param to
the persistence deployer.  For the baby persistence, we do parse the persistence
-mapping but for other persistence backend we don't do anything with the params
  </description>
   <ejb-name>customerbean</ejb-name>
   <persistence-name>psi-ri</persistence-name>
   <psi-ri>
      <schema>SCOTT</schema>
      <table>customers</table>
      <attr-mapping>
        <field-name>custid</field-name>
        <column-name>cust_id</column-name>
      </attr-mapping>
      <attr-mapping>
        <field-name>name</field-name>
        <column-name>cust_name</column-name>
      </attr-mapping>
      <attr-mapping>
        <field-name>addr</field-name>
        <column-name>cust_addr</column-name>
      </attr-mapping>
   </psi-ri>
  </persistence-descriptor>
 </oracle-descriptor>
</oracle-ejb-jar>

Define Persistence Storage Database

By default, the Container stores the persistence data into the database that is local to where the transaction was started--or continued with the Supports attribute--by the Container. If you want to designate a certain database as the persistence storage database--as in an Oracle9i Application Server middle-tier--do the following:

  1. Bind a JTA DataSource that designates the persistence storage database.

  2. Designate this DataSource within the <persistence-datasource> element in the Oracle-specific deployment descriptor.

The following defines the PSI-RI persistence provider that uses a remote database to store the persistence fields. The "/test/empDatabase" JTA DataSource is defined in the following example as the remote persistence storage. This DataSource was bound by bindds with the -type jta option.

<persistence-provider>
  <description> specifies a type of persistence manager </description>
  <persistence-name>psi-ri</persistence-name>
  <persistence-deployer>oracle.aurora.ejb.persistence.ocmp.OcmpEntityDeployer
</persistence-deployer> <persistence-datasource>/test/empDatabase</persistence-datasource> </persistence-provider>

If you are using Container-managed entity beans within your Oracle9i Application Server middle-tier, the Container defaults to storing the persistent data in the local database. However, the middle-tier contains a read-only cache; thus, you must specify the persistence storage database within the <persistence-database> element.

Map Container-Managed Persistence Fields

All CMP data fields defined within your bean must be declared within the deployment descriptor in the <cmp-field> element. See "Entity Bean Elements" for a full description. In addition, you must map these fields to the intended database table and respective columns. See "Persistence Fields" for more information.

The following is a portion of the Oracle-specific deployment descriptor, which maps the primary key and any container-managed persistence fields from the customer example (with the single primary key field) to the database table and column that the persistence provider stores the values for these fields within. Specifically, the container-manager stores the persistent fields into the customers table in SCOTT's schema. The persistent fields are mapped as follows:

Persistent Field  Table Column 

custid (primary key) 

cust_id column in the customers table 

name 

cust_name column in the customers table 

addr 

cust_addr column in the customers table 

<psi-ri>
      <schema>SCOTT</schema>
      <table>customers</table>
      <attr-mapping>
        <field-name>custid</field-name>
        <column-name>cust_id</column-name>
      </attr-mapping>
      <attr-mapping>
        <field-name>name</field-name>
        <column-name>cust_name</column-name>
      </attr-mapping>
      <attr-mapping>
        <field-name>addr</field-name>
        <column-name>cust_addr</column-name>
      </attr-mapping>
</psi-ri>

Accessing EJB References and JDBC DataSources

You can access EJB references and JDBC DataSources through your bean's environment.

EJB References

The entity bean may create an environment reference for a target bean within the deployment descriptors. The URL of an EJB environment reference should have the following syntax:

"java:comp/env/ejb/"<ejb-ref-name>

The "java:comp/env/ejb" prefix is a subcontext that instructs JNDI to locate the EJB reference within the EJB references defined in the deployment descriptor. The <ejb-ref-name> is the logical environment name of the EJB reference defined in the deployment descriptor. The following shows how a bean looks up another bean's reference within its deployed environment:

Context ic = new InitialContext ( );

CustomerHome ch = (CustomerHome)ic.lookup ("java:comp/env/ejb/PurchaseOrder");

See "Environment References To Other Enterprise JavaBeans" for a full description of EJB environment references.

JDBC DataSources

The entity bean had the option of creating an environment reference for JDBC DataSource objects bound within JNDI. These were declared for the bean within the deployment descriptors. If defined, the serviceURL and objectName contains the URL of an EJB environment reference, which is of the following syntax:

"java:comp/env/jdbc/"<resource-ref-name>


The "java:comp/env/jdbc" prefix is a subcontext that instructs JNDI to locate the JDBC DataSource within the <resource-ref> elements defined in the deployment descriptor, which actually defines the logical environment name.

The following is the definition of the JDBC DataSource within the EJB deployment descriptor for the purchase order:

<resource-ref>
           <res-ref-name>jdbc/EmployeeAppDB</res-ref-name>
           <res-type>javax.sql.DataSource</res-type>
           <res-auth>Application</res-auth>
</resource-ref>


Note:

Only the Application option is supported for <res-auth> for this release. 


The following shows the JNDI context initialization for the purchase order example:

#import javax.sql.*

String dbURL = "java:comp/env/jdbc/EmployeeAppDB";

DataSource dbRes = (DataSource)ic.lookup (dbURL);
Connection conn = dbRes.getConnection;


See "Environment References To Resource Manager Connection Factory References" for a full description of JDBC DataSource variables.


Go to previous page Go to next page
Oracle
Copyright © 1996-2001, Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Product List
Book List
Go To Table Of Contents
Contents
Go To Index
Index

Master Index

Feedback