Download
FAQ History |
API
Search Feedback |
The SavingsAccountBean Example
The entity bean illustrated in this section represents a simple bank account. The state of
SavingsAccountBean
is stored in thesavingsaccount
table of a relational database. Thesavingsaccount
table is created by the following SQL statement:CREATE TABLE savingsaccount (id VARCHAR(3) CONSTRAINT pk_savingsaccount PRIMARY KEY, firstname VARCHAR(24), lastname VARCHAR(24), balance NUMERIC(10,2));The
SavingsAccountBean
example requires the following code:This example also uses the following classes:
The source code for this example is in this directory:
Entity Bean Class
The sample entity bean class is called
SavingsAccountBean
. As you look through its code, note that it meets the requirements of any entity bean that uses bean-managed persistence. First, it implements the following:In addition, an entity bean class with bean-managed persistence has these requirements:
The EntityBean Interface
The
EntityBean
interface extends theEnterpriseBean
interface, which extends theSerializable
interface. TheEntityBean
interface declares a number of methods, such asejbActivate
andejbLoad
, which you must implement in your entity bean class. These methods are discussed in later sections.The ejbCreate Method
When the client invokes a
create
method, the EJB container invokes the correspondingejbCreate
method. Typically, anejbCreate
method in an entity bean performs the following tasks:The
ejbCreate
method ofSavingsAccountBean
inserts the entity state into the database by invoking the privateinsertRow
method, which issues the SQLINSERT
statement. Here is the source code for theejbCreate
method:public String ejbCreate(String id, String firstName, String lastName, BigDecimal balance) throws CreateException { if (balance.signum() == -1) { throw new CreateException ("A negative initial balance is not allowed."); } try { insertRow(id, firstName, lastName, balance); } catch (Exception ex) { throw new EJBException("ejbCreate: " + ex.getMessage()); } this.id = id; this.firstName = firstName; this.lastName = lastName; this.balance = balance; return id; }Although the
SavingsAccountBean
class has only oneejbCreate
method, an enterprise bean can contain multipleejbCreate
methods. For an example, see theCartBean.java
source code in this directory:When you write an
ejbCreate
method for an entity bean, be sure to follow these rules:The
throws
clause can include thejavax.ejb.CreateException
and exceptions that are specific to your application. AnejbCreate
method usually throws aCreateException
if an input parameter is invalid. If anejbCreate
method cannot create an entity because another entity with the same primary key already exists, it should throw ajavax.ejb.DuplicateKeyException
(a subclass ofCreateException
). If a client receives aCreateException
or aDuplicateKeyException
, it should assume that the entity was not created.The state of an entity bean can be directly inserted into the database by an application that is unknown to the Application Server. For example, an SQL script might insert a row into the
savingsaccount
table. Although the entity bean for this row was not created by anejbCreate
method, the bean can be located by a client program.The ejbPostCreate Method
For each
ejbCreate
method, you must write anejbPostCreate
method in the entity bean class. The EJB container invokesejbPostCreate
immediately after it callsejbCreate
. Unlike theejbCreate
method, theejbPostCreate
method can invoke thegetPrimaryKey
andgetEJBObject
methods of theEntityContext
interface. For more information on thegetEJBObject
method, see the section Passing an Enterprise Bean's Object Reference. Often, yourejbPostCreate
methods will be empty.The signature of an
ejbPostCreate
method must meet the following requirements:The
throws
clause can include thejavax.ejb.CreateException
and exceptions that are specific to your application.The ejbRemove Method
A client deletes an entity bean by invoking the
remove
method. This invocation causes the EJB container to call theejbRemove
method, which deletes the entity state from the database. In theSavingsAccountBean
class, theejbRemove
method invokes a private method nameddeleteRow
, which issues an SQLDELETE
statement. TheejbRemove
method is short:public void ejbRemove() { try { deleteRow(id); catch (Exception ex) { throw new EJBException("ejbRemove: " + ex.getMessage()); } } }If the
ejbRemove
method encounters a system problem, it should throw thejavax.ejb.EJBException
. If it encounters an application error, it should throw ajavax.ejb.RemoveException
. For a comparison of system and application exceptions, see the section deploytool Tips for Entity Beans with Bean-Managed Persistence.An entity bean can also be removed directly by a database deletion. For example, if an SQL script deletes a row that contains an entity bean state, then that entity bean is removed.
The ejbLoad and ejbStore Methods
If the EJB container needs to synchronize the instance variables of an entity bean with the corresponding values stored in a database, it invokes the
ejbLoad
andejbStore
methods. TheejbLoad
method refreshes the instance variables from the database, and theejbStore
method writes the variables to the database. The client cannot callejbLoad
andejbStore
.If a business method is associated with a transaction, the container invokes
ejbLoad
before the business method executes. Immediately after the business method executes, the container callsejbStore
. Because the container invokesejbLoad
andejbStore
, you do not have to refresh and store the instance variables in your business methods. TheSavingsAccountBean
class relies on the container to synchronize the instance variables with the database. Therefore, the business methods ofSavingsAccountBean
should be associated with transactions.If the
ejbLoad
andejbStore
methods cannot locate an entity in the underlying database, they should throw thejavax.ejb.NoSuchEntityException
. This exception is a subclass ofEJBException
. BecauseEJBException
is a subclass ofRuntimeException
, you do not have to include it in thethrows
clause. WhenNoSuchEntityException
is thrown, the EJB container wraps it in aRemoteException
before returning it to the client.In the
SavingsAccountBean
class,ejbLoad
invokes theloadRow
method, which issues an SQLSELECT
statement and assigns the retrieved data to the instance variables. TheejbStore
method calls thestoreRow
method, which stores the instance variables in the database using an SQLUPDATE
statement. Here is the code for theejbLoad
andejbStore
methods:public void ejbLoad() { try { loadRow(); } catch (Exception ex) { throw new EJBException("ejbLoad: " + ex.getMessage()); } } public void ejbStore() { try { storeRow(); } catch (Exception ex) { throw new EJBException("ejbStore: " + ex.getMessage()); } }The Finder Methods
The finder methods allow clients to locate entity beans. The
SavingsAccountClient
program locates entity beans using three finder methods:SavingsAccount jones = home.findByPrimaryKey("836"); ... Collection c = home.findByLastName("Smith"); ... Collection c = home.findInRange(20.00, 99.00);For every finder method available to a client, the entity bean class must implement a corresponding method that begins with the prefix
ejbFind
. TheSavingsAccountBean
class, for example, implements theejbFindByLastName
method as follows:public Collection ejbFindByLastName(String lastName) throws FinderException { Collection result; try { result = selectByLastName(lastName); } catch (Exception ex) { throw new EJBException("ejbFindByLastName " + ex.getMessage()); } return result; }The finder methods that are specific to your application, such as
ejbFindByLastName
andejbFindInRange
, are optional, but theejbFindByPrimaryKey
method is required. As its name implies, theejbFindByPrimaryKey
method accepts as an argument the primary key, which it uses to locate an entity bean. In theSavingsAccountBean
class, the primary key is theid
variable. Here is the code for theejbFindByPrimaryKey
method:public String ejbFindByPrimaryKey(String primaryKey) throws FinderException { boolean result; try { result = selectByPrimaryKey(primaryKey); } catch (Exception ex) { throw new EJBException("ejbFindByPrimaryKey: " + ex.getMessage()); } if (result) { return primaryKey; } else { throw new ObjectNotFoundException ("Row for id " + primaryKey + " not found."); } }The
ejbFindByPrimaryKey
method may look strange to you, because it uses a primary key for both the method argument and the return value. However, remember that the client does not callejbFindByPrimaryKey
directly. It is the EJB container that calls theejbFindByPrimaryKey
method. The client invokes thefindByPrimaryKey
method, which is defined in the home interface.The following list summarizes the rules for the finder methods that you implement in an entity bean class with bean-managed persistence:
- The
ejbFindByPrimaryKey
method must be implemented.- A finder method name must start with the prefix
ejbFind
.- The access control modifier must be
public
.- The method modifier cannot be
final
orstatic
.- The arguments and return type must be legal types for the Java RMI API. (This requirement applies only to methods defined in a remote--and not a local--home interface.)
- The return type must be the primary key or a collection of primary keys.
The
throws
clause can include thejavax.ejb.FinderException
and exceptions that are specific to your application. If a finder method returns a single primary key and the requested entity does not exist, the method should throw thejavax.ejb.ObjectNotFoundException
(a subclass ofFinderException
). If a finder method returns a collection of primary keys and it does not find any objects, it should return an empty collection.The Business Methods
The business methods contain the business logic that you want to encapsulate within the entity bean. Usually, the business methods do not access the database, and this allows you to separate the business logic from the database access code. The
SavingsAccountBean
class contains the following business methods:public void debit(BigDecimal amount) throws InsufficientBalanceException { if (balance.compareTo(amount) == -1) { throw new InsufficientBalanceException(); } balance = balance.subtract(amount); } public void credit(BigDecimal amount) { balance = balance.add(amount); } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public BigDecimal getBalance() { return balance; }The
SavingsAccountClient
program invokes the business methods as follows:BigDecimal zeroAmount = new BigDecimal("0.00"); SavingsAccount duke = home.create("123", "Duke", "Earl", zeroAmount); ... duke.credit(new BigDecimal("88.50")); duke.debit(new BigDecimal("20.25")); BigDecimal balance = duke.getBalance();The requirements for the signature of a business method are the same for session beans and entity beans:
- The method name must not conflict with a method name defined by the EJB architecture. For example, you cannot call a business method
ejbCreate
orejbActivate
.- The access control modifier must be
public
.- The method modifier cannot be
final
orstatic
.- The arguments and return types must be legal types for the Java RMI API. This requirement applies only to methods defined in a remote--and not a local--home interface.
The
throws
clause can include the exceptions that you define for your application. Thedebit
method, for example, throws theInsufficientBalanceException
. To indicate a system-level problem, a business method should throw thejavax.ejb.EJBException
.The Home Methods
A home method contains the business logic that applies to all entity beans of a particular class. In contrast, the logic in a business method applies to a single entity bean, an instance with a unique identity. During a home method invocation, the instance has neither a unique identity nor a state that represents a business object. Consequently, a home method must not access the bean's persistence state (instance variables). (For container-managed persistence, a home method also must not access relationships.)
Typically, a home method locates a collection of bean instances and invokes business methods as it iterates through the collection. This approach is taken by the
ejbHomeChargeForLowBalance
method of theSavingsAccountBean
class. TheejbHomeChargeForLowBalance
method applies a service charge to all savings accounts that have balances less than a specified amount. The method locates these accounts by invoking thefindInRange
method. As it iterates through the collection ofSavingsAccount
instances, theejbHomeChargeForLowBalance
method checks the balance and invokes thedebit
business method. Here is the source code of theejbHomeChargeForLowBalance
method:public void ejbHomeChargeForLowBalance( BigDecimal minimumBalance, BigDecimal charge) throws InsufficientBalanceException { try { SavingsAccountHome home = (SavingsAccountHome)context.getEJBHome(); Collection c = home.findInRange(new BigDecimal("0.00"), minimumBalance.subtract(new BigDecimal("0.01"))); Iterator i = c.iterator(); while (i.hasNext()) { SavingsAccount account = (SavingsAccount)i.next(); if (account.getBalance().compareTo(charge) == 1) { account.debit(charge); } } } catch (Exception ex) { throw new EJBException("ejbHomeChargeForLowBalance: " + ex.getMessage()); } }The home interface defines a corresponding method named
chargeForLowBalance
(see Home Method Definitions). Because the interface provides the client view, theSavingsAccountClient
program invokes the home method as follows:SavingsAccountHome home; ... home.chargeForLowBalance(new BigDecimal("10.00"), new BigDecimal("1.00"));In the entity bean class, the implementation of a home method must adhere to these rules:
The
throws
clause can include exceptions that are specific to your application; it must not throw thejava.rmi.RemoteException
.Database Calls
Table 26-1 summarizes the database access calls in the
SavingsAccountBean
class. The business methods of theSavingsAccountBean
class are absent from the preceding table because they do not access the database. Instead, these business methods update the instance variables, which are written to the database when the EJB container callsejbStore
. Another developer might have chosen to access the database in the business methods of theSavingsAccountBean
class. This choice is one of those design decisions that depend on the specific needs of your application.Before accessing a database, you must connect to it. For more information, see Chapter 31.
Home Interface
The home interface defines the
create
, finder, and home methods. TheSavingsAccountHome
interface follows:import java.util.Collection; import java.math.BigDecimal; import java.rmi.RemoteException; import javax.ejb.*; public interface SavingsAccountHome extends EJBHome { public SavingsAccount create(String id, String firstName, String lastName, BigDecimal balance) throws RemoteException, CreateException; public SavingsAccount findByPrimaryKey(String id) throws FinderException, RemoteException; public Collection findByLastName(String lastName) throws FinderException, RemoteException; public Collection findInRange(BigDecimal low, BigDecimal high) throws FinderException, RemoteException; public void chargeForLowBalance(BigDecimal minimumBalance, BigDecimal charge) throws InsufficientBalanceException, RemoteException; }create Method Definitions
Each
create
method in the home interface must conform to the following requirements:
- It must have the same number and types of arguments as its matching
ejbCreate
method in the enterprise bean class.- It must return the remote interface type of the enterprise bean.
- The
throws
clause must include the exceptions specified by thethrows
clause of the correspondingejbCreate
andejbPostCreate
methods.- The
throws
clause must include thejavax.ejb.CreateException.
- If the method is defined in a remote--and not a local--home interface, then the
throws
clause must include thejava.rmi.RemoteException
.Finder Method Definitions
Every finder method in the home interface corresponds to a finder method in the entity bean class. The name of a finder method in the home interface begins with
find
, whereas the corresponding name in the entity bean class begins withejbFind
. For example, theSavingsAccountHome
class defines thefindByLastName
method, and theSavingsAccountBean
class implements theejbFindByLastName
method. The rules for defining the signatures of the finder methods of a home interface follow.
- The number and types of arguments must match those of the corresponding method in the entity bean class.
- The return type must be the entity bean's remote interface type or a collection of those types.
- The exceptions in the
throws
clause must include those of the corresponding method in the entity bean class.- The
throws
clause must contain thejavax.ejb.FinderException
.- If the method is defined in a remote--and not a local--home interface, then the
throws
clause must include thejava.rmi.RemoteException
.Home Method Definitions
Each home method definition in the home interface corresponds to a method in the entity bean class. In the home interface, the method name is arbitrary, provided that it does not begin with
create
orfind
. In the bean class, the matching method name begins withejbHome
. For example, in theSavingsAccountBean
class the name isejbHomeChargeForLowBalance
, but in theSavingsAccount
interface the name is
HomechargeForLowBalance
.The home method signature must follow the same rules specified for finder methods in the preceding section (except that a home method does not throw a
FinderException
).Remote Interface
The remote interface extends
javax.ejb.EJBObject
and defines the business methods that a remote client can invoke. Here is theSavingsAccount
remote interface:import javax.ejb.EJBObject; import java.rmi.RemoteException; import java.math.BigDecimal; public interface SavingsAccount extends EJBObject { public void debit(BigDecimal amount) throws InsufficientBalanceException, RemoteException; public void credit(BigDecimal amount) throws RemoteException; public String getFirstName() throws RemoteException; public String getLastName() throws RemoteException; public BigDecimal getBalance() throws RemoteException; }The requirements for the method definitions in a remote interface are the same for session beans and entity beans:
- Each method in the remote interface must match a method in the enterprise bean class.
- The signatures of the methods in the remote interface must be identical to the signatures of the corresponding methods in the enterprise bean class.
- The arguments and return values must be valid RMI types.
- The
throws
clause must includejava.rmi.RemoteException.
A local interface has the same requirements, with the following exceptions:
Running the SavingsAccountBean Example
Before you run this example, you must define the data source, create the database, and deploy the
SavingsAccountApp.ear
file.Defining the Data Source
Follow the instructions in Creating a Data Source. This data source is a factory for database connections. For more information, see DataSource Objects and Connection Pools.
Creating the Database Table
The instructions that follow explain how to use the
SavingsAccountBean
example with PointBase, the database software that is included in the Application Server bundle.
- Start the PointBase server. For instructions, see Starting and Stopping the PointBase Database Server.
- Create the
savingsaccount
database table by running thecreate.sql
script.Deploying the Application
For detailed instructions, see Deploying the J2EE Application.
Running the Client
To run the
SavingsAccountClient
program, do the following:
- In a terminal window, go to this directory:
<
INSTALL
>/j2eetutorial14/examples/ejb/savingsaccount/
- Type the following command on a single line:
appclient -client SavingsAccountAppClient.jar
- The client should display the following lines:
balance = 68.25
balance = 32.55
456: 44.77
730: 19.54
268: 100.07
836: 32.55
456: 44.77
4
7To modify this example, see the instructions in Modifying the J2EE Application.
Download
FAQ History |
API
Search Feedback |
All of the material in The J2EE(TM) 1.4 Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.