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

Part Number B31974-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

19 Understanding the Fusion Page Lifecycle

This chapter describes the ADF page lifecycle, its phases, and how to best use the lifecycle within a Fusion web application.

This chapter includes the following sections:

19.1 Introduction to the Fusion Page Lifecycle

When a page is submitted and a new page requested, the application invokes both the ADF Faces page lifecycle, which extends the standard JSF request lifecycle, and the ADF page lifecycle. The extended JSF lifecycle handles submitting the values on the page, validating component values, navigating pages, displaying components on the resulting page, and 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 servlet manages the request processing lifecycle in JSF applications. FacesServlet creates an object called FacesContext, which contains the information necessary for request processing, and invokes an object that executes the lifecycle. For more details about the extended JSF lifecycle, see the "Understanding the JSF and ADF Faces Lifecycles" chapter of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

The ADF page lifecycle handles preparing and updating the data model, validating the data at the model layer, and executing methods on the business layer. The ADF page lifecycle uses the binding container to make data available for easy referencing by the page during the current page request.

The combined JSF and ADF page lifecycle is only one sequence within a larger sequence of events that begins when an HTTP request arrives at the application server and continues until the page is returned to the client. This overall sequence of events can be called the web page lifecycle. It follows processing through the model, view, and controller layers as defined by the MVC architecture. The page lifecycle is not a rigidly defined set of events, but is rather a set of events for a typical use case. Figure 19-1 shows a sequence diagram of the lifecycle of a web page request using JSF and Oracle ADF in tandem.

Figure 19-1 Lifecycle of a Web Page Request Using JSF and Oracle ADF

Control Flow in an ADF application

The basic flow of processing a web page request using JSF and Oracle ADF happens as follows:

  1. A web request for http://yourserver/yourapp/faces/some.jsp arrives from the client to the application server.

  2. The ADFBindingFilter object looks for the ADF binding context in the HTTP session, and if it is not yet present, initializes it for the first time. Some of the functions of the ADFBindingFilter include finding the name of the binding context metadata file, and finding and constructing an instance of each data control.

  3. The ADFBindingFilter object invokes the beginRequest() method on each data control participating in the request. This method gives the data control a notification at the start of every request so that it can perform any necessary setup.

  4. The JSF Lifecycle object, which is responsible for orchestrating the standard processing phases of each request, notifies the ADFPhaseListener class during each phase of the lifecycle, so that it can perform custom processing to coordinate the JSF lifecycle with the ADF Model data binding layer. For more information about the details of the JSF and ADF page lifecycle phases, see Section 19.2, "The JSF and ADF Page Lifecycles".

    Note:

    The FacesServlet class (in javax.faces.webapp), configured in the web.xml file of a JSF application, is responsible for initially creating the JSF Lifecycle class (in javax.faces.lifecycle) to handle each request. However, since it is the Lifecycle class that does all the interesting work, the FacesServlet class is not shown in the diagram.
  5. The ADFPhaseListener object creates an ADF PageLifecycle object to handle each request and delegates appropriate before and after phase methods to corresponding methods in the ADF PageLifecycle class. If the appropriate binding container for the page has never been used before during the user's session, it is created.

  6. The first time an application module data control is referenced during the request, it acquires an instance of the application module from the application module pool.

  7. The JSF Lifecycle object forwards control to the page to be rendered.

  8. The UI components on the page access value bindings and iterator bindings in the page's binding container and render the formatted output to appear in the browser.

  9. The ADFBindingFilter object invokes the endRequest() method on each data control participating in the request. This method gives a data control notification at the end of every request, so that they can perform any necessary resource cleanup.

  10. An application module data control uses the endRequest notification to release the instance of the application module back to the application module pool.

  11. The user sees the resulting page in the browser.

The ADF page lifecycle also contains phases that are defined simply to notify ADF page lifecycle listeners before and after the corresponding JSF phase is executed (that is, there is no implementation for these phases). These phases allow you to create custom listeners and register them with any phase of both the JSF and ADF page lifecycles, so that you can customize the ADF page lifecycle if needed, both globally or at the page level.

19.2 The JSF and ADF Page Lifecycles

Figure 19-2 shows how the JSF and ADF phases integrate in the lifecycle of a page request. For more information about how the JSF lifecycle operates on its own, see the "Understanding the JSF and ADF Faces Lifecycles" chapter of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

Figure 19-2 Lifecycle of a Page Request in a Fusion Web Application

The ADF and JSF phases work together

In a JSF application that uses the ADF Model layer, the phases in the page lifecycle are as follows:

19.2.1 What You May Need to Know About Using the Refresh Property Correctly

The Refresh and RefreshCondition attributes are used to determine when and whether to invoke an executable. Refresh determines the phase in which to invoke the executable, while the refresh condition determines whether the condition has been met. By default, when JDeveloper adds an executable to a page definition (for example, when you drop an operation as a command component), the Refresh attribute for the executable binding is set to deferred, which enforces execution whenever demanded the first time, (for example, when a binding value is referenced in an EL expression). If no RefreshCondition value exists, the executable is invoked. If a value for RefreshCondition exists, then that value is evaluated, and if the return value of the evaluation is true, then the executable is invoked. If the value evaluates to false, the executable is not invoked. For details about the refresh attribute, see Section A.7.1, "PageDef.xml Syntax".

For most cases in a Fusion web application, you should not change the refresh condition on an iterator binding or a taskFlow executable binding. Additionally, instead of inserting invokeAction executables into a page definition, you should use method activities in a task flow to invoke methods before a page renders. However, there may be cases when you do need to add an invokeAction executable and set the refresh property correctly.

The valid values for the Refresh property of an invokeAction are as follows:

  • prepareModel: Executes the invokeAction executable during the Prepare Model phase.

  • renderModel: Executes the invokeAction executable during the Prepare Render phase.

    Tip:

    Notice in Figure 19-2 that the key distinction between the Prepare Model phase and the Prepare Render phase is that one comes before JSF's Invoke Application phase, and one after. Since JSF's Invoke Application phase is when action listeners fire, if you need the method or operation associated with the invokeAction to execute after these action listeners have performed their processing, you'll want to set the Refresh property to renderModel.
  • ifNeeded: Executes the invokeAction if needed, based on the refreshCondition attribute or, if no value is supplied, during the Prepare Model phase. To determine if the execution is needed, it performs an optimization to compare the current set of evaluated parameter values with the set that was used to invoke the method action binding previously. If the parameter values for the current invocation are exactly the same as those used previously, the invokeAction does not invoke its bound method action binding. Use this setting if the invokeAction executable binds to a method action binding that accepts parameters.

    Tip:

    For invokeAction executables that are bound to methods that do not take parameters, the invokeAction will be called twice. To use the invokeAction executable with parameterless methods, you should use the RefreshCondition attribute so that the condition evaluates to only invoke the method if the value has changed. This will prevent multiple invocations.
  • prepareModelIfNeeded and renderModelIfNeeded: Same as ifNeeded, except that the invokeAction is executed during the named phase.

Tip:

Any invokeAction executable in a page definition file must have a value other than the default (deferred) for its refresh attribute, or it will not be refreshed and invoked.

Other values of Refresh are either not relevant to invokeAction objects (such as Never), or reserved for future use. For information about the other settings, see Table A-4 in Appendix A, "Oracle ADF XML Files".

Tip:

You can determine the order of executable invocation using the refreshAfter attribute. For example, say you have two invokeAction elements; one with an ID of myAction and another with an ID of anotherAction, and you want myAction to fire after anotherAction. You would set the refreshAfter condition on myAction to anotherAction.

19.2.2 What You May Need to Know About Task Flows and the Lifecycle

The task flows associated with ADF Regions are initially refreshed when their parent page is first displayed. At that time, the task flow's parameter values are passed in from the parent page to the region, and the initial page fragment within the region is displayed. The task flow's bindings will only be refreshed based on its Refresh and RefreshCondition attributes.

Tip:

If you have a region on a page that is not initially disclosed (for example, a popup dialog), the parameters still need to be available when the parent page is rendered, even though the region might not be displayed. If a region requires parameters, but those parameter values will not be available when the parent page is rendered, then you should use a router activity as the initial activity in the region's flow. If the parameters are null, the flow should not continue and the region will not display. If the parameter values are available, the flow should forward to the first view activity.

If you set an EL expression as the value of the RefreshCondition attribute, it will be evaluated during the Prepare Render phase of the lifecycle. When the expression evaluates to true, the task flow will be refreshed again. When RefreshCondition evaluates to false, the behavior is the same as if the RefreshCondition had not been specified.

Note:

If the variable bindings is used within the EL expression, the context refers to the binding container of the parent page, not the page fragment displayed within the region.

The valid values for the Refresh property of a task flow executable are as follows:

  • default: The region will be refreshed only once, when the parent page is first displayed.

  • ifNeeded: Refreshes the region only if there has been a change to taskFlow Binding parameter values. If the taskFlow binding does not have parameters, then ifNeeded is equivalent to the default. When ifNeeded is used, the RefreshCondition attribute is not considered.

    Note:

    ifNeeded is not supported when you pass parameters to the taskFlow Binding using a dynamic parameter Map. Instead, use RefreshCondition="#{EL.Expression}".

Because the only job of the taskFlow binding is to refresh its parameters, Refresh="always" doesn't apply. If the taskFlow binding's parameters don't change, there is no reason to refresh the ADF Region. The Refresh attribute does not need to be specified: the RefreshCondition and Refresh attributes are mutually exclusive. Note that setting the Refresh attribute to ifNeeded takes precedence over any value for the RefreshCondition attribute.

Note that the child page fragment's page definition still handles the refresh of the bindings of the child page fragments.

19.3 Object Scope Lifecycles

At runtime, ADF objects such as the binding container and managed beans are instantiated. Each of these objects has a defined lifespan set by its scope attribute. You can access a scope as a java.util.Map from the RequestContext API. For example, to access an object named foo in the request scope, you would use the expression #{requestScope.foo}.

There are six types of scopes in a Fusion web application:

Note:

When you create objects (such as a managed bean) that require you to define a scope, you can set the scope to none, meaning that it will not live within any particular scope, but will instead be instantiated each time it is referenced.

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

By default, the binding container and the binding objects it contains are defined in session scope. However, the values referenced by value bindings and iterator bindings are undefined between requests and for scalability reasons do not remain in session scope. Therefore, the values that binding objects refer to are valid only during a request in which that binding container has been prepared by the ADF lifecycle. What stays in session scope are only the binding container and binding objects themselves.

Figure 19-3 shows the time period during which each type of scope is valid.

Figure 19-3 Relationship Between Scopes and Page Flow

Scopes in ADF lifecycle

When determining what scope to register a managed bean with, always try to use the narrowest scope possible. Only use the session scope for information that is relevant to the whole session, such as user or context information. Avoid using session scope to pass values from one task flow to another. When creating a managed bean for a page fragment or a declarative component, you must use backing bean scope.

19.3.1 What You May Need to Know About Object Scopes and Task Flows

When determining what scope to use for variables within a task flow, you should use any of the scope options other than application or session scope. These two scopes will persist objects in memory beyond the life of the task flow and therefore compromise the encapsulation and reusable aspects of a task flow. In addition, application and session scopes may keep objects in memory longer than needed, causing unneeded overhead.

When you need to pass data values between activities within a task flow, you should use page flow scope. View scope is recommended for variables that are needed only within the current view activity, not across view activities. Request scope should be used when the scope does not need to persist longer than the current request. It is the only scope that should be used to store UI component information. Lastly, backing bean scope must be used for backing beans in your task flow if there is a possibility that your task flow will appear in two region components or declarative components on the same page and you would like to achieve region instance isolations.

19.4 Customizing the ADF Page Lifecycle

The ADF lifecycle contains clearly defined phases that notify ADF lifecycle listeners before and after the corresponding JSF phase is executed. You can customize this lifecycle by creating a custom phase listener that invokes your needed code, and then registering it with the lifecycle to execute during one of these phases.

For example, you can create a custom listener that executes custom code and then register it with the JSFApplyRequestValues phase so that it can be invoked either before or after the Apply Request Values phase.

Note:

An application cannot have multiple phase listener instances. An initial ADFPhaseListener instance is by default, registered in the META-INF/faces-config.xml configuration file. Registering, for example, a customized subclass of the ADFPhaseListener creates a second instance. In this scenario, only the instance that was most recently registered is used.

The following warning message indicates when an instance has been replaced by a newer one: "ADFc: Replacing the ADF Page Lifecycle implementation with class name of the new listener."

19.4.1 How to Create a Custom Phase Listener

To create a custom phase listener, you must create a listener class that implements the PagePhaseListener interface. You then add methods that execute code either before or after the phase that the code needs to execute.

Example 19-1 contains a template that you can modify to create a custom phase listener. See Section 4.12.1, "How to Generate Custom Classes" for more information about creating a class in JDeveloper.

Example 19-1 Example Custom Phase Listener

public class MyPagePhaseListener implements PagePhaseListener{
   public void afterPhase(PagePhaseEvent event)   {      System.out.println("In afterPhase " + event.getPhaseId());   }     public void beforePhase(PagePhaseEvent event)   {      System.out.println("In beforePhase " + event.getPhaseId());   }}

Once you create the custom listener class, you need to register it with the phase in which the class needs to be invoked. You can either register it globally (so that the whole application can use it), or you can register it only for a single page.

19.4.2 How to Register a Listener Globally

To customize the ADF lifecycle globally, register your custom phase listener by editing the adf-settings.xml configuration file. The adf-settings.xml file is shared by several ADF components, including ADF Controller, to store configuration information. If the adf-settings.xml file does not yet exist, you need to create it. For information, see the "ADF Faces Configuration" appendix of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

To register the listener in adf-settings.xml:

  1. In the adf-settings.xml file, scroll down to <adfc-controller-config xmlns="http://xmlns.oracle.com/adf/controller/config">

    If this entry does not exist, add it to the file as shown in Example 19-2.

    Example 19-2 adf-settings.xml Configuration File with Listener Registration

    <?xml version="1.0" encoding="US-ASCII" ?> <adf-config xmlns="http://xmlns.oracle.com/adf/config">
      .
      .
      .
        <adfc-controller-config xmlns="http://xmlns.oracle.com/adf/controller/config">
           <lifecycle>
             <phase-listener>
                <listener-id>MyPagePhaseListener</listener-id>
                <class>mypackage.MyPagePhaseListener</class>        
             </phase-listener>
          </lifecycle>
       </adfc-controller-config> 
      .
      .
      .
    </adf-config>
    
  2. Enter the remaining elements shown in italics in Example 19-2.

  3. Add values for the following elements:

    • <listener-id> A unique identifier for the listener (you can use the fully qualified class name)

    • <class> The class name of the listener

19.4.3 What You May Need to Know About Listener Order

You can specify multiple phase listeners in the adf-settings.xml and, optionally, the relative order in which they are called. When registering a new listener in the file, the position in the list of listeners is determined using two parameters:

  • beforeIdSet: The listener is called before any of the listeners specified in beforeIdSet

  • afterIdSet: The listener is called after any of the listeners specified in afterIdSet

Example 19-3 contains an example configuration file in which multiple listeners have been registered for an application.

Example 19-3 adf-settings.xml Configuration File with Multiple Listener Registration

<lifecycle>
   <phase-listener>
      <listener-id>MyPhaseListener</listener-id>
      <class>view.myPhaseListener</class>
      <after-id-set>
         <listener-id>ListenerA</listener-id
         <listener-id>ListenerC</listener-id
      </after-id-set>
      <before-id-set>
         <listener-id>ListenerB</listener-id
         <listener-id>ListenerM</listener-id
         <listener-id>ListenerY</listener-id
      </before-id-set>
   </phase-listener>
</lifecycle>

In the example, MyPhaseListener is a registered listener that executes after listeners A and C but before listeners B, M, and Y. To execute MyPhaseListener after listener B, move the <listener-id> element for listener B under the <after-id-set> element.

19.4.4 How To Register a Lifecycle Listener for a Single Page

To customize the lifecycle of a single page, you set the ControllerClass attribute on the page definition file. This listener will be valid only for the lifecycle of the particular page described by the page definition. For more information about the page definition file and its role in a Fusion web application, see Section 11.6, "Working with Page Definition Files".

You specify a different controller class depending on whether it is for a standard JSF page or a page fragment:

To customize the ADF Lifecycle for a single page or page fragment:

  1. In the Application Navigator, right-click the page or page fragment and choose Go To Page Definition.

  2. In the Structure window, select the page definition node.

  3. In the Property Inspector, click the dropdown menu next to the ControllerClass field and choose Edit.

  4. Click Hierarchy and navigate to the appropriate controller class for the page or page fragment. Following are the controller classes to use for different types of pages:

    • Standard JSF page - specify oracle.adf.controller.v2.lifecycle.PageController

      If you need to receive afterPhase/beforePhase events, specify oracle.adf.controller.v2.lifecycle.PagePhaseListener

    • Page fragment - specify oracle.adf.model.RegionController

    Tip:

    You can specify the value of the page definition's ControllerClass attribute as a fully qualified class name using the method above, or you can enter an EL expression that resolves to a class directly in the ControllerClass field.

    When using an EL expression for the value of the ControllerClass attribute, the Structure window may show a warning indicating that e "#{YourExpression}" is not a valid class. You can safely ignore this warning.

19.4.5 What You May Need to Know About Extending RegionController for Page Fragments

Bindings inside page fragments used as regions are refreshed through the refreshRegion and validateRegion events of the RegionController interface. These events are available if you specify oracle.adf.model.RegionController in the ControllerClass field as described in Section 19.4.4 above.

As shown in Example 19-4, you can use the refreshRegion event to add custom code that executes before the region is refreshed. For example, you may want to refresh the bindings used by the page fragment in the region so that the refreshed binding values are propagated to the inner binding container.

To do this, create a new class that implements the RegionController interface. Then, write the following refreshRegion method, including your custom code that you want to execute before the Prepare Model phase.

Example 19-4 regionRefresh Method

public boolean refreshRegion(RegionContext regionCtx)
   {
      int refreshFlag = regionCtx.getRefreshFlag();
      if (refreshFlag == RegionBinding.PREPARE_MODEL)
      {
         // Execute some code before
      }
      // Propagate the refresh to the inner binding container
      regionCtx.getRegionBinding().refresh(refreshFlag);
      
      return false;
   }
 
   public boolean validateRegion(RegionContext regionCtx)
   {
      // Propagate the validate to the inner binding container
      regionCtx.getRegionBinding().validate();
      
      return false;
   }

As shown in Example 19-4, the refresh flag value can be:

  • RegionBinding.PREPARE_MODEL - corresponds to the event occurring during the ADF Lifecycle PREPARE_MODEL phase

  • RegionBinding.RENDER_MODEL - corresponds to the event occurring during the ADF Lifecycle PREPARE_RENDER phase