Tuesday, 6 October 2009

Exceptions in Java world: agree or not to agree, this is the question

1.     Introduction 
In this article I try to explain generic rules or tips that can be followed to try to create a robust application with decouple layers. This topic is very polemic because everybody has a particular opinion about this and actually there is no a golden rule to follow. 








2.     Exceptions
The Java programming language provides three kinds of throwables:

2.1  Checked exceptions
Checked exceptions are all subclasses of java.lang.Exception, except java.lang.RuntimeException and its subclasses.

2.1.1       Business exceptions
The business exceptions should be used for exceptional conditions and not for ordinary control flow. A well-designed API must not force its client to use exceptions for ordinary control flow.

The business exceptions are used for conditions from which the caller can reasonably be expected to recover. It is important to mention that the business exceptions are associated with a business semantic.

Avoid unnecessary use of business exceptions. The overuse of checked exceptions can make an API far less pleasant to use. If a method throws one or more checked exceptions, the code that invokes the method must handle the exceptions in one or more catch blocks, or it must declare that it throws the exceptions and let them propagate outward. Either way, it places a nontrivial burden on the programmer.

Example
public void transferMoney(AccountDTO accountTo, AccountDTO accountFrom , double amount) throws NoSufficientFundsException

Exception in business meaning:

NoSufficientFundsException is thrown if you try to transfer money from an account to another account and you have no enough money.

This checked exception bring business semantics to the caller.

2.1.2       ‘Infrastructure’ Checked exceptions
For example, we could consider as ‘infrastructure’ checked exceptions J2SE API checked exceptions, JEE API checked exceptions, Third Party API checked exceptions etc.

For instance:

§          java.io.IOException
§          javax.naming.NamingException
§          java.sql.SQLException.
§          javax.mail.MessagingException
§          javax.resource.ResourceException
§          javax.ejb.FinderException.

If an ‘infrastructure’ checked exception is thrown, it can be catch and either a business exception will be thrown up or it will be logged.

Note: The high-level classes should not know the low-level details of implementation.

Example 1.
       // Exception Translation with infrastructure checked exceptions
       try {
       // ...
       } catch (IOException e) {
                     throw new NotFoundResourceException();
}

Example 2.
       // Exception log
       try {
       // ...
       } catch (IOException e e) {
              log.error(e,”The resource was not found”);
              … // solve the problem somehow. 
       }

2.2  Unchecked exceptions

2.2.1       Runtime exceptions
Runtime exceptions are all subclasses of java.lang.RuntimeException.

The runtime exceptions should not be thrown explicitly in developer java code. These exceptions mean precondition violations or bugs. This is simply a failure by the client of an API to adhere to the contract established by the API specification.

2.2.2       Errors
All subclasses of java.lang.Error.

There is a strong convention that errors are reserved for use by the JVM to indicate resource deficiencies, invariant failures, or other conditions that make it impossible to continue execution. It is very recommended to extend the error class.

3.     Advisable Rules

3.1  Throw exceptions appropriate to the abstraction.
It is disconcerting when a method throws an exception that has no apparent connection to the task that it performs. This often happens when a method propagates an exception thrown by a lower-level abstraction. This pollutes the API of the higher layer with implementation details. If the implementation of the higher layer changes in a subsequent release, the exceptions that it throws will change too, potentially breaking existing client programs.
To avoid this problem, higher layers should catch lower-level exceptions and, in their place, throw exceptions that can me explained in terms of the higher-level abstraction. This is known as exception translation.

Example 1.
              // Exception Translation
       try {
              // Use lower-level abstraction to do our bidding
             
       } catch (LowerLevelException e) {
              throw new HigherLevelException(...);
       }
     
A special form of exception translation called exception chaining is appropriate in cases where the lower-level exception might be helpful to someone debugging the problem that caused the higher-level exception. The lower-level exception (the cause) is passed to the higher-level exception, which provides an accessor method (Throwable.getCause) to retrieve the lower-level exception:

Example 2.
       // Exception Chaining
       try {
              // Use lower-level abstraction to do our bidding
             
       } catch (LowerLevelException cause) {
              throw new HigherLevelException(cause);
       }
     
The higher-level exception’s constructor passes the cause to a chaining-aware superclass constructor, so it is ultimately passed to one of Throwable’s chaining-aware constructors, such as Throwable(Throwable):

Example 3.
//Exception with chaining-aware constructor
              Class HigherLevelException extends Exception {
                     HigherLevelException(Throwable cause){
                            super(cause);
                     }
              }

Most standard exceptions have chaining-aware constructor. For exceptions that don’t, you can set the cause using Throwable’s initCause method.

3.2  Never declare that a method throws Exception or worse yet, throws Throwable.

3.3  Include failure-capture information in detail messages.
To capture the failure, the detail message of an exception should contain the values of al parameters and fields that “contributed to the exception”.

Example 1.
// Including detail message about the exception
              try {
                     // Use lower-level abstraction to do our bidding
                    
              } catch (LowerLevelException cause) {
                     throw new HigherLevelException(“This the cause”,cause);

Example 2.
// Including detail message about the exception
throw new LowerLevelException(“This the cause”);




4.     Case studies – Bank Website
In this section I show different use cases with different perspective about how the exceptions are focus. We start thinking that we have an application in the way that is represented in the figure.







4.1  Use case – Balance


Client Component

try {
      
Double balance = façadeBank.balanceAccount(userDTO);  
       …
} catch (RuntimeException e) {
       log.error(e,”Some message”);                          
       forward = “error_page”;                        

}

return forward;

The RuntimeException can be catch in the client component but it should not be catch in lower layers. In this example in case of RuntimeException I am forwarding the output to an error page.

4.2  Use case - Transfer money

Client Component
            try{
              …     
                     façadeBank.transferMoney(accountFrom, accountTo, amount);
                    

              } catch (TransactionMoneyException e){
                     log.error(e,”Some message”);
                     addMessageUI(“It was no possible to transfer money.”);

       }

If the TransactionMoneyException is thrown in the client component, I add a message to the user interface reporting that it was an error trying to transfer money.
      
Façade
      
       void transferMoney (AccounDTO fromAccount, AccounDTO accountTo, Double amount) throws TransactionMoneyException {      

              try {
                     AccountAppService.transferMoney(fromAccount, toAccount,amount);
               
              } catch (TransferTransactionException e) {
                           throw new TransactionMoneyException (“No Money sent");

              }
       }

If the TransferTransactionException is thrown I translate to a more readable transaction TransactionMoneyException and throw up to the caller.

ApplicationService

public void transferMoney(AccountDTO fromAccount, AccountDTO toAccount, Double money) throw TransferTransactionException {
      
       try {
              …            
              thirdPartyAPIObject.createBankTransaction(…);
                    
} catch (ThirdPartyConnectionException e) {
              log.error(e, “Transfer Transaction aborted”);
              throws new TransferTransactionException()
       }


The ThirdPartyConnectionException is a checked exception thrown by thirdPartyAPIObject object when we execute the method createBankTransaction. This exception is low level therefore I translate to higher level checked exception.





4.3  Use case - Withdraw money

Client Component

       try{
              …     
              façadeBank.withdrawMoney(account);
             
       } catch (TransactionMoneyException e){
              log.error(e,”Some message”);
              addMessageUI(“Some UI error message”);
       }
       …
If the TransactionMoneyException is thrown in the client component, I add a message to the user interface reporting that it was an error trying to transfer money.


Façade

void withdrawMoney (AccountDTO account, Double amount) throws TransactionMoneyException {             
       try {
             
              TransferOperationAppService.withdrawMoney (account, amount);
             

       } catch (NoFundsException e) {
              throw new TransactionMoneyException (“No money in the account");
       }
       
}

If the NoFundsException is thrown I translate to a more readable transaction TransactionMoneyException and throw up to the caller.

ApplicationService

public void withdrawMoney (AccountDTO account, Double amount) throws NoFundsException {
             
              throw new NoFundsException();
             
}     


This method throws checked exception NoFundsException when there is not money in the account.

4.4  Use case – Checking personal details.

ApplicationService

       public void checking (UserDTO user) {
             
              try {
                    
                     somethingThrowsSQLException
                    
                    
} catch (SQLException e) {
                     log.error(e, “It is not possible to check the details.”);
                    
}     


       }

In this example a ‘infrastructure’ checked exception is thrown. I log the error.


Friday, 25 September 2009

I must say, I am not very convinced to use EXTENDED PERSISTENCE CONTEXT

Introduction

I decided to share a special situation that I lived when I attempted to improve my code following some JEE specification principles. But as always, the thing is not easy. I realised that the two possible solutions did not work because of hibernate bug. Therefore I had to adapt my solution with a hibernate workaround.

Initial situation

We have the screen that shows:


§          Entity A instance name property.
§          Description properties from B instances linked with A instance.
§          Description properties from C instances linked with A instance.
§          Description properties from D instances linked with A instance.
§          Description properties from E instances linked with A instance.





In the server side we could have to following class diagram (we do not care about best practises):

The business object model for this example is the following:




We have to mention important points here:



§          The find method code in the Server Component is:

String queryStr = "select distinct a from A a where a.id = :id";    
Query query = em.createQuery(queryStr).setParameter("id", id);
A a = query.getSingleResult();

§          The extended persistence context is binding to the life cycle of the Client Component.

§          All the relationships from entity A are using Lazy Loading Strategy.

§          When the user interface is rendered in the server side, from A instance, we can get all its relationship instance properties because A is attached to the persistence context.

If this approach is working, Why Do I want to swap from extended persistence context to transactional?



The main reason is the following:

Aurelio - The Guru says: Any change in the database that has been done outside our scope (other user) and affects an entity that appears in the extended persistent context will potentially create inconsistencies once the extended persistence context is NOT notified from DB that an entity that it "caches" has been changed, so by that time the data in that entity is stale (dirty). To workaround this, you have to explicitly refresh() that entity from PC every time you query that, so, what the point of extended persistence context?.

Note:  The solution is not just change from extended to transactional persistence context. In this case happens the following:

When the user interface is rendered, the entity A instance is detached (the transactional persistence context does not exist anymore after finishing the transaction), therefore we can not access to the lazy loading collections linked to entity A instance.

Each vendor solves this situation in a different way (i.e Hibernate: org.hibernate.LazyInitializationException: failed to lazily initialize a collection - no session or session was closed).

Solution - First Approach with transactional persistence context.


The server side we could have to following class diagram:





The business object model for this example is the following:




We have to mention important points here:


§          The code In the Application Service find method is:

String queryStr = "select distinct a from A a LEFT OUTER JOIN FETCH a.b “ +  
               “LEFT OUTER JOIN FETCH a.c ” +
 “LEFT OUTER JOIN FETCH a.d ” +
 “LEFT OUTER JOIN FETCH a.e ” +
 “where a.id = :id";
Query query = em.createQuery(queryStr).setParameter("id", id);
A a = query.getSingleResult();

§          The transactional persistence context is binding to the transaction.

§          All the relationships from entity A are using Lazy Loading Strategy.

§          When the user interface is rendered in the server side, from A instance, we can get all its relationship instance properties because all of them were fetched in the query.

Solution - Second Approach with transactional persistence context.

The server side we could have to following class diagram:




The business object model for this example is the following:



We have to mention important points here:

§          The code In the Application Service find method is:

String queryStr = "select distinct a from A a where a.id = :id";    
Query query = em.createQuery(queryStr).setParameter("id", id);
A a = query.getSingleResult();

§          The transactional persistence context is binding to the transaction.

§          All the relationships from entity A are using Eager Loading Strategy.

§          When the user interface is rendered in the server side, from A instance, we can get all its relationship instance properties because all of them were fetched in the query because are declared Eager.

What a Surprise! These solutions do not work with Hibernate. Hibernate´s bug.

For both approaches we get the next exception:

org.hibernate.HibernateException: cannot simultaneously fetch multiple bags 

After investigating I found this website:

The problem is described as:

“For class X, multiple collection fields are marked for eager fetching: a, b, c; this is not supported by Hibernate in releases after 3.2.x

Hibernate workaround with transactional persistence context.

The server side we could have to following class diagram:










The business object model for this example is the following:

We have to mention important points here: 


§          The code In the Application Service find method is:

String queryStr = "select distinct a from A a where a.id = :id";    
Query query = em.createQuery(queryStr).setParameter("id", id);
A a = query.getSingleResult();

§          The persistence context is binding to the transaction.

§          All the relationships from entity A are using Eager Loading Strategy.

§          Hibernate workaround:

Add a new annotation @Fetch(value = FetchMode.SUBSELECT) in the collections.
@JoinTable(… …
@ManyToMany(fetch = FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)

@JoinTable(… …
@ManyToMany(fetch = FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)

@OneToMany(fetch = FetchType.EAGER, … …)
@Fetch(value = FetchMode.SUBSELECT)

@OneToMany(fetch = FetchType.EAGER, … …)
@Fetch(value = FetchMode.SUBSELECT)
  
§          When the user interface is rendered in the server side, from A instance, we can get all its relationship instance properties because all of them were fetched in the query because are declared Eager.