As Published In
Oracle Magazine
January/February 2010

DEVELOPER: Frameworks


The Route to Success

By Steve Muench Oracle Employee ACE

Use task flow routers for conditional navigation.

Task flows in Oracle Application Development Framework (Oracle ADF) enable you to define an application’s control flow. In “Developing a Regional Accent” (Oracle Magazine, November/December 2008), you worked with bounded task flows to create reusable page regions. This column shows how to capture task flow parameter values from the user, invoke model-layer initialization logic when a task flow starts, and perform conditional routing based on method results—all without writing any backing-bean code.

To begin, download the starter workspace at o10frame.zip and ensure that you’re using the studio edition of the Oracle JDeveloper 11.1.1.1 production release, available as a free download at oracle.com/technetwork/jdev. Start by extracting the contents of the o10frame.zip file and opening the FrameworksJanFeb2010.jws workspace in Oracle JDeveloper. The Model project in the workspace defines a base set of Oracle ADF components for working with the data in the EMP table in the SCOTT schema. The ViewController project includes FindEmployees.jspx and three JavaServer Pages (JSP) page fragments used in the find-employee bounded task flow.

Before proceeding, adjust the properties of the scott connection in the Application Resources zone of the Application Navigator until you can successfully test a connection to a SCOTT schema. If you need to create the tables, use the provided CreateDeptEmpTables.sql script.

You’ll complete a simple application that enables the user to enter a search value—an employee number, name, or job—and view the resulting employee details. If the search matches a single employee, the data will appear immediately. If the search identifies two or more matches, the user will be able to pick one of them to view. If no rows match, the user will see a message to that effect.

Using Page Definition Variables

Start by selecting the ViewController project in the Application Navigator and pressing Ctrl + Alt + minus (the keyboard shortcut for Navigate -> Go to File ). When the Go to File dialog box appears, type FE in the search field to narrow the list and then double-click FindEmployees.jspx to open the page in the visual editor. You can see that an inputText field, a Search button, and a decorative box component are already set up on the page.

Select the inputText component, and note in the Property Inspector that the Value property field is empty, indicating that the field is not currently bound to any data value. The value in this field will only be passed along as a parameter to the task flow. You’ll use an Oracle ADF feature called a Page Definition Variable to provide temporary storage for the value, without needing to create a backing-bean class.

Click the Bindings tab of the visual editor to see the page definition. To create a new page definition variable, right-click the variables iterator binding that appears in the Executables box and choose Insert inside variables -> variable . In the Insert variable dialog box, enter SearchStringVar in the Name field and java.lang.String in the Type field and then click OK . Note that the new variable does not appear in the main editing surface of the Bindings tab but that you can see it as a child node of variables in the Structure window.

Next, you’ll create a control binding based on this page definition variable to give the page access to its value. Click the Create control binding (green plus sign) toolbar button in the header of the Bindings box. When the Insert Item dialog box appears, ensure that the category of components is Generic Bindings , select attributeValues in the list of items, and click OK . In the Create Attribute Binding dialog box, select the variables iterator binding for Data Source , select SearchStringVar for Attribute , and click OK . Select the new SearchStringVar1 binding in the Bindings box, and in the Property Inspector, change the id property to SearchString to give the binding a more meaningful name.

Click the Design tab to return to the visual editor, and select the inputText field. In the Property Inspector, click in the Value field and use the menu to the right of the field to choose Expression Builder . In the Expression Builder dialog box, expand the ADF Bindings folder, the bindings node it contains, and the SearchString binding. Scroll down to select the SearchString binding’s inputValue property. Note that a corresponding EL expression appears in the Expression text box above, and then click OK to use that expression. Now the text field is bound to the page definition variable you created, using the attribute binding.

In the Application Navigator, expand the Page Flows folder inside Web Content in the ViewController project. Drag the find-employee task flow, and drop it into the center of the panelGroupLayout (inside the decorative box) that is already on the page. When the Create context menu appears, choose Region to add the bounded task flow to your page as a region. Because the find-employee task flow has a required parameter named searchString , the Edit Task Flow Binding dialog box appears. Enter the same EL expression you used previously— #{bindings.SearchString.inputValue} —into the Input Parameters table’s Value field. This configures the region to get the value of its searchString parameter from the page definition variable the user populates, using the text field you configured earlier. Click OK to create the region.

Using a Wildcard Rule and a Default Router

Now that the containing page is set up, you’ll complete the declarative configuration of the task flow. Double-click the find-employee task flow in the Application Navigator to open it in the editor. The diagram contains four annotations to remind you of the steps required to complete the task flow’s functionality. (After you complete each step, feel free to delete the reminder note.)

Multiple activities will enable the user to complete the task flow, so rather than cluttering up the diagram with many navigation case lines that all connect to the Done task flow return activity, you can keep the diagram readable by creating a wildcard control flow rule. Drag a Wildcard Control Flow Rule from the Component Palette (select View -> Component Palette , if necessary), and drop it onto the diagram close to the existing Done activity. Accept the default name, *, by pressing Enter . Next, select the Control Flow Case tool in the Component Palette. First click the wildcard rule icon and then the Done activity to connect them. When the box for assigning a name to the control flow case appears, enter Done and press Enter . You can think of the flow as this: From wherever we might be, if the outcome is Done, we’ll come here next .

Next you’ll configure a router activity as the default activity in the task flow to perform conditional handling of the passed-in parameters. If the parameter value is not null, your router will navigate to the initializeTaskFlow method call activity to perform the necessary model-layer setup before showing the first view activity. If the parameter value is null, the router will go directly to the Done activity to complete the task flow without performing any work.

To create a router activity, drag a Router from the Component Palette and drop it onto the diagram near the STEP 2 note. Change the new router’s name to ProcessParameters . To mark the router as the default activity, right-click the router’s icon and choose Mark Activity -> Default Activity . Then select the Control Flow Case tool in the Component Palette. First click the ProcessParameters router activity and then the initializeTaskFlow method call activity to connect them. Name the control flow case Initialize . Select ProcessParameters (the router activity) in the diagram, and use the Property Inspector to set the value of its Default Outcome property to Done —the name of the wildcard rule you created. In the Cases table in the Property Inspector’s General category, click the green plus icon to create a new router case. Enter #{pageFlowScope.searchString != null} as the Expression , and for Outcome select Initialize from the list. Because #{pageFlowScope.searchString} is where the searchString task flow parameter is configured to store its value, this condition will route to the Initialize activity when the parameter’s value is not null.

Initializing a Task Flow with a Client Interface Method

The HRModule application module uses a custom method named initialize FindEmployeeFlow() to encapsulate all the model-layer business logic necessary for initializing the task flow. You’ll expose this method on the client interface, so you can then drag it from the Application Navigator’s Data Controls zone and drop it onto the initializeTask Flow method call activity. This will cause the initializeFindEmployeeFlow() method to be invoked declaratively before the first view activity renders.

Start by double-clicking HRModule in the Model project in the Application Navigator to open it in the editor. Select the editor’s Java page, and then click the pencil icon in the title bar of the Client Interface section. When the Edit Client Interface dialog box appears, select the InitializeFindEmployeeFlow() method in the Available list, click > to shuttle it into the Selected list, and click OK .

To take a closer look at what this method does, click the hyperlink to the right of the Application Module Class label to navigate to the HRModuleImpl class in the code editor. As the comments explain, the method accepts a string argument; sets two view object bind variable values on the EmpView1 view object instance; executes its query; and then returns an integer result to indicate whether zero, one, or multiple rows were retrieved.

To see how the EmpView1 view instance is configured, return to the HRModule editor, navigate to its Data Model page, select the EmpView1 view instance in the Data Model tree on the right, and click the Edit button. In the Edit View Instance dialog box, note that the FindByEmpnoEnameOrJob view criteria is applied to the view instance. As its name implies, that view criteria uses the bind variable values being set in the initialization method to find an employee based on employee number, name, or job. Click Cancel to close the dialog box, and click back on the find-employee task flow editor ( find-employee.xml tab).

Next, you’ll drag the initialize FindEmployeeFlow() method from the Data Controls onto the method call activity in the task flow. Expand the Data Controls section of the Application Navigator. Right-click HRModuleDataControl , and choose Refresh to ensure that the Data Controls reflect the latest changes you’ve made to the model layer. Expand HRModuleDataControl , drag the initializeFindEmployeeFlow() method, and drop it directly onto the initialize TaskFlow method call activity. When the Edit Action Binding dialog box appears, click in the Value field in the Parameters table for the searchString method parameter. Enter the EL expression #{pageFlowScope.searchString} to use the task flow parameter value as the method argument’s value, and click OK . Recall that the initializeFindEmployeeFlow() method returns an integer result.

Next you’ll configure the method call activity to store its result in order to perform conditional routing based on its value. Select the initializeTaskFlow activity. In the Component Palette’s Parameters section (expand the Parameters node, if necessary), set the Return Value property to the EL expression #{pageFlowScope.numRowsFound} to store the method result in a pageFlowScope attribute named numRowsFound.

Routing Based on Method Results

Drag another Router from the Component Palette onto the diagram near the STEP 4 note, and name it RouteByNumRows . Use the Control Flow Case tool to connect the initializeTaskFlow activity to this new router, accepting the default name for the flow case name. Use the same tool again to connect the RouteByNumRows activity to the FoundNone activity, giving the new router activity the name FoundNone . Repeat the process to connect RouteByNumRows to ShowEmployee , naming the new router activity FoundOne , and then repeat one last time to connect RouteByNumRows to SelectEmployee , naming the last router activity FoundMultiple.

Next, configure the RouteBy NumRows router to forward conditionally to the appropriate view activity, based on the method result you stored earlier in the #{pageFlowScope.numRowsFound} attribute. Select the activity, and in the General section of the Property Inspector (expand the General node, if necessary), use the list to set Default Outcome to FoundNone . As you did earlier for the other router, click the green plus icon to add a new router case. Enter an Expression of #{pageFlowScope.numRowsFound == 1} , and choose an Outcome of FoundOne . Repeat to add a second router case with an Expression of #{pageFlowScope.numRowsFound == 2} and an Outcome of FoundMultiple . With the notes deleted and the nodes rearranged a bit, your diagram should resemble Figure 1.

 

figure 1
Figure 1: Task flow with conditional routing


The final two steps are to wire a couple of buttons onto the view activity page fragments to navigate to the Done activity and to configure the Search button on the main page to refresh the region when the button is clicked. 

Next Steps


 READ more Frameworks

READ more about
Oracle JDeveloper and Oracle Application Development Framework
otn.oracle.com/products/jdev
otn.oracle.com/products/jdev/tips/muench/designpatterns
Oracle Fusion Middleware Fusion Developer’s Guide for Oracle Application Development Framework 11g

Oracle Fusion Middleware
download.oracle.com/docs/cd/E12839_01/index.htm
otn.oracle.com/documentation

DOWNLOAD
Oracle JDeveloper 11g
the starter workspace for this column

To complete the first of these tasks, double-click the ShowEmployee view activity to open its page fragment in the visual editor. Select the Done button, and in the Property Inspector, use the list to set its Action property to Done . Return to the find-employee task flow (the find-employee.xml tab), and double-click the SelectEmployee view activity. Select its Cancel button, and set its Action property to Done.

To configure the Search button, return to the FindEmployees.jspx page in the editor (the FindEmployees.jspx tab) and click the Search button. In the Property Inspector, click in the ActionListener property and select Edit from the list at the right. In the Edit Property: ActionListener dialog box, select RegionHelper for Managed Bean and refreshRegionUsingButtonId for Method and then click OK . The method you selected is a helper method on a managed bean named RegionHelper in the ViewController project that refreshes a region in the current page, based on the ID of the button that is being clicked. Because refreshRegion_r1 is the ID value of the Search button, the helper code will refresh the region whose ID is equal to r1, whenever it’s clicked.

Now you’re ready to try out the application. Right-click the FindEmployees.jspx page in the Application Navigator, and choose Run . When the page appears in your browser, enter 7934 into the Search field and click Search . Note that because this search identifies a single employee, the application routes to the page that shows that employee’s details. Next, enter clerk in the Search field and click Search . This time the navigation goes to a page that displays multiple matches and enables you to select the one you want. Finally, enter 9999 or the name of a nonexistent employee and repeat the search. This time you should see the “no matches” page fragment.

Having followed and understood this column’s steps, you’re now well prepared to use Oracle ADF’s declarative task flow capabilities in your own applications. For more information, see Chapter 15, “Working with Task Flow Activities,” in Oracle Fusion Middleware Fusion Developer’s Guide for Oracle Application Development Framework 11g. 


Steve Muench is a consulting product manager for Oracle Jdeveloper and an Oracle ACE. Since 1990 he has developed and supported Oracle tools and XML technologies and continues to evangelize them. Muench coauthored Oracle ADF Developer’s Guide for Forms/4GL Developers (Oracle, 2006), wrote Building Oracle XML Applications (O’Reilly Media, 2000), and shares tips and tricks on Oracle Technology Network and in his Dive into ADF blog.

Send us your comments