1) Introduction

This article will explain the sequence of activities that will take place while processing the Request in a typical Web Application. The various phases like the Restore View Phase, Apply Request Values Phase, Process Validations Phase, Update Model Values Phase, Invoke Application Phase and Render Response Phase are covered briefly. First-time readers of JSF are requested to read the introductory article Introduction to Java Server Faces in JavaBeat.

2) Life-cycle Phases

As soon as a JSF Application in initiated by calling the Faces Servlet (which is configured in the web.xmlfile), series of activities will take place. These activities come under the category of JSF Request Processing Life-cycle Phases. The phases are,

  • Restore View
  • Apply Request Values
  • Process Validations
  • Update Model Values
  • Invoke Application
  • Render Response

 

The above Life-cycle Phases are not sequential. For example, the control may be re-directed to Render Response Phase from Process Validation phase in case of any Conversion or Validation Errors.

3) Restore View

A JSF View or Simple View is nothing but a collection of UI Components. For example, consider the following login form,

<f:view>
<h:form>

<p>Enter your username:
<h:inputText
value="#{LoginBean.username}"
id="usernameTextField"
required="true"/>
<h:message for="usernameTextField"/>
</p>

<p>Enter your password:
<h:inputSecret
value="#{LoginBean.password}"
id="passwordTextField"
required="true"/>
<h:message for="passwordTextField"/>
</p>

<h:commandButton value="Submit Values" action="loginWelcome"/>

</h:form>
</f:view>

The above form has a root UI Component called 'view'. It is having three child components namely a text-field (with identifier 'usernameTextField'), a password-field (with identifier 'passwordTextField') and a command button with name 'Submit Values'. So, this whole set-up represents a view. It is also possible to have any number of sub-views as represented by a 'sub-view' tag in a single form. The state of the view can either be stored in the Server or in the Client Browser. If it is stored in Server, then it might be cached in the HttpSession object, else it may be represented as hidden text-fields in the client end. The strategy whether the view state is stored in Server or Client is determined by the property called 'javax.faces.STATE_SAVING_METHOD'.

The default value for this property is 'server' which means that the view state is restored in the Server. The other permitted value is 'client'. This property is specified in the Configuration file (web.xml) as follows,

<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>

Now, let us see the activities happening in this phase. If the request is made to a URL for the first time, then a new View object is created and rendered to the Client. Else (because the view state is already found in the cache), the view is restored and displayed. In our example case, we saw three child components. Any Custom Convertors, Validators, Renderers, if attached for the UI components, will be restored in this phase.

In case, if the UI Component values are directly mapped to the property defined in a Managed Bean, then the value for the property is restored and it is associated with the View. Most of the works are handled by the ViewHandler class through its method restoreView().

4) Apply Request Values

In this phase, the values that are entered by the user will be updated on each and every individual component defined in the View graph. More specifically, the processDecodes() on the UIComponentBase method will be called for all components. Here, the process of applying the Request values to the UI Components is called Decoding. For example, in the above sample login form that we have taken, the user input values will be applied on the components (text-field and password). The outcome of this phase may either end in Process Validations Phase or the Render Response Phase.

If the child components include Action components (such as command button or a hyper-link), and the immediate property is set to true, then any Action Events associated with it will be queued by calling the UIComponentBase.queueEvent(FacesEvent) method. Since the immediate property is set to true, the Action Event will be immediately fired at then end of this Phase. On the other hand, if the immediate property is set to false, then the Action Events are queued and fired only at the end of Invoke Application phase, and for editable components (more specifically, components that implement the EditableValueHolder interface), all the conversions and the validations will take place if the property 'immediate' is set to 'true'.

If any of the Conversions or the Validations fail, then the current processing is terminated and the control directly goes to the Render Response for rendering the conversion or the validation errors to the Client.

5) Process Validations

This Phase will process any Validations that are configured for UI Components. For example, consider the following code snippet,

<p>Enter your phone-number 
<h:inputText
value="#{UserBean.phoneNumber}"
id="phoneNumberTextField"
required="true">

<f:validator validatorId="PhoneNumberValidator"/>

</h:inputText>
<h:message for="phoneNumberTextField"/>
</p>

The above code defines a Custom Validator called PhoneNumber Validator which will validate the given string against some standard format. It is possible to define and attach any number of Validators to a Component. In this phase, JSF Implementation will traverse over the UIViewRoot to fetch all the child components and ask the child components to validate themselves by calling the method UIComponentBase.processValidators().

So, the child components will get a list of Validators that are defined for them and then invoke the Validation logic defined on them. These validations will only happen for the UI Components only if the property 'rendered' property is set to 'true'. If the property is set to false, then Validations would not take place. It is important to understand that even before Validations occur on UI Components, conversions will happen. For example, consider the following code snippet,

<p>Enter your birthday: 

<h:inputText
value="#{UserBean.birthday}"
id="birthdayTextField"
required="true">
<f:convertDateTime pattern="MMM-dd-yyyy"/>
</h:inputText> (MMM-dd-yyyy)

<h:message for="birthdayTextField"/>

</p>

The above code attaches a Date Time Converter to the component 'birthdayTextField'. So, the user entered request value is made to get converted to the pattern 'MMM-dd-yyyy'. If any Conversion error happens here, then the current Process Validations Phase is terminated and the control is directed to the 'Render Response' Phase for reporting any errors.

6) Updating Model Values

If the Application has reached this phase, then it is obvious that the user entered request values are syntactically valid. The values that are stored in UI Components will be made to synchronize with the Model objects, which are usually Backing Beans. For example, consider the following code snippet,

<p>Enter your username: 
<h:inputText
value="#{LoginBean.username}"
id="usernameTextField"
required="true"/>
<h:message for="usernameTextField"/>
</p>

<p>Enter your password:
<h:inputSecret
value="#{LoginBean.password}"
id="passwordTextField"
required="true"/>
<h:message for="passwordTextField"/>
</p>

In the above code snippet, we have defined two UI Components namely a text-field and a password field. The corresponding model object for this form is the LoginBean class. Since the LoginBean is treated as a Backing Bean (else, it can't be used in Method Expressions), the Application should have defined this in the Faces Configuration file as follows,

<managed-bean>
<managed-bean-name>UserBean</managed-bean-name>
<managed-bean-class>user.registration.UserBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

In this phase, the processUpdates() method in the UIComponentBase will be called, which in turn will call all the processUpdates() method that are defined in the child components. Setting the request value to the Model object may also result in Events to get queued and fired.

7) Invoke Application

In this phase, all the Listeners that are registered for the UI Components will get invoked and the Listeners will usually contain the Application specific logic. Note that for all Action Components (like the Command Button or the Hyper-link), there always exists Default Action Listeners which when invoked will display the current page. Consider the code snippet which defines an Action Listener for the Button click,

<h:commandButton value="Submit Values" action="#{ActionListener.doSomeAction}"/>

In this phase, JSF Implementation will call the method UIComponentBase.processApplications() method which can immediately call the Render Response Phase.

8) Render Response

And finally, we have reached the Render Response whose job is to render the response back the Client Application. Before rendering the response, the state of View is stored in the cache by calling the method UIViewRoot.saveState() method.

9) Conclusion

This article provided an overview about the various phases that are involved in JSF Request Processing. It should be noted that, not at all times, phases will occur in a sequential manner. A phase encountering Errors (like Conversion or Validation Errors) or Events may redirect the control to the final phase without passing through any of the intermediatary phases.

posted on 2011-11-02 21:32  七月逆流  阅读(283)  评论(0编辑  收藏  举报