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
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:
- Get hold of a Datasource object using JNDI
- Get hold of a JDBC Connection from the datasource
- Do some work
- 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.
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.
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.
|