24 Creating Complex Task Flows

This chapter describes how to use advanced features of ADF task flows that you create in Fusion web applications. These include the ability to define transaction options for a task flow, configure reentry options to a task flow for a user that previously exited, handle exceptions, configure save points for your task flow, use ADF Faces components such as train, and create task flows from task flow templates.

This chapter includes the following sections:

24.1 About Creating Complex Task Flows

After creating a task flow, adding activities to it, and configuring control flow between the activities, you can extend the task flow´s functionality by adding some of the features described in the following list:

  • Bounded task flows can be configured to include additional transactional management facilities beyond those provided by the underlying data controls so that a Fusion web application can commit or roll back the data controls associated with the task flow's activities as a group.

  • Reentry options can be configured for bounded task flows to determine the response if a user clicks the browser's back button.

  • Task flows contain a number of features that allow you to proactively handle exceptions. In addition, you can write custom code to handle exceptions thrown by a task flow.

  • Task flows can also be configured to capture the state of a Fusion web application at a particular instance using save points. These allow you to save the application's state if, for example, a user leaves a page without finalizing a task.

  • Train components are ADF Faces components that render navigation items to guide a user through a multistep process. You can configure a bounded task flow to render these navigation items by default for the view activities in a task flow.

  • Task flow templates can serve as a starting point for the creation of task flows that share common elements.

  • Create a page hierarchy from the view activities that the default unbounded task flow in your application (and additional task flows in the application) reference.

  • Invoke initializers and finalizers when a bounded task flow is entered and exited. An initializer is custom code that is invoked when a bounded task flow is entered. A finalizer is custom code that is invoked when a bounded task flow is exited via a task flow return activity or because an exception occurred. The finalizer is a method on a managed bean. Common finalizer tasks include releasing all resources acquired by the bounded task flow and performing cleanup before exiting the task flow.

    You specify both the initializer and the finalizer as an EL expression for a method on a managed bean, for example:

    #{pageFlowScope.modelBean.releaseResources}

    There are two techniques for running initializer code at the beginning of the bounded task flow, depending on whether or not the task flow may be reentered via a browser back button:

24.1.1 Complex Task Flows Use Cases and Examples

Figure 24-1 shows the Structure window for a task flow that implements many of the use cases discussed in Section 24.1, "About Creating Complex Task Flows." For example, it specifies an error page to handle errors, makes use of the ADF Faces train component to render navigation items, and specifies two task flow return activities that either commit or roll back changes that the task flow makes as part of transaction management.

Figure 24-1 Task Flow in the Structure Window

Customer Registration Task Flow in the Structure Window

24.1.2 Additional Functionality for Complex Task Flows

You may find it helpful to understand other Oracle ADF features before you configure or use task flows. Additionally, you may want to read about what you can do with your task flows. Following are links to other functionality that may be of interest.

24.2 Sharing Data Controls Between Task Flows

When one task flow calls another, the task flows can either share an instance of a data control, or create two separate isolated instances of the same data control so the task flows can maintain independent state. The internal object that task flows use to share their data controls or to store their own isolated data control is known as a data control frame.

Task flows making use of the task flow transaction management options when committing or rolling back use the data control frame to know which data controls to perform the transaction operations on. A data control frame is created at runtime for your application's unbounded task flow and any bounded task flow with a data-control-scope value of isolated. When a task flow specifies a data-control-scope value of shared, the called task flow uses the data control frame of the calling task flow rather than creating its own. This allows the called task flow to share data control instances attached to the data control frame. Alternatively, if a called task flow specifies a data-control-scope value of isolated, a new data control frame is created and a new instance of any data controls used by the bounded task flow will be attached to the newly-created data control frame.

To specify whether data controls are shared between the calling and called task flows, you must set a data-control-scope value of either shared or isolated on the called bounded task flow. The default value is shared.

If data-control-scope is set to shared on both the calling and called bounded task flow, the data control frame used will be the one for the calling task flow.

In Figure 24-2, the bounded task flows BTF1, BTF2, and BTF3 use the data control frame created for the application's unbounded task flow (UTF1) because these bounded task flows all have a data-control-scope value of shared. In contrast, the bounded task flow BTF4 uses a different data control frame because it has a data-control-scope value of isolated. It shares this data control frame with the bounded task flow that it calls (BTF5) because this latter bounded task flow has a data-control-scope value of shared.

Figure 24-2 Sharing and Isolating Data Control Frames

Sharing and Isolating Data Control Frames

The value that you set for the data-control-scope element of a called task flow determines if a calling task flow and a called task flow share flow data controls. Other factors, such as whether a task flow renders in a page or page fragment, do not change this behavior.

24.2.1 How to Share a Data Control Between Task Flows

You share data controls between task flows by specifying a value for the data-control-scope element of the called task flow.

Before you begin:

It may be helpful to have an understanding of the properties that determine how you share data controls between task flows. For more information, see Section 24.2, "Sharing Data Controls Between Task Flows."

You may also find it helpful to understand functionality that can be added using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To share a data control between task flows:

  1. In the Applications window, double-click the called task flow.

  2. In the Properties window expand the Behavior section and select Shared from the Share data controls with calling task flow list.

    Note:

    After you select Shared from the Share data controls with calling task flow list (data-control-scope), you may need to configure transaction options for the task flow. For more information, see Section 24.3.3, "What You May Need to Know About Sharing Data Controls and Managing Transactions."

24.2.2 What Happens When You Share a Data Control Between Task Flows

JDeveloper writes an entry in the source file for the called task flow when you select Shared from the Share data controls with calling task flow list, as illustrated in Example 24-1.

Example 24-1 Metadata to Share Data Controls Between Task Flows

<task-flow-definition id="task-flow-definition">
    ...
    <data-control-scope id="__1">
      <shared/>
    </data-control-scope>
    ...
</task-flow-definition>

24.2.3 What Happens at Runtime: How Task Flows Share Data Controls

An end user can open the same application more than once in different browser windows or browser tabs. If an end user does this, each window or tab has its own view port, and each window or tab is isolated from all other windows or tabs within the same HTTP session. As a result, the windows or tabs do not share data controls and, therefore, state. The windows or tabs start with a new data control frame as if they were running with an isolated data control scope. The exception to this rule is if an end user opens a modal dialog in a secondary browser window, then the primary and secondary browser windows have the same server-side state and share data controls. For more information about using modal dialogs, see Section 25.2, "Running a Bounded Task Flow in a Modal Dialog." For more information about view ports, see Section 23.1.2, "About View Ports and ADF Regions."

Data controls are not instantiated until needed. One of two things can occur when a parent task flow calls a child task flow that specifies data-control-scope as shared (the default) and references a data control named D:

  1. If a data control named D already exists in the parent task flow's data control frame, then the child task flow's reference to D resolves to the existing data control named D that is in scope.

  2. If a data control named D does not exist in the parent task flow's data control frame, then Oracle ADF instantiates the first data control named D that it finds when performing a top-down search through the DataBindings.cpx files for the task flow call stack.

The above rules are unlikely to be applied because most applications define data controls with unique names. However, if a task flow from an application calls a task flow in an ADF Library JAR, the application and the ADF Library JAR task flows may reference data controls that use the same names. It is important to consider the above rules if this happens.

If, when the parent task flow calls the child task flow, the data control D from the parent task flow's ADF Library JAR is already instantiated, then the child task flow uses it. If it is not already instantiated, then the data control D from the parent task flow will be instantiated and used by the child task flow. In particular, in this task flow calling scenario, the child task flow's data control D will not be instantiated.

Another scenario to consider is where a parent task flow in a JSF page calls a child task flow that renders in a region in the same JSF page. The region's location in the JSF page can determine which data control frame the task flows use. If the JSF page's calling task flow references a data control before the region with the called task flow renders, the calling task flow's data control frame is used. If the region with the called task flow is the first databound component in the JSF page, then the called task flow's data control is used.

For more information about data controls, see Section 17.3, "Exposing Application Modules with ADF Data Controls."

24.3 Managing Transactions in Task Flows

In the context of systems relating to databases, a transaction is a persisted collection of work items that can be committed or rolled back together as a group. ADF, through technologies such as ADF Business Components, offers all the advantages that transactions provide. However, support for transactions does not stop at the ADF Model layer. In the ADF Controller layer, bounded task flows optionally provide their own abstract implementation of transactions over the underlying ADF Model layer. This implementation allows you to control transactions from the task flow and also declaratively manage the transaction boundaries.

The transaction options that you can configure on a called bounded task flow can be grouped into two categories:

  • You delegate transaction management to the ADF Model layer by choosing the <No Controller Transaction> option for the called bounded task flow. The called bounded task flow does not use the ADF Controller's task flow transaction management facilities to commit or rollback all data controls attached to the task flow and associated data control frame. Instead, you must individually commit and rollback data controls attached to the task flow.

  • You use one of the following ADF task flow transaction management options:

    • Always Begin New Transaction: A new transaction starts when the bounded task flow is entered, regardless of whether or not a transaction is in progress. The new transaction completes when the bounded task flow exits.

    • Always Use Existing Transaction: When called, the bounded task flow participates in an existing transaction already in progress.

    • Use Existing Transaction If Possible: When called, the bounded task flow either participates in an existing transaction if one exists, or starts a new transaction upon entry of the bounded task flow if one does not exist.

Best Practice:

Oracle recommends that you choose one of the above categories for transaction management when you chain task flows together. That is, do not configure a set of task flows that call each other where one or more task flows in the set use the <No Controller Transaction> option and one or more of the remaining task flows in the set use one of the ADF task flow transaction management options (Always Begin New Transaction and so on). This type of configuration can lead to complex runtime behavior.

If a called bounded task flow starts a new ADF task flow transaction (based on the transaction option that you selected), you can specify whether the transaction commits or rolls back when the task flow returns to its caller. The commit and rollback options are set on the task flow return activity that returns control back to the calling task flow. The same task flow that starts a transaction must also resolve the transaction.

In a called bounded task flow, you can specify two different return task flow activities that result in either committing or rolling back a transaction in the called bounded task flow. Each of the task flow return activities pass control back to the same calling task flow. The difference is that one task flow return activity specifies the commit option, while the other specifies the rollback option. Figure 24-3 shows the orders-select-many-items.xml task flow from the Summit ADF task flow sample application. If transaction processing successfully completes, control flow passes to the commit task flow return activity, which specifies options to commit the transaction. If the transaction is cancelled before completion, the rollback task flow activity specifies options to roll back the transaction.

Figure 24-3 Task Flow Return Activities in Called Bounded Task Flow

Multiple task flow return activities.

Use the restore-save-point option on the task flow return activity if you want to discard the changes an end user makes within a called bounded task flow when the called bounded task flow exits. ADF Controller rolls back to the previous ADF Model save point that was created when the bounded task flow was entered. The restore-save-point option applies only to cases when a bounded task flow is entered by joining an existing transaction (either the requires-existing-transaction or requires-transaction option is also specified) and a save point is created upon entry.

If you use the ADF task flow transaction management features that commit and rollback the data controls associated with the data control frame of the current task flow, you must use task flow return activities with their End Transaction property set to commit or rollback, or programmatically commit the associated data control frame. Alternatively if you use the <No Controller Transaction> setting or you only want to commit or rollback one data control, use the associated commit or rollback operations from the Data Controls panel or programmatically execute the associated commit and rollback bindings.

In the Summit sample application for ADF task flows, a number of task flows create transactions. For example, the orders-select-many-items.xml task flow uses the ADF task flow transaction management's Use Existing Transaction if Possible option. This task flow allows an end user to add multiple items to an order and commit or rollback this change when the end user interacts with the showshuttle.jsf page shown in Figure 24-4.

Figure 24-4 Task Flow Transaction

Task Flow Transaction

24.3.1 How to Enable Transactions in a Bounded Task Flow

You define the transaction options on a bounded task flow that is called by another task flow. Add a task flow return activity on the called bounded task flow that returns control to the task flow that calls the bounded task flow.

Before you begin:

It may be helpful to have an understanding of what a transaction is and how you can configure it. For more information, see Section 24.3, "Managing Transactions in Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To enable a bounded task flow to run as a transaction:

  1. In the Applications window, double-click the called bounded task flow.

  2. In the editor window, click the Overview tab

  3. In the overview editor, click the Behavior navigation tab.

  4. In the Behavior page, expand the Transaction section and choose one of the following from the dropdown list:

    • <No Controller Transaction>: The called bounded task flow does not use the task flow transaction management facilities to commit or rollback all data controls attached to the task flow and associated data control frame. Instead, you must individually commit and rollback data controls attached to the task flow. The Data Controls panel exposes operations that you can invoke using command components to commit and rollback data controls. For more information, see Section 28.4, "Creating Command Components Using Data Control Operations."

    • Always Use Existing Transaction: When called, the bounded task flow participates in an existing transaction already in progress.

    • Use Existing Transaction If Possible: When called, the bounded task flow either participates in an existing transaction if one exists, or starts a new transaction upon entry of the bounded task flow if one does not exist.

    • Always Begin New Transaction: A new transaction starts when the bounded task flow is entered, regardless of whether or not a transaction is in progress. The new transaction completes when the bounded task flow exits.

    Note:

    After choosing a transaction option, you may also need to configure the Share data controls with calling task flow option (data-control-scope) for the bounded task flow to determine whether there are any interactions between the options. For more information, see Section 24.3.3, "What You May Need to Know About Sharing Data Controls and Managing Transactions."

  5. Optionally, select Isolated from the Share data controls with calling task flow checkbox (data-control-scope) so that data controls are not shared with the calling task flow if you chose one of the following options in Step 4:

    • Use Existing Transaction If Possible

    • Always Begin New Transaction

    The default behavior is to share data controls. For more information, see Section 24.3.3, "What You May Need to Know About Sharing Data Controls and Managing Transactions."

  6. Optionally, select the No save point on task flow entry checkbox to prevent the creation of an ADF Model save point on task flow entry if you chose one of the following options in Step 4:

    • Always Use Existing Transaction

    • Use Existing Transaction If Possible

    An ADF Model save point is a saved snapshot of ADF Model state. Selecting the No save point on task flow entry checkbox means that overhead associated with a save point is not created for the transaction.

  7. Select the task flow return activity in the called bounded task flow.

  8. In the Properties window, expand the Behavior section.

  9. If the called bounded task flow supports creation of a new transaction (bounded task flow specifies Use Existing Transaction If Possible or Always Begin New Transaction options), select one of the following in the End Transaction dropdown list:

    • commit: Select to commit the existing transaction to the database.

    • rollback: Select to roll back a new transaction to its initial state on task flow entry. This has the same effect as cancelling the transaction.

  10. In the Restore Save Point dropdown list, select true if you want changes the user makes within the called bounded task flow to be discarded when the task flow exits. The save point that was created upon task flow entry will be restored.

24.3.2 What Happens When You Specify Transaction Options

Example 24-2 shows the metadata for transaction options on a called bounded task flow. The <new-transaction> element indicates that a new transaction always starts when the called bounded task flow is invoked. The <new-transaction> element is generated when you select Always Begin New Transaction value in the Transaction section's dropdown list.

Example 24-2 Called Bounded Task Flow Metadata

 <task-flow-definition id="trans-taskflow-definition">     
    <default-activity>taskFlowReturn1</default-activity>
    <transaction>
      <new-transaction/>
    </transaction>
    <task-flow-return id="taskFlowReturn1">
      <outcome>
        <name>success</name>
        <commit/>
      </outcome>
    </task-flow-return>
 </task-flow-definition>

Example 24-2 also shows the metadata for transaction options on the task flow return activity on the called task flow. The <commit/> element commits the existing transaction to the database. The <outcome> element specifies a literal outcome, for example, success, that is returned to the caller when the bounded task flow exits. The calling ADF task flow can define control flow rules based on this outcome. For more information about defining control flow upon return, see Section 21.7, "Using Task Flow Return Activities."

24.3.3 What You May Need to Know About Sharing Data Controls and Managing Transactions

Data controls cannot be shared across more than one transaction at the same time. If your task flow is involved in managing transactions, the value you select for the data-control-scope option may affect the transaction option settings for a bounded task flow. Table 24-1 describes how these options interact.

The ADF Model layer exposes the DataControlFrame interface to manage a transaction in which the data controls within the frame participate. The DataControlFrame interface exposes methods such as:

  • beginTransaction()

  • commit()

  • rollback()

Similarly, ADF Controller allows a task flow to demarcate a transaction boundary, to begin a transaction at task flow entry, and to either commit or roll back the transaction on task flow exit. It does this by invoking methods exposed by ADF Model layer's DataControlFrame interface.

ADF Controller supports the transaction options listed in Table 24-1. The behavior of these transaction options depends on whether you select Shared or Isolated from the Share data controls with calling task flow list (XML element: <data-control-scope>) in the overview editor for a task flow.

Table 24-1 Transaction Settings Behavior

Transaction Setting Share Data Control Scope Isolate Data Control Scope

<No Controller Transaction>

The DataControlFrame is shared without the need for an open transaction on the frame.

A new DataControlFrame is created without an open transaction.

Always Begin New Transaction

XML element: <new-transaction/>

Begins a new transaction if one is not already open and throws an exception if one is already open.

Always begins a new transaction.

Always Use Existing Transaction

XML element: <requires-existing-transaction/>

Throws an exception if the transaction is not already open.

Invalid. The checkbox cannot be deselected.

Use Existing Transaction if Possible

XML element: <requires-transaction/>

Begins a new transaction if one is not already open.

Always begins a new transaction.


A number of examples illustrate how bounded task flows interact when you configure different combinations of values for the data control scope and transaction properties described in Table 24-1:

The above list describes common use cases rather than all possible configuration options.

24.3.3.1 Creating Completely Separate Transactions

Figure 24-5 shows a number of task flows that are configured to create separate transactions. Two bounded task flows are chained together in Figure 24-5 yet maintain completely separate transactions. This implementation may be appropriate where you have a call center agent taking an order from a customer and entering the order details in your application. At some point near the end of the order process, the customer realizes that the delivery address that they have provided is incorrect. To assist the call center agent, you designed your application so that it updates and commits the delivery address in a separate transaction to the transaction for the order details (order number, quantity, and so on). In the scenario where the customer wishes to modify the delivery address, the call center agent does not need to roll back changes to the order details in order to modify the delivery address because a separate transaction manages the order details.

In Figure 24-5, the unbounded task flow calls Bounded Task Flow #1. This results in the creation of Data Control Frame #1 because Bounded Task Flow #1 is configured as follows:

  • A data-control-scope value of isolated

  • Always Begin New Transaction

Bounded Task Flow #1 exposes attributes from two different view objects as data control fields (viewObject1.X and viewObject2.Y). X and Y are initially set to 10 and 20 respectively. The end user, while accessing Bounded Task Flow #1, updates X from 10 to 30 and leaves Y unchanged. This marks the transaction as changed or "dirty". That is, there are changes in the transaction that must be committed or rolled back.

Bounded Task Flow #1 calls Bounded Task Flow #2. The application creates Data Control Frame #2 because Bounded Task Flow #2 is configured as follows:

  • A data-control-scope value of isolated

  • Always Begin New Transaction

Note that the transaction of Data Control Frame #1 has yet to be committed and that Data Control Frame #2 has a separate database connection and a separate task flow transaction. As a result, the initial values of the data control fields X and Y in Bounded Task Flow #2 are 10 and 20. The end user, while accessing Bounded Task Flow #2, updates Y to 40 and leaves X unchanged. This marks the transaction for Bounded Task Flow #2 as dirty. Bounded Task Flow #2 next calls a task flow return activity that commits the change to Y to the database and returns control to Bounded Task Flow #1. As Bounded Task Flow #2 did not modify the value of X, no change for this data control field occurs.

Because Bounded Task Flow #1 has a separate data control frame (Data Control Frame #1) and transaction, the values of the data control fields X and Y in Bounded Task Flow #1 remain at 30 and 20, their values when Bounded Task Flow #1 called Bounded Task Flow #2. Bounded Task Flow #1 now calls a task flow return activity (set to commit), saving the value of X to the database. The value of Y remains unchanged because Bounded Task #1's transaction did not modify the value of Y.

On returning to the unbounded task flow and refreshing the values of X and Y from the database, the updated values of 30 and 40 are returned.

Figure 24-5 Completely Separate Transactions

This image is described in the surrounding text

24.3.3.2 Guaranteeing a Called Bounded Task Joins an Existing Transaction

Figure 24-6 shows two bounded task flows in a configuration that guarantees that the second bounded task flow joins the transaction of the first bounded task flow that calls it. An example scenario where such an implementation may be appropriate is if your application creates invoices and, separately, the individual lines of the invoice. When creating an invoice line, it does not make sense that an invoice line is created without the parent invoice that is to contain the invoice line. If you were to build two separate task flows to create the invoice and invoice lines, the invoice line task flow needs to enforce that it wants to join a transaction of the calling task flow, in this case the invoice task flow, rather than creating a separate transaction.

Figure 24-6 illustrates how the above use case can be addressed by configuring an unbounded task flow that calls a bounded task flow (Bounded Task Flow #1). The unbounded task flow has its own data control frame (Data Control Frame #1). Bounded Task Flow #1 starts a transaction and also has a data control frame (Data Control Frame #0) because it is configured as follows:

  • A data-control-scope value of isolated

  • Always Begin New Transaction

Bounded Task Flow #1 exposes attributes from two different view objects as data control fields (viewObject1.X and viewObject2.Y). X and Y are initially set to 10 and 20 respectively. The end user, while accessing Bounded Task Flow #1, updates X from 10 to 30 and leaves Y unchanged. This marks Task Flow Transaction A associated with Data Control Frame #1 as changed or "dirty". That is, there are changes in the transaction that must be committed or rolled back.

Bounded Task Flow #1 calls Bounded Task Flow #2. Bounded Task Flow #2 is configured as follows:

  • A data-control-scope value of shared

  • Always Use Existing Transaction

Because of this configuration, no new data control frames are created. Bounded Task Flow #2 uses the same data control frame (Data Control Frame #1) as Bounded Task Flow #1. The changes applied to X in Bounded Task Flow #1 are visible to Bounded Task Flow #2. Updates made to Y in Bounded Task Flow #2 are visible to Bounded Task Flow #1 when it receives control back from Bounded Task Flow #2 after it executes a task flow return activity that specifies a commit. This update to Y is visible in Bounded Task Flow #1 because of the shared data control scope, not because of the commit option that the task flow return activity of Bounded Task Flow #2 specifies.

Remember that the commit and rollback options of a task flow return activity are only valid for the bounded task flow that starts a transaction. That is why the commit of Bounded Task Flow #1´s task flow return activity finalizes changes in the database and not Bounded Task Flow #2.

Figure 24-6 Guaranteed Joined Transactions

This image is described in the surrounding text

24.3.3.3 Using an Existing Transaction if Possible

Section 24.3.3.2, "Guaranteeing a Called Bounded Task Joins an Existing Transaction," described how to configure a bounded task flow to call a second bounded task flow and guarantee that the called bounded task flow joins the transaction of the calling bounded task flow. The effect of changing the configuration of the calling bounded task flow to have:

  • A data-control-scope value of isolated

  • <No Controller Transaction>

while leaving the called bounded task flow unchanged is to stop execution of the bounded task flows and throw the following error message at runtime:

ADFC-00006: Existing transaction is required when calling task flow ''{0}''

The above scenario illustrates the benefit of configuring the called bounded task flow as follows:

  • A data-control-scope value of shared

  • Use Existing Transaction if Possible

This latter configuration means that the called bounded task flow creates a transaction if the calling bounded task flow has not created a transaction.

Another configuration option for a called bounded task that guarantees it creates its own transaction is to configure it as follows:

  • A data-control-scope value of isolated

  • Use Existing Transaction if Possible

This causes the called bounded task flow to create its own transaction regardless of the transaction options that you configure for the calling bounded task flow. The effect is the same as if you set the called bounded task flow to use Always Begin New Transaction.

24.3.4 What You May Need to Know About ADF Business Component Database Connections and Task Flow Transaction Options

ADF Controller shares the ADF Business Component application modules' database connections in an application that has more than one root application module (and each application module has a database connection) where task flow transaction options combine to share connections. That is, you configured a set of chained task flows in your application that have a have a data-control-scope value of shared in combination with the following transaction options:

  • Always Begin New Transaction

  • Always Use Existing Transaction

  • Use Existing Transaction if Possible

This implementation helps to reduce the number of database connections that each user creates and, as a result, makes the application more scalable. This is particularly useful when you add task flows and root application modules to your application through ADF Library JARs.

A set of chained task flows is where task flows call other task flows so that your application contains a chain with two or more task flows. For example, in Figure 24-2 the unbounded task flow UTF1 calls the bounded task flow BTF1 that in turn calls the bounded task flow BTF2, and so on.

Note:

Remember to configure your application's chained task flows to use a data-control-scope value of isolated if you do not want root application modules to share database connections.

However, you may want to configure different behavior where you want to have separate root application modules connect to different data sources within the same ADF Model project. For example, you may want to show data from two different database systems or you need to connect to two different schemas in the same database.

To implement this last scenario (have the root application modules maintain their own database connections), you set the transaction property's value to No Controller Transaction (the default value) for the task flows in your application. This makes sure that each root application module manages its own database connection in isolation and that the ADF Controller does not manage the transaction behavior of the ADF Business Components.

24.4 Reentering Bounded Task Flows

To deal with cases in which the end user clicks the back button to navigate back into a bounded task flow that was already exited, you can specify task-flow-reentry options for the bounded task flow. These options specify whether a page in the bounded task flow can be reentered.

Upon reentry, bounded task flow input parameters are evaluated using the current state of the application, not the application state existing at the time of the original bounded task flow entry.

24.4.1 How to Set Reentry Behavior

You can set reentry behavior on a bounded task flow by specifying task-flow-reentry options.

Before you begin:

It may be helpful to have an understanding of what reentry options you can configure for a bounded task flow. For more information, see Section 24.4, "Reentering Bounded Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To set reentry behavior:

  1. In the Applications window, double-click the bounded task flow.

  2. In the editor window, click the Overview tab.

  3. In the overview editor, click the Behavior navigation tab.

  4. In the Behavior page, choose one of the following from the Task Flow Reentry dropdown list:

    • reentry-allowed: Reentry is allowed on any view activity within the bounded task flow.

    • reentry-not-allowed: Reentry of the bounded task flow is not allowed. If you specify reentry-not-allowed on a bounded task flow, an end user can still click the browser back button and return to a page within the bounded task flow. However, if the user does anything on the page such as clicking a button, an exception (for example, InvalidTaskFlowReentry) is thrown indicating the bounded task flow was reentered improperly. The actual reentry condition is identified upon the submit of the reentered page.

      You can set up an exception handler to display the exception and route control flow in order to navigate to the default activity of the called bounded task flow. If the bounded task flow was not called from another bounded task flow, a normal web error is posted and handled as specified in the web.xml file.

    • reentry-outcome-dependent: Reentry of a bounded task flow using the browser back button is dependent on the outcome that was received when the same bounded task flow was previously exited via task flow return activities. If specified, any task flow return activities on the called bounded task flow must also specify either reentry-allowed or reentry-not-allowed to define outcome-dependent reentry behavior.

      If you choose this option, the user can navigate to a task flow using a back button based solely on how the user originally exited the task flow. For example, a task flow representing a shopping cart can be reentered if the user exited by canceling an order, but not if the user exited by completing the order.

24.4.2 How to Set Outcome-Dependent Options

You can set outcome-dependent options on bounded task flows that have specified the reentry-outcome-dependent option, as described in Section 24.4.1, "How to Set Reentry Behavior."

Before you begin:

It may be helpful to have an understanding of what reentry options you can configure for a bounded task flow. For more information, see Section 24.4, "Reentering Bounded Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To set outcome-dependent options:

  1. In the Applications window, double-click the bounded task flow.

  2. In the task flow diagram for the bounded task flow, select the task flow return activity.

    For information about adding a task flow return activity, see Section 21.7, "Using Task Flow Return Activities."

  3. In the Properties window, expand the General section and enter the name of a literal outcome, for example, success or failure in the Name field.

  4. Expand the Behavior section and choose one of the following options in the Reentry dropdown list:

    • reentry-allowed: Reentry is allowed on any view activity within the bounded task flow.

    • reentry-not-allowed: Reentry of the bounded task flow is not allowed. If you specify reentry-not-allowed on a bounded task flow, an end user can still click the browser back button and return to a page within the bounded task flow. However, if the user does anything on the page such as clicking a button, an exception (for example, InvalidTaskFlowReentry) is thrown indicating the bounded task flow was reentered improperly. The actual reentry condition is identified upon the submit of the reentered page.

      You can set up an exception handler to display the exception and route control flow in order to navigate to the default activity of the called bounded task flow. If the bounded task flow was not called from another bounded task flow, a normal web error is posted and handled as specified in the web.xml file.

24.4.3 What Happens When You Configure a Bounded Task Flow for Reentry

JDeveloper updates the task flow's metadata with the configuration options that you specify for reentry. Example 24-3 shows a task flow that has been configured to allow reentry based on a specific outcome.

Example 24-3 Task Flow Configured for Outcome Dependent Reentry

<task-flow-definition id="task-flow-definition1">
    <default-activity>view1</default-activity>
    <task-flow-reentry>
      <reentry-outcome-dependent/>
    </task-flow-reentry>
    <view id="view1">
      <page>/page1.jsf</page>
    </view>
    <task-flow-return id="taskFlowReturn1">
      <outcome>
        <name>taskFlowReturn1</name>
        <reentry-allowed/>
      </outcome>
    </task-flow-return>
</task-flow-definition>

At runtime, the following events occur to a task flow that is configured to allow reentry:

  • The task flow is reentered if the user invokes a component that, in turn, invokes a HTTP POST or GET method.

  • The task flow's managed bean values in pageFlow scope are not restored to the values they had when the task flow exited.

  • If the reentered task flow defines input parameters, as described in Chapter 22, "Using Parameters in Task Flows," their values are recreated using the current state of the parent task flow at the time that the task flow is reentered.

24.5 Handling Exceptions in Task Flows

During execution of a task flow, exceptions can occur that may require some kind of exception handling, for example:

  • A method call activity throws an exception.

  • A custom method you have written as a task flow initializer or finalizer throws an exception.

  • A user is not authorized to execute the activity.

To handle exceptions thrown from an activity or caused by some other type of ADF Controller error, you can designate one activity in a bounded or unbounded task flow as an exception handler.

When a task flow throws an exception, control flow passes to the designated exception handling activity. For example, the exception handling activity might be a view activity that displays an error message. Alternatively, the activity might be a router activity that passes control flow to a method based on an EL expression that evaluates the type of exception. For example:

#{controllerContext.currentViewPort.exceptionData.class.name == 'oracle.adf.controller.ControllerException'}

After control flow passes to the exception handling activity, flow from the exception handling activity uses standard control flow rules. For example, you designate a router activity as the exception handling activity. At runtime, the task flow passes control to the exception handling activity (in this example, a router activity) in response to an exception. In addition to designating the router activity as an exception handler, you can define task flow control cases that the router invokes based on the type of exception that it has to handle. This allows you to manage your end user's application session gracefully when an exception occurs. For more information, see Section 20.1.3, "About Control Flows."

You can optionally specify an exception handler for both bounded and unbounded task flows. Each task flow can have only a single exception handler. However, a task flow called from another task flow can have a different exception handler from that of the caller. In addition, a region on a page can have a different exception handler from that of the task flow containing the page. The exception handler activity can be any supported activity type, for example, a view or router activity.

If a bounded task flow does not have a designated exception handler activity, control passes to an exception handler activity in a calling bounded task flow, if there is a calling task flow and if it contains an exception handler activity. The exception is propagated up the task flow stack until either an exception handler activity or the top-level unbounded task flow is reached. If no exception handler is found, the exception is propagated to the web container.

If a bounded task flow does have a designated exception handler activity, make sure the exception handler activity leaves the application in a valid state after it handles an exception. One way to do this is to redirect to a view activity in the same task flow after the exception handler activity.

Other modules, such as ADF Model, also provide exception handling capabilities. In certain scenarios this can determine the way that your application handles exceptions. For example, a databound method activity is a method activity that has a page definition and an EL expression with the following format:

#{bindings.somebindingname.execute}

where somebindingname is a method binding defined in the page definition.

An exception thrown by any type of binding is caught by ADF Model which calls the reportException() method and stores the exception in the binding container. Later, when the page renders, the error displays in the page.

When a method activity invokes a method binding, there is no page to display an error that the exception raises because the exception occurs during navigation between two pages. To make the application aware of an error, Oracle ADF rethrows the exception so that it is caught by ADF Controller's exception handler mechanism that navigates to an exception handler activity if one exists.

Keep this in mind, particularly if you decide to override methods, such as the reportException() method, described in Section 18.3, "Customizing Error Handling," because in that scenario both ADF Controller and ADF Model exception handlers will be called.

24.5.1 How to Designate an Activity as an Exception Handler

You can designate an exception handler activity for a bounded task flow running as an ADF region. If an exception occurs in the bounded task flow and it is not handled by the task flow's exception handler, the exception is not propagated up the task flow stack of the parent page. Instead, it becomes an unhandled exception.

Before you begin:

It may be helpful to have an understanding of what exception handling options you can configure for a task flow. For more information, see Section 24.5, "Handling Exceptions in Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To designate an activity as an exception handler for a task flow:

  1. In the Applications window, double-click the task flow where you want to designate an activity as an exception handler.

  2. In the task flow diagram, right-click the activity and choose Mark Activity > Exception Handler.

    A red exclamation point is superimposed on the activity in the task flow to indicate that it is an exception handler. Figure 24-7 shows an example.

    Figure 24-7 Example of an Activity Designated as an Exception Handler

    An activity designated as an exception handler.
  3. To unmark the activity, right-click the activity in the task flow diagram, and choose Unmark Activity > Exception Handler.

    If you mark an activity as an exception handler in a task flow that already has a designated exception handler, the old handler is unmarked.

24.5.2 What Happens When You Designate an Activity as an Exception Handler

After you designate an activity to be the exception handling activity for a task flow, JDeveloper updates the task flow metadata with an <exception-handler> element that specifies the ID of the activity, as shown in Example 24-4.

Example 24-4 <exception-handler> element

<exception-handler>activityID</exception-handler>

24.5.3 How to Designate Custom Code as an Exception Handler

Rather than designate a task flow activity as the activity to invoke, you can write custom code to invoke when a task flow throws an exception. This requires you to:

  • Write a Java class that extends the class ExceptionHandler from the following package:

    oracle.adf.view.rich.context.ExceptionHandler

  • Register the Java class that you write as a service in the .adf\META-INF directory of your Fusion web application

Example 24-5 shows custom code that checks if an exception thrown by a task flow corresponds to a particular type of error message (ADF_FACES-30108). If it does, the custom code redirects the task flow to the faces/SessionExpired.jsf page.

Example 24-5 Custom Code for an Exception Handler

package oracle.summit.frmwkext; 

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;
import oracle.adf.view.rich.context.ExceptionHandler;
 
public class CustomExceptionHandler extends ExceptionHandler {
 
    public CustomExceptionHandler() {
        super();
    }
 
    public void handleException(FacesContext facesContext, Throwable throwable,
                                PhaseId phaseId) throws Throwable {
        
        String error_message;
        error_message = throwable.getMessage();
        
        if (error_message != null &&
            error_message.indexOf("ADF_FACES-30108") > -1) {
            ExternalContext ectx = facesContext.getExternalContext();
            ectx.redirect("faces/SessionExpired.jsf");
        }
 
        else {
            //Code to execute if the if condition is not met
            throw Throwable
        }
    }
}

For information about the APIs that you can use to write custom code, see the following reference documents:

Before you begin:

It may be helpful to have an understanding of what exception handling options you can configure for a task flow. For more information, see Section 24.5, "Handling Exceptions in Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To designate custom code as an exception handler:

  1. In the .adf\META-INF directory of your application, create a directory named services so that you have the following directory path:

    application_root\.adf\META-INF\services

    where application_root refers to the root directory of application.

  2. Create a text file named oracle.adf.view.rich.context.ExceptionHandler in the services folder.

  3. Write the package name and class name of the custom code that you wrote to handle exceptions in the text file named oracle.adf.view.rich.context.ExceptionHandler.

    For example, if you want to register the custom code in Example 24-5, write the following:

    oracle.summit.frmwkext.CustomExceptionHandler

  4. Save and close the text file.

24.5.4 What Happens When You Designate Custom Code as an Exception Handler

At runtime, the task flow passes control to the custom code that you specified if the task flow throws an exception.

24.5.5 What You May Need to Know About Handling Exceptions During Transactions

Designate an exception handling activity for a bounded task flow that is enabled to run as a transaction. A Fusion web application attempts to commit a transaction if you set commit as the value for a task flow return activity's End Transaction property on a bounded task flow that runs as a transaction. If an exception occurs when the Fusion web application attempts to commit a transaction, the exception handling activity receives control and provides the end user with an opportunity to correct the exception. You can use the exception handling activity (for example, a view activity) to display a warning message to an end user with information about how to correct the exception and how to recommit the transaction. For information about enabling a bounded task flow as a transaction and setting commit as a value for the End Transaction property, see Section 24.3.1, "How to Enable Transactions in a Bounded Task Flow."

24.5.6 What You May Need to Know About Handling Validation Errors

For validation errors on a JSF page, you can rely on standard JSF to attach validator error messages to specific components on a page or to the whole page. A component-level validator typically attaches an error message inline with the specific UI component. There is no need to pass control to an exception handler activity.

In addition, your application should define validation logic on data controls that are executed during the Validate Model Updates phase of the JSF lifecycle. In this way, data errors are found as they are submitted to the server without waiting until attempting the final commit.

Validations done during the Validate Model Updates phase typically do not have direct access to the UI components because the intention is to validate the model after the model has been updated. These validations are often things like checking to see whether dependent fields are synchronized. In these cases, the error message is usually attached to the whole page, which this logic can access.

You should attach errors detected during the Validate Model Updates phase to the JSF page, and call FacesContext.renderResponse(). This signals that following this phase, the current (submitting) page should be rendered showing the attached error messages. There is no need to pass control to an exception handler activity.

For more information, see Chapter 12, "Implementing Validation and Business Rules Programmatically."

24.6 Configuring Your Application to Use Save Points

Before you can add save points to a task flow, as described in Section 24.7, "Using Save Points in Task Flows," and configure related functionality, you need to make sure that the Fusion web application allows save points. To do this, you define a value for the <savepoint-datasource> element in the adf-config.xml file to specify the JNDI name for the data source that contains the save points' database table. You may also need to run a SQL script (adfc_create_save_point_table.sql), as described in Section 24.6.3, "What You May Need to Know About the Database Table for Save Points," to create the database table that stores save points. Once your Fusion web application starts using save points, you can use another SQL script (adfc_cleanup_save_point_table.sql) to delete expired save points.

24.6.1 How to Configure Your Fusion Web Application to Use Save Points

You define a value for the <savepoint-datasource> element in your application's adf-config.xml file to specify the JNDI name for the data source that contains the save points' database table. Optionally, you can also specify an expiration time for save points.

Before you begin:

It may be helpful to have an understanding of what save point options you can configure for a task flow. For more information, see Section 24.6, "Configuring Your Application to Use Save Points."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To configure your Fusion web application to allow save points:

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

  2. In the overview editor, click the Controller navigation tab and then expand the Savepoints section to write a value for the Data Source property that specifies the JNDI name for the data source that contains the database table for save points.

    For example, write the following:

    java:comp/env/jdbc/Connection1DS

    where Connection1 is the JDeveloper connection name.

  3. Optionally, write a value in seconds for the Expiration property to specify the time between when a task flow creates a save point and when the save point manager removes it. The default value is 86400 seconds.

    For more information, see Section 24.7.9, "What You May Need to Know About the Time-to-Live Period for a Save Point."

  4. Save the adf-config.xml file.

24.6.2 What Happens When You Configure a Fusion Web Application to Use Save Points

JDeveloper generates an entry, similar to Example 24-6, in the adf-config.xml file to specify the JNDI name for the data source that contains the save points' database table.

Example 24-6 Save Point Data Source Definition in adf-config.xml

<adf-controller-config xmlns="http://xmlns.oracle.com/adf/controller/config">
    ...
    <savepoint-datasource>
      java:comp/env/jdbc/Connection1DS
    </savepoint-datasource>
    <savepoint-expiration>
      86399
    </savepoint-expiration>
  </adf-controller-config>

For more information about the adf-config.xml file, see Section A.11, "adf-config.xml."

24.6.3 What You May Need to Know About the Database Table for Save Points

A database table named ORADFCSAVPT stores save points. If this database table does not exist, it is created the first time that a save point is created if your Fusion web application has the necessary permissions to create a database table. If your Fusion web application does not have the necessary permissions, you or an administrator with the necessary permissions can use SQL scripts to create and maintain the ORADFCSAVPT database table. These SQL scripts are:

  • adfc_cleanup_save_point_table.sql

    Each save point in the ORADFCSAVPT database table has an expiration date. Use this script to delete save points that have passed their expiration date.

  • adfc_create_save_point_table.sql

    Use this script to create the ORADFCSAVPT database table that stores save points.

You can find these SQL scripts in the following directory of your JDeveloper installation:

jdev_install\oracle_common\common\sql

24.7 Using Save Points in Task Flows

You can configure a task flow to capture the state of a Fusion web application at a particular instance creating what is called a save point. This allows you to save application state if, for example, a user leaves a page without finalizing it. The application state can be restored at a later point.

Table 24-2 describes what information a save point captures.

Table 24-2 Saved Application State Information

Saved State Information Description

User Interface State

UI state of the current page, including selected tabs, selected checkboxes, selected table rows, and table column sort order.

This state assumes the end user cannot select the browser back button on save point restore.

Managed Beans

State information saved in several possible memory scopes, including session and page flow scope. The managed beans must be serializable in order to be saved. If you have page flow scope beans that are not serializable and you attempt to create a save point, a runtime exception occurs.

Request scope is not supported since its lifespan is a single HTTP request and its lifespan cannot be used to store cross request application state.

Save points will not save and restore application-scoped managed beans since they are not passivated in failover scenarios. Therefore, the application is always responsible for making sure that all required application-scoped state is available.

Potential naming conflicts for managed beans already existing within the session scope at restore time will not occur because multiple managed beans using the same name should not be implemented within an application.

Navigation State

Task flow call stack, which ADF Controller maintains as one task flow calls another at runtime.

The task flow call stack tracks where the end user is in the application and the navigation path for getting there. The task flow stack also identifies the starting point of any persisted data transactions originated for the end user.

ADF Model State

Fusion web applications use ADF Model to represent the persisted data model and business logic service providers. The ADF Model holds any data model updates made from when the current bounded task flow begins. The model layer determines any limits on the saved state lifetime. For more information, see Chapter 49, "Using State Management in a Fusion Web Application."


You add a method call activity to a bounded task flow that invokes a createSavePoint method to create save points. Later, you use a save point restore activity to restore application state and data associated with the created save points.

The same save point can be used if a user repeatedly performs a save for later on a task flow instance that executes in one session within the same browser window. The new save point overwrites the existing save point when a user performs a save for later following navigation from page to page in a task flow. For more information about restoring a save point, see Section 24.7.3, "How to Restore a Save Point."

You can specify the createSavePoint method exposed by the currentViewPort node of ADF Controller Objects in the Expression Builder. Alternatively, you can write a custom method that updates the save point with the values of attributes you specify in your custom method, as illustrated in Example 24-7.

Example 24-7 Example Custom Method for Creating a Save Point

package viewController;
 
import java.io.Serializable;
 
import oracle.adf.controller.ControllerContext;
import oracle.adf.controller.savepoint.SavePointManager;
 
public class SaveForLater implements Serializable {
    public SaveForLater() {
        super();
    }
 
    public String saveTaskFlow() {
        ControllerContext cc = ControllerContext.getInstance();
        if (cc != null) {
            SavePointManager mgr = cc.getSavePointManager();
            if (mgr != null) {
                String id = mgr.createSavePoint();
                System.out.println("Save point is being set " + id);
            ...

The SavePointListener interface exposes methods that notify clients when save point events occur. The following package contains the SavePointListener interface:

oracle.adf.controller.savepoint

Note:

All save points created inside a bounded task flow are deleted when the bounded task flow exits.

24.7.1 How to Add a Save Point to a Task Flow

You drag and drop a method call activity to the task flow diagram and configure it to invoke the createSavePoint method or to invoke a custom method if you created one.

Before you begin:

It may be helpful to have an understanding of what save point options you can configure for a task flow. For more information, see Section 24.7, "Using Save Points in Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

You will need to complete this task:

Confirm that your Fusion web application leaves the value of the jbo.locking.mode property set to the default value optimistic. This is required if you use a save point in a Fusion web application. The value pessimistic causes an old session to lock until the session has timed out. In pessimistic mode, if you run an application and change data without committing changes to the database, you may get an error when you create a save point and try to restore it at a later point. For information about the jbo.locking.mode property, see Section 49.11.1, "How to Confirm That Applications Use Optimistic Locking."

To add a save point to a task flow:

  1. In the Applications window, double-click the bounded task flow where you want to add a save point.

  2. In the ADF Task Flow page of the Components window, from the Component panel, in the Activities group, drag and drop a Method Call onto the diagram.

  3. In the Properties window, expand the General node and write an EL expression in the Method field to specify the save point method that the method call activity invokes. If needed, select Method Expression Builder in the dropdown menu that you invoke from the icon that appears when you hover over the property field.

    If you use the Expression Builder to specify the createSavePoint method exposed by the currentViewPort node of ADF Controller Objects, the resulting EL expression is similar to the following:

    #{controllerContext.currentViewPort.createSavePoint}

  4. Use a control flow to connect the method call activity with other activities in the bounded task flow.

    For more information, see Section 20.4.1, "How to Add a Control Flow Rule to a Task Flow."

  5. Optionally, configure save point options in the Fusion web application's adf-config.xml file to determine, for example, if implicit save points can be created for the application.

    For more information, see Section 24.7.7, "How to Enable Implicit Save Points."

24.7.2 What Happens When You Add Save Points to a Task Flow

JDeveloper generates entries similar to those shown in Example 24-8 in the task flow's source file when you configure a method call activity to invoke the createSavePoint method.

Example 24-8 Method Call Metadata to Invoke the createSavePoint Method

<method-call id="methodCall1">
      <method id="__3">#{controllerContext.currentViewPort.createSavePoint}</method>
</method-call>

24.7.3 How to Restore a Save Point

Use the save point restore activity to restore a previously persisted save point for an application. The save point restore activity uses the save point that was originally created by invoking the createSavePoint method to identify the save point to restore.

You can obtain a list of the current persisted save points with createSavePoint. However, ADF Controller does not determine which save points to restore. A user must select the save point from a list or the application developer must select it programmatically. The savepoint ID is then passed to a save point restore activity to perform the restore.

Before you begin:

It may be helpful to have an understanding of what save point options you can configure for a task flow. For more information, see Section 24.7, "Using Save Points in Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To add a save point restore activity to a bounded or unbounded task flow:

  1. In the Applications window, double-click the task flow where you want to add the save point restore activity.

  2. In the ADF Task Flow page of the Components window, from the Components panel, in the Activities group, drag and drop a Save Point Restore onto the diagram.

  3. In the Properties window, expand the General section and write an EL expression in the Save Point ID field that, when evaluated, retrieves the save point that was originally created when the createSavePoint method was invoked.

    If you use the Expression Builder to specify the getSavePoint method of ADF Controller Objects, the resulting EL expression is similar to the following:

    #{SessionScope.myBean.savepointID}

24.7.4 What Happens When You Restore a Save Point

JDeveloper generates entries similar to Example 24-9 in the task flow's source file when you add a save point restore activity that gets a save point ID.

Example 24-9 Metadata for a Save Point Restore Activity in a Task Flow

<save-point-restore id="savePointRestore1">
      <save-point-id id="__4">#{sessionScope.myBean.savepointID}</save-point-id>
</save-point-restore>

24.7.5 How to Use the Save Point Restore Finalizer

When using the save point restore activity, you may need to invoke application-specific logic as part of restoring the application state. You can write an EL expression for the Save Point Restore Finalizer property of a bounded task flow that specifies a finalizer method. The bounded task flow invokes the specified method after the task flow's state has been restored. It performs any necessary logic to make sure that the application's state is correct before proceeding with the restore.

Before you begin:

It may be helpful to have an understanding of what save point options you can configure for a task flow. For more information, see Section 24.7, "Using Save Points in Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To use the save point restore finalizer:

  1. In the Applications window, double-click the bounded task flow that you want to use a save point restore finalizer.

  2. In the Structure window, right-click the node for the bounded task flow (task-flow-definition) and choose Go to Properties.

  3. In the Properties window, expand the General section, and select Expression Builder in the dropdown list that you invoke from the icon that appears when you hover over the Save Point Restore Finalizer property field.

  4. Write an EL expression that specifies the finalizer method to invoke.

24.7.6 What Happens When a Task Flow Invokes a Save Point Restore Finalizer

JDeveloper generates entries similar to Example 24-10 in the task flow's source file when you write an EL expression for the Save Point Restore Finalizer property.

Example 24-10 Metadata to Invoke a Save Point Restore Finalizer

<task-flow-definition id="task-flow-definition1">
    <save-point-restore-finalizer id="__2">#{sessionScope.MyBean.invokeFinalizer}
    </save-point-restore-finalizer>
</task-flow-definition>

24.7.7 How to Enable Implicit Save Points

A save point in a task flow can be categorized as implicit or explicit. An explicit save point requires an end user action before a bounded or unbounded task flow creates a save point. For example, an end user clicks a button that invokes a method call activity that, in turn, creates a save point.

An implicit save point can only originate from a bounded task flow. It includes everything from when the originating task flow creates a save point. It occurs when data is saved automatically because:

  • A session times out due to end user inactivity.

  • An end user logs out without saving the data.

  • An end user closes the only browser window, thus logging out of the application.

  • An end user navigates away from the current application using control flow rules (for example, uses a link component to go to an external URL) and having unsaved data.

Enabling implicit save points requires you to add an element to your Fusion web application's adf-config.xml file and to make the bounded task flow critical.

You configure the adf-config.xml file in your application and the bounded task flow(s) for which you want to create implicit save points. Enabling implicit save points involves a performance cost because your Fusion web application has to do extra work that it would otherwise not do. This is why you have to explicitly enable implicit save points in your application and specify the task flows to which it applies.

Before you begin:

It may be helpful to have an understanding of what save point options you can configure for a task flow. For more information, see Section 24.7, "Using Save Points in Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To enable implicit save points:

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

  2. In the overview editor, click the Controller navigation tab and then expand the Savepoints section and select the Enable Implicit Savepoints checkbox.

    JDeveloper generates the following entry in the adf-config.xml file:

    <adf-controller-config xmlns="http://xmlns.oracle.com/adf/controller/config">
        ...
        <enable-implicit-savepoints>true</enable-implicit-savepoints>
    </adf-controller-config>
    

    For more information about the adf-config.xml file, see Section A.9, "adfc-config.xml."

  3. In the Applications window, double-click the bounded task flow.

  4. In the editor window, click the Overview tab.

  5. In the overview editor, click the Behavior navigation tab and select the Critical checkbox.

24.7.8 What You May Need to Know About Enabling Implicit Save Points

If multiple windows are open when the implicit save point is created, a different save point is created for each browser window. This includes everything from the root view port of the browser window on down. You can write an EL expression for the Method property of a method call activity to retrieve the list of implicit save points using the savePointManager node under ADF Controller Objects. The resulting EL expression is similar to the following:

ControllerContext.savePointManager.listSavePointIds

Implicit save points are generated only if a critical task flow is present in any of the page flow stacks for any view port under the current root view port. An implicit save point is not generated if the request is for an ADF Controller resource, such as:

  • Task flow call activity

  • Task flow return activity

  • Save point restore activity

  • A dialog

Implicit save points are deleted when the task flow at the bottom of the stack completes or a new implicit save point is generated, whichever comes earlier.

24.7.9 What You May Need to Know About the Time-to-Live Period for a Save Point

An application-level property (savepoint-expiration) that is defined in the adf-config.xml file determines the period between when a task flow creates a save point and when the save point manager removes it (time-to-live period). The default value is 86400 seconds (24 hours).

You can change the time-to-live period for individual save points by calling the setSavePointTimeToLive method on an instance of SavePointManger from the following package:

oracle.adf.controller.savepoint

An instance of SavePointManager can be obtained as follows:

SavePointManager mgr = ControllerContext.getInstance().getSavePointManager();

Example 24-11 shows the syntax for the setSavePointTimeToLive method.

Example 24-11 Syntax for the setSavePointTimeToLive Method

    public void setSavePointTimeToLive(long timeInSeconds) {
       }

If you supply a value for the setSavePointTimeToLive method argument (timeInSeconds in Example 24-11) equal to or less than zero, the default value is used (86400).

The SavePointManger defines methods that help you manage save points. For example, it defines getSavePoint and removeSavePoint methods that can retrieve and remove save points. Note that the removeSavePoint method does not get called automatically when a save point expires. You must explicitly call the removeSavePoint method to remove save points (including expired save points) from the ORADFCSAVPT database table. Alternatively, Oracle ADF provides a SQL script (adfc_cleanup_save_point_table.sql) that removes expired save points. For more information, see Section 24.6.3, "What You May Need to Know About the Database Table for Save Points."

Consider calling the setSavePointTimeToLive method at the same time that you call the method to create save points, as illustrated in Example 24-7. For more information about the SavePointManger, see the Java API Reference for Oracle ADF Controller.

24.8 Using Train Components in Bounded Task Flows

You can create a task flow as a train. This allows you to create a user interface where you navigate end users through a multistep process. ADF Faces provides the user interface components that render the train functionality in the task flow view activities that appears to the end user. These components are the train and trainButtonBar components. Figure 24-8 shows a runtime view of the edit-customer-task-flow-definition.xml task flow from the Summit ADF task flow sample application. This task flow uses the train and trainButtonBar components to navigate an end user through the task of editing a customer's data.

Figure 24-8 Train and Train Button Bar Components in a Task Flow

Train Component in a Summit Task Flow

The train component in Figure 24-8 renders three train stops. Each stop corresponds to a page fragment in the edit-customer-task-flow-definition.xml task flow where the end user can enter and review information to complete the task of editing a customer's data. Figure 24-8 shows the Address train stop where the end user enters an address for postage. The other stops are:

  • General Information

  • Comments

The Train Button Bar component, also shown in Figure 24-8, is optional and provides additional controls to navigate between the train stops. This component can be used in conjunction with the train component to provide multiple ways to navigate through train stops.

Bounded task flows and task flow templates can make use of these train components if you select the Create Train checkbox on the dialogs provided by JDeveloper to create a bounded task flow or a task flow template. A bounded task flow or a task flow template can render one train only. If you want to use multiple trains, create a separate bounded task flow or task flow template for each train.

Figure 24-9 displays an extract from the design-time view of the task flow where you can see the view activities that render at runtime as train stops in Figure 24-8.

The dotted lines connecting the view activities indicates the sequence in which the end user navigates between the view activities when the view activities render as train stops.

Figure 24-9 Task Flow Configured to Render as a Train

Task Flow Configured to Render as a Train

JDeveloper displays a context menu with options to change the position of the activity when your right-click a view activity or task flow call activity that is configured as a train stop, as illustrated in Figure 24-10.

Figure 24-10 Context Menu to Edit a Train Stop

Context Menu to Edit a Train Stop

Configure a task flow call activity as a train stop when you want to group a number of activities as a train stop or call a child train stop. For example, there are cases when other task flow activities, such as router and method call activities, should be considered part of a train stop along with the corresponding view activity. A method call activity might need to precede a view activity for initialization purposes. When grouped this way, the activities can be performed as a set each time the train stop is visited. For more information, see Section 24.8.3, "Grouping Task Flow Activities to Execute Between Train Stops."

Branching using router activities and control flow cases is supported on the task flow diagram containing the train, as well as in child bounded task flows called from the train.

24.8.1 Creating a Task Flow as a Train

You need to configure a bounded task flow to use train components before you can implement the type of functionality discussed in Section 24.8, "Using Train Components in Bounded Task Flows." Use one of the methods outlined in the following list to configure a bounded task flow to use train components:

  • Select the Create Train checkbox in the dialog that appears when you create a new bounded task flow or task flow template.

    For more information, see Section 20.2, "Creating a Task Flow" or Section 24.9, "Creating Task Flow Templates."

  • Right-click an existing bounded task flow in the diagram and choose Train > Create Train.

  • Open an existing bounded task flow in the overview editor, click the Behavior navigation tab and select the Train checkbox.

Once you have configured the bounded task flow to use train components, you drag and drop the task flow activities that you want to render in the train to the diagram in the bounded task flow.

24.8.1.1 How to Create a Train in a Bounded Task Flow

You drag and drop the task flow activities that you want to render in the train to the diagram for the bounded task flow.

Before you begin:

It may be helpful to have an understanding of the configuration options that you can configure for a train. For more information, see Section 24.8.1, "Creating a Task Flow as a Train."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

You will need to complete this task:

Configure the bounded task flow to use train components, as described in Section 24.8, "Using Train Components in Bounded Task Flows."

To create a train in a bounded task flow:

  1. In the Applications window, double-click the bounded task flow or task flow template where you want to render train stops.

  2. Drag each view activity or JSF page you want to include in the train to the diagram for the bounded task flow.

    • If you drag a JSF page, JDeveloper automatically adds a view activity to the diagram. You drag a JSF page that you want to include from the Applications window to the diagram for the bounded task flow.

    • If you drag a view activity to the diagram, you can double-click it to invoke the dialog to create a new JSF page. To drag a view activity, in the ADF Task Flow page of the Components window, from the Component panel, in the Activities group, drag and drop a View onto the diagram.

    You can reorder the train stop sequence at a later point. For more information, see Section 24.8.4, "Disabling the Sequential Behavior of Train Stops in a Train."

  3. In the diagram for the bounded task flow, double-click each view activity that you want to define as a train stop.

    A dialog appears to create a new JSF page if the view activity is not yet associated with a JSF page. Use the dialog to create a new JSF page.

    If the view activity is already associated with a JSF page, the JSF page opens.

  4. In the ADF Faces page of the Components window, from the General Controls panel, in the Location group, drag a Train, and, optionally, a Train Button Bar component and drop it on the JSF page.

    You must manually add each Train and Train Button Bar component that you want to appear in a task flow view activity. Consider using a page template. For more information, see Section 26.2, "Using Page Templates."

24.8.1.2 What Happens When You Create a Task Flow as a Train

JDeveloper writes the <train/> element to the source file for the bounded task flow or task flow template that you enable as a train, using one of the methods outlined in Section 24.8.1, "Creating a Task Flow as a Train."

JDeveloper writes entries to the JSF page where you add train and trainButtonBar components. Example 24-12 shows code snippets from the GeneralInfo.jsff page fragment in the Summit ADF task flow sample application. Both types of train component bind to instances of the train model object (trainModel).

Example 24-12 Metadata for Train Components in a JSF Page

 <af:train value="#{controllerContext.currentViewPort.taskFlowContext.trainModel}"
         id="t1"/>
  ...
  <af:trainButtonBar value="#{controllerContext.currentViewPort.taskFlowContext.trainModel}"
        id="tbb1"/>

Dotted lines appear between each view activity that you add to the bounded task flow and define as a train stop, as illustrated in Figure 24-9. The dotted lines indicate the order in which the bounded task flow navigates through the train stops. JDeveloper defines the sequence in the order that you add the view activities to the bounded task flow. You can change the sequence. For more information, see Section 24.8.4, "Disabling the Sequential Behavior of Train Stops in a Train." You can also skip a train stop. For more information, see Section 24.8.6, "Configuring a Train to Skip a Train Stop."

24.8.2 Invoking a Child Bounded Task Flow from a Train Stop

An alternative approach to grouping task flow activities in one train stop, as described in Section 24.8.3, "Grouping Task Flow Activities to Execute Between Train Stops," is to create another bounded task flow as a train that you invoke from your current bounded task flow. This bounded task flow is referred to as a child bounded task flow. You configure the parent bounded task flow to invoke it using a task flow call activity. To implement this functionality, you:

  • Create a child bounded task flow as a train

  • Add the task flow activities that you want end users to access from the train stop on the parent bounded task flow to the child bounded task flow

  • Designate a task flow call activity as a train stop in the parent bounded task flow to invoke the child bounded task flow

  • Add a task flow return activity to the child bounded task flow that returns control to the parent bounded task flow once the child bounded task flow finishes execution

Task flow activities in the child bounded task flow execute together regardless of whether the end user visits the train stop for the first time or returns at a later point. Nonview task flow activities in the child bounded task flow typically precede the view activity in the child bounded task flow's flow control. You can invoke a child bounded task flow from a bounded task flow that itself is a child to another bounded task flow.

24.8.2.1 How to Invoke a Child Bounded Task Flow From a Train Stop

You create a bounded task flow as a train, add task flow activities to it, and configure a task flow call activity on the parent bounded task flow to invoke it.

Before you begin:

It may be helpful to have an understanding of the configuration options that you can configure for a child bounded task flow that you invoke from a train. For more information, see Section 24.8.2, "Invoking a Child Bounded Task Flow from a Train Stop."

You may also find it helpful to read about the additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

You will need to complete this task:

Create a bounded task flow as a train. This is a child bounded task flow that is to be invoked from a task flow call activity in the parent task flow. Add the task flow activities that you require to it. For more information, see Section 24.8.1, "Creating a Task Flow as a Train."

To invoke a child bounded task flow from a train stop:

  1. In the Applications window, double-click the bounded task flow that is the child bounded task flow configured as a train.

  2. In the ADF Task Flow page of the Components window, from the ADF Task Flow panel, in the Activities group, drag and drop a Task Flow Return onto the diagram.

  3. Configure the task flow return activity to return control to the parent task flow when the child bounded task flow finishes execution.

    For more information, see Section 21.7, "Using Task Flow Return Activities."

  4. In the Applications window, double-click the parent bounded task flow that is going to invoke the child bounded task flow.

    For more information, see Section 24.8.1, "Creating a Task Flow as a Train."

  5. In the ADF Task Flow page of the Components window, from the ADF Task Flow panel, in the Activities group, drag and drop a Task Flow Call onto the diagram.

  6. Configure the task flow call activity to invoke the child bounded task flow that you configured in Steps 1 to 3.

    For more information, see Section 21.6, "Using Task Flow Call Activities."

24.8.3 Grouping Task Flow Activities to Execute Between Train Stops

You can group task flow activities together to form a single train stop. For example, a train stop that renders as Address at runtime might group together the following task flow activities:

  • defineAddress view activity

  • createAddress method call activity

  • addressDetails view activity

Each time a user visits the runtime Address train stop, the task flow would provide access to the task flow activities listed previously. The defineAddresses view activity renders the train stop and the associated defineAddresses.jsff page fragment. The defineAddresses.jsff page fragment, in turn, exposes a button to invoke the createAddress method call activity. This method call activity validates user input in the Address page and defines an outcome that (optionally) passes control to the addressDetails view activity. The addressDetails view activity renders the Address Information page at runtime where an end user may choose to enter additional addresses.

Figure 24-11 Task Flow Activities Grouped into One Train Stop

Task Flow Activities Grouped into One Train Stop

The train considers all task flow activities that lead from the first nonview activity through the next view activity to be part of the train. Make sure that all task flow activities, except for view and task flow call activities, for the train stop follow the view or task flow call activity that you define as a train stop.

You can also group task flow activities to execute between train stops. Figure 24-12 shows a possible configuration where a method call activity (doSomethingBeforePage2) invokes before control flow passes to page2. The callMethodBeforePage2 wildcard control flow rule passes control to the doSomethingBeforePage2 method call activity. This method call activity defines a fixed outcome (continue) that passes control to the next train stop (page2) in the train.

Figure 24-12 Method Call Activity Between Train Stops

Method Call Activity Between Train Stops

24.8.4 Disabling the Sequential Behavior of Train Stops in a Train

By default, train stops are sequential. This means end users can select a train stop only after visiting the previous train stop in the train. Figure 24-13 shows a train component that a registration task flow renders. End users cannot visit the Payment options and Review train stops until they first visit the Address train stop. All train stops in this train are sequential.

Figure 24-13 Sequential Train Stops in a Task Flow

Sequential Train Stops in Customer Registration Task Flow

You can change this default behavior (make a train stop nonsequential) by configuring the view activity that renders the train stop to make it nonsequential.

24.8.4.1 How to Disable the Sequential Behavior of a Train

You write a value for the task flow view activity's sequential property that evaluates to false at runtime.

Before you begin:

It may be helpful to have an understanding of the configuration options that you can configure for a train. For more information, see Section 24.8, "Using Train Components in Bounded Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To disable the sequential behavior of a train stop:

  1. In the Applications window, double-click the bounded task flow containing the view activity that renders the train stop.

  2. In the diagram for the bounded task flow, select the view activity.

  3. In the Properties window, expand the Train Stop section and write a value in the Sequential field to determine if the train stop is sequential or nonsequential.

    Write false or write an EL expression that resolves to false at runtime to make the train stop nonsequential. For example, write an EL expression similar to the following:

    #{myTrainModel.isSequential}

24.8.4.2 What Happens When You Disable the Sequential Behavior of a Train Stop

JDeveloper writes an entry to the source file for the bounded task flow, as illustrated in Example 24-13.

Example 24-13 Metadata to Disable the Sequential Behavior of a Train Stop

<view id="paymentOptionDetails">
      <page>/account/paymentOptionDetails.jsff</page>
      <train-stop id="__1">
        <sequential>#{myTrainModel.isSequential}</sequential>
      </train-stop>
</view>

Figure 24-14 shows the corresponding runtime view when the value specified for sequential evaluates to false. End users can now navigate directly to payment options by clicking the Payment options train stop.

Figure 24-14 Train with a Nonsequential Train Stop

Train with a Nonsequential Train Stop

24.8.5 Changing the Label of a Train Stop

You can configure a train stop to display a label that you define. The label that you define can be a static value or a value in a resource bundle that you reference using an EL expression, for example. For more information about using localized strings, see the "Internationalizing and Localizing Pages" chapter of Developing Web User Interfaces with Oracle ADF Faces.

24.8.5.1 How to Change the Label of a Train Stop

You change the label of a train stop by configuring a value for the view activity's Display Name property.

Before you begin:

It may be helpful to have an understanding of the configuration options that you can configure for a train. For more information, see Section 24.8, "Using Train Components in Bounded Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To change the label of a train stop:

  1. In the Applications window, double-click the bounded task flow containing the view activity that renders the train stop.

  2. In the diagram for the bounded task flow, select the view activity.

  3. In the Properties window, expand the Description section and write a value in the Display Name to specify the label that the train stop renders at runtime.

    Write a literal value or write an EL expression that references a value in a resource bundle to render at runtime.

24.8.5.2 What Happens When You Change the Label of a Train Stop

JDeveloper writes an entry to the source file for the bounded task flow, as illustrated in Example 24-14 from the edit-customer-task-flow-definition.xml bounded task flow in the Summit ADF task flow sample application.

Example 24-14 Metadata to Change the Label of a Train Stop

<view id="GeneralInfo">  <page>/customers/GeneralInfo.jsff</page>
  <train-stop>
    <display-name>General Information</display-name>
    <sequential>false</sequential>  
  </train-stop></view>

At runtime, the Fusion web application displays the value you specified for the display-name property as the label for the train stop.

24.8.6 Configuring a Train to Skip a Train Stop

You can configure a train so that it skips an individual train stop. At runtime, the Fusion web application disables the train stop that you configure to skip. The end user can only navigate to the next train stop in the train.

Implement this functionality if you want the train to execute at a train stop other than the first train stop. For example, configure train stops 1 and 2 to skip if you want to execute train stop 3 first. Use this approach rather than defining the view activity associated with the train stop as the default activity, as discussed in Section 20.2.3, "What You May Need to Know About the Default Activity in a Bounded Task Flow."

24.8.6.1 How to Configure a Train to Skip a Train Stop

You write a value for the view activity's skip property that evaluates to true at runtime.

Before you begin:

It may be helpful to have an understanding of the configuration options that you can configure for a train. For more information, see Section 24.8, "Using Train Components in Bounded Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To configure a train to skip a train stop:

  1. In the Applications window, double-click the bounded task flow containing the view activity that renders the train stop.

  2. In the diagram for the bounded task flow, select the view activity.

  3. In the Properties window, expand the Train Stop and write a value in the Skip field to determine if the train navigates to the train stop or skips it.

    Write true or write an EL expression that resolves to true at runtime to make the train skip the train stop. For example, write an EL expression similar to the following:

    #{myTrainModel.shouldSkip}

24.8.6.2 What Happens When You Configure a Train to Skip a Train Stop

JDeveloper writes an entry to the source file for the bounded task flow, as illustrated in Example 24-15.

Example 24-15 Metadata to Make a Train Skip a Train Stop

 <view id="defineAddresses">
      <display-name>Address</display-name>
      <page>/account/defineAddresses.jsff</page>
      <train-stop>
        <display-name>Address</display-name>
        <skip>#{myTrainModel.shouldSkip}</skip>
      </train-stop>
 </view>

Example 24-15 shows the corresponding runtime view when the value specified for skip evaluates to true. End users must now navigate to the next train stop in the train (Payment options) if the train is sequential.

Figure 24-15 Train Configured to Skip a Train Stop

Train Configured to Skip a Train Stop

24.9 Creating Task Flow Templates

You can create task flow templates for yourself or other application developers to use as a starting point when creating new bounded task flows. Unbounded task flows cannot be created using task flow templates. A bounded task flow created from a task flow template will have definitions for the same set of task flow activities, control flows, input parameters, and managed beans as the task flow template. For example, Figure 24-16 shows a bounded task flow that has been created from a task flow template. The view1 and view2 view activities plus the goToView2 control flow in this bounded task flow have been defined in the task flow template while the start and view3 view activities have been defined in the bounded task flow itself.

Figure 24-16 Bounded Task Flow Displaying Activities Defined in Task Flow Template

Bounded Task Flow With Activities Defined in Template

An example use case for a task flow template is where you define a task flow activity as an exception handler on a bounded task flow. The task flow activity could be a view activity associated with a page that you display to end users when an exception occurs. Rather than define this view activity in each bounded task flow, you define it in a task flow template and select the task flow template when you create new bounded task flows. For more information about exception handling, see Section 24.5, "Handling Exceptions in Task Flows."

You can base a new task flow template on an existing task flow template. You can also refactor an existing bounded task flow to create a new task flow template. For more information, see Section 20.6.4, "How to Convert Bounded Task Flows."

When you create a bounded task flow or another task flow template based on a task flow template, you can specify that subsequent changes you make to a task flow template be automatically propagated to bounded task flows and templates. To do this, you select the Update the Task Flow When the Template Changes checkbox in the dialog that you use to create a bounded task flow or a template. Subsequent changes that you make to the task flow template (add new view activities, for example) get propagated to the bounded task flows. You can change, update, or disassociate the parent task flow template of a child bounded task flow or task flow template at any point during development of the child.

At runtime, the contents of a child bounded task flow or a child task flow template combine with the contents of the parent task flow template if you selected the Update the Task Flow When the Template Changes checkbox when creating the child. The child task flow and task flow template override the parent task flow template when conflict occurs, even if you selected the Update the Task Flow When the Template Changes checkbox when creating the child task flow or task flow template. For example, you create a parent task flow template to use as a train, as described in Section 24.8, "Using Train Components in Bounded Task Flows," and then create a bounded task flow based on this task flow template. Later, you disable the train component on the parent task flow template. The child task flow overrides the parent task flow template and continues to execute as a train.

Table 24-3 describes in more detail how ADF Controller resolves conflicts between parent task flow templates and child task flows and child task flow templates.

Table 24-3 Conflict Resolution between Parent Templates and Child Task Flows

Bounded Task Flow Metadata Combination Algorithm

Default activity

Child bounded task flow or child task flow template overrides parent task flow template.

Transaction

Child bounded task flow or child task flow template overrides parent task flow template as an entire block of metadata, including all subordinate elements.

Task flow reentry

Child bounded task flow or child task flow template overrides parent task flow template as an entire block of metadata, including all subordinate elements.

Control flow rules

Combination algorithm occurs at the control flow case level, not the control flow rule level. Control flow cases fall into the following categories:

  • Both from action and from outcome specified

  • Only from action specified

  • Only from outcome specified

  • Neither from action nor from outcome specified

Each of these categories is merged additively. The child bounded task flow or template overrides parent task flow template for identical matches within each of the four categories.

Input parameter definitions

Child bounded task flow or child task flow template overrides parent task flow template for identical input parameter definition names.

Return value definitions

Child bounded task flow or child task flow template overrides parent task flow template for identical return value definition names.

Activities

Child bounded task flow or child task flow template overrides parent task flow template for identical activity IDs.

Managed beans

Child bounded task flow or child task flow template overrides parent task flow template for identical managed bean names.

Initializer

Child bounded task flow or child task flow template overrides parent task flow template.

Finalizer

Child bounded task flow or child task flow template overrides parent task flow template.

Critical

Child bounded task flow or child task flow template overrides parent task flow template.

Use page fragments

Child bounded task flow or child task flow template overrides parent task flow template.

Exception handler

Child bounded task flow or child task flow template overrides parent task flow template.

Security - permission

Child bounded task flow or child task flow template overrides parent task flow template.

Privilege maps are additive. Child bounded task flow or child task flow template overrides parent task flow template for identical privilege map operations.

Security - transport guarantee

Child bounded task flow or child task flow template overrides parent task flow template.

Train

Child bounded task flow or child task flow template overrides parent task flow template.


Validations at both design time and runtime verify that the resulting parent-child extension hierarchy does not involve cycles of the same task flow template.

24.9.1 How to Create a Task Flow Template

You create a task flow template by selecting ADF Task Flow Template from the New Gallery.

Before you begin:

It may be helpful to have an understanding of what task flow template options you can configure. For more information, see Section 24.9, "Creating Task Flow Templates."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To create a task flow template:

  1. In the Applications window, right-click the project where you want to create the task flow template and choose New > From Gallery.

  2. In the New Gallery, expand Web Tier, select JSF/Facelets and then ADF Task Flow Template, and click OK.

  3. In the Create ADF Task Flow Template dialog, choose the appropriate options:

    • File Name: Accept the default value proposed by JDeveloper or enter a new file name. The value is used to name the XML source file for the task flow template you create. The source file includes the activities and control flow rules that are in the task flow template. The default name for the XML source file is task-flow-template.xml.

    • Create with Page Fragments: Leave this checkbox selected (the default) if you expect that a bounded task flow based on the template will be used as an ADF region. Clear the checkbox if you want to add JSF pages instead of JSF page fragments to a task flow based on the task flow template.

  4. Click OK.

24.9.2 What Happens When You Create a Task Flow Template

As shown in Example 24-16, an XML file is created each time you create a new task flow template using JDeveloper. You can find the XML file in the Applications window in the location that you specified in the Directory field of the Create ADF Task Flow Template dialog, for example,.../WEB-INF.

The contents of the XML source file for the task flow template can be similar to those of a bounded task flow. One difference is the inclusion of the <task-flow-template> tag.

Example 24-16 Task flow template source file

<?xml version="1.0" encoding="windows-1252" ?>
<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2" id="__1">
  <task-flow-template id="task-flow-template">
     <default-activity>view1</default-activity>
     <view id="view1">view1.jsff</view>
  </task-flow-template>
</adfc-config>

24.9.3 What You May Need to Know About Task Flow Templates

If you use a task flow template that contains bindings, you must change the component IDs of task flows based on the task flow template. Doing this makes sure that the IDs are unique. Task flows generated from the template inherit the same ID as the template. This may cause an exception at runtime. For more information, see Section 26.2.1, "How to Use ADF Data Binding in ADF Page Templates."

If your Fusion web application has configured ADF security, you have to make grants on both the task flow template and task flows that use the template. Usually, the grant on the task flow template is to the anonymous-role application role so that the grant that really matters is on the task flow, but not always. For more information about ADF security, see Section 41, "Enabling ADF Security in a Fusion Web Application."

24.10 Creating a Page Hierarchy Using Task Flows

Creating a page hierarchy is a useful way of organizing the JSF pages in your Fusion web application so that end users can more easily navigate the application. End users access information on the pages by navigating a path of links. Figure 24-17 shows a sample page hierarchy.

Figure 24-17 Page Hierarchy

Page Hierarchy

To navigate this hierarchy, an end user clicks links on each page to drill down or up to another level of the hierarchy. For example, clicking Human Resources on the Fusion App home page displays the Human Resources page hierarchy shown in Figure 24-17. Clicking the link on the Benefits tab displays the page hierarchy shown in Figure 24-18.

Figure 24-18 Benefits Page

Benefits Page

The user can click links on the Benefits page to display other pages, for example, the Medical, Dental or Vision pages. The breadcrumbs on each page indicate where the current page fits in the hierarchy. The user can click each node in a breadcrumb to navigate to other pages in the hierarchy. The bold tab labels match the path to the current page shown by the breadcrumbs.

Pages referenced by view activities in a bounded task flow can also be included in any page hierarchy that you generate. Figure 24-19 shows the runtime view of a page hierarchy that renders view activities referenced by a bounded task flow.

Figure 24-19 Runtime Menu Hierarchy Including a Bounded Task Flow

Runtime Menu Hieararchy Including a Bounded Task Flow

You can use ADF Controller with an XMLMenuModel implementation to create the previously discussed page hierarchies. If you do, JDeveloper generates the following for you:

  • Control flow metadata that determines the view or page to display when an end user selects a menu item

  • An XMLMenuModel metadata file

  • Default navigation widgets such as Previous and Next buttons

  • Breadcrumbs

  • Managed bean configuration

If you decide not to use ADF Controller, you can create the page hierarchy using an XMLMenuModel implementation. For more information about this method of building a page hierarchy, see the "Using a Menu Model to Create a Page Hierarchy" section in Developing Web User Interfaces with Oracle ADF Faces.

24.10.1 How to Create a Page Hierarchy

Create an unbounded task flow or open an existing one. Add view activities or bounded task flows to the unbounded task flow. Each view activity or bounded task flow that you add to the unbounded task flow contains references to pages to appear in the proposed page hierarchy. Use JDeveloper's Create ADF Menu Model dialog to generate an XMLMenuModel metadata file. Organize the item nodes in the generated XMLMenuModel metadata file to create the page hierarchy you want. Connect submenus to parent menus to finalize the hierarchy.

Figure 24-20 shows an example page hierarchy that consists of view activities:

  • The top-level menu (Home Page) is the root parent page. It contains a single tab that links to the Human Resources submenu.

    In JDeveloper, Home Page page is represented as an item node and Human Resources page as a shared node.

  • Human Resources has four tab links to Payroll, Time, Labor, and Benefits pages.

    In this menu, Human Resources is a group node that references child item nodes (Payroll, Time, and Labor) and a shared node (Benefits) that references the Benefits submenu.

  • Benefits is a group node that references child item nodes (Medical, Dental, and Vision) pages.

Figure 24-20 Menu Hierarchy

Menu hierarchy.

Note:

It is possible to create the entire menu hierarchy in one menu model. However, breaking a menu hierarchy into submenus makes maintenance easier. In addition, breaking the menu hierarchy into smaller submenu models enables each separate development organization to develop its own menu. These separate menus can later be combined using shared nodes to create the complete menu hierarchy.

Figure 24-21 shows the corresponding design-time view in JDeveloper of the unbounded and bounded task flows that render the page hierarchy shown in Figure 24-19. The unbounded task flow (adfc-config.xml) contains a view activity (view1) and a task flow call activity (task-flow-definition) that invokes the bounded task flow (task-flow-definition.xml) shown in the lower part of Figure 24-21.

Figure 24-21 Design Time Menu Hierarchy Including a Bounded Task Flow

Design Time Menu Hierarchy Including a Bounded Task Flow

24.10.1.1 How to Create an XMLMenuModel Metadata File

You use JDeveloper's Create ADF Menu Model dialog to generate an XMLMenuModel metadata file once you have defined what menus (unbounded task flows) and nodes (pages) you want to appear in the final page hierarchy.

Before you begin:

It may be helpful to have an understanding of what page hierarchy options you can configure. For more information, see Section 24.10, "Creating a Page Hierarchy Using Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

You will need to complete these tasks:

  1. Create an unbounded task flow for each menu in the final page hierarchy.

    For example, to achieve the page hierarchy illustrated in Figure 24-20, you create two unbounded task flows (Human Resources menu and Benefits menu).

    For more information about creating an unbounded task flow, see Section 20.2.1, "How to Create a Task Flow."

    Tip:

    Prefix the name of the file for unbounded task flows that you create with adfc- to help you to identify the file as the source of an unbounded task flow, as opposed to a bounded task flow.

  2. Add view activities that reference pages to each unbounded task flow. The pages referenced by the view activities correspond to the menu nodes in the menu.

    For example, the Benefits menu contains one group node (benefits) and three item nodes (medical, dental and vision) so you add four view activities to the unbounded task flow for the Benefits menu, as illustrated in Figure 24-22.

    Figure 24-22 View Activities on a Task Flow

    Task Flow View Activity

    Do not add view activities for menus that include other menus using shared nodes. For example, the Human Resources menu in Figure 24-20 has a tab called Benefits that references the Benefits menu using a shared node. The bounded task flow for the Benefits menu already includes a view activity for Benefits so there is no need to add a view activity to the bounded task flow for the Human Resources menu.

    For more information about view activities, see Section 21.2, "Using View Activities."

    Note:

    If the page hierarchy includes pages referenced by a bounded task flow, add a task flow call activity to the unbounded task flow that calls the bounded task flow.

To create the XMLMenuModel metadata file:

  1. In the Applications window, right-click the file(s) for each of the unbounded task flows you created and choose Create ADF Menu Model.

  2. In the Create ADF Menu Model dialog, enter a file name for the XMLMenuModel metadata file and a directory to store it.

  3. Click OK.

24.10.1.2 How to Create a Submenu with a Hierarchy of Group and Child Nodes

You open the XMLMenuModel metadata file you created and convert the item nodes that you want to make group nodes to group nodes. You then create a hierarchy where a group node is a parent to one or more item nodes.

Before you begin:

It may be helpful to have an understanding of what page hierarchy options you can configure. For more information, see Section 24.10, "Creating a Page Hierarchy Using Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To create a submenu with a hierarchy of group and item nodes:

  1. In the Applications window, double-click the XMLMenuModel metadata file.

    An item node appears in the Structure window for each view activity in the unbounded task flow. By default, no hierarchy is defined.

  2. In the Structure window, drag and drop the item nodes to become child nodes of the item node that you are going to convert to a group node.

    Each item node that you convert to a group node must have at least one child item node. For example, to create the menu hierarchy in Figure 24-20, you convert the item node for Benefits to a group node, you drag and drop the item nodes for Medical, Dental, and Vision so that they become child nodes of the Benefit item node.

  3. In the Structure window, right-click the parent item node and choose Convert To groupNode.

  4. In the groupNode Properties dialog, in the id field, enter a new identifier or accept the default value.

    The identifier must be unique among all of the nodes in all of the XMLMenuModel metadata files. It is good practice to specify a value that identifies the node. For example, if you change the Benefits node to a group node, you can update its default ID, itemNode_benefits, to groupNode_benefits.

  5. In the idref field, enter the ID of one of the other nodes in the menu, for example, itemNode_Medical.

    The value you enter can be an ID of a child item node that is a group node or an item node.

  6. Enter or change the existing default value in the label field to match what you want to appear at runtime.

    For example, you might change label_benefits to Benefits.

  7. Accept the rest of the default values in the fields and click Finish

    A Confirm Convert dialog asks if you want to delete the action and focusViewID attributes on the groupNode element. Group nodes do not use these attributes, always click OK

  8. Click OK

24.10.1.3 How to Attach a Menu Hierarchy to Another Menu Hierarchy

You use a shared node element to link two menus together. For example, the Human Resources menu shown in the menu hierarchy in Figure 24-20 contains four submenus (Payroll, Time, Labor, and Benefits). The Benefits submenu is itself a menu with submenu entries. In the XMLMenuModel metadata file for the Human Resources menu, you convert the item node for the Benefits submenu to a shared node. You write an EL expression for an attribute (ref) of the newly created shared node that references the XMLMenuModel metadata file for the Benefits menu.

Before you begin:

It may be helpful to have an understanding of what page hierarchy options you can configure. For more information, see Section 24.10, "Creating a Page Hierarchy Using Task Flows."

You may also find it helpful to read about additional functionality that you can add using other task flow features. For more information, see Section 24.1.2, "Additional Functionality for Complex Task Flows."

To attach a menu hierarchy to another hierarchy using a shared node:

  1. In the Applications window, double-click the XMLMenuModel metadata file for the menu that is going to reference the other menu.

  2. In the Structure window, select a node, right-click and select the appropriate menu options to insert a sharedNode element.

  3. In the Insert sharedNode dialog, in the ref field, enter an EL expression to reference the XMLMenuModel metadata file for the other menu.

  4. Click OK.

    Note:

    If your page hierarchy has more than one unbounded task flow, make sure that the file name for each additional unbounded task flow appears as a value for the <metadata-resources> element in the adfc_config.xml file. For more information, see Section 24.10.2, "What Happens When You Create a Page Hierarchy."

24.10.2 What Happens When You Create a Page Hierarchy

Changes occur in a number of different files when you create a page hierarchy.

Changes to the adfc-config.xml File

When you create a new unbounded task flow, JDeveloper automatically adds a reference in the adfc-config.xml file to the source file for the newly created unbounded task flow. In Example 24-17, adfc-unbounded_tflow.xml is the name of the source file for a newly created unbounded task flow.

Example 24-17 Unbounded task flow referenced by adfc-config.xml

<?xml version="1.0" encoding="windows-1252" ?>
<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2"
             id="__1">
  <metadata-resource id="__2">
     /WEB-INF/adfc-unbounded_tflow.xml
  </metadata-resource>
</adfc-config>

For more information about adfc-config.xml, see Section A.9, "adfc-config.xml."

At runtime, the Fusion web application loads the adfc-config.xml file when it first starts. The adfc-config.xml file can contain:

  • ADF navigation metadata for an unbounded task flow

  • ADF activity metadata for an unbounded task flow

  • Managed bean definitions used by ADF activities

XMLMenuModel Metadata File

JDeveloper generates an XMLMenuModel metadata file with nodes for each of the view activities that you added to the unbounded task flow, as illustrated in Example 24-4.

Example 24-18 Example XMLMenuModel Metadata File

<?xml version="1.0" encoding="windows-1252" ?>
<menu xmlns="http://myfaces.apache.org/trinidad/menu">
  <groupNode id="groupNode_benenfits" label="Benefits" idref="itemNode_medical">
    <itemNode id="itemNode_medical" label="label_medical"
              action="adfMenu_medical" focusViewId="/medical"/>
    <itemNode id="itemNode_dental" label="label_dental" action="adfMenu_dental"
              focusViewId="/dental"/>
    <itemNode id="itemNode_vision" label="label_vision" action="adfMenu_vision"
              focusViewId="/vision"/>
  </groupNode>
</menu>

Diagram for an Unbounded Task Flow

JDeveloper updates the file for the unbounded task flow with the control flow rules and managed beans used to navigate the page hierarchy. Figure 24-23 shows the updated unbounded task flow in the diagrammer that corresponds to the unbounded task flow in Figure 24-22.

Figure 24-23 Updated Unbounded Task Flow

Updated unbounded task flow diagram.