|
State Design
Continuing on with the Forethought business logic, package com.forethought.ejb.account; import java.rmi.RemoteException; import java.util.List; import javax.ejb.EJBObject; import com.forethought.ejb.account.AccountInfo; // Account bean import com.forethought.ejb.accountType.UnknownAccountTypeException; // AccountType bean public interface AccountManager extends EJBObject { public AccountInfo add( String type, float balance ) throws RemoteException, UnknownAccountTypeException; public AccountInfo get( int accountId ) throws RemoteException; public List getAll() throws RemoteException; public AccountInfo deposit( AccountInfo accountInfo, float amount ) throws RemoteException; public AccountInfo withdraw( AccountInfo accountInfo, float amount ) throws RemoteException; public float getBalance( int accountId ) throws RemoteException; public boolean delete( int accountId ) throws RemoteException; }
As you can see, the manager operates upon a single account for a single user. package com.forethought.ejb.account; import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EJBHome; public interface AccountManagerHome extends EJBHome { public AccountManager create( String username ) throws CreateException, RemoteException; }
This provides a means to create a new account or to find all existing accounts for a given username.
This is all basic EJB material, and should not cause you any problems.
To deploy the AccountManager bean, you would use this (additional) XML entry in your ejb-jar.xml deployment descriptor:
Additions to your application server's vendor-specific descriptors should be equally simple. public interface AccountManager extends EJBObject { public AccountInfo add( String username, String type, float balance ) throws RemoteException, UnknownAccountTypeException; public AccountInfo get( int accountId ) throws RemoteException; public List getAll( String username ) throws RemoteException; public AccountInfo deposit( AccountInfo accountInfo, float amount ) throws RemoteException; public AccountInfo withdraw( AccountInfo accountInfo, float amount ) throws RemoteException; public float getBalance( int accountId ) throws RemoteException; public boolean delete( int accountId ) throws RemoteException; }
In this case, only two methods require this information, so it is not terribly inconvenient. private User getUser(String username) throws RemoteException { try { Context context = new InitialContext(); // Get an InitialContext // Look up the Account bean UserHome userHome = (UserHome) context.lookup("java:comp/env/ejb/UserHome"); User user = userHome.findByUserDn(LDAPManager.getUserDN(username)); return user; } catch (NamingException e) { throw new RemoteException("Could not load underlying User bean."); } catch (FinderException e) { throw new RemoteException("Could not locate specified user."); } }Then remove the username and user member variables, and modify three methods (those affected by the change to stateless): public void ejbCreate() throws CreateException { // Nothing to be done for stateless beans } public AccountInfo add(String username, String type, float balance) throws UnknownAccountTypeException { try { Context context = new InitialContext(); // Get an InitialContext User user = getUser(username); // Get the correct user // Look up the Account bean AccountHome accountHome = (AccountHome) context.lookup("java:comp/env/ejb/AccountHome"); Account account = accountHome.create(type, balance, user); return account.getInfo(); } catch (RemoteException e) { return null; } catch (CreateException e) { return null; } catch (NamingException e) { return null; } } public List getAll(String username) { List accounts = new LinkedList(); try { User user = getUser(username); Integer userId = user.getId(); // Get an InitialContext Context context = new InitialContext(); // Look up the Account bean AccountHome accountHome = (AccountHome) context.lookup("java:comp/env/ejb/AccountHome"); Collection userAccounts = accountHome.findByUserId(userId); for (Iterator i = userAccounts.iterator(); i.hasNext(); ) { Account account = (Account)i.next(); accounts.add(account.getInfo()); } } catch (Exception e) { // Let fall through to the return statement } return accounts; }Finally, don't forget to change your deployment descriptor:
All things considered, these are relatively simple changes to make, and have the net effect of making your bean faster, more efficient,
package com.forethought.client;
import java.rmi.RemoteException;
import java.util.List;
import javax.ejb.CreateException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
// Account bean
import com.forethought.ejb.account.AccountInfo;
import com.forethought.ejb.account.AccountManager;
import com.forethought.ejb.account.AccountManagerHome;
// AccountType bean
import com.forethought.ejb.accountType.UnknownAccountTypeException;
public class AccountManagerHelper
{
private String username; /** The username for this account's user */
private AccountManager manager; /** The
Looking at the methods available on this helper class, you should realize pretty quickly that it mirrors the remote interface of the AccountManager session bean; // Look up the AccountManager bean System.out.println("Looking up the AccountManager bean."); AccountManagerHelper accountHelper = new AccountManagerHelper("gqg10012"); // Create an account AccountInfo everydayAccount = accountHelper.add("Everyday", 5000); if (everydayAccount == null) { System.out.println("Failed to add account.\n"); return; } System.out.println("Added account.\n"); // Get all accounts List accounts = accountHelper.getAll(); for (Iterator i = accounts.iterator(); i.hasNext(); ) { AccountInfo accountInfo = (AccountInfo)i.next(); System.out.println("Account ID: " + accountInfo.getId()); System.out.println("Account Type: " + accountInfo.getType()); System.out.println("Account Balance: " + accountInfo.getBalance() + "\n"); } // Deposit accountHelper.deposit(everydayAccount, 2700); System.out.println("New balance in everyday account: " + accountHelper.getBalance(everydayAccount.getId()) + "\n"); // Withdraw accountHelper.withdraw(everydayAccount, 500); System.out.println("New balance in everyday account: " + accountHelper.getBalance(everydayAccount.getId()) + "\n"); // Delete account accountHelper.delete(everydayAccount.getId()); System.out.println("Deleted everyday account.");
You may find that helper classes like this can simplify your own client code, even if you do not need to provide stateful session bean masquerading, |