JaVa
   

Session Bean Implementation issues

Now that we've considered which type of session bean to use and some idioms frequently used with session beans, let's take a look at some important implementation issues concerning session beans. In this section we'll consider the EJB error handling model and how it affects bean developers; transaction propagation using EJB CMT and its implications for implementing session beans; and an EJB implementation pattern that can help us to avoid a common cause of deployment errors.

Error Handling in EJBs

As EJBs are managed objects, the EJB container steps in to handle some types of exceptions they throw. This section discusses the rules defined in the EJB specification, and how developers can use them to advantage. These considerations are important as we implement business logic in session beans and define session bean local and remote interfaces.

The EJB Container's Behavior on Exceptions

The EJB specification's approach to exceptions thrown by EJBs is simple and elegant. The specification distinguishes between app exceptions and all other exceptions, referred to as system exceptions. An app exception is a checked exception defined in the throws clause of a method of an EJB's local or remote home or local or remote interface, other than java.remote.RemoteException. (Remember that Java RMI requires that all remote methods declare this exception in their throws clause.) A system exception is an unchecked exception or throwable thrown by an EJB implementation class method at run time, or an uncaught java.remote.RemoteException resulting from a call on another EJB within the app. (It's up to the bean developer to decide whether or not a method in a bean class catches RemoteExceptions resulting from calling other EJBs. It will usually only make sense to do so if the error is recoverable, or to add context information to the nested exception.) It is assumed that the EJB client understands app exceptions, and how they might be recovered from. It is up to the client to decide that a particular exception is unrecoverable. Consequently, the container does not step in when an app exception is thrown. It simply causes the EJB client to catch the same app exception. The container will not normally log app exceptions, and the status of the current transaction will be unaffected. System exceptions are handled very differently. The container assumes that the client didn't expect such an exception, and that it's likely to prove fatal for the current use case. This is a reasonable assumption. In contrast to app exceptions, which are checked and which the client must know about because it is forced by the Java compiler to catch them, system exceptions may be meaningless to the client. Take, for example, a runtime exception from a JDO persistence manager. The client should not even know the EJB tier's persistence mechanism, and can't be expected to recover from a problem it doesn't understand. Accordingly, the container takes drastic action. It marks the current transaction irreversibly for rollback. It discards the EJB instance so that it can service no further calls. The fact that the EJB instance will be discarded means that the developer need not make any effort to clean up any conversational or internal state maintained in the bean. This reduces developer workload and removes a potential source of bugs. The EJB container must log the offending system exception. If the client is remote, the EJB container throws a java.remote.RemoteException (or a subclass) to the client. If the client is local, the EJB container throws a javax.ejb.EJBException to the client. A bean that has encountered an unrecoverable checked exception that it cannot rethrow should throw a javax.ejb.EJBException or subclass wrapping the checked exception. This will be treated as an unexpected exception by the container. This container behavior on unexpected exceptions should not be used as a substitute for explicitly rolling back transactions using the setRollbackOnly() method. It is a convenient cleanup facility offered by the container when a bean instance encounters an unrecoverable error. Since it results in the bean instance being discarded, it will reduce performance if this situation occurs frequently at run time. Let's now consider some of the implications when designing and implementing session beans:

Important 

The guarantee that the EJB container will step in to handle an unchecked exception and ensure transaction rollback makes it particularly attractive to define fatal exceptions thrown by helper classes likely to be used by EJBs to be unchecked exceptions. For example, the JDBC abstraction framework discussed in throws the unchecked DataAccessException, which EJBs that use it can simply ignore, on encountering an unrecoverable java.sql.SQLException. In the unlikely event that an EJB needs to intercept this exception, it still can implement a catch block.

Understanding EJB API Exceptions

The javax.ejb package defines eleven exceptions. Those of most interest to J2EE developers are:

The following are standard EJB app exceptions. They are reported to clients:

Transaction Attributes for EJBs using CMT

EJBs are normally transactional components. As we saw in , one of the strongest arguments for using session EJBs to implement business logic is the option of using declarative Container Managed Transactions (CMT). We specify CMT behavior in EJB deployment descriptors, causing the container to create transactions if necessary for EJB method invocations, freeing the developer from the need to use JTA directly. This is an important productivity gain. However, it's important to understand exactly how CMT works. There is an overhead associated with creating a transaction, so we don't want to create transactions unnecessarily. Yet, transactions are vital to the integrity of business logic that involves multiple updates of transactional resources. Focusing on session beans with CMT, let's consider the transaction attributes allowed by the deployment descriptor and how they affect the behavior of our code. (As we saw in we should always prefer CMT to BMT if we have a choice.) The EJB specification recognizes six transaction attributes, which are associated with EJB methods in the ejb-jar.xml deployment descriptor. The following table summarizes the behavior each confers:

Transaction attribute as
specified in deployment
descriptor

Meaning for the method so marked
(referred to as method m) and other
resources m invokes

Effect if a caller already
has a transaction

Notes

Recommended use


Required

The method is guaranteed to run in a JTA transaction. If the caller has a transaction, it will be used. If not, a new transaction will be created.

Method m will run in the caller's transaction.

If the caller's transaction is rolled back, the work of method m will be rolled back automatically.

This should be the default transaction attribute for session bean methods, which define the public interface of the EJB tier.

     

This is the most flexible option. It allows the caller to use method m as a piece of a larger, reversible, unit of work. Yet method m can still be used independently. For example, it is able to support calls from clients outside the EJB tier.

 

RequiresNew

The method is guaranteed to run in a new transaction, whether or not the caller has a transaction.

The caller's transaction is suspended during execution of the method.

This can be dangerous. If method m will not be reversed. This means that the caller does not have overall control of the business operation.
Note that the creation of a new transaction when the client already has a transaction context does not amount to a nested transaction. With nested transactions, rollback of the parent transaction will cause rollback of all child transactions. In the RequiresNew case we have two separate flat transactions, with no relationship and no effect on each other's rollback status.

Only useful in the unusual case that method m implements a distinct piece of work that must commit regardless of the success of any higher-level operation in progress. An example might be an auditing action, where a persistent record must be made of the fact that a user attempted a certain action, regardless of its success.

NotSupported

The method is assumed not to be interested in JTA transactions, and will execute without a transaction context. If the method invokes other EJBs or resource managers, no transaction context will be propagated.

The caller's transaction is suspended during execution of the method.

Rollback of the caller's transaction will have no effect on any changes made by method m.
Not available to entity beans.

Appropriate if the method's implementation is non-transactional.
Don't use if the method updates persistent data.
Can be useful for read-only methods. For example, Oracle SELECTs do not need to run in a transaction, and Oracle won't create a transaction if none exists. Therefore query methods will be most efficient with a NotSupported transaction attribute.

Supports

If the caller has a transaction, it will be propagated to the method, and execution will occur as in the Required case. If the caller does not have a transaction, the container will not create one, and the method will execute without one, as in the NotSupported case.

Method m will run in the caller's transaction, as in the Required case.

Potentially dangerous. The semantics of method m will vary depending on whether the client has a transaction context.
Not available to entity beans.

Don't use this transaction attribute for updates. In the case of read-only operations, it can be used safely way as NotSupported.

Mandatory

The method requires a JTA transaction, which must be provided by the client. If the client does not have a transaction context when calling the method, the container throws a
javax.transaction.TransactionRequiredException.

This is the only valid case.

Often an alternative to Requires. Limits the situations in which the method may be called. However, this may be a good thing.

Useful for entity bean methods when using a session façade. In this case, we want the client to work through the façade, rather than manipulate low-level components such as entity beans, possibly coming in under the radar of our business logic and breaking system integrity.
Of course, a client could still obtain the UserTransaction object and create a transaction before invoking method m.
Do not use for session bean methods, as this would prevent their use by clients without transactions (the ideal client scenario).

Never

The opposite of Mandatory. The method must not be called by a client with a transaction context. If it is, the container throws a java.rmi.RemoteException. Within the method, behaviour will be the same as in the NotSupported case.

Not permitted.

An alternative to NotSupported if it is considered essential to prevent a client with a transaction context calling the method. Not available to entity beans.

 
Important 

The safest EJB transaction attributes are Required (for session beans) and Mandatory (for entity beans). These attributes ensure the expected transaction behavior, regardless of the caller's transaction context A transaction attribute of NotSupported can be used to boost the performance of read-only methods, for which transactions are not required. This situation arises often, as web apps frequently use read-only data.

Note 

The EJB specification suggests that an "app Assembler", distinct from the EJB developer, may set transaction attributes. This is potentially dangerous. As we've seen, changing the transaction attributes of an EJB method can change the method's semantics. Only if the bean developer defines the transaction attributes can they develop meaningful unit tests for EJBs. While the removal of the specification of EJB transaction attributes from Java code is desirable, their removal from the control of the bean developer is misguided.

Although the details of transaction management are best left to the EJB container, deciding whether a transaction should be rolled back is usually a matter of business logic (remember that if there's a runtime exception, the EJB container will automatically ensure rollback, whether a bean uses BMT or CMT). Accordingly, it's easy to ensure rollback in a bean using CMT.

All EJBs have access to an instance of the EJB context interface, supplied at run time by the container. There are three subinterfaces of javax.ejb.EJBContext, available at run time to the three kinds of EJB: javax.ejb.SessionContext, javax.ejb.EntityContext, and javax.ejb.MessageDrivenContext. The EJBContext superinterface offers a setRollbackOnly() method that allows CMT beans to mark the current transaction irreversibly for rollback.

The Business Methods Interface "Pattern"

As the EJB container, not the bean developer, provides the implementation of an EJB's component interface (the local or remote interface), how do we ensure that the component interface and bean implementation class remain in synch? Lack of such synchronization is a common cause of problems at deployment time, so this is an important issue, unless we are prepared to become dependent on tool support for EJB development. We can choose to make the bean implementation class implement the component interface, but this has the following disadvantages:

Fortunately, there is a simple and effective solution, which is widely recognized: to have both component interface and bean implementation class implement a common "business methods" interface. The business methods interface does not extend any EJB infrastructure interfaces, although it may extend other app business interfaces. If we're dealing with an EJB with a remote interface, each method in the business methods interface must be declared to throw javax.remote.RemoteException. In the case of EJBs with remote interfaces, the business methods interface is normally an EJB-tier implementation detail: clients will work with the bean's remote interface, not the business methods interface. In the case of EJBs with a local interface, the business method interface's methods may not throw RemoteException, which means that the business methods interface need not be EJB-specific. Often the business methods interface, rather than the EJB's local interface, is of most interest to clients of the EJB. In the sample app, for example, the com.wrox.expertj2ee.ticket.boxoffice.BoxOffice interface is an ordinary Java interface, which could be implemented without using EJB. Clients invoke methods on this interface, rather than the EJB's local interface, which extends it. Use of a "Business Methods Interface" isn't really a design pattern – it's more a workaround for an inelegant feature of the EJB specification. But as it's often referred to as a pattern, I'm following established terminology. Let's look at how we use this pattern for the sample app's BoxOffice EJB, and the naming conventions used. Using this pattern involves the following four classes for the EJB:

The following UML class diagram illustrates the relationship between these classes and interfaces and those required by the EJB specification. The business methods interface is circled. Note that the bean implementation class, BoxOfficeEJB, extends a generic superclass, com.interface21.ejb.support.AbstractionStatelessSessionBean, that helps to meet the requirements of the EJB specification. We'll discuss this and other EJB support classes when we look at app infrastructure in the next chapter:

Java Click To expand

The following is a complete listing of the BoxOffice EJB's local interface, which defines no new methods:

 public interface BoxOfficeLocal extends javax.ejb.EJBObject,
 com.wrox.expertj2ee.ticket.boxoffice.BoxOffice {
 }


The following shows how the bean's implementation class implements the business interface as well as the javax.ejb.SessionBean interface required by the EJB specification:

 public class BoxOfficeEJB extends AbstractStatelessSessionBean
 implements SessionBean, BoxOffice {
 // Implementation omitted
 }


Note 

Although the EJB Business Methods Interface is widely advocated, not everyone agrees on naming conventions. Some sources advocating using a BusinessMethods suffix for the name of the business methods interface. Whatever naming convention you decide to adopt, use it consistently in all your EJB implementations to avoid confusion.

The Business Methods Interface pattern is a simple technique that can save a lot of time. However, it can't detect problems in synchronization between an EJB's home interface and implementation class. For example, home interface create() methods must correspond to ejbCreate() methods. Problems synchronizing between home interface and bean implementation class may produce mysterious "abstract method errors" in some servers. The generic superclasses discussed in the next chapter help to avoid such errors, where stateless session beans and message-driven beans are concerned.

Important 

Use the Business Methods Interface pattern to help avoid problems with keeping component interface and business methods in sync. Errors will be picked up at compile time, rather than when the beans are deployed to an EJB container. Although it may be possible to synchronize these classes with an IDE, the business methods interface uses the compiler, and is thus guaranteed to work whatever the development environment.

JaVa
   
Comments