Skip Headers

Oracle Application Server Containers for J2EE Enterprise JavaBeans Developer's Guide 10g (9.0.4) Part Number B10324-01 |
Home | Contents | Index

# B
EJB 1.1 CMP Entity Beans

If you have EJB 1.1 CMP entity beans from last release, this appendix informs you of how OC4J maps your EJB 1.1 CMP deployment descriptor elements to OC4J-specific mappings. Oracle encourages you to migrate to using the EJB 2.0 method for CMP entity beans; however, Oracle supports both specifications.

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

This chapter demonstrates the following:

- Creating Entity Beans--Demonstrates how to create a simple container-managed persistent entity bean.

- Advanced CMP Entity Beans--Demonstrates advanced configuration for finder methods, object-relational mapping, and so on.

See Chapter 3, "CMP Entity Beans" for details on CMP EJB 2.0 entity beans.

## 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 B-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:

- the target methods for the methods that are declared in the home interface, which includes the `ejbCreate` method and any finder methods, including `ejbFindByPrimaryKey`

- the business logic methods that are declared in the remote interface

- the methods that are inherited from the `EntityBean` interface

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.

- Database--The default database as set up in your OC4J instance configuration. For the JNDI name, use the `<location>` element for emulated data sources and `<ejb-location>` element for non-emulated data sources.

  Upon installation, the default database is a locally installed Oracle database that must be listening on port 1521 with a SID of `ORCL`. To customize the default database, change the first configured database (including its `<ejb-location>`) to point to your database.

- Table with correct column names--The container creates a default table with the same name as the bean name (defined in `<ejb-name>`), with columns having the same name as the `<cmp-field>` elements in the designated database. The data types for the database, translating Java data types to database data types, are defined in the specific database XML file, such as `oracle.xml`.

If you want to designate another database or generate a table that has a different naming convention, see "EJB 1.1 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:

- Define the type of the primary key to be a well-known type. The type is defined in the `<prim-key-class>` in the deployment descriptor. The data field that is identified as the persistent primary key is identified in the `<primkey-field>` element in the deployment descriptor. The primary key variable that is declared within the bean class must be declared as `public`.

- Define the type of the primary key as a serializable object within a <`name`>`PK` class that is serializable. This class is declared in the `<prim-key-class>` element in the deployment descriptor. This is an advanced method for defining a primary key, so it is discussed in "Defining the Primary Key in a Class".

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:

- Be defined within a `<cmp-field><field-name>` element in the deployment descriptor. This enables the container to manage the primary key fields.

- Be declared within the bean class as `public` and restricted to be either primitive, serializable, or types that can be mapped to SQL types.

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:

- EJB 1.1 Advanced Finder Methods

- EJB 1.1 Object-Relational Mapping of Persistent Fields

### EJB 1.1 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 EJB 1.1 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 EJB 1.1 Finder Method Definition to the OC4J-Specific Deployment Descriptor

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

The EJB 1.1 `<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.

For entity bean finder methods, lazy loading can cause the select method to be invoked more than once. To turn on lazy loading and enforce only a single execution of this finder method, set the `lazy-loading` property to true.

    <finder-method partial="false"
                   query="select * from EMP where $empName = $1"
                   lazy-loading=true>
            <!-- 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>

### EJB 1.1 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 EJB 1.1 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 `Collection` or `Set` of fields, then define these fields within the `<collection-mapping>`, `<set-mapping>` elements.

| Copyright © 2002, 2003 Oracle Corporation. All Rights Reserved. |
Home | Contents | Index