J3 Limited
 
Google
WWW J3Ltd
 
BMP EJB's

 

The previous section gave a brief overview of enterprise Java beans (EJB).

This section explains how bean managed persistence entity beans (BMP EJB's) should be coded.

The next section deals with the details of writing a deployment descriptor for BMP EJB's.

Overview

An entity bean is composed of several files: interfaces, class(es) and a deployment descriptor.

Entity Bean Class is the implementation of the bean. It contains code to insert, update, delete, select data from the database. It has member variables to hold the current bean's data, and methods to perform business logic.

Entity Bean Home Interface is the interface used by clients to create, remove and find a given bean.

Entity Bean Remote Interface is the interface used by clients to interact with a given bean, for example load all the record's fields, update some data columns in it, store changes, delete (remove) the record. Business logic methods associated with the bean implementation are also present here. The container manages the marshaling of calls between the remote interface and the bean class behind the scenes.

Entity Bean Primary Key Class defines the underlying object's primary key. Using the primary key class it should be possible to locate at most one object in the underlying storage. The class must be Serializable. Hence simple keys (such as String, Integer) can use Java's classes as the primary key class. Composite keys require the developer to write the code to represent the primary key.

Application Exception Class(es) may be defined to signal that an Entity bean method caused an application level error. It is worth noting that EJB defines its own set of exceptions too.

Deployment Descriptor is an xml file which details what each Java class file is for. For example, which file is the remote interface, which is the home interface, what the primary key is....

Next we look at each file in detail.


Entity Bean Class

Entity Contexts

Developers of entity bean classes, need good knowledge of the EntityContext interface, and the EJBContext interface. These interfaces allow the bean to:

  • Get datasource information, and hence create a connection (preferably via JNDI).
  • Get the security role the bean is in
  • Get an EJBHome instance to create additional beans
  • Get an EJBObject of itself, if it needs to pass itself to other beans
  • Get the primary key value of the underlying entity it currently represents
  • Get the current transaction status (is it OK, or currently about to be rolled back?)
  • Get properties assigned to it. This is done via JNDI.

This class contains all the code that must be written: it is a class, not an interface. The class name usually ends with Bean or EJB. For example a Person bean implementation class would be called PersonBean.

The entity bean class must implement javax.ejb.EntityBean, by doing so, several methods are coded:

public void setEntityContext(EntityContext ctx) throws EJBException, java.rmi.RemoteException. The container calls this method on the bean before it is used. This method is typically called once by the container, after the class instance is constructed. The method allows the bean to keep hold of the container's context. The context can be used to get hold of database connections and other resources when they are needed and/or available.

void ejbActivate() throws javax.ejb.EJBException, java.rmi.RemoteException. When the bean is taken out of the container's pool of beans, this method is called. It allows the bean to grab any resources it may need. At this point the bean can get its primary key value from the context. It can also safely get its EJBObject from the context.

public void ejbLoad() throws EJBException, java.rmi.RemoteException. The container calls this method on the bean when it wants the bean to load its data from the underlying storage. When this method is called the bean has already been activated.

public void ejbStore() throws EJBException, java.rmi.RemoteException. The container calls this method on the bean when it wants the bean to save its data to the underlying storage. When this method is called the bean has already been activated.

public void ejbRemove() throws RemoveException, EJBException, java.rmi.RemoteException. The container calls this method to delete the record from the underlying storage. When this method is called the bean has already been activated. After this method is called the bean is returned to the pool of available beans (in effect the remove method passivates the bean). Hence, the bean should perform the same shutdown steps in the ejbRemove() method and in the ejbPassivate() method.

void ejbPassivate() throws javax.ejb.EJBException, java.rmi.RemoteException. When the client application has finished with the bean, the container may return it to its pool of beans. This method is called so that the bean can release any resources it has grabbed.

public void unsetEntityContext() throws EJBException, java.rmi.RemoteException. The container calls this method before the bean is destroyed.

All of the above method signatures throw two types of exceptions. The code should only throw the EJBException, RemoteException is only there for backwards compatibility with EJB 1.0. When an exception is thrown, the container treats the bean as invalid: the transaction is rolled back, no other method will be invoked on the bean instance.

EJBLoad and EJBStore may throw NoSuchEntityException (which extends EJBException) if the underlying object no longer exists in the database/storage mechanism.

Finders

The bean must define a method called ejbFindByPrimaryKey() which finds at most one record in the underlying storage mechanism. Additional finders can be coded to return one primary key, or a Collection/Enumeration of primary key class instances.

The rule for additional finders is that their name must start with "ejbFind". Hence we could define several finders in addition to the primary key finder. For example ejbFindAll(), ejbFindFirstFew(int maxRecords), findNextFew(int lastId, int maxRecords), and so on.

In finders the bean is not activated. The container can retrieve a bean from its pool of available beans, call a finder on it, and then return the bean to the pool of available beans. This means that during the ejbFind() call the context must not be used to retrieve the bean's EJBObject or primary key.

Creators

The bean can define creator methods to insert a record into the underlying storage mechanism. It is optional, you do not have to define create methods in your enterprise bean. Though if the application intends to insert records into the underlying storage mechanism, then creators will have to be defined.

Multiple create methods may be defined. Each one must be named ejbCreate(). The ejbCreate() method must return the primary key value of the object created. Any number of ejbCreate() methods can be defined, each one with a different set of parameters.

Matching ejbPostCreate() methods (one per ejbCreate() defined) must be defined. The post create method allows the bean to finalize initialisation, with the knowledge that the create call succeeded. At this point the bean is considered to be activated; hence do not expect ejbActivate() to be called by the container, if ejbCreate() is called on the bean. In the post create method, the bean can safely get its EJBObject and primary key from the context

Members, Getters And Setters

The entity bean class typically contains member variables which hold the entity's data. For example it might contain:

  • private String firstName;
  • private String lastName;
  • private String title;.

For each property to expose, the bean can define get and set methods to allow an application to get at the entity's data. For example it could define:

  • public String getFirstName() and public void setFirstName(String name)
  • public String getLastName() and public void setLastName(String name)
  • public String getTitle() and public void setTitle(String title)

Any of the above can throw an application exception to tell the client that something went wrong, without necessarily rolling back the transaction..

The above methods can also throw an EJBException, even though it is not in the method's signature. This is because EJBException is a RuntimeException. Such exceptions are deemed to be system level exceptions: the container will roll back the transaction and no further methods will be called on the bean instance.

The methods may throw NoSuchEntityException (which extends EJBException) if the underlying object no longer exists in the database/storage mechanism.

Business Logic

The bean can also contain business logic methods it wants to expose. For example:

  • public void wakeUp() throws AlreadyAwakeException
  • public void switchOnTV(int channel)

Any of the above can throw an application exception to tell the client that something went wrong, without necessarily rolling back the transaction..

The above methods can also throw an EJBException, even though it is not in the method's signature. This is because EJBException is a RuntimeException. Such exceptions are deemed to be system level exceptions: the container will roll back the transaction and no further methods will be called on the bean instance.

The methods may throw NoSuchEntityException (which extends EJBException) if the underlying object no longer exists in the database/storage mechanism.

Database Connections & JNDI

In most cases, the entity bean will be accessing a database to store and retrieve the data it represents. With entity beans the preferred method of getting a JDBC connection is as follows:

  1. Get hold of a Datasource object using JNDI
  2. Get hold of a JDBC Connection from the datasource
  3. Do some work
  4. Close the connection

Below is an example code snippet to get a Datasource::

javax.naming.InitialContext ctx = new javax.naming.InitialContext();

javax.sql.DataSource datasource = (javax.sql.DataSource) ctx.lookup("java:comp/env/jdbc/DataSourceName");

Notes

  • Once a datasource is acquired the class can keep hold of it. The datasource is used to get a JDBC Connection one or more times.
  • Methods which do database work should acquire a Connection, then close/release it before exiting. It is important not to hold on to database connections.
  • Some containers supply proprietary classes to get hold of database connections. The JDBC 2.0 specification allows for connection pooling to happen behind the scenes, so long as a DataSource object is used to acquire a connection. Later close() calls on the connection return the connection to a pool.

Home Interface

This interface is also referred to as a bean factory: it is used to find or create the entity beans. Hence it contains the methods to find and create the entity bean(s). The exact method signatures depend on what methods have been coded in the entity bean class. But there is a twist, some return types are not quite the same as the entity bean methods, some exceptions are not the same type as the ones thrown by the entity bean class. The container has got in the middle, and marshals the calls between the entity bean and the client.

The home interface name usually ends with Home. For example a Person home interface would be called PersonHome. This interface must extend EJBHome.

Methods In EJBHome

By extending EJBHome, this interface supplies the following methods:

  • public EJBMetaData getEJBMetaData() throws java.rmi.RemoteException
  • public HomeHandle getHomeHandle() throws java.rmi.RemoteException
  • public void remove(Handle handle) throws java.rmi.RemoteException, RemoveException
  • public void remove(java.lang.Object primaryKey) throws java.rmi.RemoteException, RemoveException

Create Method Signatures

This interface lists all the create methods defined in the Entity Bean Class. The create signatures are of the form:

RemoteInterface create(parameters...) throws CreateException, RemoteException

  • The return value is always a Remote Interface, this reflects the bean throwing a system level exception EJBException
  • The method name must be create
  • any number of create methods can be defined, each with a different set of parameters (which the bean implementation uses to create the entity).
  • Each create method defined in this interface throws a RemoteException and a CreateException. This reflects the possibility of the bean throwing an application exception, such as the DuplicateKeyException. Additional application exceptions may be entered here.

Find Method Signatures

All finder methods defined in the entity bean class are present here. The following finder must be present::

RemoteInterface findByPrimaryKey(primaryKeyClass keyValue) throws FinderException, RemoteException

All other finders defined in the bean implementation should have a corresponding entry in this interface. The signature for these finders is as follows:

RemoteInterface find...(parameters...) throws RemoteException, FinderException

or

Enumeration find...(parameters...) throws RemoteException, FinderException

or

Collection find...(parameters...) throws RemoteException, FinderException

  • The return value is the remote interface, or an Enumeration of remote interfaces, or a Collection of remote interfaces. If no objects are present the list returned is empty. For findByPrimaryKey only, FinderException is thrown.
  • The method name must start with find.
  • For findByPrimaryKey only, FinderException is thrown. Other methods should return an empty list if no data was found.

Remote Interface

The remote interface name is usually the name of the bean. For example a PersonBean implementation has a corresponding remote interface called Person. The remote interface must extend EJBObject.

Methods

Each method defined in this interface should have a corresponding entry in the entity bean class.

This interface is the client's view of the bean instance. It represents an existing bean, hence it has methods to get and set individual data member values. Business logic methods to to perform some bean specific operations on the underlying object are also defined here.

The method signatures defined in this interface depend on what is in the bean implementation. Each method should throw a RemoteException, and may throw additional application exceptions.

For example a Person remote interface could define the following getters and setters:

  • public String getFirstName() throws RemoteException
  • public void setFirstName(String name) throws RemoteException
  • public String getLastName() throws RemoteException
  • public void setLastName(String name) throws RemoteException
  • public String getTitle() throws RemoteException
  • public void setTitle(String title) throws RemoteException

The following business logic methods could be defined for a Person remote interface:

  • public void wakeUp() throws RemoteException, AlreadyAwakeException
  • public void switchOnTV(int channel) throws RemoteException

Methods In EJBObject

The remote interface extends EJBObject, and so provides the following methods:

  • public EJBHome getEJBHome() throws java.rmi.RemoteException
  • public Handle getHandle() throws java.rmi.RemoteException
  • public boolean isIdentical(EJBObject obj) throws java.rmi.RemoteException
  • public java.lang.Object getPrimaryKey() throws java.rmi.RemoteException
  • public void remove() throws java.rmi.RemoteException, RemoveException


Primary Key Class

The primary key class name usually ends with PK. For example a Person bean primary key class would be called PersonPK. It is possible to use the same primary key class for different entity bean classes, for clarity's sake it is probably better to avoid sharing key classes.

Every entity bean must have a primary key class associated with it. The primary key must be able to uniquely identify an entity bean instance. If the primary key is a simple Java type such as String, Integer... Then there is no need to define a class. Otherwise a class must be defined.

The primary key class should implement the java.io.Serializable interface, and implement the following methods:

  • boolean equals(Object compareTo)
  • public int hashCode()

 

Implementing the hashCode() method can be done by appending all the primary key components into a StringBuffer, with some delimiter in between each value (eg a '|' character). The resulting String from the StringBuffer can then yield a reasonable hash code.


Application Exception Class(es)

Application exceptions are meant to represent business logic errors. An application exception should not extend RuntimeException or java.rmi.RemoteException. It should really extend Exception.

Standard Application Exceptions

The EJB specification supplies a set of application exceptions we can use.

  • javax.ejb.CreateException is thrown when an application level error happened during object creation. The bean implementation does not usually have to mark the transaction for rollback.
  • javax.ejb.DuplicateKeyException is a subclass of CreateException. It is meant to signal that an object could not be created, because another object with the same primary key exists. The bean implementation does not usually mark the transaction for rollback for this exception.
  • javax.ejb.FinderException is thrown by the bean implementation when an application level error occurred during a find() call. The transaction should not usually be marked for rollback.
  • javax.ejb.ObjectNotFoundException is meant for single object finders. Finders which return collections (or enumerations) should return an empty collection/enumeration if no matching object was found.
  • javax.ejb.RemoveException is meant to be thrown when an application error happened during a remove operation. After this call the client does not know if the object was removed, or not. The transaction is not usually marked for rollback if this happens.

If the bean code throws an application exception, it should decide whether or not it should mark the bean's transaction to rollback, via the EJBContext. The transaction should be marked for rollback only if the database integrity is in question, were the client to commit the transaction. In most cases the database integrity is not in question, but in some cases (for example if the method changes several database table records, and an error happened in the middle somewhere) the bean implementation may need to mark the transaction for rollback: it's up to the person implementing the bean to decide.

In our example of a Person bean, we could define an AlreadyAwakeException application exception as follows:

public class AlreadyAwakeException extends Exception {
  public AlreadyAwakeException() { super(); }
  public AlreadyAwakeException(String message) { super(message); }
}

The next page explains the deployment descriptor.

 


  Copyright © 2000 J3 Ltd Permission is granted to reproduce material on this page, on the condition that a reference to "WWW.J3Ltd.com" is given as the source of the material.