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:

5.1 About Using the JSF Lifecycle and ADF Faces

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

The ADF and JSF phases work together

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. For more information, see Section 5.2, "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 more information about conversion and validation, see Chapter 7, "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. Example 5-1 shows the code for the example.

Example 5-1 Sample Code to Illustrate the JSF Lifecycle

<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

Example of a page going through the lifecycle

5.2 Using the Immediate Attribute

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 button) 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.

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 more information about navigation, see Chapter 20, "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

Lifecycle skips validation and model update

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.

You can also set components that invoke disclosure events (such as a showDetail component), and components that are editableValueHolder components (components that hold values that can change, such as an inputText component), to immediate. As with actionSource components, the events are then delivered to the Apply Request Values phase. However, for editableValueHolder components, instead of skipping phases, conversion, validation, and delivery of valueChangeEvents events 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 button is clicked.

Figure 5-4 Immediate Attribute on an Input Component

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.

Performance Tip:

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 Section 20.9.1, "How 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.

As another example, suppose you have a form with an input component used to search for a string, with a button configured to invoke the search execution, and another input text component used to enter a date, with an associated button used to submit the date. In this example, you want to set the search input component and its button both to be immediate. This will allow the user to execute a search, even if an invalid string is entered into the date field, because the date input component's converter is never fired. Also, because the search input text is set to immediate and the date input field is not, only the search input text will be processed. And because both fields are within the same form, if the user enters a valid date in the date field, but then performs a search and does not click the Save button, the entered value will still be displayed when the search results are displayed. Example 5-2 shows the code used for the two fields and two buttons.

Example 5-2 Input Component and Command Components Using Immediate

<af:form>
  <af:inputText immediate="true" label="Search"  value="#{mybean.search}"
                valueChangeListener="#{mybean.searchValueChangeListener}"/>
  <af:button immediate="true" text="search"
                    actionListener="#{mybean.searchActionListener}"/>
  [.... tags to render search result ....]
 
  <af:inputText label="Date" value="#{mybean.date}"
                valueChangeListener="#{mybean.valueChangeListener}">
    <af:convertDateTime dateStyle="long"/>
  </af:inputText>
  <af:button text="save"  actionListener="#{mybean.actionListener}"/>
</af:form>

Figure 5-5 shows the lifecycle for this page when a user does the following:

  • Enters apple into the Date input field (which is not a valid entry)

  • Enters orange into the Search field

  • Clicks the Search button to execute the search on orange

  • Clicks the Save button to save the value apple as the date

Figure 5-5 Immediate Attribute on Both Command Component and Input Component

Using immediate on both input and command

When using the immediate attribute for editableValueHolder and actionSource components on the same page, note the following issues:

  • If an actionSource component requires data from an editableValueHolder component, that data will not be available to the model until after the Update Model Values phase. If you have an immediate actionSource component, and that component needs data, then set immediate on the editableValueHolder fields as well. Then, you can call the getValue method on the editableValueHolder component and the local value will be returned. It will not have been pushed into the model yet, but it will be available on the component.

  • If an immediate editableValueHolder component fails validation, any immediate actionSource component will still execute.

5.2.1 How to Use the Immediate Attribute

Before you begin

It may be helpful to have an understanding of the immediate attribute. For more information, see Section 5.2, "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.

5.3 Using the Optimized Lifecycle

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. An event root component can be decided in two ways:

  • Components: Certain components are always event root components. Regions and popups are an examples of a component which the framework knows is a boundary. No matter what event is triggered inside a region or popup, the lifecycle does not run on components outside the region or popup.

  • Events: Certain events indicate a component as a root. For example, the disclosure event sent when expanding or collapsing a showDetail component (see Section 9.9, "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. Table 6-1 in Section 6.1.1, "Events and Partial Page Rendering" shows the events that have a corresponding event root component.

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 more information about how the ADF Faces framework uses PPR, and how you can use PPR throughout your application, see Chapter 8, "Rerendering Partial Page Content."

5.4 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 more information about subforms, see Section 5.5, "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. Example 5-3 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.

Example 5-3 Simple Client-Side Validation Example

<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-6. There will be no trip to the server; this error detection and message generation is all done on the client.

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

Client-side validation for required attribute

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 more information about using client-side validation and conversion, see Chapter 7, "Validating and Converting Input."

5.5 Using Subforms to Create Sections on a Page

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 more information about subforms, see Section 11.2, "Defining Forms."

5.6 Object Scope Lifecycles

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-7 shows the time period in which each type of scope is valid, and its relationship with the page flow.

Figure 5-7 Relationship Between Scopes and Page Flow

Scopes in ADF lifecycle

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. For more information, see the "Using a Managed Bean in a Fusion Web Application" section in Developing Fusion Web Applications with Oracle Application Development Framework.

5.7 Passing Values Between Pages

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 the "Getting Started with ADF Task Flows" chapter of Developing Fusion Web Applications with Oracle Application Development Framework.

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.

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.

5.7.1 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 more information, see Section 5.6, "Object Scope Lifecycles." You may also want to understand how pageFlow scope is used to pass values. For more information, see Section 5.7, "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();
    

5.7.2 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 more information about creating command components, see Section 20.3, "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.

To access a value from the pageFlowScope scope:

  1. On the page from which you want to access the value, drop the component that you want to display the value.

  2. 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}.

5.7.3 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.