0 Replies Latest reply on Jul 1, 2007 10:57 AM by k d

    EJB exception handling

    k d Newbie

      Hi everyone,

      Here is a thought about exception handling within an EJB container. Let me first start with a little example to demonstrate the nature of a potential problem with the conventional exception handling practices.

      Suppose we have an EJB called MortgageDAOBean which implements Stateless interface.

      public class MortgageDAOBean
      {
       public BigDecimal getCurrentRate()
       {
       // get current rate from the database.
       }
      }


      We also have an EJB called MortgageCalculatorBean which implements Stateless interface.

      public class MortgageCalculatorBean
      {
       private MortgageDAOBean mortgageDAOBean;
      
       public BigDecimal getMortgageAmount()
       {
       BigDecimal currentRate = mortgageDAOBean.getCurrentRate();
      
       // do some further calculations here.
       }
      }


      And finally we have an EJB called MortgatePublisherBean which implements Stateless interface and sends the results of mortgage calculations to some JMS destination.

      public class MortgatePublisherBean
      {
       private MortgageCalculatorBean mortgageCalculatorBean;
      
       public void publishMortgageAmount()
       {
       BigDecimal mortgageAmount = mortgageCalculatorBean.getMortgageAmount();
      
       // do some publishing logic here.
       }
      }


      For the sake of simplicity we can assume that methods of MortgageDAOBean and MortgageCalculatorBean throw only EJBException, which is a system exception that makes the container to roll back the transaction, log the exception and discard the instance of the EJB.

      Note that our MortgatePublisherBean does not do any exception handling because at this stage we are not interested in any particular type of exception, as long as EJBException is thrown that suffices us.

      However, we may have a situation when we need to do some exception handling depending on whether the exception was thrown by MortgageDAOBean or MortgageCalculatorBean. Furthermore, this requirement only exists in the context of MortgatePublisherBean and should not be applied to any other potential users of MortgageDAOBean or MortgageCalculatorBean. This task cannot be achieved with our current implementation of EJB?s, because both of the EJB?s throw the same type of exception, which is EJBException.

      What we would need is some type of exceptions which are associated with a particular type of activity. In our case we could have, for example, DataAccessException associated with MortgageDAOBean and CalculationException associated with MortgageCalculatorBean. These exceptions must not force users to catch them (remember that it?s only MortgatePublisherBean that needs to handle these exceptions), must be delivered as they are (without being wrapped within EJBException) and must result in transaction rollback. This can be achieved by sub classing our exceptions from RuntimeException and defining them as application exceptions which cause transaction rollback.

      So now our MortgatePublisherBean would look like this:

      public class MortgatePublisherBean
      {
       private MortgageCalculatorBean mortgageCalculatorBean;
      
       public void publishMortgageAmount()
       {
       try
       {
       BigDecimal mortgageAmount = mortgageCalculatorBean.getMortgageAmount();
       }
       catch(DataAccessException exception)
       {
       // do some exception handling here.
       }
       catch(CalculationException exception)
       {
       // do some exception handling here.
       }
       }
      }


      This works fine and solves the problem with exact exception handling. However this approach has a major drawback. The problem comes from the fact that application exceptions do not signal the container to discard EJB instances in which such exceptions occur.
      To demonstrate the consequences of this problem, imagine that our MortgatePublisherBean would implement Stateful instead of Stateless interface. This would mean that a new instance of MortgatePublisherBean will have to be created and associated with its own client for the length of its lifecycle. Whenever CalculationException occurs within an instance of MortgatePublisherBean the instance will not be automatically destroyed by the container and will exist until it is explicitly destroyed by its client or expires according to its timeout settings. This can potentially lead to multiple instances of MortgatePublisherBean with incorrect internal state remaining in memory of the container.

      It may seem like a useful thing to be able to define application exceptions as those that will cause destruction of EJB?s within which they occurred and as those that will not cause destruction of EJB?s.
      For example, both DataAccessException and CalculationException exceptions may be defined as application exceptions that cause EJB instance destruction. This is because both of these exceptions are unrecoverable and there is no point to keep instances of EJB?s within which the exceptions occurred (in other words there is not much we can do to those instances because their state may be corrupt). On the other hand checked application exceptions such as IllegalArgumentException may be defined as application exceptions that do not cause EJB instance destruction. This is because we may want to do some recovery procedures and call the instance of the EJB again, in which case it must still exist within the container.

      Introducing this level of customisation for application exceptions will allow to use more specific types of exceptions than just EJBException, but also preserve the interaction between EJB?s and a container that is currently ensured by EJBException.

      This is rather a suggestion and I may well miss something, anyway it would be great to hear what other people think of this idea.