Skip Headers
Oracle® Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework
11g Release 1 (11.1.1)

Part Number B31973-02
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

4 Understanding the JSF and ADF Faces Lifecycles

This chapter describes the JSF and ADF Faces lifecycles and how to use them properly in your application.

This chapter includes the following sections:

4.1 Introduction to the JSF and ADF Faces Lifecycles

Because the ADF Faces rich client framework (RCF) extends the JSF framework, any application built using the ADF Faces rich client framework uses the standard JSF lifecycle. However, the ADF Faces framework extends that lifecycle, providing additional functionality, such as a client-side value lifecycle, a subform component that allows you to create independent submittable regions on a page without the drawbacks of using multiple forms on a single page (for example, lost user edits), and additional scopes.

4.2 The JSF Lifecycle

Before the lifecycle enhancements that ADF Faces rich client framework delivers are introduced, it is important to understand the standard JSF lifecycle. This section provides only an overview; for a more detailed explanation, refer to the JSF specification at http://java.sun.com.

When a JSF page is submitted and a new page is requested, the JSF request lifecycle is invoked. The JSF lifecycle handles the submission of values on the page, validation for components, navigation, and display of the components on the resulting page, as well as saving and restoring state. 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. The FacesServlet object manages the 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.

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

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

The ADF and JSF phases work together

In a JSF application, the lifecycle is as follows:

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 command button to submit the entered value. A valueChangeListener method is also registered on the component. Example 4-1 shows the code for the example.

Example 4-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:commandButton text="Save"  actionListener="#{mybean.actionListener}"/>
</af:form>

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

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

Example of a page going through the lifecycle

4.2.1 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. For actionSource components set to immediate (such as a commandButton), events are delivered in the Apply Request Values phase instead of the Invoke Application phase. The actionListener handler 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 more information about navigation, see Chapter 17, "Working with Navigation Components"). When the user clicks the Cancel button, all validation is skipped, and entered data is not updated to the model, and the user navigates as expected (the same is true if no navigation is set; the actionListener handler invokes the Render Response phase).

Note:

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

For components that invoke disclosure events, (such as a showDetail component), the event is delivered to the Apply Request Values phase. For editableValueHolder components (components that hold values that can change, such as an inputText component), conversion, validation, and delivery of valueChangeEvents events are done earlier in the lifecycle, during the Apply Request Values phase.

Note:

For editableValueHolder components, no lifecycle phases are skipped.

For example, if you have one or more input components validated before other components, you might set their immediate attribute to true. Then, if one of those components is found to have invalid data, validation is skipped for the other input components in the same page. This can reduce 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 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 while navigating to the new page.

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

When using the immediate attribute for editableValueHolder and actionSource components on the same page, you should be aware of the following issues:

  • If an editableValueHolder component is marked as immediate, it will execute before the Update Model Values phase. This could be an issue when an immediate actionSource component requires data from an editableValueHolder component, as data entered into an editableValueHolder component is not available to the model until after the Update Model 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 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

To use the immediate attribute:

  1. On the JSF page, select the component that you want to be immediate.

  2. In the Property Inspector, expand the Behavior section.

  3. In the Validation section, set the immediate attribute to true.

4.3 Using the Optimized Lifecycle

ADF Faces provides an optimized lifecycle that you can use when you want the lifecycle to be run (including conversion and validation) only for certain components on a page. For example, suppose you have an inputText component on a page whose required attribute is set to true. On the same page are radio buttons that when selected, cause the page to either show or hide text in an outputText component, as shown in Figure 4-3.

Figure 4-3 Required Field and Boolean with Auto-Submit

Auto submit skips validation on inputText component

Also assume that you want the user to be able to select a radio button before entering the required text into the field. While you could set the radio button components to automatically trigger a submit action and also set their immediate attribute to true so that they are processed before the inputText component, you would also have to add a valueChangeEvent listener and in it, call the Render Response phase so that validation is not run on the input text component.

Instead of having to write this code in a listener, ADF Faces allows you to set boundaries on the page that allow the lifecycle to run just on components within the boundary. In order to determine the boundary, the framework must be notified of the root component to process. This can be determined in two ways:

Cross-component refresh allows you to set up dependencies so that the events from one component act as triggers for another component, known as the target. When any event occurs on the trigger component, the lifecycle is run on any target components, as well as any child components of both the trigger and the target, causing only those components to be rerendered. This is considered a partial page rendering (PPR).

In the radio button example, you would set the radio buttons to be triggers and the panelGroupLayout component that contains the output text to be the target, as shown in Example 4-2.

Example 4-2 Example of Cross-Component Rendering

<af:form>
  <af:inputText label="Required Field" required="true"/>
  <af:selectBooleanRadio id="show" autoSubmit="true" text="Show"                                      
                        value="#{validate.show}"/>
  <af:selectBooleanRadio id="hide" autoSubmit="true" text="Hide" 
                         value="#{validate.hide}"/>
  <af:panelGroupLayout partialTriggers="show hide" id="panel">
    <af:outputText value="You can see me!" rendered="#{validate.show}"/>
  </af:panelGroupLayout>
</af:form>

Because the autoSubmit attribute is set to true on the radio buttons, when they are selected, a SelectionEvent is fired, for which the radio button is considered the root. Because the panelGroupLayout component is set to be a target to both radio components, when that event is fired, only the selectOneRadio (the root), the panelGroupLayout component (the root's target) and its child component (the outputText component) are processed through the lifecycle. Because the outputText component is configured to render only when the Show radio button is selected, the user is able to select that radio button and see the output text, without having to enter text into the required input field above the radio buttons.

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

4.3.1 What You May Need to Know About Using the Immediate Attribute and the Optimized Lifecycle

There may be cases where PPR will not be able to keep certain components from being validated. For example, suppose instead of using an outputText component, you want to use an inputText component whose required attribute is set to true, inside the panelGroupLayout component, as shown in Example 4-3.

Example 4-3 inputText Component Within a panelGroup Component Will Be Validated with Cross-Component PPR

<af:form>
  <af:selectBooleanRadio id="show2" autoSubmit="true" text="Show" 
                         value="#{validate.show2}"/>
  <af:selectBooleanRadio id="hide2" autoSubmit="true" text="Hide" 
                         value="#{validate.hide2}"/>
  <af:panelGroupLayout partialTriggers="show2 hide2">
    <af:inputText label="Required Field" required="true" 
                                         rendered="#{validate.show2}"/>
  </af:panelGroupLayout>
</af:form>

In this example, the inputText component will be validated because the lifecycle runs on the root (the selectOneRadio component), the target (the panelGroupLayout component) and the target's child, the inputText component. Validation will fail because the inputText component is marked as required and there is no value, so an error will be thrown. Because of the error, the lifecycle will skip to the Render Response phase and the model will not be updated. Therefore, the panelGroupLayout component will not be able to show or hide because the value of the radio button will not be updated.

For cases like these, you can skip validation using the immediate attribute on the radio buttons. This means that the valueChangeEvent on the buttons would run before validation phase of the inputText component. Then need add a valueChangeListener handler method that would call the Render Response phase (thereby skipping validation of the input component), and set the values on the radio buttons and input component. Example 4-4 shows the JSF code to do this.

Example 4-4 Using the immediate Attribute and a valueChangeListener

<af:form>
  <af:selectOneRadio immediate="true" 
                         valueChangeListener="#{validate.toggle}"
                         id="show2" autoSubmit="true" text="Show"                    
                         value="#{validate.show2}"/>
  <af:selectOneRadio id="hide2" autoSubmit="true" text="Hide" 
                         value="#{validate.hide2}"/>
  <af:panelGroupLayout partialTriggers="show2 hide2">
    <af:inputText label="Required Field" required="true"
                  rendered="#{validate.show2}"/>
  </af:panelGroupLayout>
</af:form>

Example 4-5 shows the valueChangeListener code.

Example 4-5 valueChangeListener Sets the Value and Calls Render Response

public void toggle(ValueChangeEvent vce)
  {
    setShow2(Boolean.TRUE.equals(vce.getNewValue()));
    FacesContext.getCurrentInstance().renderResponse();
  }

4.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 and have them 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 4.5, "Using Subforms to Create Regions 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 command 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 is called. This is similar to server-side validation in that when validation fails on the server, the lifecycle jumps to the Render Response phase, and 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 4-6 shows code that has an inputText component's required attribute set to true, and a command button whose actionListener attribute is bound to a method on a managed bean.

Example 4-6 Simple Client-Side Validation Example

<af:form>
  <af:inputText id="input1" required="true" value="a"/>
  <af:commandButton 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 would redisplay with a red outline. If you then click into the field, an error message would state that a value is required, as shown in Figure 4-4. There would be no trip to the server; this error detection and message generation is all done on the client.

Figure 4-4 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 will not be submitted because the required field is empty and therefore an error occurs, the action event is not delivered, and the method bound to the action listener is not executed. This 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 6, "Validating and Converting Input".

4.5 Using Subforms to Create Regions on a Page

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

ADF Faces adds support for a subform component, which represents an independently submittable region 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. This allows for comparatively fine-grained control of which components 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 Tip:

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 9.2, "Defining Forms".

4.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 three types of scopes in a standard JSF application:

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

Note:

Because these are not standard JSF scopes, you cannot register a managed bean to these scopes. However, the value of a managed bean property can refer to values in these scopes.

Also, EL expressions must explicitly include the scope to retrieve values. For example, to retrieve foo from the pageFlowScope scope, your expression would be #{pageFlowScope.foo}.

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

Figure 4-5 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.

4.7 Passing Values Between Pages

Note:

For 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 the Oracle Fusion Middleware Fusion Developer's Guide for 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. This is true 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:commandButton 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, commandButton) 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 commandButton 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.

4.7.1 How to Use the pageFlowScope Scope Within Java Code

You can access pageFlow scope from within any Java code in your application.

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();
    

4.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 Component Palette.

  2. From the Component Palette, drag a setPropertyListener component and drop it as a child to the command component.

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

  3. In the Insert Set Property Listener dialog, set the From field to be the value you need to set.

    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 t#{myBean.empName} in he 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. Select Action from the Type dropdown menu.

    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 where you want to access the value, drop the component that you wish 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}.

4.7.3 What Happens at Runtime: Passing Values

When a user clicks a command 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.