5.1 About Using the JSF Lifecycle and ADF Faces

Because the ADF Faces framework extends the JSF framework, any application built using the ADF Faces framework uses the standard JSF page request 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 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 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 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.

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

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:

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

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

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 2010, and you had a dateRestrictionValidator validator that did not allow the user to pick Sundays. If the user entered July 5, 2009 (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.

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

Suppose a user enters the string "June 25, 2005" 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

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

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 Command Button Set to Immediate

Note:

A command 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) 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 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

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 command button configured to invoke the search execution, and another input text component used to input a date with an associated command button used to submit the date. In this example, we 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.

When using the immediate attribute for editableValueHolder and actionSource components on the same page, note 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 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.

In the Property Inspector, expand the Behavior section and set the immediate attribute to true.

5.3 Using the Optimized Lifecycle

ADF Faces provides an optimized lifecycle that you can use when you want the JSF page request lifecycle (including conversion and validation) to be run 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 5-6.

Figure 5-6 Required Field and Boolean with Auto-Submit

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 when the radio buttons are processed.

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. Event root components determine these boundaries on the page, and so allow the lifecycle to run just on components within that boundary. The event root component can be determined 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.

Aside from the lifecycle running on the event root and it's child components, the lifecycle may also be run on any components configured to listen for that event. Configuring a component to listen for events on root components in order to be processed is called cross-component refresh.

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 on 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, to have the lifecycle run just on the radio buttons and the output text component, 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 5-3.

Tip:

Because the output text won't be rendered when it's configured to hide, it cannot be a target. Therefore it is placed in a panelGroupLayout component, which is then configured to be the target.

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.

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

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

In this example, the inputText component will be validated because the lifecycle runs on the root (the selectBooleanRadio 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. Doing so causes the valueChangeEvent on the buttons to run before the Process Validation phase of the inputText component. Then you need to 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 5-5 shows the JSF code to do this.

Suppose you have an inputListOfValues component from which a user selects an employee name, and an inputText component whose required attribute is set to true, which is updated with the employee's ID number once the employee is selected, as shown in Figure 5-7.

Figure 5-7 LOV component Updates the Input Component

To achieve this, you might set the Empno field to have the Ename field as a partial trigger, as shown in Example 5-7.

However, the solution recommended in Section 5.3.1, "What You May Need to Know About Using the Immediate Attribute and the Optimized Lifecycle," of setting the LOV component's immediate attribute to true and using a ValueChangeListener on the LOV will not fix the validation error. For LOV components, the ValueChangeEvent is queued only when the value of the LOV component changes. For this reason, setting the immediate attribute to true has no effect when the user clicks the search icon, because at that point the ADF LaunchPopupEvent is queued for the Invoke Application phase always, regardless of the value of the immediate attribute. In other words, the optimized lifecycle is run as normal on both the root and target components and therefore the input component throws a validation error.

When the user selects a new value from the LOV popup, the LOV component queues two events. One is a ValueChangeEvent to signal a change in value for the component. The second is a ReturnPopupEvent queued for the Invoke Application phase, which gives application methods a chance to handle the selection. Both these events need to occur in order for the LOV to behave as expected.

As mentioned, the LOV component queues a ValueChangeEvent only when the user selects a new value. If you were to set the immediate attribute to true on the LOV component, this event would be queued for the Apply Request Values phase and the new value would be validated. In addition if you were to create a ValueChangeListener method for the LOV component, and in its implementation jump to the Render Response phase to avoid validation of the input component, the selected value would never get pushed to the model, the ReturnPopupListener would never get called during the Invoke Application phase, and the target input component would not get updated with new value, as shown in Figure 5-9.

Figure 5-9 Model is Not Updated

To resolve this issue of needing both the ValueChangeEvent and the ReturnPopupEvent to be queued as part of the same request and to have any target fields refreshed with newly selected values, instead of declaratively setting the LOV component as a partial trigger for the input component and creating a method for the ValueChangeListener, you need to create a listener for the ReturnPopupEvent. This listener must programmatically set the input components as partial targets for the LOV. You do not need to set the LOV's immediate attribute to true because the input component is no longer a target for the LOV until the ReturnPopupListener method is executed, and so it will not fail validation because the lifecycle will not be run on it. And because a listener method is used for the ReturnPopupEvent instead of for the ValueChangeEvent, both events can be queued and the model updated appropriately.

Example 5-8 shows the needed page code for the LOV and input components.

The input component uses its binding attribute to store the instance on a backing bean, allowing the instance to be accessed by the listener method. The listener method then accesses the input component and sets it as a partial target for the LOV, as shown in Example 5-9.

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 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; 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-10 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.

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

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

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.

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

Figure 5-11 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. For more information, see the "Using a Managed Bean in a Fusion Web Application" section of the Oracle Fusion Middleware Fusion Developer's Guide for 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 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, 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:

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.

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 Oracle ADF Controller, then you do not have to manually clear the scope.

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:

On the page from where you want to set the value, create a command component using the Component Palette.

In the Component Palette, from the Listeners group of the Operations panel, drag a Set Property Listener and drop it as a child to the command component.

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.

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

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

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:

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

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

Scripting on this page enhances content navigation, but does not change the content in any way.