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 application. If the application is distributed, we'll need to use session EJBs to expose as much of the application's business logic as remote clients require. When dealing with a true distributed application, 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:

  • Performance
    Invoking EJBs through local interfaces is much faster than true remote invocation, but it's still slower than calling ordinary Java objects (remember that the overhead of remote invocation is only part of the overhead of invoking an EJB: method interception is quite distinct).

  • Complexity
    Using EJBs with local interfaces is more complex than using ordinary Java objects. As with all EJBs with component interfaces, we have at least three source files per bean. Like remote home interfaces, local home interfaces must be looked up in JNDI. Bean instances cannot be obtained directly, but must be obtained through JNDI. And of course deployment is more complex.

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 Chapter 11.

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 application 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:

  • It is potentially confusing to have the same object supporting both call-by-value and call-by-reference, even if this doesn't happen through the same methods.

  • Remote and local interfaces are likely to vary in level of abstraction and granularity, conflicting with it being good OO practice for all an object's methods to be at a consistent level of abstraction. Remote interfaces should be coarse-grained; the local interfaces may be finer grained.

  • If the bean is really a remote object, yet provides a local interface to support local callers, it might be better to refactor the functionality used by the local callers into a helper class. Having one EJB call another indicates questionable design.

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 application should be distributed and whether RMI is really appropriate. They implement the application 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 applications where it wouldn't otherwise have performed adequately. However, I think it is a poor solution today, for the following reasons:

  • I feel uncomfortable with systems that are intended to run in a configuration inconsistent with their declared semantics. Often such applications cannot be run with the configuration their declared semantics implies: they won't perform adequately if deployed using RMI.

  • Applications that depend on this optimization for adequate performance aren't guaranteed to be portable, as this optimization is not part of the J2EE specifications. Although I argue against overemphasis on 100% portability, predicating an application's performance on a single non-standard extension is not something that can easily be modified.

  • Client code is forced to allow for remote exceptions that will never happen. Client code can still encounter java.rmi.RemoteException, but this will indicate a failure within the EJB, not a failure to connect to it.

  • Vulnerability to hard-to-find bugs due to code being written to RMI semantics failing when called by reference (for example, if callers modify objects passed by reference which are subsequently passed to other callers).

  • Adverse impact on OO design. Remote object interfaces are usually designed to coarse granularity for performance reasons. This is a very bad thing if those interfaces will never be invoked remotely.

  • It's no longer necessary. EJB 2.0 gives developers the power to specify the desired call semantics in a standard way.

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 application 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 Chapter 8) 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 application 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 application that is basically local (such as a web application) also needs to support remote callers using RMI. In this case we can either add remote interfaces to some of the application'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 application 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 Application

We've already decided that the sample application 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 application components will be collocated in each server running the application, 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 programming restrictions are likely to cause any difficulties. The booking process is the only obvious application for EJB in the sample application.

The following diagram – based on the diagram of the second of the four architectures discussed in Chapter 1 – illustrates the architecture:

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 booking 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.



Expert One-on-One J2EE Design and Development
Microsoft Office PowerPoint 2007 On Demand
ISBN: B0085SG5O4
EAN: 2147483647
Year: 2005
Pages: 183

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net