Mastering Enterprise JavaBeans™ and the Java 2 Platform, Enterprise Edition - Roman E
..pdf
J2EE in the Real World: Implementing Our E-Commerce Session Beans 
441
package com.wiley.compBooks.ecommerce;
import javax.ejb.*; import java.rmi.*; import java.util.*; import javax.naming.*;
/**
*Stateless Session Bean that acts as a bank teller,
*operating a bank. Behind the scenes, this Teller
*Bean interacts with the Account entity bean.
*/
public class TellerBean implements SessionBean {
/*
*Although this is a stateless session bean,
*we do have state - the session context, and
*a home object used to find/create accounts.
*Remember that stateless session beans can
*store state, they just can't store state on
*behalf of particular clients.
*/
private AccountHome home; private SessionContext ctx;
//----------------------------------------------
// Begin internal methods //----------------------------------------------
/**
* Finds the Home Object for Bank Accounts. */
private void findHome() throws Exception { try {
/*
*Get properties from the
*Session Context.
*/
Properties props = ctx.getEnvironment();
/*
*Get a reference to the AccountHome
*Object via JNDI. We need the
*Account's Home Object to create
*Accounts.
*
*We rely on app-specific properties
*to define the Initial Context params
Source 14.14 TellerBean.java (continues).
Go back to the first page for a quick link to buy this book online!
442 
M A S T E R I N G E N T E R P R I S E J A V A B E A N S
* which JNDI needs. */
Context initCtx = new InitialContext(props);
home = (AccountHome) initCtx.lookup("Ecommerce.AccountHome");
}
catch (Exception e) { e.printStackTrace(); throw e;
}
}
//----------------------------------------------
// End internal methods //----------------------------------------------
//----------------------------------------------
// Begin business methods //----------------------------------------------
/**
*Private helper method. Finds an Account Entity
*Bean based upon its ID.
*/
private Account findAccountByNumber(String accountID) throws TellerException, RemoteException {
try { /*
*Construct a Primary Key from the
*passed accountID, and call the
*Entity Bean Home's default finder
*method.
*/
return home.findByPrimaryKey(new AccountPK(accountID));
}
catch (FinderException e) { e.printStackTrace();
throw new TellerException(e.toString());
}
}
/**
*Private helper method. Finds an Account Entity
*Bean based on its owner's name.
*/
private Account findAccountByOwnerName(String name) throws TellerException, RemoteException {
try { /*
* Call our Entity's custom finder
Source 14.14 TellerBean.java (continues).
Go back to the first page for a quick link to buy this book online!
J2EE in the Real World: Implementing Our E-Commerce Session Beans 
443
* method that finds by name. */
return home.findByOwnerName(name);
}
catch (FinderException e) { e.printStackTrace();
throw new TellerException(e.toString());
}
}
/**
*Looks up an account number based on your name
*(perhaps you forgot it).
*
*@exception TellerException thrown if error occurs,
*such as a name not found.
*@param name Your full name
*/
public String lookupAccountNumber(String name) throws RemoteException, TellerException {
/*
* Get the Account Entity Bean */
Account account = findAccountByOwnerName(name);
/*
*Return the value of the getAccountID()
*accessor method on our Entity Bean.
*/
return ((AccountPK)account.getPrimaryKey()).accountID;
}
/**
*Creates a new account with a starting deposit.
*@param name Your full name
*@param initialDeposit The initial starting balance
*you want to deposit.
*
* @return Your new account number */
public String createNewAccount(String name, double initialDeposit) throws RemoteException, TellerException {
/*
*Generate a unique Bank Account Number. This
*is a hard problem to solve, in general, with
*EJB. We'll see the issues at hand in Chapter
*15. For now, we'll punt and use the System
Source 14.14 TellerBean.java (continues).
Go back to the first page for a quick link to buy this book online!
444 
M A S T E R I N G E N T E R P R I S E J A V A B E A N S
*Clock to create a unique identifier. However,
*note that this will cause our bank account to
*fail if two accounts are created in the same
*millisecond.
*/
String accountNum = Long.toString(System.currentTimeMillis());
try { /*
* Create a new Account Entity Bean */
Account account = home.create(accountNum, name);
/*
* Start the account off with an initial deposit */
account.deposit(initialDeposit);
/*
* Return the new account number */
return accountNum;
}
catch (CreateException e) { e.printStackTrace();
throw new TellerException("Could not create account: " + e.toString());
}
}
/**
*Closes your account.
*@return The funds left in your account are
*returned to you.
*/
public double closeAccount(String accountNum) throws RemoteException, TellerException {
/*
* Find the correct Account Entity Bean */
Account account = findAccountByNumber(accountNum);
/*
* Withdraw all the funds from the Entity */
double balance = account.getBalance();
Source 14.14 TellerBean.java (continues).
Go back to the first page for a quick link to buy this book online!
J2EE in the Real World: Implementing Our E-Commerce Session Beans 
445
/*
* Close the account by removing the Entity Bean */
try { account.remove();
}
catch (RemoveException e) { e.printStackTrace();
throw new TellerException("Could not close account: " + e.toString());
}
/*
* Return the remaining funds */
return balance;
}
/**
*Gets your current balance for the account
*numbered accountNum.
*/
public double getBalance(String accountNum) throws RemoteException, TellerException {
/*
* Find the correct Account Entity Bean */
Account account = findAccountByNumber(accountNum);
/*
* Get the Entity Bean's balance, and return it */
return account.getBalance();
}
/**
* Switches names on an account. */
public void changeNames(String accountNum, String newName) throws RemoteException, TellerException {
/*
* Find the correct Account Entity Bean */
Account account = findAccountByNumber(accountNum);
/*
* Change the Entity Bean's owner name field
Source 14.14 TellerBean.java (continues).
Go back to the first page for a quick link to buy this book online!
446 
M A S T E R I N G E N T E R P R I S E J A V A B E A N S
*/
account.setOwnerName(newName);
}
/**
* Transfers funds from accountNum1 to accountNum2 */
public void transfer(String accountNum1, String accountNum2, double funds) throws RemoteException, TellerException {
/*
* Withdraw from account #1 into account #2. */
withdraw(accountNum1, funds); deposit(accountNum2, funds);
}
/**
*Withdraws from your account.
*@exception TellerException thrown if you have
*insufficient funds.
*@return Your withdrawn funds.
*/
public double withdraw(String accountNum, double amt) throws RemoteException, TellerException {
/*
* Find the correct Account Entity Bean */
Account account = findAccountByNumber(accountNum);
/*
* Withdraw from it */
try {
return account.withdraw(amt);
}
catch (AccountException e) { e.printStackTrace();
throw new TellerException(e);
}
}
/**
* Deposits into your account. */
public void deposit(String accountNum, double funds) throws RemoteException, TellerException {
Source 14.14 TellerBean.java (continues).
Go back to the first page for a quick link to buy this book online!
J2EE in the Real World: Implementing Our E-Commerce Session Beans 
447
/*
* Find the correct Account Entity Bean */
Account account = findAccountByNumber(accountNum);
/*
* Deposit into it */
account.deposit(funds);
}
//----------------------------------------------
// End business methods //----------------------------------------------
//----------------------------------------------
//Begin EJB-required methods. The methods below
//are called by the Container and never called
//by client code.
//----------------------------------------------
public void ejbCreate() throws RemoteException { System.out.println("ejbCreate() called.");
/*
*Retrieve Home Object for Bank Accounts.
*If failure, throw a system-level error. */
try { findHome();
}
catch (Exception e) {
throw new RemoteException(e.toString());
}
}
public void ejbRemove() { System.out.println("ejbRemove() called.");
}
public void ejbActivate() { System.out.println("ejbActivate() called.");
}
public void ejbPassivate() { System.out.println("ejbPassivate() called.");
}
Source 14.14 TellerBean.java (continues).
Go back to the first page for a quick link to buy this book online!
448 
M A S T E R I N G E N T E R P R I S E J A V A B E A N S
public void setSessionContext(SessionContext ctx) { System.out.println("setSessionContext called"); this.ctx = ctx;
}
//----------------------------------------------
// End EJB-required methods //----------------------------------------------
}
Source 14.14 TellerBean.java (continued).
to work with. Because we’re stateless, our bean will never be passivated/activated; it will simply be destroyed when the container’s working set is too large. Therefore we don’t need to reconstruct the home object on passivation/activation.
Most of the application logic methods involve an initial step of finding the correct Bank Account based on the account number passed into the method. We then delegate calls to the Bank Account object.
Notice our implementation of transfer()—it withdraws from one bank account and deposits into another. This is the classic debit-credit problem, which needs a transaction to run securely. If we don’t run in a transaction, we might withdraw but not deposit, or we might be in an unknown state. Therefore we’ll make sure that this method (as well as the other methods in the bean-—they are also critical because we’re dealing with money) run in a transaction.
TellerException.java
Our final Java file is a custom exception class, TellerException.java, shown in Source 14.15. We use it to report any problems occurring with bank account operations.
The Deployment Descriptor
Now that we’ve written our Teller bean code, we’ll specify the system-level properties on our component by writing a deployment descriptor. The container will inspect the deployment descriptor at runtime to gain information about managing our bean. The deployment descriptor values are shown in Table 14.5.
Our Bank Account needs to run in a transactionally safe mode. Therefore, we require all transactions to run in a transaction via TX_REQUIRED. We also impose the toughest transaction isolation mode—TRANSACTION_SERIALIZABLE. This is necessary because we’re performing both read and write operations on
Go back to the first page for a quick link to buy this book online!
J2EE in the Real World: Implementing Our E-Commerce Session Beans 
449
package com.wiley.compBooks.ecommerce;
/**
* Exceptions thrown by Tellers */
public class TellerException extends Exception {
public TellerException() { super();
}
public TellerException(Exception e) { super(e.toString());
}
public TellerException(String s) { super(s);
}
}
Source 14.15 TellerException.java.
Bank Accounts from our Teller, and because monetary issues are so important to get right. These transaction settings should be applied to our Bank Account bean as well.
Table 14.5 Deployment Descriptor Settings for TellerBean
DEPLOYMENT
DESCRIPTOR SETTING |
VALUE |
Bean home name |
TellerHome |
Enterprise bean class name |
com.wiley.compBooks.entity.Teller.TellerBean |
Home interface class name |
com.wiley.compBooks.entity.Teller.TellerHome |
Remote interface class name |
com.wiley.compBooks.entity.Teller.Teller |
Environment properties |
<empty> |
Session timeout |
15 minutes |
Transaction attribute |
TX_REQUIRED |
Transaction isolation level |
TRANSACTION_SERIALIZABLE |
Run-as mode |
CLIENT_IDENTITY |
Go back to the first page for a quick link to buy this book online!
450 
M A S T E R I N G E N T E R P R I S E J A V A B E A N S
Summary
In this chapter, we’ve written the session beans for our e-commerce deployment. This completes the work we need to do for our business logic tier. In the next chapter, we’ll complete our deployment by writing a few Java servlets that make up our presentation tier.
Go back to the first page for a quick link to buy this book online!
