Skip to main content

EJB best practices: The limits of delegation

What do you do when the business delegate just isn't enough?

Brett McLaughlin (brett@newInstance.com), Author and Editor, O'Reilly Media Inc.
Photo of Brett McLaughlin
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

Summary:  While the business delegate pattern is a popular solution to EJB abstraction, it has some serious limitations. In this installment of EJB best practices, Brett McLaughlin outlines those limitations, and shows you how to avoid them.

View more content in this series

Date:  01 Dec 2002
Level:  Intermediate
Activity:  978 views
Comments:  

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.

EJB technology in theory and practice

In theory, EJB applications are completely component driven and always designed and architected in advance of actual coding. Entity beans are always accessed through session facade beans, and those beans are often grouped into more logical business units by additional session beans (and sometimes message-driven beans). In this scenario, the only methods exposed to clients are business-driven methods such as and addUser().

In practice, however, what we tend to see is spaghetti-style coding. Entity beans are designed from scratch and then session beans are layered on top of those beans, often with very little design or planning time in between. While the entity beans aren't always exposed to clients, business logic requires that several methods be called on session beans (for example, getBookISBN(), then reserveBook(), then decreaseInventory(), and finally makePurchase()). Rather than calling one business-specific method, the client is left to cobble together all the server application's business logic on its own.

Delegates in the real world

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.


The command delegate at work

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.


Resources

About the author

Photo of Brett McLaughlin

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



Trademarks

static.content.url=/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=10731
ArticleTitle=EJB best practices: The limits of delegation
publish-date=12012002
author1-email=brett@newInstance.com
author1-email-cc=