When an error occurs during the execution of a transaction, the transaction may or may not need to be rolled back. It all depends on the nature of the error. Exceptions are classified as either checked exceptions, a java.lang.Exception
derived class, or unchecked exceptions, a java.lang.RuntimeException
derived class.
If an unchecked exception is thrown, a transaction is automatically rolled back. For checked exceptions, the UserTransaction's rollback
method or the SessionContext's setRollbackOnly
method are used to explicitly force a rollback.
Checked exceptions are considered to be application exceptions while unchecked exceptions are system exceptions. However, an application can declare its own unique exceptions which can be checked or unchecked.
To assist in the creation and use of application-specific exceptions, the @ApplicationException
annotation is available. This annotation is used to mark an application-specific exception and specify whether a rollback should occur when this exception occurs. Here we focus on the use of this annotation.
The steps used to create such an application-specific exception involve:
The EJB @ApplicationException
annotation is used to declare a class as an application exception. The annotation has two optional elements: inherited and rollback. The inherited element is used to indicate whether any derived classes should have the annotation applied to them. The rollback element indicates whether the exception should force a rollback of a transaction or not. Both of these elements are Boolean. The inherited element defaults to true and the rollback element defaults to false.
To illustrate the use of this annotation, add a class called IllegalPopulationException
, which extends the Exception
class to the packt
package. Add a default constructor and a single argument constructor that uses a simple error message. The rollback element should be set to true
.
@ApplicationException(rollback=true) public class IllegalPopulationException extends Exception { public IllegalPopulationException() { } public IllegalPopulationException(String message) { super("IllegalPopulationException"); } }
To test its use, modify the CityFacade's changePopulation
method to throw an IllegalPopulationException
exception if the count
parameter is a negative value. While a negative value is not necessarily an incorrect value, we will use this test to illustrate the exception handling process.
@TransactionAttribute(TransactionAttributeType.REQUIRED) public void changePopulation(String cityName, long count) throws IllegalPopulationException { System.out.println("Executing changePopulation"); if(count<0) { throw new IllegalPopulationException(); } ... }
Next, modify the PopulationManager's updatePopulation
method by catching the IllegalPopulationException
when the changePopulation
method is invoked. In the catch block, use the println
method to display a message that the exception has been caught.
@TransactionAttribute(TransactionAttributeType.REQUIRED) public void updatePopulation(String cityName, long count) { try { cityFacade.changePopulation(cityName, count); } catch(IllegalPopulationException e) { System.out.println("IllegalPopulationException caught"); } }
Modify the PopulationServlet's processRequest
method. Replace the body of the try block with the following:
clearTables(); populationManager.addCity("Tokyo", "Japan", 32450000); populationManager.updatePopulation("Tokyo", -1000); List<City> cities = cityFacade.findAll(); out.println("<html>"); out.println("<head>"); out.println("<title>Servlet PopulationServlet</title>"); out.println("</head>"); out.println("<body>"); for (City c : cities) { out.println("<h5>Rio: " + c.getName() + " - " + c.getPopulation() + "</h5>"); } out.println("</body>"); out.println("</html>");
This code sequence adds a city and then attempts to update its population with a negative number.
Execute the PopulationServlet
. The browser output will show that the population has not been updated as shown in the following screenshot:
The console output will show the IllegalPopulationException
exception being caught.
INFO: PopulationManager afterBegin
INFO: CityFacade afterBegin
INFO: Executing changePopulation
INFO: IllegalPopulationException caught
INFO: PopulationManager afterCompletion
INFO: CityFacade afterCompletion
The ApplicationException annotation marked the IllegalPopulationException
as one which will result in a rollback if thrown. The exception was created and thrown in the changePopulation
method and propagated to the updatePopulation
method where it was caught. Notice that the output from the changePopulation
method did not reflect the execution of the last two println
methods:
INFO: result: 1
INFO: --- end changePopulation
These statements were bypassed and the population was not changed.
3.15.186.79