If you've been following along with the EJB best practices series for a while, you might be getting tired of hearing about the business delegate pattern. In previous installments you've learned how to diagnose the need for a business delegate in your application code, how to write a delegate class, and how (and when) to turn that simple class into a dynamic proxy (see the series archive for links to all the articles). In this tip we're going to go in the opposite direction, and talk about the times when a business delegate could hinder your programming, rather than help it.
In our example applications up to now the business logic has always been clearly defined in a session bean, and the business delegate's methods have simply mirrored those of the session bean. In this type of scenario, it's a given that the bean's business interface and the business delegate must be tightly coupled. When methods in the business interface (and its corresponding bean's remote interface) changed, the methods in the business delegate also had to change. While this design works well in theory, it isn't based on the most accurate picture of an EJB programming environment.
A more common scenario is one in which your session beans contain a collection of available methods that can be combined to perform a single unit of business logic. Each session bean method provides part of a larger transaction, which the client sees as a single operation (see "EJB technology in theory and practice" below). In this situation, implementing the business delegate pattern would actually be a poor design choice.
When business delegates don't work
The problem with a business delegate in this case is that it delegates, but it doesn't actually do business. While the delegate allows clients to access the session beans' methods, the client still has to do the work of assembling those methods into business units. Because different programmers assemble and order methods in different ways, clients will execute a business process (for example, ordering a new amplifier) in a variety of ways. Some clients will omit important steps, while others may add new steps that increase processing time. To ensure consistent application performance across multiple clients, you have to free the client of the burden of interpreting your application's business logic.
What we need is a class that looks and acts like a business delegate, but actually provides clients with a business view of our application rather than a more granular one. I call this type of class a command delegate. Instead of providing direct access to session beans, the command delegate provides a set of commands that are delegated to several session bean methods, and sometimes even across several session beans.
Let's look at a simple use-case scenario in which a command delegate is a better programming solution than a business delegate. Listing 1 shows the business interface for an Inventory bean, which controls an online audio-video store's inventory:
Listing 1. The Inventory bean's business interface
package com.ibm.inventory;
import java.rmi.RemoteException;
public interface IInventory {
public String getItemId(String productName)
throws RemoteException;
public boolean reduceInventory(String itemId, int quantity)
throws RemoteException;
public boolean increaseInventory(String itemId, int quantity)
throws RemoteException;
// Overloaded version: reduce inventory by one
public boolean reduceInventory(String itemId)
throws RemoteException;
// Overloaded version: increase inventory by one
public boolean increaseInventory(String itemId)
throws RemoteException;
}
|
Listing 2 shows the business interface for a purchasing bean; it takes in payment information and debits the account accordingly:
Listing 2. The Purchaser bean's business interface
package com.ibm.purchaser;
import java.rmi.RemoteException;
public interface IPurchaser {
public boolean makePayment(PurchaseInfo purchaseInfo, float amount)
throws RemoteException;
public boolean makeCredit(PurchaseInfo purchaseInfo, float amount)
throws RemoteException;
}
|
The above purchasing scenario is composed of several steps. First, the purchase item's ID is looked up. Next, the payment is made. Finally, once that payment has been made, the inventory for the purchased item is decreased. If we used the business delegate pattern to handle this scenario, we would need two business delegate classes (one for each bean), and at least three method invocations.
The command delegate pattern is a much better choice. Whereas the business delegate can only provide the client with access to individual chunks of business logic (which the client must then assemble and execute on), the command delegate class works across sessions beans, aggregates the business logic, and provides it to the client as a single executable method. Listing 3 shows the command delegate class for this sample use-case scenario:
Listing 3. The PurchaserDelegate class
package com.ibm.purchase;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.naming.NamingException;
import com.ibm.purchaser.*;
import com.ibm.inventory.*;
public class PurchaserDelegate {
private IPurchaser purchaser;
private IInventory inventory;
public PurchaserDelegate() {
init();
}
public void init() {
// Look up and obtain our session beans
try {
PurchaserHome purchaserHome =
(PurchaserHome)EJBHomeFactory.getInstance().lookup(
"java:comp/env/ejb/PurchaserHome", PurchaserHome.class);
purchaser = purchaserHome.create();
InventoryHome inventoryHome =
(InventoryHome)EJBHomeFactory.getInstance().lookup(
"java:comp/env/ejb/InventoryHome", InventoryHome.class);
inventory = inventoryHome.create();
} catch (NamingException e) {
throw new RuntimeException(e);
} catch (CreateException e) {
throw new RuntimeException(e);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
public boolean purchase(String itemName, float price,
PurchaseInfo purchaseInfo)
throws InsufficientFundsException, PurchaserException {
try {
String itemID = inventory.getItemId(itemName);
if (purchaser.makePurchase(purchaseInfo, price)) {
inventory.reduceInventory(itemID);
return true;
} else {
throw new InsufficientFundsException();
}
} catch (RemoteException e) {
throw new PurchaserException(e);
}
}
// Other business-specific methods
public void destroy() {
// In this case, do nothing
}
}
|
In a more realistic example, of course, the business logic could get quite a bit more complex. For example, a client might have to deal with a shipping bean to ship out purchased items, your shopping carts might have to hold multiple items rather than just one at a time, or you might have to include functionality to handle item discounts or automatic inventory checks and ordering processes. Instead of just two beans, your client would need to interact with three or four beans and even more methods. Whatever the complexities of your application, however, the command delegate pattern can handle them with a single method invocation. With the command delegate pattern, complexity in the business and EJB tiers does not translate into complexity on the application client. And that's good programming technique.
It can be confusing to sort through the numerous EJB design patterns and try to figure out which one is best for a given scenario. As you add new patterns to your toolbox and try them out in different situations, however, you will find that it becomes more natural to analyze problems in the light of specific solutions, and then apply the solution that is most suited to your scenario. In this tip, you've learned about a useful alternative to the business delegate pattern. The command delegate pattern is particularly valuable in applications that apply complex business logic. To further your understanding of the two patterns, try applying each one to a programming task and see which one works best. Until next tip, I'll see you online.
- The "Enterprise JavaBeans fundamentals" tutorial (developerWorks, March 2001) is a great way to get started with EJB technology.
- David Gallardo's "Java design patterns 101" tutorial (developerWorks, January 2002) is a good introduction to design patterns.
- Paul Monday's follow-up tutorial, "Java design patterns 201" (developerWorks, April 2002), is for the more advanced student of design patterns.
- In his article "Best practices in EJB exception handling" (developerWorks, May 2002), Java architect Srikanth Shenoy demonstrates how to code for faster problem resolution on EJB technology-based systems.
- Sun Microsystems's EJB technology home page is a good starting place for information on EJB technology.
- Another great resource, TheServerSide.com, offers articles and information pertaining to J2EE.
- See the developerWorks Java technology tutorials page for a listing of free J2EE- and EJB technology-related tutorials from developerWorks.
- Find hundreds more Java technology resources on the developerWorks Java technology zone.

Brett McLaughlin has been working in computers since the Logo days (remember the little triangle?). He currently specializes in building application infrastructure using Java and Java-related technologies. He has spent the last several years implementing these infrastructures at Nextel Communications and Allegiance Telecom, Inc. Brett is one of the co-founders of the Java Apache project Turbine, which builds a reusable component architecture for Web application development using Java servlets. He is also a contributor of the EJBoss project, an open source EJB application server, and Cocoon, an open source XML Web-publishing engine. Contact Brett at brett@oreilly.com
Comments (Undergoing maintenance)





