5 Using the JSF Lifecycle with ADF Faces

This chapter describes the JSF page request lifecycle and the additions to the lifecycle from ADF Faces, and how to use the lifecycle properly in your application.

This chapter includes the following sections:

About Using the JSF Lifecycle and ADF Faces

The lifecycle of a JavaServer Faces application begins when the client makes an HTTP request for a page and ends when the server responds with the page, translated to HTML. You can learn about the different phases of JSF lifecycle and ADF Faces lifecycle on a page request and how the events are processed before and after each phase.

ADF Faces applications use both the JSF lifecycle and the ADF Faces lifecycle. The ADF Faces lifecycle extends the JSF lifecycle, providing additional functionality, such as a client-side value lifecycle, a subform component that allows you to create independent submittable sections on a page without the drawbacks (for example, lost user edits) of using multiple forms on a single page, and additional scopes.

To better understand the lifecycle enhancements that the framework delivers, it is important that you understand the standard JSF lifecycle. This section provides only an overview. For a more detailed explanation, refer to the JSF specification at http://www.jcp.org/en/jsr/detail?id=314.

When a JSF page is submitted and a new page is requested, the JSF page request lifecycle is invoked. This lifecycle handles the submission of values on the page, validation for components on the current page, navigation to and display of the components on the resulting page, as well as saving and restoring state. The FacesServlet object manages the page request lifecycle in JSF applications. The FacesServlet object creates an object called FacesContext, which contains the information necessary for request processing, and invokes an object that executes the lifecycle.

The JSF lifecycle phases use a UI component tree to manage the display of the faces components. This tree is a runtime representation of a JSF page: each UI component tag in a page corresponds to a UI component instance in the tree.

Figure 5-1 shows the JSF lifecycle of a page request. As shown, events are processed before and after each phase.

Figure 5-1 Lifecycle of a Page Request in an ADF Faces Application

Description of Figure 5-1 follows
Description of "Figure 5-1 Lifecycle of a Page Request in an ADF Faces Application"

In a JSF application, the page request lifecycle is as follows:

  • Restore View: The component tree is established. If this is not the initial rendering (that is, if the page was submitted back to server), the tree is restored with the appropriate state. If this is the initial rendering, the component tree is created and the lifecycle jumps to the Render Response phase.

  • Apply Request Values: Each component in the tree extracts new values from the request parameters (using its decode method) and stores the values locally. Most associated events are queued for later processing. If a component has its immediate attribute set to true, then the validation, the conversion, and the events associated with the component are processed during this phase. See Using the Immediate Attribute.

  • Process Validations: Local values of components are converted from the input type to the underlying data type. If the converter fails, this phase continues to completion (all remaining converters, validators, and required checks are run), but at completion, the lifecycle jumps to the Render Response phase.

    If there are no failures, the required attribute on the component is checked. If the value is true, and the associated field contains a value, then any associated validators are run. If the value is true and there is no field value, this phase completes (all remaining validators are executed), but the lifecycle jumps to the Render Response phase. If the value is false, the phase completes, unless no value is entered, in which case no validation is run. For information about conversion and validation, see Validating and Converting Input.

    At the end of this phase, converted versions of the local values are set, any validation or conversion error messages and events are queued on the FacesContext object, and any value change events are delivered.

    Tip:

    In short, for an input component that can be edited, the steps for the Process Validations phase is as follows:

    1. If a converter fails, the required check and validators are not run.

    2. If the converter succeeds but the required check fails, the validators are not run.

    3. If the converter and required check succeed, all validators are run. Even if one validator fails, the rest of the validators are run. This is because when the user fixes the error, you want to give them as much feedback as possible about what is wrong with the data entered.

      For example suppose you have a dateTimeRange validator that accepted dates only in the year 2015 and you had a dateRestrictionValidator validator that did not allow the user to pick Sundays. If the user entered November 16, 2014 (a Sunday), you want to give the feedback that this fails both validators to maximize the chance the user will enter valid data.

  • Update Model Values: The component's validated local values are moved to the model, and the local copies are discarded.

  • Invoke Application: Application-level logic (such as event handlers) is executed.

  • Render Response: The components in the tree are rendered. State information is saved for subsequent requests and for the Restore View phase.

To help illustrate the lifecycle, consider a page that has a simple input text component where a user can enter a date and then click a button to submit the entered value. A valueChangeListener method is also registered on the component. The following shows the code for the example.

<af:form>
  <af:inputText value="#{mybean.date}"
      valueChangeListener="#{mybean.valueChangeListener}">
    <af:convertDateTime dateStyle="long"/>
  </af:inputText>
  <af:button text="Save"  actionListener="#{mybean.actionListener}"/>
</af:form>

Suppose a user enters the string "June 25, 2015" and clicks the submit button. Figure 5-2 shows how the values pass through the lifecycle and where the different events are processed.

Figure 5-2 Example of Values and Events in the JSF Lifecycle

Description of Figure 5-2 follows
Description of "Figure 5-2 Example of Values and Events in the JSF Lifecycle"

Using the Immediate Attribute

In ADF Faces lifecycle or in JSF lifecycle, when a component's immediate attribute is set to true, the validation, conversion, and events associated with these components are processed during the Apply Request Values phase rather than in a later phase. Use this attribute to navigate to another page without processing any data currently in the input fields of the current screen.

You can use the immediate attribute to allow processing of components to move up to the Apply Request Values phase of the lifecycle. When actionSource components (such as a commandButton) are set to immediate, events are delivered in the Apply Request Values phase instead of in the Invoke Application phase. The actionListener handler then calls the Render Response phase, and the validation and model update phases are skipped.

For example, you might want to configure a Cancel button to be immediate, and have the action return a string used to navigate back to the previous page (for information about navigation, see Working with Navigation Components). Because the Cancel button is set to immediate, when the user clicks the Cancel button, all validation is skipped, any entered data is not updated to the model, and the user navigates as expected, as shown in Figure 5-3.

Figure 5-3 Lifecycle for Button Set to Immediate

Description of Figure 5-3 follows
Description of "Figure 5-3 Lifecycle for Button Set to Immediate"

Note:

A button that does not provide any navigation and is set to immediate will also go directly to the Render Response phase: the Validation, Update Model, and Invoke Application phases are skipped, so any new values will not be pushed to the server.

As with command components, for components that invoke disclosure events, (such as a showDetail component), and for editableValueHolder components (components that hold values that can change, such as an inputText component), when set to immediate, the events are delivered to the Apply Request Values phase. However, for editableValueHolder components, instead of skipping phases, conversion, validation, and delivery of valueChangeEvents events for the immediate components are done earlier in the lifecycle, during the Apply Request Values phase, instead of after the Process Validations phase. No lifecycle phases are skipped.

Figure 5-4 shows the lifecycle for an input component whose immediate attribute is set to true. The input component takes a date entered as a string and stores it as a date object when the command button is clicked.

Figure 5-4 Immediate Attribute on an Input Component

Description of Figure 5-4 follows
Description of "Figure 5-4 Immediate Attribute on an Input Component"

Setting immediate to true for an input component can be useful when one or more input components must be validated before other components. Then, if one of those components is found to have invalid data, validation is skipped for the other input components in the same page, thereby reducing the number of error messages shown for the page.

For example, suppose you have a form used to collect name and address information and you have the Name field set to required. The address fields need to change, based on the country chosen in the Country dropdown field. You would set that dropdown field (displayed using a selectOneChoice component) to immediate so that when the user selects a country, a validation error doesn’t occur because the name field is blank. The following example shows the code for the address field (the switching functionality between countries is not shown)

<af:form id="f1">
  <af:panelFormLayout id="pfl1">
    <af:panelGroupLayout id="pgl2" layout="vertical">
      <af:inputText label="Name" id="it1" value="#{bean.name}"
                    required="true"/>
      <af:inputText label="Street" id="it2" value="#{bean.street}"/>
      <af:panelGroupLayout id="pgl1" layout="horizontal">
        <af:inputText label="City" id="it3" value="#{bean.city}"/>
        <af:inputText label="State" id="it4" value="#{bean.state}"/>
        <af:inputText label="Zip" id="it5" value="#{bean.zip}"/>
       </af:panelGroupLayout>
       <af:selectOneChoice label="Country" id="soc1" immediate="true">
                           valueChangeListener="bean.countryChanged">
         <af:selectItem label="US" value="US" id="si1"/>
         <af:selectItem label="Canada" value="Canada" id="si2"/>
       </af:selectOneChoice>
     </af:panelGroupLayout>
    </af:panelFormLayout>
</af:form>

In this example, the selectOneChoice value change event is fired after the Apply Request Values phase, and so the countryChanged listener method is run before the Name inputText component is validated. However, remember that for editable components, phases are not skipped - validation will still be run during this request. To prevent validation of the other components, you need to call the renderResponse method directly from your listener method. This call skips the rest of the lifecycle, including validation and jumps directly to the Render Response phase.

public void countryChanged(ValueChangeEvent event)
  FacesContext context = Facescontext.getcurrentInstance();
. . .
  some code to change the locale of the form
. . .
context.renderresponse();

Note:

Be careful when calling RenderResponse(). Any component that goes through a partial lifecycle will have an incomplete state that may cause trouble. The values on those components are decoded but not validated and pushed to model, so you need to clear their submitted value when calling RenderResponse().

Note:

Only use the immediate attribute when the desired functionality is to leave the page and not ever submit any values other than the immediate components. In the Cancel example, no values will ever be submitted on the page. In the address example, we want the page to be rerendered without ever submitting any other values.

The immediate attribute causes the components to be decoded (and thus have a submitted value), but not processed further. In the case of an immediate action component, the other components never reach the validation or update model phases, where the submitted value would be converted to a local value and then the local value pushed into the model and cleared. So values will not be available.

Don’t use the immediate attribute when you want a number of fields to be processed before other fields. When that is the case, it’s best to divide your page up into separate sub-forms, so that only the fields in the sub-forms are processed when the lifecycle runs.

There are some cases where setting the immediate attribute to true can lead to better performance: When you create a navigation train, and have a commandNavigationItem component in a navigationPane component, you should set the immediate attribute to true to avoid processing the data from the current page (train stop) while navigating to the next page. For more information, see SeeHow to Create the Train Model. If an input component value has to be validated before any other values, the immediate attribute should be set to true. Any errors will be detected earlier in the lifecycle and additional processing will be avoided.

How to Use the Immediate Attribute

Before you begin:

It may be helpful to have an understanding of the immediate attribute. See Using the Immediate Attribute.

To use the immediate attribute:

  1. On the JSF page, select the component that you want to be immediate.
  2. In the Properties window, expand the Behavior section and set the immediate attribute to true.

Using the Optimized Lifecycle

In ADF Faces, Partial Page Rendering (PPR) optimizes the JSF lifecycle. Use the event root components to determine boundaries on the page and to allow the lifecycle to run just on components within that boundary.

ADF Faces provides an optimized lifecycle that runs the JSF page request lifecycle (including conversion and validation) only for certain components within a boundary on a page. This partial page lifecycle is called partial page rendering (PPR). Certain ADF Faces components are considered event root components, and are what determine the boundaries on which the optimized lifecycle is run. There are two ways event root components are determined. First, certain components are always considered event roots. For example, the panelCollection component is an event root component. It surrounds a table and provides among other things, a toolbar. Action events triggered by a button on the toolbar will cause the lifecycle to be run only on the child components of the panelCollection.

The second way event root components are determined is that certain events designate an event root. For example, the disclosure event sent when expanding or collapsing a showDetail component (see Displaying and Hiding Contents Dynamically) indicates that the showDetail component is a root, and so the lifecycle is run only on the showDetail component and any child components. For information about PPR and event roots, including a list of event root components, see Events and Partial Page Rendering.

Aside from running on the event root component and its child components, you can declaratively configure other components outside the event root hierarchy to participate in the optimized lifecycle. You can also specifically configure only certain events for a component to trigger the optimized lifecycle, and configure which components will actually execute or will only be refreshed.

For information about how the ADF Faces framework uses PPR, and how you can use PPR throughout your application, see Rerendering Partial Page Content.

Using the Client-Side Lifecycle

The ADF Faces framework provides client-side conversion and validation. You can create your own JavaScript-based converters and validators that run on the page without a trip to the server.

You can use client-side validation so that when a specific client event is queued, it triggers client validation of the appropriate form or subform (for information about subforms, see Using Subforms to Create Sections on a Page). If this client validation fails, meaning there are known errors, then the events that typically propagate to the server (for example, a button's actionEvent when a form is submitted) do not go to the server. Having the event not delivered also means that nothing is submitted and therefore, none of the client listeners are called. This is similar to server-side validation in that when validation fails on the server, the lifecycle jumps to the Render Response phase; the action event, though queued, will never be delivered; and the actionListener handler method will never be called.

For example, ADF Faces provides the required attribute for input components, and this validation runs on the client. When you set this attribute to true, the framework will show an error on the page if the value of the component is null, without requiring a trip to the server. The following example shows code that has an inputText component's required attribute set to true, and a button whose actionListener attribute is bound to a method on a managed bean.

<af:form>
  <af:inputText id="input1" required="true" value="a"/>
  <af:button text="Search" actionListener="#{demoForm.search}"/>
</af:form>

When this page is run, if you clear the field of the value of the inputText component and tab out of the field, the field will redisplay with a red outline. If you then click into the field, an error message will state that a value is required, as shown in Figure 5-5. There will be no trip to the server; this error detection and message generation is all done on the client.

Figure 5-5 Client-Side Validation Displays an Error Without a Trip to the Server

This image is described in the surrounding text

In this same example, if you were to clear the field of the value and click the Search button, the page would not be submitted because the required field is empty and therefore an error occurs; the action event would not be delivered, and the method bound to the action listener would not be executed. This process is what you want, because there is no reason to submit the page if the client can tell that validation will fail on the server.

For information about using client-side validation and conversion, see Validating and Converting Input.

Using Subforms to Create Sections on a Page

ADF Faces provides the subform component, which adds flexibility by defining subregions whose component values can be submitted separately within a form. The content of a subform can be validated based on certain criteria.

In the JSF reference implementation, if you want to independently submit a section of the page, you have to use multiple forms. However multiple forms require multiple copies of page state, which can result in the loss of user edits in forms that aren't submitted.

ADF Faces adds support for a subform component, which represents an independently submittable section of a page. The contents of a subform will be validated (or otherwise processed) only if a component inside of the subform is responsible for submitting the page, allowing for comparatively fine-grained control of the set of components that will be validated and pushed into the model without the compromises of using entirely separate form elements. When a page using subforms is submitted, the page state is written only once, and all user edits are preserved.

Best Practice:

Always use only a single form tag per page. Use the subform tag where you might otherwise be tempted to use multiple form tags.

A subform will always allow the Apply Request Values phase to execute for its child components, even when the page was submitted by a component outside of the subform. However, the Process Validations and Update Model Values phases will be skipped (this differs from an ordinary form component, which, when not submitted, cannot run the Apply Request Values phase). To allow components in subforms to be processed through the Process Validations and Update Model Value phases when a component outside the subform causes a submit action, use the default attribute. When a subform's default attribute is set to true, it acts like any other subform in most respects, but if no subform on the page has an appropriate event come from its child components, then any subform with default set to true will behave as if one of its child components caused the submit. For information about subforms, see Defining Forms.

Object Scope Lifecycles

When an object is created in a JSF application, it defines or defaults to a given scope; this object scope describes how widely it is available and who has access to it. You can use the standard JSF scopes or the ADF Faces scopes that are available for an object in a JSF application.

At runtime, you pass data to pages by storing the needed data in an object scope where the page can access it. The scope determines the lifespan of an object. Once you place an object in a scope, it can be accessed from the scope using an EL expression. For example, you might create a managed bean named foo, and define the bean to live in the Request scope. To access that bean, you would use the expression #{requestScope.foo}.

There are five types of scopes in a standard JSF application:

  • applicationScope: The object is available for the duration of the application.

  • sessionScope: The object is available for the duration of the session.

  • viewScope: The object is available until the user finishes interaction with the current view. The object is stored in a map on the UIViewRoot object. Note that this object is emptied upon page refresh or a redirect to the view.

    Tip:

    If you need the object to survive a page refresh or redirect to the same view, then use the ADF Faces version of viewScope.

  • flashScope: The object is available during a single view transition, and is cleaned up before moving on to the next view. You can place a parameter value in flashScope and it will be available to the resulting page, surviving redirects.

  • requestScope: The object is available for the duration between the time an HTTP request is sent until a response is sent back to the client.

In addition to the standard JSF scopes, ADF Faces provides the following scopes:

  • pageFlowScope: The object is available as long as the user continues navigating from one page to another. If the user opens a new browser window and begins navigating, that series of windows will have its own pageFlowScope scope.

  • backingBeanScope: Used for managed beans for page fragments and declarative components only. The object is available for the duration between the time an HTTP request is sent until a response is sent back to the client. This scope is needed because there may be more than one page fragment or declarative component on a page, and to avoid collisions between values, any values must be kept in separate scope instances. Use backingBeanScope scope for any managed bean created for a page fragment or declarative component.

  • viewScope: The object is available until the ID for the current view changes. Use viewScope scope to hold values for a given page. Unlike the JSF viewScope, objects stored in the ADF Faces viewScope will survive page refreshes and redirects to the same view ID.

Note:

Because these are not standard JSF scopes, EL expressions must explicitly include the scope to reference the bean. For example, to reference the MyBean managed bean from the pageFlowScope scope, your expression would be #{pageFlowScope.MyBean}.

Object scopes are analogous to global and local variable scopes in programming languages. The wider the scope, the higher the availability of an object. During their lifespan, these objects may expose certain interfaces, hold information, or pass variables and parameters to other objects. For example, a managed bean defined in sessionScope scope will be available for use during multiple page requests. However, a managed bean defined in requestScope scope will be available only for the duration of one page request.

Figure 5-6 shows the time period in which each type of scope is valid, and its relationship with the page flow.

Figure 5-6 Relationship Between Scopes and Page Flow

Description of Figure 5-6 follows
Description of "Figure 5-6 Relationship Between Scopes and Page Flow"

When determining what scope to register a managed bean with or to store a value in, always try to use the narrowest scope possible. Use the sessionScope scope only for information that is relevant to the whole session, such as user or context information. Avoid using the sessionScope scope to pass values from one page to another.

Note:

If you are using the full Fusion technology stack, then you have the option to register your managed beans in various configuration files. See Using a Managed Bean in a Fusion Web Application in Developing Fusion Web Applications with Oracle Application Development Framework.

Passing Values Between Pages

Oracle ADF provides the pageFlowScope bean scope that supports storing temporary values created at runtime. You can use different procedures to access pageFlowScope from within any Java code in your application or use pageFlowScope without writing any Java code.

The ADF Faces pageFlowScope scope makes it easier to pass values from one page to another, thus enabling you to develop master-detail pages more easily. Values added to the pageFlowScope scope automatically continue to be available as the user navigates from one page to another, even if you use a redirect directive. But unlike session scope, these values are visible only in the current page flow or process. If the user opens a new window and starts navigating, that series of windows will have its own process. Values stored in each window remain independent.

Note:

If you are using the full Fusion technology stack and you need information about passing values between pages in an ADF bounded task flow, or between ADF regions and pages, refer to Getting Started with ADF Task Flows in Developing Fusion Web Applications with Oracle Application Development Framework.

Like objects stored in any standard JSF scope, objects stored in the pageFlow scope can be accessed through EL expressions. The only difference with the pageFlow scope is that the object names must use the pageFlowScope prefix. For example, to have a button's label provided by a managed bean stored in the pageFlow scope, and to have a method on the bean called when the button is selected, you might use the following code on your page:

<af:button text="#{pageFlowScope.buttonBean.label}"
                  action="#{pageFlowScope.buttonBean.action}"/>

The pageFlowScope is a java.util.Map object that may be accessed from Java code. The setPropertyListener tag allows you to set property values onto a scope, and also allows you to define the event the tag should listen for. For example, when you use the setPropertyListener tag with the type attribute set to action, it provides a declarative way to cause an action source (for example, button) to set a value before navigation. You can use the pageFlowScope scope with the setPropertyListener tag to pass values from one page to another, without writing any Java code in a backing bean. For example, you might have one page that uses the setPropertyListener tag and a command component to set a value in the pageFlowScope scope, and another page whose text components use the pageFlowScope scope to retrieve their values.

You can also use the pageFlowScope scope to set values between secondary windows such as dialogs. When you launch secondary windows from, for example, a button component, you can use a launchEvent event and the pageFlowScope scope to pass values into and out of the secondary windows without overriding values in the parent process.

How to Use the pageFlowScope Scope Within Java Code

You can access pageFlow scope from within any Java code in your application. Remember to clear the scope once you are finished.

Note:

If your application uses ADF Controller, then you do not have to manually clear the scope.

Before you begin:

It may be helpful to have an understanding of object scopes. For information, see Object Scope Lifecycles. You may also want to understand how pageFlow scope is used to pass values. For information, see Passing Values Between Pages.

To use pageFlowScope in Java code:

  1. To get a reference to the pageFlowScope scope, use the org.apache.myfaces.trinidad.context.RequestContext. getPageFlowScope() method.

    For example, to retrieve an object from the pageFlowScope scope, you might use the following Java code:

    import java.util.Map;
    import org.apache.myfaces.trinidad.context.RequestContext;
    . . .
    Map pageFlowScope = RequestContext.getCurrentInstance().getPageFlowScope();
    Object myObject = pageFlowScope.get("myObjectName");
    
  2. To clear the pageFlowScope scope, access it and then manually clear it.

    For example, you might use the following Java code to clear the scope:

    RequestContext afContext = RequestContext.getCurrentInstance();
    afContext.getPageFlowScope().clear();
    

How to Use the pageFlowScope Scope Without Writing Java Code

To use the pageFlowScope scope without writing Java code, use a setPropertyListener tag in conjunction with a command component to set a value in the scope. The setPropertyListener tag uses the type attribute that defines the event type it should listen for. It ignores all events that do not match its type. Once set, you then can access that value from another page within the page flow.

Tip:

Instead of using the setActionListener tag (which may have been used in previous versions of ADF Faces), use the setPropertyListener tag and set the event type to action.

To set a value in the pageFlowScope scope:

  1. On the page from where you want to set the value, create a command component using the Components window. For information about creating command components, see Using Buttons and Links for Navigation.
  2. In the Components window, from the Listeners group of the Operations panel, drag a Set Property Listener and drop it as a child to the command component.

    Or right-click the component and choose Insert inside Button > ADF Faces > setPropertyListener.

  3. In the Insert Set Property Listener dialog, set the From field to the value that will be set on another component.

    For example, say you have a managed bean named MyBean that stores the name value for an employee, and you want to pass that value to the next page. You would enter #{myBean.empName} in the From field.

  4. Set the To field to be a value on the pageFlowScope scope.

    For example, you might enter #{pageFlowScope.empName} in the To field.

  5. From the Type dropdown menu, choose Action.

    This allows the listener to listen for the action event associated with the command component.

  6. On the page from which you want to access the value, drop the component that you want to display the value.
  7. Set the value of the component to be the same value as the To value set on the setPropertyListener tag.

    For example, to have an outputText component access the employee name, you would set the value of that component to be #{pageFlowScope.empName}.

What Happens at Runtime: How Values Are Passed

When a user clicks a button that contains a setPropertyListener tag, the listener executes and the To value is resolved and retrieved, and then stored as a property on the pageFlowScope scope. On any subsequent pages that access that property through an EL expression, the expression is resolved to the value set by the original page.