Specifying a BMP Entity Bean

Following the pattern of Session beans, specifying an Entity bean involves defining the local-home and the local interface:

  • The local-home interface extends javax.ejb.EJB LocalHome.

  • The local interface extends javax.ejb.EJBLocalObject.

A discussion on each of these interfaces follows.

NOTE

Although Entity beans usually use the local interface, there is no reason why the remote interface cannot be used instead of, or as well as, the local interface. In the following discussion, EJBHome and EJBLocalHome and EJBOject and EJBLocalObject can be considered synonymous; however all methods in the remote interfaces must throw RemoteException (as discussed on Day 5, “Session EJBs”).


Local-Home Interface

Listing 6.1 shows the complete JobLocalHome interface as an example.

Listing 6.1. JobLocalHome Interface
package data;

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

public interface JobLocalHome extends EJBLocalHome
{
   JobLocal create (String ref, String customer) throws CreateException;
   JobLocal findByPrimaryKey(JobPK key) throws FinderException;
   Collection findByCustomer(String customer) throws FinderException;
   Collection findByLocation(String location) throws FinderException;
   void deleteByCustomer(String customer);
}

Each of these methods has a corresponding method in the bean class itself. Taking the JobBean code as an example, Listing 6.2 shows the template functions for the bean itself:

Listing 6.2. Job Entity Bean Class Simplified to Show Similarity to JobLocalHome Interface
package data;

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

public class JobBean implements EntityBean
{
   JobPK ejbCreate (String ref, String customer) throws CreateException {...}
   JobPK ejbFindByPrimaryKey(JobPK key) throws FinderException {...}
   Collection ejbFindByCustomer(String customer) throws FinderException {...}
   Collection ejbFindByLocation(String location) throws FinderException {...}
   void ejbHomeDeleteByCustomer(String customer) {...}
}

NOTE

Note that for home methods discussed shortly, the convention is to append ejbHome, not just ejb, to the bean's method name.


This seems straightforward enough, but note that the return types of the bean's ejbCreate() and ejbFindXxx() methods are different from the return types of the methods in the local-home interface. Specifically, while the bean returns (to the EJB container) either primary key objects or a Collection of primary key objects, the local-home interface methods returns either local proxies (that is, instances of objects that implement the JobLocal interface, for the example) or a Collection of local proxies.

Create and Remove Methods

The list of exceptions thrown by the local-home methods and the bean's corresponding methods should match in each case. For the createXXX() method, the list should be the union of the exceptions thrown by both ejbCreateXXX() and ejbPostCreateXXX().

As well as the create() method, the local-home interface inherits a remove(Object o) method from javax.ejb.EJBLocalHome. This corresponds to the ejbRemove() lifecycle method of the bean itself.

Finder Methods

Finder methods in the bean return either a single primary key (if a single bean matches the underlying query) or a java.util.Collection of primary keys (if there is more than one matching bean). The ejbFindByPrimaryKey() method is always required to be one of the bean's methods, although it is not part of the EntityBean interface (this is because the argument type and return type will depend on the bean).

NOTE

It is also possible for finder methods to return a java.util.Enumeration. This dates from EJB 1.0 before the Java Collections API was introduced in J2SE 1.2 and should not be used.


Obviously, to specify the findByPrimaryKey() method, the primary key of the Entity bean must have been identified. As was noted earlier today, if persisting to a database, identifying the primary key is probably quite easy, because the primary key will correspond to the columns of the primary key of the underlying database table. A custom-developed primary key class is needed when two or more fields identify the bean; otherwise, the type of the single field of the bean that represents the key is used.

NOTE

If a single field of the bean is used as the primary key, that field must be an Object and not a primitive type. Furthermore, the EJB specification does not allow primary keys to change once assigned, so it is best if the class chosen is immutable. The standard java.lang classes such as String, and the primitive wrapper classes (Integer, Long, and so on) are all immutable.


Custom Primary Key Classes

As noted earlier, the primary key can be either a field of the bean (in which case, the primary key class is just the class of that field), or it can be a custom-developed class. The latter is required if more than one field is needed to identify the bean.

For the JobBean, the primary key is a combination of the customer and the job reference (the customer and ref fields, respectively). Because the primary key is composite, a custom primary key class is needed; this is the JobPK class.

Custom primary key classes are required to follow a number of rules. Specifically,

  • The class must implement java.io.Serializable or java.io.Externalizable.

  • The instance variables in the class must all be primitives or be references to objects that are, in turn, serializable.

  • The equals() method and the hashCode() methods must be implemented to compare objects using the value of the data in the primary key fields.

  • There must be a no-arg constructor (there can also be other constructors that take arguments).

In other words, the class must be what is referred to as a value type (see the discussion of the Value Object pattern on Day 18, “Patterns”). It is usual to define the primary key class to conform to JavaBean semantics by adding getter methods to retrieve the individual fields of the primary key.

NOTE

At least conceptually, value types are immutable (there should be no setter methods; they cannot be changed). Sadly, the requirement for a no-arg con structor sometimes requires methods to be supplied that will change the primary key fields. However the fields must not be changed once an initial value has been given to the primary key object.


Listing 6.3 shows the JobPK primary key class.

Listing 6.3. JobPK Class Identifies a Job
package data;

import java.io.*;
import javax.ejb.*;

public class JobPK implements Serializable {
    public String ref;
    public String customer;

    public JobPK() {
    }
    public JobPK(String ref, String customer) {
        this.ref = ref;
        this.customer = customer;
    }


    public String getRef() {
        return ref;
    }
    public String getCustomer() {
        return customer;
    }


    public boolean equals(Object obj) {
        if (obj instanceof JobPK) {
            JobPK pk = (JobPK)obj;
            return (pk.ref.equals(ref) && pk.customer.equals(customer));
        }
        return false;
    }
    public int hashCode() {
        return (ref.hashCode() ^ customer.hashCode());
    }
    public String toString() {
        return "JobPK: ref="" + ref + "", customer="" + customer + """;
    }
}

Note that the ref and customer fields have public visibility. This is a requirement of the EJB 1.1 specification. Each field must correspond—in name and type—to one of the fields of the bean itself. This might seem like a strange requirement, but is needed by the EJB container to manage CMP beans.

Because this is a Value Object, you are required to override the equals() method. To implement the equals() method, test that all fields of the object have the same value as the fields in the provided object. For primitive values, the regular == operator should be used, but for object references, the equals() method must be called.

If you override equals() you must also override hashCode(). To implement the hashCode() method, you must generate an int value that is based entirely and deterministically on the value of the fields, such that

if A.equals(B) then A.hashCode() == B.hashCode().

A simple technique is to obtain the hashCode() values for all of the fields within the bean and XOR these values together (using the ^ operator) to generate the required hash code. This simplistic approach may result in poor distribution of hash codes for primary keys with many fields but is usually sufficient.

NOTE

Creating these primary key classes can be somewhat tedious. But remember that if there is a single (non-primitive) field in the bean that identifies that bean, this can be used instead.


Home Methods

In addition to finder, create, and remove methods, it is also possible to define home methods within the local-home interface. These are arbitrary methods that are expected to perform some business-type functionality related to the set of Entity beans rather than an individual bean. In other words, they are an EJB equivalent of static Java class methods.

Some common uses for home methods include

  • Defining a batch operation to be performed on all bean instances (such as decreasing the price of all catalogue items for a sale)

  • Manipulating the collection of Entity beans rather than individual beans (such as deleting all paid invoices over two years old)

Local Interface

Just as for Session beans with their remote interfaces, the local interface defines the capabilities of the bean. Because an Entity bean represents data, it is usual for many of the local interface methods to be simple getter and setter methods. Listing 6.4 shows the local interface for the Job bean.

Listing 6.4. JobLocal Interface
package data;

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

public interface JobLocal extends EJBLocalObject
{
    String getRef();
    String getCustomer();
    CustomerLocal getCustomerObj(); // derived

    void setDescription(String description);
    String getDescription();

    void setLocation(LocationLocal location);
    LocationLocal getLocation();

    Collection getSkills();
    void setSkills(Collection skills);
}

Note that the setLocation() method accepts a LocationLocal reference rather than, say, a String containing the name of a location. In other words, the Job bean is defining its relationships to the Location bean directly, effectively enforcing referential integrity. The client of the Job Entity bean is thus required to supply a valid location or none at all.

Each of these methods has a corresponding method in the bean itself, and must throw the same application exceptions. The implementation is shown in the “Implementing the Local-Interface Methods” section later today.

NOTE

Entity beans can also provide a timer service using the same interface as session beans. EJB timer services were discussed on Day 5.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.251.70