June 4, 2009, 7:12 p.m.
posted by hashspark
Exceptions and TransactionsExceptions have a large impact on the outcome of transactions. Application Exceptions Versus System ExceptionsSystem exceptions represent unknown internal errors. The EJB container throws system exceptions when it encounters an internal application server failure. Business logic can throw system exceptions when it wants to abort the business process. Application exceptions are exceptions that are part of your business logic. They denote a strongly typed definition of a specific business problem or failure but do not necessarily abort or roll back the business process. System exceptionsSystem exceptions include java.lang.RuntimeException and its subclasses. EJBException is a subclass of RuntimeException, so it is considered a system exception. System exceptions also include java.rmi.RemoteException and its subclasses. The RuntimeException and RemoteException subclasses differ in that they can be turned into application exceptions using the @javax.ejb.ApplicationException annotation. This annotation is discussed later in this chapter. System exceptions always cause a transaction to roll back when they are thrown from an enterprise bean method. Any RuntimeException not annotated with @ApplicationException that is thrown within the bookPassage( ) method (for instance, EJBException, NullPointerException, IndexOutOfBoundsException , and so on) is handled by the container automatically and results in a transaction rollback. In Java, RuntimeException types do not need to be declared in the throws clause of the method signature or handled using try/catch blocks; they are automatically thrown from the method. The container handles system exceptions automatically and it will always do the following:
When a system exception is thrown from any callback method (@PostConstruct, @PostActivate , and so on), it is treated the same way as exceptions thrown from any business method. Although EJB requires system exceptions to be logged, it does not specify how they should be logged or the format of the logfile. The exact mechanism for recording exceptions and reporting them to the system administrator is left to the vendor. When a system exception occurs, the EJB instance is discarded, which means that it is dereferenced and garbage collected. The container assumes that the EJB instance may have corrupt variables or otherwise be unstable and is therefore unsafe to use. The impact of discarding an EJB instance depends on the enterprise bean's type. In the case of stateless session beans, the client does not notice that the instance has been discarded. These instance types are not dedicated to a particular client; they are swapped in and out of an instance pool, so any instance can service a new request. With stateful session beans, however, the impact on the client is severe. Stateful session beans are dedicated to a single client and maintain conversational state. Discarding a stateful bean instance destroys the instance's conversational state and invalidates the client's reference to the EJB. When stateful session instances are discarded, subsequent invocations of the EJB's methods by the client result in a NoSuchEJBException , which is a subclass of RuntimeException.[*]
With message-driven beans, a system exception thrown by the onMessage( ) method or one of the callback methods (@PostConstruct or @PreDestroy ) will cause the bean instance to be discarded. If the MDB was a BMT bean, the message it was handling may or may not be redelivered, depending on when the EJB container acknowledges delivery. In the case of container-managed transactions, the container will roll back the transaction, so the message will not be acknowledged and may be redelivered. In session beans, when a system exception occurs and the instance is discarded, a RuntimeException is always thrown whether the client is a remote or a local invocation. If the client started the transaction, which was then propagated to the EJB, a system exception (thrown by the enterprise bean method) will be caught by the container and rethrown as a javax.ejb.EJBTransactionRolledbackException . EJBTransactionRolledbackException is a subtype of RuntimeException and gives a more explicit indication to the client that a rollback occurred. If the client did not propagate a transaction to the EJB, the system exception will be caught and rethrown as an EJBException. An EJBException should generally be thrown when a nonbusiness subsystem throws an exception, such as JDBC throwing an SQLException or JMS throwing a JMSException . In some cases, however, the bean developer may attempt to handle the exception and retry an operation instead of throwing an EJBException. This should be done only when the exceptions thrown by the subsystem and their repercussions on the transaction are well understood. As a rule of thumb, rethrow nonbusiness subsystem exceptions as EJBExceptions (or @ApplicationExceptions that cause a rollback) and allow the EJB container to roll back the transaction and discard the bean instance automatically. Application exceptionsAn application exception is normally thrown in response to a business-logic error, as opposed to a system error. Application exceptions are always delivered directly to the client without being repackaged as an EJBException type. By default, they do not cause a transaction to roll back. In this case, the client has an opportunity to recover after an application exception is thrown. For example, the bookPassage( ) method throws an application exception called IncompleteConversationalState ; this is an application exception because it does not extend RuntimeException or RemoteException. The IncompleteConversationalState exception is thrown if one of the arguments passed into the bookPassage( ) method is null. (Application errors are frequently used to report validation errors in this manner.) In this case, the exception is thrown before tasks are started and is clearly not the result of a subsystem failure (e.g., JDBC, JMS, Java RMI, and JNDI). Because it is an application exception, an IncompleteConversationalState exception does not result in a transaction rollback by default. The exception is thrown before any work is done, avoiding unnecessary processing by the bookPassage( ) method and providing the client (the enterprise bean or application that invoked the bookPassage( ) method) with an opportunity to recover and possibly retry the method call with valid arguments. The @javax.ejb.ApplicationException annotation may be used to force an application exception to roll back the transaction automatically:
package javax.ejb;
@Target(TYPE) @Retention(RUNTIME)
public @interface ApplicationException {
boolean rollback( ) default false;
}
For instance, the PaymentException used in the ProcessPayment EJB in Chapter 11 is a good candidate for an application exception that causes an automatic rollback:
@ApplicationException(rollback=true)
public class PaymentException extends java.lang.Exception {
public PaymentException( ) {
super( );
}
public PaymentException(String msg) {
super(msg);
}
}
We want the transaction to be rolled back automatically, but business logic may be able to catch PaymentExceptions and retry the transaction automatically (as it would if another credit card were on file, for example). The @ApplicationException annotation can also be used on subclasses of java.lang.RuntimeException and java.rmi.RemoteException . This is useful because you may not want a thrown RuntimeException to be wrapped in an EJBException, or you may not want a particular subclass of RemoteException to roll back the exception. Application exceptions are declarable in XML, as well, with the <application-exception> element:
<ejb-jar>
<assembly-descriptor>
<application-exception>
<exception-class>java.sql.SQLException
</exception-class>
<rollback>true</rollback>
</application-exception>
</assembly-descriptor>
</ejb-jar>
The <application-exception> element is a subelement of <assembly-descriptor>. XML gives you the added capability of declaring a third-party exception as an application exception. In this example, we made java.sql.SQLException an application exception that causes a rollback. We could then let the ProcessPayment EJB throw SQLExceptions directly instead of wrapping them in an EJBException. Figure summarizes the interactions among different types of exceptions and transactions in session and entity beans. Figure summarizes the interactions among different types of exceptions and transactions in message-driven beans. |
- Comment