Skip Headers

Oracle9iAS Containers for J2EE Enterprise JavaBean Developer's Guide and Reference
Release 2 (9.0.2)

Part Number A95881-01
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Go to previous page Go to next page

3
CMP Entity Beans

An entity bean manages persistent data in one of two manners: container-managed persistence and bean-managed persistence. The primary difference between the two is as follows:

This chapter demonstrates simple CMP EJB development with a basic configuration and deployment. Download the CMP entity bean example (cmpapp.jar) from the OC4J sample code page on the OTN site.

This chapter demonstrates the following:

See Chapter 4, "BMP Entity Beans", for an example of how to create a simple bean-managed persistent entity bean.

Creating Entity Beans

To create an entity bean, 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 be either a well-known class, such as java.lang.String, or defined within its own class.

  4. Implement the bean. This includes the following:

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

    2. The methods that are defined in the javax.ejb.EntityBean interface.

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

      • the ejbCreate and ejbPostCreate methods with parameters matching the associated create method defined in 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. Create the bean deployment descriptor. The deployment descriptor specifies properties for the bean through XML elements. This step is where you identify the data within the bean that is to be managed by the container.

  6. If the persistent data is saved to or restored from a database and you are not using the defaults provided by the container, then you must ensure that the correct tables exist for the bean. In the extreme default scenario, the container will actually create the table and columns for your data based on deployment descriptor and datasource information.

  7. Create an EJB JAR file containing the bean, the remote and home interfaces, and the deployment descriptor. Once created, configure the application.xml file, create an EAR file, and install the EJB in OC4J.

The following sections demonstrate a simple CMP entity bean. This example continues the use of the employee example, as in other chapters--without adding complexity.

Home Interface

The 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. Optionally, you can develop other finder methods for the bean, which are named find<name>.

Example 3-1 Entity Bean Employee Home Interface

To demonstrate an entity bean, this example creates a bean that manages a purchase order. The entity bean contains a list of items that were ordered by the customer.

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

package employee;

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

public interface EmployeeHome extends EJBHome
{

  public Employee create(Integer empNo)
    throws CreateException, RemoteException;

  // Find an existing employee
  public Employee findByPrimaryKey (Integer empNo)
    throws FinderException, RemoteException;

  //Find all employees
  public Collection findAll()
    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 employee entity bean, the remote interface contains methods for adding and removing employees, and retrieving and setting employee information.

package employee;

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

public interface Employee extends EJBObject
{
  // getter remote methods
  public Integer getEmpNo() throws RemoteException;
  public String getEmpName() throws RemoteException;
  public Float getSalary() throws RemoteException;

  // setter remote methods
  public void setEmpName(String newEmpName) throws RemoteException;
  public void setSalary(Float newSalary) throws RemoteException;
}

Entity Bean Class

The entity bean class must implement the following methods:

However, with container-managed persistence, the container manages most of the target methods and the data objects. This leaves little for you to implement.

package employee;

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

public class EmployeeBean extends Object implements EntityBean
{

  public Integer empNo;
  public String empName;
  public Float salary;
  public EntityContext entityContext;

  public EmployeeBean()
  {
    // Constructor. Do not initialize anything in this method.
    // All initialization should be performed in the ejbCreate method.
  }

  public Integer getEmpNo()
  {
    return empNo;
  }

  public String getEmpName()
  {
    return empName;
  }

  public Float getSalary()
  {
    return salary;
  }

  public void setEmpName(String empName)
  {
    this.empName = empName;
  }

  public void setSalary(Float salary) {
    this.salary = salary;
  }

  public Integer ejbCreate(Integer empNo)
    throws CreateException, RemoteException
  {
    this.empNo = empNo;
    return empNo;
  }

  public void ejbPostCreate(Integer empNo)
    throws CreateException, RemoteException
  {
    // Called just after bean created; container takes care of implementation
  }

  public void ejbStore()
  {
    // Called when bean persisted; container takes care of implementation
  }

  public void ejbLoad()
  {
    // Called when bean loaded; container takes care of implementation
  }

  public void ejbRemove()
  {
    // Called when bean removed; container takes care of implementation
  }

  public void ejbActivate()
  {
    // Called when bean activated; container takes care of implementation.
    // If you need resources, retrieve them here.
  }

  public void ejbPassivate()
  {
    // Called when bean deactivated; container takes care of implementation.
    // if you set resources in ejbActivate, remove them here.
  }

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

  public void unsetEntityContext()
  {
    this.entityContext = null;
  }
}

Persistent Data

In CMP entity beans, you define the persistent data both in the bean instance and in the deployment descriptor. The declaration of the data fields in the bean instance creates the resources for the fields. The deployment descriptor defines these fields as persistent.

In our employee example, the data fields are defined in the bean instance, as follows:

public Integer empNo;
public String empName;
public Float salary;

These fields are defined as persistent fields in the ejb-jar.xml deployment descriptor within the <cmp-field><field-name> element, as follows:

<enterprise-beans>
      <entity> 
         <display-name>Employee</display-name>
         <ejb-name>EmployeeBean</ejb-name>
         <home>employee.EmployeeHome</home>
         <remote>employee.Employee</remote>
         <ejb-class>employee.EmployeeBean</ejb-class>
         <persistence-type>Container</persistence-type>
         <prim-key-class>java.lang.Integer</prim-key-class>
         <reentrant>False</reentrant>
         <cmp-field><field-name>empNo</field-name></cmp-field>
         <cmp-field><field-name>empName</field-name></cmp-field>
         <cmp-field><field-name>salary</field-name></cmp-field>
         <primkey-field>empNo</primkey-field>
      </entity>
...
</enterprise-beans>

In most cases, you map the persistent data fields to columns in a table that exists in a designated database. However, you can accept the defaults for these fields--thus, avoiding more deployment descriptor configuration.

OC4J contains some defaults for mapping these fields to a database and its table.

If you want to designate another database or generate a table that has a different naming convention, see "Object-Relational Mapping of Persistent Fields" for a description of how to customize your database, table, and column names.

Primary Key

Each entity bean instance has a primary key that uniquely identifies it from other instances. You must declare the primary key (or the fields contained within a complex primary key) as a container-managed persistent field in the deployment descriptor. All fields within the primary key are restricted to either primitive, serializable, or types that can be mapped to SQL types. You can define your primary key in one of two ways:

For a simple CMP, you can define your primary key to be a well-known type by defining the data type of the primary key within the deployment descriptor.

The employee example defines its primary key as a java.lang.Integer and uses the employee number (empNo) as its primary key.

<enterprise-beans>
      <entity> 
         <display-name>Employee</display-name>
         <ejb-name>EmployeeBean</ejb-name>
         <home>employee.EmployeeHome</home>
         <remote>employee.Employee</remote>
         <ejb-class>employee.EmployeeBean</ejb-class>
         <persistence-type>Container</persistence-type>
         <prim-key-class>java.lang.Integer</prim-key-class>
         <reentrant>False</reentrant>
         <cmp-field><field-name>empNo</field-name></cmp-field>
         <cmp-field><field-name>empName</field-name></cmp-field>
         <cmp-field><field-name>salary</field-name></cmp-field>
         <primkey-field>empNo</primkey-field>
      </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. You define the primary key class within the <prim-key-class> element in the deployment descriptor.

The primary key variables must adhere to the following:

Within the primary key class, you implement a constructor for creating a primary key instance. Once defined in this manner, the container manages the primary key, as well as storing the persistent data.

The following example is a complex primary key made up of employee number and country code. Our company is so large that it reuses employee numbers in different countries. Thus, the combination of both the employee number and the country code uniquely identifies each employee.

package employee;

public class EmpPK implements java.io.Serializable
{
  public Integer empNo;
  public String countryCode;

  //constructor
  public EmpPK ( ) { }
}

The primary key class is declared within the <prim-key-class> element and its variables, each within a <cmp-field><field-name> element in the XML deployment descriptor, as follows:

<enterprise-beans>
      <entity> 
         <display-name>Employee</display-name>
         <ejb-name>EmployeeBean</ejb-name>
         <home>employee.EmployeeHome</home>
         <remote>employee.Employee</remote>
         <ejb-class>employee.EmployeeBean</ejb-class>
         <persistence-type>Container</persistence-type>
         <prim-key-class>employee.EmpPK</prim-key-class>
         <reentrant>False</reentrant>
         <cmp-field><field-name>empNo</field-name></cmp-field>
         <cmp-field><field-name>countryCode</field-name></cmp-field>
      </entity>
      ...
</enterprise-beans>

Deploying the Entity Bean

Archive your EJB into a JAR file. You deploy the entity bean in the same way as the session bean, which "Prepare the EJB Application for Assembly" and "Deploy the Enterprise Application to OC4J" explain in detail.

Advanced CMP Entity Beans

This section discusses how to implement your bean beyond the simple CMP entity bean. It includes the following sections:

Advanced Finder Methods

Specifying the findByPrimaryKey method is easy to do in OC4J. All the fields for defining a simple or complex primary key are specified within the ejb-jar.xml deployment descriptor. However, if you want to define other finder methods in a CMP entity bean, you must do the following:

  1. Add the finder method to the home interface.

  2. Add the finder method definition to the OC4J-specific deployment descriptor--the orion-ejb-jar.xml file.

Add the Finder Method to Home Interface

You must first add the finder method to the home interface. For example, with the employee entity bean, if we wanted to retrieve all employees, the findAll method would be defined within the home interface, as follows:

public Collection findAll() throws FinderException, RemoteException;

Add the Finder Method Definition to OC4J-Specific Deployment Descriptor

After specifying the finder method in the home interface, modify the orion-ejb-jar.xml file with the finder method specifics. The container identifies the correct query necessary for retrieving the required fields.

The <finder-method> element defines all finder methods--excluding the findByPrimaryKey method. The simplest finder method to define is the findByAll method. The query attribute in the <finder-method> element specifies the WHERE clause for the query. If you want all rows retrieved, then an empty query (query="") returns all records.

The following example retrieves all records from the EmployeeBean. The method name is findAll, and it requires no parameters because it returns a Collection of all employees.

<finder-method query="">
  <method>
     <ejb-name>EmployeeBean</ejb-name>
     <method-name>findAll</method-name>
         <method-params></method-params>
     </method>
</finder-method>

After deploying the application with this bean, OC4J adds the following statement of what query it invokes as a comment in the finder method definition:

<finder-method query="">
<!-- Generated SQL: "select EmployeeBean.empNo, EmployeeBean.empName, 
    EmployeeBean.salary from EmployeeBean" -->
  <method>
     <ejb-name>EmployeeBean</ejb-name>
     <method-name>findAll</method-name>
         <method-params></method-params>
     </method>
</finder-method>

Verify that it is the type of query that you expect.

To be more specific, modify the query attribute with the appropriate WHERE clause. This clause refers to passed in parameters using the '$' symbol: the first parameter is denoted by $1, the second by $2. All <cmp-field> elements that are used within the WHERE clause are denoted by $<cmp-field> name.

The following example specifies a findByName method (which should be defined in the home interface) where the name of the employee is given as in the method parameter, which is substituted for the $1. It is matched to the CMP name, "empName". Thus, our query attribute is modified to contain the following for the WHERE clause: "$empname=$1".

<finder-method query="$empname = $1">
  <method>
    <ejb-name>EmployeeBean</ejb-name>
    <method-name>findByName</method-name>
    <method-params>
      <method-param>java.lang.String</method-param>
    </method-params>
  </method>
</finder-method>

If you have more than one method parameter, each parameter type is defined in successive <method-param> elements and referred to in the query statement by successive $n, where n represents the number.


Note:

You can also specify a SQL JOIN in the query attribute.


If you wanted to specify a full query and not just the section after the WHERE clause, specify the partial attribute to FALSE and then define the full query in the query attribute. The default value for partial is true, which is why it is not specified on the previous finder-method example.

<finder-method partial="false"
               query="select * from EMP where $empName = $1">
        <!-- Generated SQL: "select * from EMP where EMP.ENAME = ?" -->
        <method>
                <ejb-name>EmployeeBean</ejb-name>
                <method-name>findByName</method-name>
                <method-params>
                        <method-param>java.lang.String</method-param>
                </method-params>
        </method>
</finder-method>

Specifying the full SQL query is useful for complex SQL statements.

Object-Relational Mapping of Persistent Fields

As "Persistent Data" discusses, your persistent data can be automatically mapped to a database table by the container. However, if the data represented by your bean is more complex or you do not want to accept the defaults that OC4J provides for you, then map the CMP designated fields to an existing database table and its applicable rows within the orion-ejb-jar.xml file. Once mapped, the container provides the persistence storage of the CMP data to the indicated table and rows.

Before configuring the object-relational mapping, add the DataSource used for the destination within the <resource-ref> element in the ejb-jar.xml file.

Mapping CMP Fields to a Database Table and Its Columns

Configure the following within the orion-ejb-jar.xml file:

  1. Configure the <entity-deployment> element for every entity bean that contains CMP fields that will be mapped within it.

  2. Configure a <cmp-field-mapping> element for every field within the bean that is mapped. Each <cmp-field-mapping> element must contain the name of the field to be persisted.

    1. Configure the primary key in the <primkey-mapping> element contained within its own <cmp-field-mapping> element.

    2. Configure simple data types (such as a primitive, simple object, or serializable object) that are mapped to a single field within a single <cmp-field-mapping> element. The name and database field are fully defined within the element attributes.

    3. Configure complex data types using one of the many sub-elements of the <cmp-field-mapping> element. These can be one of the following:

      • If you define an object as your complex data type, then specify each field or property within the object in the <fields> or <properties> element.

      • If you specify a field defined in another entity bean, then define the home interface of this entity bean in the <entity-ref> element.

      • If you define a List, Collection, Set, or Map of fields, then define these fields within the <list-mapping>, <collection-mapping>, <set-mapping>, <map-mapping> elements.

Examples for simple and complex O-R mappings are shown in the following sections:

One-to-One Mapping Example

The following example demonstrates how to map persistent data fields in your bean instance to database tables and columns by mapping the employee persistence data fields to the Oracle database table EMP.

After deployment, OC4J maps this to the following:

Bean Database

emp/EmpBean

EMP table, located at jdbc/OracleDS in the data-sources.xml file

empNo

EMPNO column as primary key

empName

ENAME column

salary

SAL column

One-to-Many Mapping Example

If you have two beans that access two tables for their data, you must map the persistent data from both beans to the respective tables.

We added a department number to our employee example. Each employee belongs to a department; each department has multiple employees. The container will handle this object-relational mapping; however, you must specify how the data is stored.

The employee data maps to the employee database table; the department data is mapped to the database department table. The employee database table also contains a foreign key of the department number to link this information together.

The XML configuration for the employee bean, EmpBean, is as follows:

The XML configuration for the department bean, DeptBean, is as follows:


Go to previous page Go to next page
Oracle
Copyright © 2002 Oracle Corporation.

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