JSF Lifecycle

- Damodar Chetty

- Sep 03, 2008

Summary

One of the hardest parts of getting up to speed with JavaServer Faces is the complexity introduced by the lifecycle. This article attempts to demystify the actions taken by FacesServlet (the heart of JSF) as it processes each incoming request. This lifecycle formalizes how JSF implementations will process a request, and expose hooks to which you can attach your own application-specific processing.

Need For Web Frameworks

Let's assume you are doing plain vanilla servlet programming. Your servlet service method is invoked by the container with request and response objects. Your service method would then need to:

1.      interrogate the request to extract the incoming parameters (via tedious repetitive querying).

2.      convert these parameters from strings to their corresponding data types (all incoming values appear as strings.)

3.      validate the presence of required parameters, the correctness of entered values, formatting, etc.

4.      use the incoming URL or parameters to determine who should process the request

5.      perform application processing using the incoming parameters and any saved state as inputs. Retrieve information from various scopes as needed.
Your logic will store work products (or Transfer Objects for the view) in the appropriate scope.

6.      determine the view that will display the response to the user (e.g., a JSP page)

7.      either directly write out to the response object, or forward to the desired view. Retrieve information from various scopes as needed.

You also need utility mechanisms plugged into each of these steps to handle (a) conversion, validation, application, or system errors that may be discovered; (b) internationalization of resource strings as needed; (c) compose views out of reusable and tested pieces; (d) ability to access bean properties from the various scopes (context, session, request); and (e) your application logic with services either via service location or dependency injection.

And you have to repeat the above for every unique URL that your application should handle. Add to that the hassles with figuring out how to manage the mappings between URLs and handlers, and how to manage the destination views once you are done with processing. And, god forbid, having to support rendering in WML as well. As you can imagine, this quickly adds up to a fairly complex task.

Now imagine that someone helps abstract out the common portions of the tasks above - and leaves you with a fill-in-the-blanks template where you can insert your custom functionality. That's exactly what a web framework does. I.e., it hides the tedious, mundane and mind numbingly dull tasks from view, and exposes well defined points into which you can plug in your own custom application logic.

So what does JSF bring to the party? It brings all of the above and adds in a rather unique stateful component model that further automates a lot of the work described here.

A typical JSF lifecycle flows as follows:

1.      JSF interrogates the request to extract the incoming parameters (yay!)

2.      JSF converts these parameters from strings to their corresponding data types (yay!)

3.      JSF validates the presence of required parameters, the correctness of entered values, etc. (yay!)

4.      JSF uses the incoming URL to determine who should process the request (yay!)
This is usually done using post-backs.

5.      JSF will execute any custom logic that you provide it. (yay!)
Your logic will store work products (or Transfer Objects for the view) in the appropriate scope.
JSF defines interfaces for event handlers and clear guidelines as to when a particular handler will be invoked.

6.      JSF determines the view that will display the response to the user (yay!)
JSF uses the return value of your application handler to look up the desired view in a mapping file that you provide.

7.      JSF will execute any custom logic that you provide to render your response, or will forward to the desired view. (yay!)

During all of this, JSF provides utilities for errors to be exposed to the user, for internationalization using resource bundles, etc. JSF does not provide a native composition facility - so you'll need to include Tiles or Facelets.

The recognized standard pattern for web development today is Model-View-Controller (MVC). JSF encourages this split in your application's logic by giving you guidance as to how you might make this division of labor possible. With JSF, your views are your template files; your model is a combination of your component model (that backs a given page) and your domain or application model (that contains your domain entities and business rules); and your controller is a combination of FacesServlet (provided by JSF) and the handlers that you expose.

As you can see there's a lot that JSF provides. (To be fair, all web frameworks provide this level of support to some degree or the other).

What's unique to JSF (and to most component oriented frameworks) is JSF's UI component model, which adds some truly unique advantages. It lets JSF map incoming String parameters to bean properties (with the appropriate data conversions). It lets JSF remember component state across invocations. It allows JSF to compartmentalize pluggable bits of functionality, such as renderers, converters, and validators, on a per component basis. It lets you manipulate components directly from within Java code. And more.

Arguably, its this combination of complex life cycle and the flexibility of the component model that makes JSF feel unapproachable to new web developers, and make it look over-engineered to experienced web developers. In this article, I'm going to attempt making the life cycle more accessible and will leave the component model for another day.

JSF Life Cycle

I designed this diagram for use as a reference wall chart (I have it on mine.)

A few words of explanation before we begin:

1.      Each yellow box is a distinct processing step within the request processing life cycle.

2.      Each green box represents optional event processing, and gives your application a chance to insert itself into the processing flow. Events stereotyped with <regular> indicate the normal location where the event will be broadcast to its listeners. Events stereotyped with <immediate> indicate when immediate events are broadcast. Immediate events are always broadcast before their regular equivalents (- else what would be the point.)

3.      The arrows departing each box indicate the next step in the life cycle. The three possible options at each step are to (a) continue on to the next step; (b) skip to the Render Response phase; or (c) end the life cycle completely. Options (a) and (b) are represented by arrow heads, and option (c) by a filled circle. It is important to note a technicality - while it may seem that options (b) and (c) only ever occur as a result of event processing (the green boxes), in reality any code could take on that responsibility, even code within a yellow phase box. Also, only option (a) is shown on the first and the last PhaseEvent boxes in the lifecycle. I haven't tried it myself, but I'd question the usefulness of the other options this early/late in the lifecycle.

4.      The text in the white boxes describe the processing that occurs within each phase. Whereas the blue boxes share useful, but ancillary, information.

 

We're now ready to take this one step at a time. Rather than repeat all the text in the diagram above, I'm going to provide some additional background in the following sections.

Phase 1: Restore View

Goal for this phase:

Generate or retrieve a component tree to represent the requested view, and set the locale to be used.

Important Concepts required to understand this phase:

         View:
A traditional JSP page is referred to, in JSF, as a view. This is appropriate since a JSP page forms the View part of the Model-View-Controller pattern.

         Component Tree:
In JSF, a view is also known as a component tree. This is also appropriate since a JSP view models the elements of a JSP page (such as the form, input boxes, buttons, and links) using Java objects, where these objects are organized into a tree, based on the hierarchical containment hierarchy of a typical HTML page.

         View Root:
Each component tree is rooted at a UIViewRoot object - which is represented by the <f:view> JSF tag.

         View Identifier:
Each view/component-tree has a unique id. When using JSPs and prefix mapping, this is the part of the URL between the prefix and the query string. I.e., for a request URL of http://localhost/myapp/faces/admin/users.faces the unique id is /admin/users.jsp.

When using JSPs and suffix/extension mapping, this is the part of the URL with the extension replaced by .jsp. I.e., for a request URL of http://localhost/myapp/admin/users.faces the unique id is /admin/users.jsp.

Note that a view identifier is a critical concept and comes back into play during the navigation step of the Invoke Application phase.

         Faces Context:
A FacesContext describes the runtime environment for the request currently in progress. This is a critical object for many reasons. It allows you to set/retrieve the current view root - thereby affecting the view that will be displayed to the user; it houses the all important renderResponse() and responseComplete() methods that allow the lifecycle to short circuited; it lets you access the external servlet or portlet context; and much more.

Important activities in this phase:

This phase treats first time requests different from form submits (aka postbacks).

If this is a first request for this resource, i.e., if the incoming request carries no parameters, JSF will extract a view ID from the URL and will construct a brand new component tree for it. The components in that tree are initialized using any default values specified in the JSP. Note that this is the only time that default values will be used.

If the user has just submitted a form that was previously rendered by JSF, then we have a possible shortcut. During the previous Render Response phase, JSF would have saved this tree either in this user's session or in a hidden field on the response. The actual location being determined by the javax.faces.STATE_SAVING_METHOD context parameter in web.xml. JSF will then either look for the tree in the session using the view id, or will regenerate it from the encrypted hidden field on the response. All components in the tree have values, validators, converters, listeners, and renderers, that were current when the tree was saved during the last Render Response phase. If JSF was unable to retrieve a previously stored tree, it constructs a brand new tree using the view ID on the request.

In either case, the net result is a component tree that will be used to process the incoming request.

A couple of housekeeping tasks remain - FacesContext must be updated to correctly represent the current request. Setters are called on it (a) to set the retrieved/constructed tree; (b) to set the user's locale - either from the saved state, from the default locale (in faces-config) or from a header on the incoming request.

For a postback, JSF will proceed to the next phase. For a fresh request, because there is no user input to process, JSF skips to Render Response to render the tree with default values.

 

Phase 2: Apply Request Values

Goal for this phase:

Allow each UI component to update itself with new information from the incoming request.

Important Concepts required to understand this phase:

         Decoding:
This is the process by which a component sifts through incoming request parameters for information that may affect its state. What a component looks for, and how it updates it's state is defined by that component. For example, input components expect to see updated values; buttons and links expect to see an indication as to whether they were clicked; and forms expect to find an indication that they were submitted.

         Component identifier:
This is the value assigned to the id attribute for a component's tag. A component id must be unique within its naming container.

         Naming container:
A naming container is commonly a form (but can be a subview or a data table), and serves as a namespace for its children components.

         Client identifier:
This is the true unique identifier for a component, and is composed of the naming container's id and the component's id, delimited by colons. Note that for a component that is nested within a naming container hierarchy, e.g., a data table in a form in a subview, the client identifier can get fairly long. It is called a client id because it is usually used to reference a component within Javascript functions. A client id can be either absolute (if it starts with a colon) or relative. It is also used by the UIComponent.findComponent() method to locate a component when it's client identifier is known.

         UI Event:
This is an event that typically redisplays the current page after making some user interface changes to it - such as toggling the display of a section, or adding/removing items from a selection list or radio buttons from a group. You will typically want to short circuit processing to avoid validation errors being displayed for other fields on the form.

         Application Event:
This is an event that invokes backed processing, and is the workhorse of your application. It is handled by the default ActionListener, which calls the specified action method, and then invokes the default NavigationHandler to determine the view to be displayed as the result of this action.

         Action event:
Represents the user clicking a UI control such as a button or hyperlink.

         Immediate action event:
This is a button or link whose immediate attribute is set to true. This forces the button's associated handler to be invoked right after this phase completes, rather than after the Invoke Application phase. A common use is to implement a Cancel button, which should not require the content of other input controls to be validated. Once your handler runs, JSF automatically invokes the navigation handler and transfers control to the Render Response phase.

         Value Change Event:
Represents the user changing the existing value of an input control such as a text box. A value change on the client will only be detected when a new connection with the server is established, e.g., when the user submits a form, or via client side scripting that causes an auto submit.

         Immediate input control:
This is an input control whose immediate attribute is set to true. This forces the input control to be converted and validated within this phase, and, if its value has been changed, causes its ValueChangeEvent to be invoked right after this phase completes, rather than after the Process Validations phase. This is used to implement user interface events, i.e., when the same page must be redisplayed incorporating any changes caused by the event handler, and no other input controls on the form need be validated just yet. A common use is to implement a checkbox that, when clicked, toggles the display of a section in the view. Note that unlike action event handlers, a value change event handler must explicitly call renderResponse() to skip to the Render Response phase - else its usefulness is questionable since validations will otherwise occur in the Process Validations phase.

Important activities in this phase:

JSF allows each component in the current component tree a chance to decode the incoming request. Each component looks for a request parameter with the same name as this component's client identifier. When a matching request parameter is found, an input component sets its submitted value property to the parameter's value; a button/link will queue an action event; and a form will set its submitted property to true.

If an input control's immediate property is set to true, it is converted/validated, and any ValueChangeEvents are invoked at the end of this phase. If an ActionSource's immediate property is true, action events are invoked at the end of this phase.

If an event handler, converter, validator, or decode() method calls responseComplete(), the life cycle is terminated once this phase has been completed; if they call renderResponse(), control skips to the Render Response phase of the life cycle once this phase has been completed. E.g., a conversion/validation error for an immediate component, would re-render the view with an error message.

Phase 3: Process Validations

Goal for this phase:

Allows each UI input component to convert and validate the value it extracted from the incoming request.

Important Concepts required to understand this phase:

         Converter:
Converts the String value in the input component's submitted value attribute into the appropriate data type for this component's value.

         Validator:
Applies validation rules to the converted value for a component.

         FacesMessage:
Represents a message that needs to be displayed to the user. FacesContext maintains a message queue that holds the messages for a given view. A message can either be general, and apply to the whole view; or it can be specific to a given component. Messages are displayed to the user using the <h:messages> or <h:message> actions.

Important activities in this phase:

Conversion:

JSF first looks for an appropriate converter that it should use to convert the String value that the component extracted into the target data type (as defined by the attribute in the managed bean to which this component is bound.) It first checks with the component's renderer; next it looks if any custom Converter implementation has been attached to this class's action via its converter attribute or a nested converter action; and finally it looks whether a converter has been registered for this component's target data type; in this order of precedence. This mechanism is mutually exclusive, i.e., the first converter found is used. If no converter was found at either of these locations, the submitted value is left untouched.

The converter is then requested to convert the String submitted value to the target data type.

If conversion fails, it asks the component to store the invalid string as its value, so that it can be presented back to the user when the page is rerendered; throws a ConverterException with an appropriate FacesMessage which is added to the message queue in FacesContext; and sets the component's valid property to false. JSF then skips to Render Response to notify the user of input errors.

If conversion succeeds, the converted value is marked as the component's converted value.

It is important to note that converters actually do double duty; they convert Strings to the target data types (as is the case in this phase), and they convert the target data type to a String (which is required during Render Response to write out the HTML response.)

Validation:

If conversion succeeded for all the components in the current tree, JSF asks each UIInput to validate this converted value.

Unlike the search for a converter, the search for a validator is cumulative. I.e., validation is delegated to all validators that are attached to this component, and all must agree before the component is marked as being valid. Validators can be attached to a component via multiple mechanisms. E.g., a component's required attribute causes an implicit validator to be attached; its validator attribute takes a binding that points to a validator method; and validators can be attached using nested f:validate actions.

If any of the validators in that stack detects a problem with the component's converted value, it will throw a ValidatorException with an appropriate FacesMessage, which is then added to the FacesContext message queue, and the component is marked as invalid by setting its valid property to false. JSF then skips to Render Response to notify the user of the validation error.

If the validation process succeeds, the converted value is marked as the component's local value. If the local value has changed, the component also generates a ValueChangeEvent.

If any event handler or validate() method calls responseComplete(), processing of the current request is terminated after this phase is completed; and if it calls renderResponse(), JSF skips to Render Response once this phase is completed.

Phase 4: Update Model Values

Goal for this phase:

Allows each UI component to transfer its updated local value into the managed bean attribute to which it is bound.

Important Concepts required to understand this phase:

         Value binding: Unified Expression Language syntax can be used to define the bean attribute to which a particular component is bound. Note that the expression may be several levels deep, if referencing a property of a property of a bean, etc.

Important activities in this phase:

Beans are connected to components via JSF EL expressions. These expressions are usually value binding expressions that indicate a managed bean in one of the servlet scopes, and a setter that references the desired property to which the value should be transferred.

If update fails, a message is queued via FacesContext.addMessage(), and the component is marked as invalid. FacesServlet then skips to Render Response to notify the user of input errors.

Phase 5: Invoke Application

Goal for this phase:

Performs custom application specific processing and determines the next view to be displayed to the user. This is the heart of your application logic.

Important Concepts required to understand this phase:

         Action Listener:
A command component (a button or a link) can be associated with handlers via (in order of preference) its action attribute, its actionListener attribute, or via nested actionListener actions. All of these action listeners will be invoked when this component is clicked. The action attribute binding is special in that it is handled by the JSF default ActionListener which also invokes the default NavigationHandler to navigate to the next view. The actionListener binding is special since it lets you access the component that fired the event. The nested actionListener actions are special because they let you bind multiple action listeners to a particular component.

Important activities in this phase:

Now that the backing beans and model objects are up-to-date, JSF broadcasts the queued ActionEvents by invoking the registered action listeners for each component. This is a safe point at which to invoke these listeners because the other components in the tree have picked up and validated their values. Note that listeners for immediate action events are notified earlier in the cycle because they are designed to handle events that will skip the validation phase, such as a Cancel button.

For an action method binding, after the action listeners are invoked; the default action listener invokes the NavigationHandler to choose the next page. If no action method is registered, the default action listener simply redisplays the current view.

 

Phase 6: Render Response

Goal for this phase:

The component tree is now rendered as HTML.

Important Concepts required to understand this phase:

         Encoding: This is the process of asking each component to write out its value into the response. The component may delegate this task to its associated renderer, and may also invoke an associated converter to convert its native data type out to a String that will be sent to the user's browser.

         State saving: This is the process of dehydrating the component tree so that it can be hydrated back into existence later.

Important activities in this phase:

At this point, we are done with all application specific processing, and all that remains is to serialize the component tree out as HTML that will be sent back to the client - and this task is handled by a javax.faces.lifecycle.ViewHandler. All JSF implementations must ship with a default ViewHandler that can encode JSPs. However, you can swap this out for a custom implementation (such as the one that ships with Facelets that can encode XHTML files.)

The component tree's current state (incl. the tree's structure) is then saved either in the request itself or on the server (session scope). You pick the location via the javax.faces.STATE_SAVING_METHOD context parameter in web.xml, which can be set to either client or server.

With client side state saving, the view's state is actually serialized out as an encoded hidden form field within the response payload. The client then returns it with its next request.

With server side state saving, the view's state is saved in the user's session on the server.

As expected, the trade off here is between memory consumption on the server and response times/bandwidth over a network connection. You should begin using server side saving, and then switch to client side only if you run into issues with memory usage.

 

Conclusion

The JSF lifecycle is not trivial. JSF does give you a lot to choose from, and that choice can be scary. However, this complexity is mitigated by the fact that (a) it automatically handles a lot of tedious stuff for you; (b) the default implementations of the ViewHandler, ActionListener, NavigationListener, Renderers etc. are adequate for most purposes so you rarely have to write custom ones; and (c) you can happily ignore a lot of the edge-case functionality, such as action listener classes and value change events, for most run-of-the-mill applications.