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

Part Number E16182-01
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

25 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:

25.1 About 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 ADF Faces page 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 25-1 shows a sequence diagram of the lifecycle of a web page request using JSF and Oracle ADF in tandem.

Figure 25-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 25.2, "About 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 the appropriate before and after phase methods to corresponding methods in the ADF PageLifecycle class. If the 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.

25.2 About the JSF and ADF Page Lifecycles

Figure 25-2 shows a high-level view of the combined JSF and ADF page lifecycles.

Figure 25-2 JSF and ADF Page Lifecycles

JSF and ADF page lifecycles

Say for example, you have a page with some text displayed in an input text component and a command button. When that page is first rendered, the component tree is built during the Restore View phase and then the lifecycle goes straight to the Render Response phase, as the components are rendered. When the user clicks the button, the full lifecycle is invoked. The component tree is rebuilt, the input text component extracts any new value during the Apply Request Values phase and Process Validations phase, and if there is an error, for example due to validation, then the lifecycle jumps to the Render Response phase. Otherwise, the model is then updated with the new value during the Update Model phase, and then any application processing associated with the command button (such as navigation), is executed during the Invoke Application phase.

Figure 25-3 shows the details of how the JSF and ADF Faces and ADF model phases integrate in the lifecycle of a page request.

Figure 25-3 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:

25.2.1 What You May Need to Know About Partial Page Rendering and Iterator Bindings

ADF Faces provides an optimized lifecycle that you can use when you want the page request lifecycle (including conversion and validation) to be run only for certain components on a page, usually for components whose values have changed.

One way to use the optimized lifecycle is to manually 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)

Example 25-1 shows radio buttons as triggers and a panelGroupLayout component that contains the output text to be the target (the panelGroupLayout component must be the target because the outputText component may not always be rendered).

Example 25-1 Example of Partial Page 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. Because the panelGroupLayout component is set to be a target for both radio components, when that event is fired, only the selectOneRadio (the trigger), the panelGroupLayout component (the trigger'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.

Instead of having to set partial triggers and targets within code manually, the ADF Faces framework provides automatic PPR. Automatic PPR happens when an event has a corresponding event root component, or when the component itself is an event root. An event root component determines the boundaries of PPR. For example, the attributeChangeEvent considers the inputText component that invokes the event, its event root. Therefore, in the previous example, when the value changes for the inputText component, because it is the initial boundary for the PPR, the lifecycle would be run only on that inputText component and any child components.

Along with event roots, by default for Fusion web applications, automatic PPR also occurs for all UI components associated with the same iterator binding. All associated components refresh whenever any one of them has a value change event. This functionality is controlled by setting the changeEventPolicy attribute for iterators to ppr. By default, this is set globally.

For example, say you create a number of inputText components using the Data Controls panel (for example, when you create a form). When the attributeChangeEvent occurs on one of those inputText components, because the other inputText components are associated with the same iterator, all those inputText components will also be refreshed.

Another example might be a page that contains a panelSplitter component, where the left part of the splitter contains a form to create a new customer (created by dropping a form using the CustomerInfoVO1 collection), and the right part of the splitter contains instructions for using the form. Because the bindings for the inputText components that make up the form are all associated with the CustomerInfoVO1Iterator iterator, anytime the form is submitted and a value for one of the inputText components has changed, only the inputText components associated with the CustomerInfoVO1Iterator will be processed through the lifecycle. The rest of the page, including the instructions in the right side of the splitter, will not be refreshed.

Note:

In order for automatic PPR to happen, the event and event root component must be listed in Table 5-1 of the "Events and Partial Page Rendering" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. If it is not listed, you will need to set up PPR manually, as described in the Enabling Partial Page Rendering Declaratively section of the same guide.

For example, say you create a form and a table from the same data control collection. The form shows the details for a row of data, while the table shows all rows in a collection, with the row currently displayed in the form shown as selected. When you click the Next button on the form, you want the table to refresh to show the new row as selected. Because the selection event is not supported by automatic PPR, the table will not refresh, even though the table and form both use the same iterator. You will need to set the Next and Previous buttons to be triggers of PPR for the target table.

Note:

Only UI components that have a control binding defined in the page definition file associated with the configured iterator will be refreshed.

If you directly access the iterator from a managed bean and expose iterator values to UI components through that bean, then automatic PPR will not happen for those UI components. In these cases, you need to configure PPR manually. For more information, see the "Enabling Partial Page Rendering Declaratively" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

Note:

The ADF Faces query components do not support automatic PPR. If you set changeEventPolicy to be ppr globally, any iterators associated with bindings for those components will have the changeEventPolicy attribute set to none.

By default, all new applications use global PPR. You do not have to set it. You can however, override the setting in the page definition file for a page.

Before you begin:

It may be helpful to have an understanding of partial page rendering. For more information, see Section 25.2.1, "What You May Need to Know About Partial Page Rendering and Iterator Bindings."

To set iterator bindings to use PPR:

  1. To set a specific iterator binding to use or not use PPR, open the associated page definition file, select the iterator, and in the Property Inspector, set ChangeEventPolicy.

  2. To set all iterator bindings to use PPR:

    1. In the Application Navigator, expand the Application Resources panel, expand the Descriptors and ADF META-INF nodes, and double click adf-config.xml.

    2. In the overview editor, select the Model tab, and then select Default Change Event Policy is Partial Page Rendering (PPR).

For more information about how the ADF Faces framework uses PPR, see the "Rendering Partial Page Content" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

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

For scalability reasons, at runtime the iterator bindings in the binding container release any reference they have to a row set iterator at the end of each request. During the next request, each iterator binding rebinds itself to a "live" row set iterator that is tracking the current row of some data collection. The process of rebinding an ADF iterator binding during the ADF page lifecycle is known as refreshing the iterator. By default, this happens only once, on demand, when the iterator is first accessed by the client layer during the lifecycle. This initial access to the iterator typically occurs during page rendering, while EL expressions in the page, which reference the iterator or a control binding related to that iterator, are being evaluated. Alternatively, you can write code that programmatically causes the first access to the iterator to be before the Prepare Render phase. To force the iterator binding to refresh its row set iterator earlier in the lifecyle, you can set the refresh attribute on the iterator binding to a value other than the default.

Tip:

Refreshing an iterator binding does not forcibly reexecute its query each time. The first time the view object instance's row set iterator is accessed during a particular user's session, it will implicitly execute the view object's query if it was not already executed, as long as a search binding in the page definition related to that iterator has not already cleared the row set in preparation for allowing the user to enter search criteria before executing the query.

Subsequent refreshing of the iterator binding related to that view object instance on page requests that are part of the same logical unit of work will only access the row set iterator again, not forcibly reexecute the query. When you want reexecuting the query to refresh its data, use the Execute or ExecuteWithParams built-in operation, or programmatically call the executeQuery() method on the iterator binding.

The refresh and refreshCondition attributes are used to determine when and whether to invoke an executable, such as an iterator binding, or an invokeAction. The value of the refresh attribute determines the lifecycle phase in which to invoke the executable, while the value of the refreshCondition attribute provides an optional boolean condition whose outcome determines whether the refresh will occur at the indicated lifecycle phase or not. 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 the binding is accessed the first time. If no refreshCondition value exists, the executable is invoked. If a value for refreshCondition exists, then that value is evaluated as an EL expression, 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.8.1, "PageDef.xml Syntax.".

For most cases in a Fusion web application, you should not need to change the refresh or refreshCondition values on an iterator binding. These values are set to ensure that the correct data is displayed.

While the invokeAction executable continues to be supported for upward compatibility from previous releases, in Oracle ADF 11g you use a method activity in a task flow to call an action binding (or any backing bean method) to perform some application behavior before the page is rendered. For example, for a page used to create an object, you might have a task flow that begins with a method activity that calls the CreateInsert operation. The task flow then proceeds to the view activity for the page where the user inputs data. Modeling this behavior as discreet method call activities provides a much cleaner separation of application logic and data bindings, making applications both self-documenting and easier to maintain. For more information, see Section 26.6, "Creating an Input Form."

However, for completeness' sake, in case you encounter situations where you decide to change the refresh attribute for iterator bindings or for invokeAction (for example, if you have programmatic code that runs after the Prepare Model phase and needs to access the iterator programmatically), you should do so, informed of the following information regarding the valid values:

  • deferred (the default): On demand

    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.
  • prepareModel: During the Prepare Model phase.

  • renderModel: During the Prepare Render phase.

    Tip:

    Notice in Figure 25-3 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 your iterator refreshed or 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 attribute to renderModel.
  • ifNeeded: During the Prepare Model and Prepare Render phases, only if needed. For iterators, the refresh is considered needed if the binding has not yet been refreshed. To determine if the execution is needed for an invokeAction, the framework compares 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 bound to methods that do not take parameters, the invokeAction executable will be called twice. To use the invokeAction executable with parameterless methods, you should use ensure that the condition associated with the refreshCondition attribute evaluates to invoke the method only if the value has changed. This will prevent multiple invocations.
  • prepareModelIfNeeded and renderModelIfNeeded: Same as ifNeeded, except that it is executed during the named phase.

  • never: Not valid for invokeAction executables. For iterators, the iterator will never be refreshed. Use when your own code calls getRowSetIterator() on the iterator binding.

  • always: Not valid for invokeAction executables. For iterators, the iterator will always be refreshed (potentially multiple times) during both the Prepare Model and Prepare Render phases, as well as during the Update Model phase.

  • refreshAfter: Use to handle dependencies between executables. For example, you can set the condition so that this executable refreshes after another executable.

    Tip:

    You can determine the order of executable invocation using the refreshAfter attribute. For example, suppose 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.

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

Task flows are initially refreshed when the parent binding container (the one associated with the page) is refreshed. This happens in the Prepare Model phase. On a subsequent request, the task flow will be refreshed during the Prepare Render phase, depending on its refresh and refreshCondition attributes and its parameter value.

Note:

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

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 dynamic regions. If the parameters are null, an empty task flow can be used until the parameters for the region are ready and that region can display. To swap in an empty task flow, you set the dynamic region's taskFlowId attribute to an empty string.

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:

    Setting the refresh attribute to ifNeeded takes precedence over any value for the refreshCondition attribute. Also note that 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, setting Refresh to always does not make sense. If the taskFlow binding's parameters don't change, there is no reason to refresh the ADF region.

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

25.3 About 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:

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 25-4 shows the time period during which each type of scope is valid.

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

Managed beans can be registered in either the adfc-config.xml or the configuration file for a specific task flow. For more information about using managed beans in a Fusion application, see Section 24.4, "Using a Managed Bean in a Fusion Web Application."

Note:

Registering managed beans within the faces-config.xml file is not recommended in a Fusion web application.

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

25.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, if you do not want to use the default "Managed State" release level for application modules, you can set the release level from the after-prepareRender phase of the ADF lifecycle using a custom ADF page phase-listener class (for more information, see Section 43.4.5, "How to Set Release Level in an ADF PagePhaseListener").

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

25.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 25-2 contains a template that you can modify to create a custom phase listener. See Section 4.13.1, "How to Generate Custom Classes," for more information about creating a class in JDeveloper.

Example 25-2 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.

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

To register the listener in adf-settings.xml:

  1. In the Application Navigator, beneath the META-INF node, double-click the adf-settings.xml file.

  2. In the editor window, click the Source tab

  3. In the source editor, 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.

  4. Enter the remaining elements shown in italics:

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

25.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, you determine the position in the list of listeners 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 25-3 contains an example configuration file in which multiple listeners have been registered for an application.

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

25.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 13.7, "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 ControllerClass and choose Edit.

  4. Click the Hierarchy tab 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 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.

25.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 25.4.4, "How to Register a Lifecycle Listener for a Single Page."

As shown in Example 25-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 25-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 25-4, the refresh flag value can be:

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

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