JaVa
   

Deciding How to Use EJB

Assuming that we decide to use EJB to take advantage of the EJB container services we've discussed, there are still many issues to discuss in how we use EJB.

What Should EJBs Do?

How we should use EJBs depends largely on whether we're implementing a distributed or collocated app. If the app is distributed, we'll need to use session EJBs to expose as much of the app's business logic as remote clients require. When dealing with a true distributed app, we need to consider interface granularity; remote EJB interfaces must not force clients into "chatty" calling and should ensure that data exchanged is kept to a minimum, or the performance overhead of remoting will become prohibitive. We can use session EJBs with local interfaces very differently. Although they're heavyweight objects compared to ordinary Java classes, the overhead they impose is far more modest. (They're likely to prove a few times slower to invoke than ordinary Java classes, compared to the hundreds or even thousands of times when using remote invocation, and they may even deliver performance benefits if we use container-managed threading appropriately.) This means that when working with local interfaces, we don't need to distort our object model to ensure that EJBs expose coarse-grained interfaces.

Important 

EJBs with remote interfaces and EJBs with local interfaces cannot be directly compared; it's not simply a question of exposing different interfaces to the same kind of object. Performance considerations are more important than OO design considerations when designing EJB remote interfaces; they must be coarse-grained, the objects exchanged must be serializable, and callers must not be forced into chatty calling. EJBs with local interfaces are much more like true objects; their interfaces will be determined by normal OO design considerations.

When to Use Local or Remote Interfaces

Local interfaces were introduced into the EJB 2.0 specification primarily to make it more efficient for EJBs to call each other. This makes the Session Façade pattern more performant and reduces the overhead associated with entity beans. The Session Façade pattern involves session beans mediating between remote clients and local entity beans running in the same EJB container. In this model, local interfaces are an optimization inside the EJB container, hidden from web components and other objects that use the EJBs behind a remote Façade. I believe that such use of entity beans (which may have relationships with other entity beans) is the one case in which it makes sense for EJBs to call each other. It's best to avoid having EJBs call one another, even through local interfaces. When the invoked EJB is a session bean, a better alternative is to use an ordinary Java helper class, for the following reasons:

Note 

We will need to provide some infrastructure to make it easier to configure helper classes in the EJB container. We discuss an approach in .

I believe that in EJB 2.0, the best use of local interfaces is to allow us to use EJB without remote interfaces and without adopting a distributed architecture. In this approach, collocated objects outside the EJB tier, such as business objects running in the web container, invoke EJBs through their local interfaces. This allows us to enjoy many of the advantages EJB offers without much of its complexity.

Important 

Unless your app is inherently distributed, I recommend against using EJBs with remote interfaces. The introduction of local interfaces in the EJB 2.0 specification justifies a rethink of our approach to EJB, making local interfaces the default choice for EJBs, and remote interfaces a special case.

Does it Make Sense for a Bean to Have Both Local and Remote Interfaces?

The EJB specification implies that the norm will be for an EJB to have either a local or a remote interface. However, it is legal to provide both. In this case, the two interfaces are independent. They cannot extend a common superclass, as every method on the remote interface must be declared to throw java.rmi.RemoteException, while methods on the local interface must not be declared to throw this exception. While the interfaces are independent, the one method in the bean implementation class may implement a method with the same name and arguments from both the local and the remote interfaces, differing only in that the remote interface signature includes java.rmi.RemoteException in the throws clause. The bean implementation may declare the method without java.rmi.RemoteException in the throws clause, satisfying both contracts. This is legal Java. However, this convenient approach can be dangerous. Callers using the local interface will be using call-by-reference, and callers using the remote interface, call-by-value. Having the same method invoked with different calling semantics is asking for trouble. Of course we don't need to double-up with method implementations in this way. It may be wiser to give local and remote interface methods distinguishing names so that the bean implementation is easily understandable. The following issues should be considered before giving an EJB both a remote and a local interface:

An alternative approach to giving one EJB both a remote and a local interface is to give the EJB that exposes the underlying business logic only a local interface and add another EJB with a remote interface as a Façade to service remote callers. This has the benefit of making explicit the local/remote split. However, we must still be aware that while the local interfaces use call-by-reference, the remote interface uses call-by-value.

Phony Remote Interfaces

Finally, there's the EJB interface approach that most existing EJB deployments end up relying on. In this approach, architects and developers duck the tough decisions of whether the app should be distributed and whether RMI is really appropriate. They implement the app using remote interfaces. However, they then collocate web tier and EJB tier in the same JVM and let the server "optimize" notionally remote calls into calls-by-reference. The EJB container behaves more or less (but not quite) as it would for local interfaces; it still intercepts EJB calls, allowing it to perform transaction management and other EJB services. However, error handling must follow the remote semantics (returning java.rmi.RemoteException and subclasses rather than javax.ejb.EJBException) on fatal errors. Strictly speaking, this subverts the EJB paradigm. However, the reality is that the overhead of remote invocation is so crippling to performance that most servers make this their default behavior when EJBs and client code are deployed in the same JVM. Call-by-reference optimization was a welcome optimization in the days of EJB 1.1; it made EJB usable in many apps where it wouldn't otherwise have performed adequately. However, I think it is a poor solution today, for the following reasons:

The one potential advantage is that we can enjoy the performance of call-by-reference without ruling out other deployment options. This can be an important consideration, but it's worth thinking long and hard about whether there will be any other deployment options. Usually there won't be. Complicating design just in case is a classic – and potentially costly – example of what XPers call You Aren't Going to Need It, and we'll only enjoy a choice of deployment options if we distort OO design to ensure that all business objects have coarse-grained interfaces.

There is one argument in favor of using EJBs with remote interfaces – or giving local EJBs additional remote interfaces – even if an app isn't inherently distributed: EJBs with remote interfaces are easier to test than EJBs with local interfaces. Access via remote interfaces means that test cases don't need to run in the J2EE server, allowing the use of simple tools such as JUnit. However, remote testing will work only if all objects exchanged are serializable, and can be "disconnected" from the J2EE server container. In some cases such as CMP entity bean container-managed collections, this is impossible to achieve.

EJB Interface Summary

Entity beans should never be given remote interfaces. Business objects within the same JVM (for example, other EJBs or components in the web container) should access entities through local interfaces. There are such overwhelming performance and design reasons against remote access to entity beans (discussed in ) that it's questionable whether the EJB specification should offer it as a design choice. The Session Façade pattern, which mediates entity bean access through session beans, is the appropriate solution for EJB deployments offering remote interfaces that use entity beans. Session beans should be given remote interfaces only if the app has to be distributed and/or remote clients will access the EJBs using RMI. EJBs that are remote objects should not normally have local interfaces, because they should not be invoked by other objects within the same EJB container. However, there is a special case in which an app that is basically local (such as a web app) also needs to support remote callers using RMI. In this case we can either add remote interfaces to some of the app's EJBs, or implement Façade EJBs that invoke them. However, we will need to consider the implications of supporting both call-by-reference and call-by-value. If an app is not inherently distributed, EJBs should be given local interfaces. I recommend against relying on call-by-reference optimization when EJBs with remote interfaces are collocated with code that calls them.

Important 

Local interfaces should be the default choice for EJBs. Remote interfaces are a special case, to deliver additional functionality (at a cost in performance, complexity and to OO design) where this is necessary.

It is possible for an EJB to expose both a local and remote interface. However, these need to be considered carefully, due to the difference between call-by-reference and call-by-value semantics.

Using EJBs in the Sample app

We've already decided that the sample app will not be distributed. Thus we'll use only EJBs with local interfaces. There is no need to expose remote interfaces, although we may be able to in future in the unlikely event that RMI access is required. This means that we don't need to ensure that all EJB invocations are coarse-grained. Since all app components will be collocated in each server running the app, there's no need for all business objects to be implemented in the EJB container. This means that we can pick and choose where to use EJB: where we want the transaction management, thread management, and other benefits of EJB, but not where the EJB coding restrictions are likely to cause any difficulties. The tutorialing process is the only obvious app for EJB in the sample app. The following diagram – based on the diagram of the second of the four architectures discussed in – illustrates the architecture:

Java Click To expand

Most of the business interfaces will be implemented by ordinary Java classes running in the web container, while the interface for the tutorialing object will be implemented by a stateless session EJB with a local interface. A business delegate in the web container will front this EJB and ensure that objects running in the web container can access it without having to handle EJB-specific details such as JNDI lookups. Thus, use of EJB is an implementation choice, rather the key to the overall architecture.

JaVa
   
Comments