Open Source Software Technical Articles

Want the Best of the Wazi Blogs Delivered Directly to your Inbox?

Subscribe to Wazi by Email

Your email:

Connect with Us!

Current Articles | RSS Feed RSS Feed

How to add exception handling to JSF applications

  
  
  

Everyone who codes Java EE web applications needs to pay attention to exception handling. When a program encounters an error, developers can display friendly messages for end users, which increases their trust in the application. Also, by adding adequate exception handling, you can troubleshoot and debug application defects. Since version 2.0 the JavaServer Faces framework has supported an exception handling mechanism to provide a centralized place for handling exceptions in JSF applications. Here's how you can utilize it to write professional applications.

A good example to illustrate everything that goes into proper exception handling is the guessNumber application, in which the application generates a random number within a specific range, and the user is asked to enter a number in this range. After the user enters a valid number, the application can provide three possible responses:

  1. If the entered number is equal to the generated number, the application congratulates the user and asks if he wants to try again.
  2. If the entered number is less than the generated number, the application asks the user to enter a number greater than the entered number.
  3. If the entered number is greater than the generated number, the application asks the user to enter a number less than the entered number.

To code the guessNumber application, we can use three pages:

  1. input.xhtml, in which the user enters a number.
  2. congratulations.xhtml, which displays the congratulations message if the user succeeds in guessing the correct number.
  3. error.xhtml, which is displayed if the application has an internal error.

The following code snippet shows the input.xhtml page:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

<h:head>
  <title>#{bundle['guessNumber.input_page.title']}</title>
</h:head>

<h:body>
    <h:form>
        <h:panelGrid columns="3">
            <h:outputText value="#{bundle['guessNumber.input_number']}"></h:outputText>
            <h:inputText id="inputNumber" 
                         value="#{randomNumber.number}" 
                         required="true">
                <f:validateLongRange minimum="0" maximum="10"/>
            </h:inputText>
            <h:message for="inputNumber"/>
        </h:panelGrid>

        <h:commandButton value="#{bundle['guessNumber.guess_now']}" 
                         action="#{randomNumber.guessNumber}"/>         
        
        <h:messages />
    </h:form>
</h:body>
</html>

Here a form contains an input text ("inputNumber") in which the user enters a number, and a command button ("Guess Now") that the user clicks in order to send the guess. The input text is required and is validated to be in the range from 0 to 10. When the command button is clicked, #{randomNumber.guessNumber} (the guessNumber action method of the RandomNumber managed bean) is executed. The code below shows the RandomNumber managed bean.

package com.wazi.guessnumber.model;

import java.io.Serializable;
import java.util.ResourceBundle;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;

@ManagedBean
@SessionScoped
public class RandomNumber implements Serializable {
    private Integer number;
    private Integer generatedNumber;
    
    public String guessNumber() {  
        
        if (generatedNumber == number) {
            return "congratulations?faces-redirect=true";
        } 
        
        FacesContext context = FacesContext.getCurrentInstance();            
        ResourceBundle bundle = ResourceBundle.getBundle(
                                "com.wazi.guessnumber.messages",
                                context.getViewRoot().getLocale());

        String tip = "";

        if (generatedNumber > number) {
            tip = bundle.getString("guessNumber.use_bigger_number");
        } else {
            tip = bundle.getString("guessNumber.use_smaller_number");
        }

        context.addMessage(null, new FacesMessage(tip));
        
        return null;
    }
    
    public String reset() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpSession session = (HttpSession) context.getExternalContext().getSession(false);
        
        session.invalidate();
        
        return "input?faces-redirect=true";
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }
    
    @PostConstruct
    public void initialize() {
        generatedNumber = (int) (Math.random() * 10);        
        
        System.out.println ("Initializing random generated number: " + 
                            generatedNumber);        
    }
}

The RandomNumber class is marked as a managed bean using the JSF @ManagedBean annotation and is set in the session scope using the @SessionScoped annotation. Using the @PostConstruct annotation, the initialize() method of the RandomNumber managed bean is called after the managed bean class is instantiated in order to initialize the managed bean. In the initialize() method, the generatedNumber property is set to a random number from 0 to 10.

Start a LIVE Chat to learn about Apache,Tomcat, CentOS, MySQL or otherEnterprise OSS support.

In the guessNumber() action method, if the user-entered a number is equal to the generatedNumber property, the user is redirected to the congratulations.xhtml page. If the entered number is less than or greater than the generatedNumber property, the user is advised to enter a number that is less than or greater than the entered number.

You can add messages to be displayed by the <h:messages> tag from the JSF action methods using the FacesContext.getCurrentInstance().addMessage() API, specifying two parameters. The first parameter represents the client ID with which this message is associated (if no client ID is available you can set this parameter to null) and the second represents the FacesMessage object.

In the reset() action method, the user session is invalidated and the user is redirected to the input.xhtml page. This method is called in the congratulations.xhtml page when the user clicks on the ("Try again") command button. The following code shows the congratulations.xhtml page:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

<h:head>
  <link href="#{request.contextPath}/css/styles.css" rel="stylesheet" type="text/css"/>      
  <title>#{bundle['guessNumber.cong_page.title']}</title>
</h:head>

<h:body>
    <h:form>
        <h:outputFormat value="#{bundle['guessNumber.correct_input']}" 
                        class="highlighted infoMessage">
            
            <f:param value="#{randomNumber.number}"/>
        </h:outputFormat>
        <br/><br/>
        <h:commandButton value="#{bundle['guessNumber.try_again']}"
                         action="#{randomNumber.reset}"/>       
    </h:form>
</h:body>
</html>

In the congratulations.xhtml page, the congratulations message is displayed and the user has the option to try again by clicking on the ("Try Again") button, which calls the reset method of the RandomNumber managed bean.

Applying the JSF exception-handling mechanism

Now we can apply the centralized JSF exception-handling mechanism on the guessNumber application. After we do so, the application will be able to handle different exceptions in a centralized place and display the exception information in an error page. In order to create a custom exception handler in JSF applications we need to do three things:

  1. Create a custom exception handler class that handles the application exceptions. This handler class should extend an exception handling wrapper class (such as the ExceptionHandlerWrapper class).
  2. Create a custom exception handler factory class that is responsible for creating the instances of the exception handler class. The custom exception handler class should extend the JSF ExceptionHandlerFactory class.
  3. Finally, register the custom exception handler factory class in the faces-config.xml file.

The following code shows the CustomExceptionHandler class, which extends the ExceptionHandlerWrapper class:

package com.wazi.guessnumber.exceptions;

import java.util.Iterator;
import javax.faces.FacesException;
import javax.faces.application.NavigationHandler;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.context.Flash;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;

public class CustomExceptionHandler extends ExceptionHandlerWrapper {
  private ExceptionHandler wrapped;
 
  
  public CustomExceptionHandler(ExceptionHandler wrapped) {
    this.wrapped = wrapped;
  }
 
  @Override
  public ExceptionHandler getWrapped() {
    return wrapped;
  }

  @Override
  public void handle() throws FacesException {
    Iterator iterator = getUnhandledExceptionQueuedEvents().iterator();
    
    while (iterator.hasNext()) {
      ExceptionQueuedEvent event = (ExceptionQueuedEvent) iterator.next();
      ExceptionQueuedEventContext context = (ExceptionQueuedEventContext)event.getSource();
 
      Throwable throwable = context.getException();
      
      FacesContext fc = FacesContext.getCurrentInstance();
      
      try {
          Flash flash = fc.getExternalContext().getFlash();
          
          // Put the exception in the flash scope to be displayed in the error 
          // page if necessary ...
          flash.put("errorDetails", throwable.getMessage());
          
          System.out.println("the error is put in the flash: " + throwable.getMessage());
          
          NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler();
          
          navigationHandler.handleNavigation(fc, null, "error?faces-redirect=true");
          
          fc.renderResponse();
      } finally {
          iterator.remove();
      }
    }
    
    // Let the parent handle the rest
    getWrapped().handle();
  }
}

The most important method of the CustomExceptionHandler class is the handle() method, which is responsible for handling JSF application exceptions. The getUnhandledExceptionQueuedEvents() method gets all the unhandled exceptions in the JSF application. Every item in the returned Iterable object of this method represents an ExceptionQueuedEvent object. From the ExceptionQueuedEvent object you can get the ExceptionQueuedEventContext object, from which you can retrieve the Throwable object. Using the Throwable object, you can verify the exceptions you want to handle in the applications.

Get a support quote from a real human.

In our custom exception handler, we get the exception message from throwable.getMessage(). It is set to be used in the error.xhtml page in an "errorDetails" attribute that is defined in the flash scope. The flash scope, which was introduced in JSF 2.0, makes objects available only for the next request of the same browser window, which makes it useful if you want to keep information for a short time for the next request only, whether the next request will result from an HTTP redirect or a JSF form postback or simply an HTTP GET for a new page.

The NavigationHandler redirects the response to the application error page (error.xhtml), and the ExceptionQueuedEvent is removed from the Iterable object. The following code shows the error.xhtml page:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<h:head>
  <link href="#{request.contextPath}/css/styles.css" rel="stylesheet" type="text/css"/>      
  <title>#{bundle['guessNumber.error_page.title']}</title>
</h:head>

<h:body>
    <div class="highlighted errorMessage">
        <h:outputText escape="false" 
                      value="#{bundle['guessNumber.error_page.content']}"/>
    </div>
    <br/><br/>
    <div class="errorDetails">
        Error details: <br/>
        #{flash.keep.errorDetails}
    </div>
</h:body>
</html>

It mainly displays the error details message (which was set from the exception handler class) using #{flash.keep.errorDetails}.

Next, we need to create CustomExceptionHandlerFactory, the custom exception handler factory class that is responsible for creating the instances of the CustomExceptionHandler class:

package com.wazi.guessnumber.exceptions;

import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;

public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {
 
  private ExceptionHandlerFactory parent;
 
  public CustomExceptionHandlerFactory(ExceptionHandlerFactory parent) {
    this.parent = parent;
  }
 
  @Override
  public ExceptionHandler getExceptionHandler() {
    ExceptionHandler result = new CustomExceptionHandler(parent.getExceptionHandler());
    return result;
  }
}

Finally, we need to register the custom exception handler factory class in the faces-config.xml file of the application, as shown below:

<?xml version='1.0' encoding='UTF-8'?>

<faces-config version="2.1"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd">
    
    <factory>
      <exception-handler-factory>
        com.wazi.guessnumber.exceptions.CustomExceptionHandlerFactory
      </exception-handler-factory>
    </factory>
    
	<!—other configurations here -->
</faces-config>

Testing the exception handling mechanism

After setting up this exception handling mechanism in the guessNumber application, if an exception is thrown from the guessNumber application for whatever reason, the error.xhtml page will be displayed. The following screenshot shows the error page if, for example, the guessNumber action method throws a RuntimeException.

Figure 1

And here's the error page you see if the guessNumber application throws the common JSF ViewExpiredException, which can result from the user session timeout that causes the JSF not able to restore the view after the JSF form postback.

Figure 1

The guessNumber application is a Maven application. You can build it from its POM file using the command mvn clean install, then deploy it on Apache Tomcat or another application server (if you specify the correct dependencies). After deploying the application on a local Tomcat server you should be able to try the application by navigating to http://localhost:8080/guessNumber-1.0/.




This work is licensed under a Creative Commons Attribution 3.0 Unported License
Creative Commons License.

Comments

Hi, I'm a JSF beginner and I tried to add the exception handling using your method, but I got the following error message when deploying 
 
Initializing... 
deploy?DEFAULT=/home/vagrant/workspace/jsfDemo/build/web&name=jsfDemo&contextroot=/jsfDemo&force=true failed on GlassFish Server 4.0  
Error occurred during deployment: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: java.lang.RuntimeException: com.sun.faces.config.ConfigurationException: Factory 'javax.faces.context.ExceptionHandlerFactory' was not configured properly.. Please see server.log for more details. 
/home/vagrant/workspace/jsfDemo/nbproject/build-impl.xml:1033: The module has not been deployed. 
See the server log for details. 
BUILD FAILED (total time: 0 seconds) 
 
I'm still searching, but I'd really be grateful if you can give me any clue in solving this problem. 
 
Thank you
Posted @ Friday, September 27, 2013 2:36 AM by Linardi
I followed this tutorial and managed to get this worked.  
Thanks.
Posted @ Tuesday, October 08, 2013 9:20 AM by AK
Hi, this solved my problem! Thank you.
Posted @ Thursday, October 17, 2013 6:26 AM by Bruno Oliveira
Thanks for article....but I followed what you said but the error page is not displayed.Instead it shows blank page. 
Can you please help me?
Posted @ Monday, January 06, 2014 1:30 AM by Shivdatta
I followed what you said but the error page is not displayed.Instead it shows blank page.  
Can you please help me?
Posted @ Wednesday, May 07, 2014 11:19 AM by Sam Punyala
Thank you so much, i followed what you said and i resolve my purpose
Posted @ Monday, August 04, 2014 4:31 AM by Ankush Mankar
If you don't wont to use the NavigationHandler mechanism (there is no  
a "middle way" for NavigationHandler, or your project it's hard configured or not), you have to redirect, but in that case instead of using the flash scope we use the session to handle the throwable message.
Posted @ Thursday, August 07, 2014 3:29 AM by Bruno Molino
I followed this tutorialUsing I followed what you said the Throwable object, you can verify the exceptions you want to handle in the applications!Replica Watches
Posted @ Friday, August 22, 2014 2:18 AM by king
true religion jeans men 
ralph lauren 
fitflop outlet 
coach factory outlet 
fitflop footwear 
ralph lauren outlet 
louis vuitton bags 
prada shoes 
louis vuitton handbags 
michael kors bags 
fitflops clearance 
louis vuitton speedy 
cheap jerseys from china 
cheap louis vuitton 
air jordan shoes 
christian louboutin sale 
tory burch flats 
hollister outlet 
red bottom shoes 
louis vuitton outlet store 
fendi purses 
joe abercrombie 
cheap jerseys 
louis vuitton purses 
michael kors outlet 
oakley sunglasses wholesale 
louis vuitton purses 
celine bag price 
louis vuitton belt 
louboutin shoes 
jordan for women 
louis vuitton 
gucci outlet store 
mont blanc pens 
abercrombie 
coach outlet store online 
crossfit workouts 
ab workouts 
ray ban sunglasses wholesale 
louis vuitton shoes 
jordan 13 
coach factory online 
louis vuitton outlet 
coach factory outlet online 
jordans for sale 
burberry scarf 
true religion sale 
kate spade outlet 
oakley sunglasses wholesale 
kate spade handbags 
ray ban sunglasses outlet 
toms outlet 
fitflop footwear 
louis vuitton outlet 
jordan shoes 
tory burch outlet 
michael kors outlet stores 
jordan retro 
toms shoes 
jordan shoes 
louis vuitton 
mont blanc legend 
hollister clothing 
toms sale 
prda outlet 
fitflop outlet 
toms shoes outlet 
celine handbags 
coach factory outlet 
chi flat iron 
juicy couture outlet 
fendi 
toms wedges 
michael kors outlet online 
coach factory online 
coach outlet stores 
louis vuitton belts 
louis vuitton outlet 
ray ban glasses 
louis vuitton sunglasses 
nfl jerseys 
prada bags 
juicy couture perfume 
gucci shoes 
kate spade 
toms shoes 
abercrombie and fitch 
coach factory outlet 
ray ban sunglasses 
bottega veneta bags 
michael kors outlet online 
trye religion outlet 
cheap ray bans 
juicy couture 
michael kors handbags 
louis vuitton wallet 
burberry handbags 
louis vuitton usa 
louis vuitton speedy 
tory burch outlet online 
michael kors handbasg 
p90x workout schedule 
tory burch shoes 
fitflops online 
coach outlet store online 
toms shoes sale 
michael kors backpack 
coach factory online 
hair dryer 
true religion outlet 
chanel online shop 
hermes birkin 
mont blanc fountain pen 
true religion 
fitflop shoes 
gucci handbags 
jordan shoes 
nfl jerseys wholesale 
marc jacobs 
red heels 
chanel handbags 
michaelkors outlet store 
hermes belt 
christian louboutin  
workout plans 
coach outlet 
coach factory outlet 
louis vuitton handbags 
coach factory outlet 
oakley suglasses cheap 
polo ralph lauren 
ray ban outlet 
workout routines 
louis vuitton purses 
louis vuitton handbags 
ray ban aviators 
michael kors handbags 
hollister co 
coach outlet store online 
true religion 
fitflops clearance 
mont blanc pens 
kate spade purses 
christian louboutin outlet 
christian louboutin outlet 
ray bans 
michael kors outlet store 
kate spade factory outlet 
gucci outlet 
oakley sunglasses 
fitflops 
oakley outlet 
kate spade outlet online 
cheap jordans 
red shoes 
red bottoms 
bottega veneta handbags 
chanel bags 
true religion jeans outlet 
jordan sneakers 
official coach factory outlet 
celine paris 
christian louboutin shoes 
louis vuitton purses 
coach outlet 
nfl jerseys 
louis vuitton outlet 
christian louboutin 
celine outlet 
fendi bags 
cheap toms 
hermes bracelet 
coach factory 
michael kors outlet 
burberry bags 
true religion jeans 
louis vuitton officail website 
cheap nfl jerseys 
gucci bags 
michael kors outlet online 
burberry outlet 
true religion outlet 
cheap jordan for sale 
bottega veneta 
true religion jeans 
cheap jordans 
tory burch outlet 
mont blanc legend 
true religion jeans outlet 
michael kors outlet 
viva la juicy 
ray ban wayfarer 
mont blanc mountain 
toms promo code 
nfl football jerseys 
insanity workout 
abercrombie fitch 
louis vuitton outlet 
louis vuitton handbags 
louisvuitton 
tory burch handbags 
hollister promo code 
tory burch outlet online 
fitflop shoes 
true religion jeans 
celine luggage tote 
louis vuitton 
michael kors purses 
hermes outlet 
oakley sunglasses 
ray ban outlet stores 
fitflop sale 
louis vuitton outlet 
louis vuitton handbags 
louis vuitton bags 
michael kors factory outlet 
chanel outlet 
cheap jerseys 
hermes delivery 
michael kors outlet stores 
louis vuitton backpack 
coach factory online 
ray bans 
louis vuitton outlet 
louis vuitton outlet 
tory burch shoes 
louboutin 
ray ban sunglasses 
chi straightener 
coach factory outlet online 
kate spade handbags 
louis vuitton neverfull 
coach outlet 
coach outlet store online 
hair straightener 
coach factory outlet 
kate spade 
marc jacobs handbags 
louis vuitton purses 
coach outlet 
ray ban sunglasses 
cheap ray ban sunglasses 
used louis vuitton 
louis vuitton handbags 
trye religion outlet 
louis vuitton bags 
louis vuitton outlet stores 
louis vuitton uk 
coach outlet 
official coach factory outlet online  
fendi outlet 
louis vuitton outlet 
ray ban outlet 
oakley outlet 
prada handbags 
cheap oakley sunglasses 
toms outlet 
marc jacobs outlet 
louis vuitton wallet 
louis vuitton 
oakley glasses 
kate spade outlet 
louis vuitton  
tory burch flats 
fitflop sandals 
jordan 11 
coach outlet 
hollister kids 
true religion outlet store 
cheap nfljerseys 
ralph lauren home 
coach factory online 
bottega veneta outlet online 
cheap oakleys 
www.louisvuitton.com 
mont blanc fountain pens 
football jersey 
michael kors outlet 
mont blanc pen 
trye religion outlet store 
christian louboutin shoes 
true religion jeans outlet 
christian louboutin sneakers 
michael kors handbags 
mont blanc pen 
louis vuitton outlet stores 
michael kors handbags 
jordan retro 
designer handbags 
louis vuitton outlet store 
coach factory  
coach factory 
fitflop sandals outlet 
bottega veneta outlet 
cheap true religion jeans 
fendi handbags 
kate spade outlet store 
abercrombie and kent 
michael kors outlet 
louis vuitton handbags 
marc by marc jacobs 
chi hair straightener 
true religion jeans 
cheap jordans 
louis vuitton purses 
fitflop outlet 
michael kors outlet online 
polo outlet 
louis vuitton bags 
Posted @ Thursday, September 11, 2014 9:56 PM by dongdong25
Post Comment
Name
 *
Email
 *
Website (optional)
Comment
 *

Allowed tags: <a> link, <b> bold, <i> italics