December 20, 2014
Hot Topics:

Using a PhaseListener to Debug JSF Development Defects

  • October 30, 2010
  • By Scott Nelson
  • Send Email »
  • More Articles »

Many traditional Java developers quickly embraced the Java Server Faces (JSF) framework and the various library extensions for Java Web development. JSF frameworks hide a large number of details from the developer, who typically has either always used JSF frameworks or is familiar with non-JSF frameworks that implement their solutions in a very different manner. This abstraction can make debugging a JSF application very difficult.

Perhaps one of the most difficult types of defect to isolate and identify in JSF are performance issues, because they are often the result of introducing one or more new technologies into a well-known software ecosystem. The more complex the architecture, such as Web applications that are exposing enterprise SOA functionalities, the more potential points of failure exist. Such systems are generally run by multiple teams, and each team is generally confident enough in their own experience and skills to assume that the root of the issue is somewhere outside their area of responsibility. Also, the more technologies are involved, the less likely it is that someone will understand enough about all of the components to determine the most likely starting point for troubleshooting. Enter the PhaseListener.

JSF does its work in phases, and knowing what is happening in which phase can yield much more useful clues as to where the trouble is originating. JSF includes the notion of running filters on given phases by implementing the PhaseListener Interface javax.faces.event.PhaseListener. In a discussion list, I came across the notion of logging the start and finish of each phase. By doing so, the log files can clearly delineate what action is occurring during which phase by using the three methods of the PhaseListener Interface and not limiting which phase it is executed in. In this article, I explain how to use a PhaseListener to help demystify debugging development defects.

Amp Up Your Logging with a PhaseListener

The first place most developers check for information about where issues are occurring is the application logs. In the case of JSF applications, simply following logging best practices may not be enough to find the precise point where the issue begins, especially if the team is new to JSF or the JSF development team is integrating with an unfamiliar backend service.

Just as complex applications are difficult to debug, they also make for poor learning references. For demonstration, this article uses a variation of the basic JSF application described for the Eclipse Web Tools Project. After the application is built, you can add your own preferred logger to follow along. I used log4j, and the basic logging results are something like this:

DEBUG LoginBean : getName(): null
DEBUG LoginBean : getPassword(): null
DEBUG LoginBean : getName(): null
DEBUG ValidatePassword: validate(FacesContext arg0, UIComponent arg1, Object arg2)
DEBUG LoginBean : getPassword(): null
DEBUG LoginBean : setName() sdfasdf
DEBUG LoginBean : setPassword(): asdfasdf
DEBUG LoginBean : getName(): sdfasdf

The three concrete class methods of the PhaseListener interface are simple:

public PhaseId getPhaseId()
{
return PhaseId.ANY_PHASE;
}

public void beforePhase(PhaseEvent event)
{
logger.debug("n++++++ START PHASE " + event.getPhaseId()+" ++++++");
}

public void afterPhase(PhaseEvent event)
{
logger.debug("n++++++ END PHASE " + event.getPhaseId()+" ++++++");
}

And the listener is registered in faces-config.xml with the following:

com.fyw.demo.LifeCycleListener

And then we have our new log output:

DEBUG LifeCycleListener:
++++++ START PHASE RESTORE_VIEW 1 ++++++
DEBUG LifeCycleListener:
++++++ END PHASE RESTORE_VIEW 1 ++++++
DEBUG LifeCycleListener:
++++++ START PHASE RENDER_RESPONSE 6 ++++++
DEBUG LoginBean : getName(): null
DEBUG LoginBean : getPassword(): null
DEBUG LifeCycleListener:
++++++ END PHASE RENDER_RESPONSE 6 ++++++
DEBUG LifeCycleListener:
++++++ START PHASE RESTORE_VIEW 1 ++++++
DEBUG LifeCycleListener:
++++++ END PHASE RESTORE_VIEW 1 ++++++
DEBUG LifeCycleListener:
++++++ START PHASE APPLY_REQUEST_VALUES 2 ++++++
DEBUG LifeCycleListener:
++++++ END PHASE APPLY_REQUEST_VALUES 2 ++++++
DEBUG LifeCycleListener:
++++++ START PHASE PROCESS_VALIDATIONS 3 ++++++
DEBUG LoginBean : getName(): null
DEBUG ValidatePassword: validate(FacesContext arg0, UIComponent arg1, Object arg2)
DEBUG LoginBean : getPassword(): null
DEBUG LifeCycleListener:
++++++ END PHASE PROCESS_VALIDATIONS 3 ++++++
DEBUG LifeCycleListener:
++++++ START PHASE UPDATE_MODEL_VALUES 4 ++++++
DEBUG LoginBean : setName() Scott
DEBUG LoginBean : setPassword(): secret
DEBUG LifeCycleListener:
++++++ END PHASE UPDATE_MODEL_VALUES 4 ++++++
DEBUG LifeCycleListener:
++++++ START PHASE INVOKE_APPLICATION 5 ++++++
DEBUG LifeCycleListener:
++++++ END PHASE INVOKE_APPLICATION 5 ++++++
DEBUG LifeCycleListener:
++++++ START PHASE RENDER_RESPONSE 6 ++++++
DEBUG LoginBean : getName(): Scott
DEBUG LifeCycleListener:
++++++ END PHASE RENDER_RESPONSE 6 ++++++

So, for example, if there were an issue with the wrong name value showing up in a component log, we can see that the name value provided by the user is not actually available to other components until the UPDATE_MODEL_VALUES phase. Obviously more complex issues occur, and being able to identify the full lifecycle can often be the key to unraveling the problem.


Tags: JavaServer Faces, JSF

Originally published on http://www.developer.com.

Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel