In the last tip, we discussed how to use a business delegate class (not to be confused with the Business Interface pattern) to access your EJB components. By inserting a business delegate class between our client code and the EJB code, we were able to insulate our application's Web tier from both EJB semantics and business logic.
One way to look at this type of design is in terms of how generic it is. Starting with an application in which business logic and technology functions are tightly entwined, we've been gradually separating out the different layers of the application and using different techniques to alleviate their interdependency. In doing so, you should be finding that the more generic an application's underlying structure is, the more robust and maintainable it is over time.
In this tip, we'll continue working with the idea of generic design. We'll start by exploring the limits of our current business delegate implementation, then I'll show you how to overcome those limitations by creating an even more generic, and thus less rigid, implementation of the business delegate class.
The business delegate class: A refresher
Recall the business delegate class for our Library bean interface we discussed last month.
Most of the LibraryDelegate class merely duplicates the methods in the original Library bean. The LibraryDelegate adds init(), destroy(), and constructor methods, and then uses these methods to delegate tasks to the Library bean. In doing so, the delegate acts as a buffer between the Web tier and your enterprise beans. Here's the original bean's business interface.
The problem with this approach doesn't become evident until you consider that many session beans have 10, 20, or more methods. In fact, it isn't uncommon to find a session bean with 50 or more methods! Because a bean's business interface must contain all the methods of the bean, so will the business delegate class. That makes for bloated code, and plenty of room for error.
In addition to bloat, we also have to consider the change factor. Because the Delegate class has to duplicate all the bean's methods, and because beans do inevitably change over time, you could find yourself spending a lot of time adding new methods to the Delegate, not to mention recompiling and, possibly, testing the new code.
By itself, this may not seem like much of a problem. But consider that we started using a business delegate class to abstract the business and presentation logic from the technology infrastructure, in this case EJB components. If changing the remote interface requires a change to the business delegate, then our business delegate is, in effect, still tied to the underlying components.
There has to be a better way, you say. And there is.
The solution is to use a dynamic delegate, which in turn uses Java reflection. Instead of having each business method hardcoded into your delegate, you can have the delegate dynamically invoke the methods (through the Java Reflection API) on the remote interface of the targeted EJB component. This allows a complete decoupling from the remote interface, in that adding a method to the business or remote interface of your beans requires no corresponding changes in the business delegate. It's also easier to make changes to your technology infrastructure with the dynamic delegate. Migrating from a remote interface and EJB technology to another technology such as Java Data Objects (JDO) would require you to change only the delegate's init() method. All the other method calls would continue to be delegated through the bean's interface, and to work with no further changes. Listing 1 shows a dynamic version of the Library business delegate:
Listing 1. A business delegate for a Library bean
package com.ibm.library;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;
import javax.ejb.CreateException;
import javax.naming.NamingException;
public class LibraryDelegate implements ILibrary {
private ILibrary library;
private Map availableMethods;
public LibraryDelegate() {
init();
}
public void init() {
// Look up and obtain our session bean
try {
LibraryHome libraryHome =
(LibraryHome)EJBHomeFactory.getInstance().lookup(
"java:comp/env/ejb/LibraryHome", LibraryHome.class);
library = libraryHome.create();
// Get the methods available for use in proxying
availableMethods = new HashMap();
Method[] methods = ILibrary.class.getMethods();
for (int i=0; i<methods.length; i++) {
availableMethods.put(methods[i].getName(),
methods[i]);
}
} catch (NamingException e) {
throw new RuntimeException(e);
} catch (CreateException e) {
throw new RuntimeException(e);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
// All the hard-coded methods are removed
public Object
invoke(Object proxy, Method method, Object[] args)
throws Throwable{
try {
// See if this is init() or destroy()
if (method.getName().equals("init")) {
init();
return null;
} else if (method.getName().equals("destroy")) {
destroy();
return null;
} else {
Method method =
(Method)availableMethods.get(method.getName());
// See if we found anything
if (method != null) {
return method.invoke(library, args);
} else {
throw new
NoSuchMethodException("The Library does not " +
"support the " + method.getName() +" method.");
}
}
} catch (InvocationTargetException e) {
// We don't support throwing RuntimeExceptions from EJBs
// directly
if (e.getTargetException() instanceof RemoteException) {
throw new RuntimeException(e);
} else {
throw e.getTargetException();
}
}
}
public void destroy() {
// In this case, do nothing
}
}
|
The dynamic delegate nicely solves the problem of coupling between the delegate, the bean, and its business interface. It isn't a perfect solution, however, nor is it always the best one. While you gain a tremendous amount of flexibility with this approach, you also pay a performance penalty. Java reflection isn't terribly fast, so you'll experience some lag time between calling invoke() and getting your results. The static business delegate class shown in the previous tip is a faster solution, but keeps your business and technology layers more coupled than you would like them to be. So, when weighing the two options, the choice comes down to design or performance. The dynamic delegate is the better choice when your application's design is more important than its overall performance. The business delegate is a better bet when performance is the more important factor.
You might find yourself using the dynamic delegate for intranet applications, where all the machines are on a local network and you're constantly adding or changing functionality. For e-commerce and customer-facing applications, the original business delegate is likely the better choice. In either case, you should now have a better understanding of business delegates and how they work. Play around, have fun, and I'll see you online!
- See the Java reflection docs from Sun to learn more about reflection.
- 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-based systems.
- Sun'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 EJB- and J2EE-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.





