Core ADF11: UIShell with Menu Driving a Dynamic Region
By Steven Davelaar on Jul 07, 2011
In this old post in the Core ADF11 series, I explained the various options you have in designing the page and taskflow structure. The preferred approach in my opinion that maximizes flexibility and reusability, is to build the application using bounded taskflows with page fragments. You then have various ways to disclose these task flows to the user. You can use an dynamic tabs as described in this post. You can also embed the taskflows using a dynamic region in a page. The application menu then drives the content of the dynamic region: clicking a menu option will load another taskflow in the dynamic region.
The initial drawback of this approach is that it adds some additional complexity:
- You can no longer use standard JSF navigation with your menu, there are no pages to navigate to, only regions
- The XMLMenuModel, an easy way to define your menu structure in XML, cannot be used as-is. The selected menu entry when using the XMLMenuModel is based on the current page, and in our design, the whole application consists of only one page, the UIShell page.
- The dynamic region taskflow binding should contain a list of all parameters of all taskflows that can be displayed in the dynamic region.
This is a rather ugly design, and the developer of the UIShell page would need to know all the parameters of all taskflows that might be displayed in the dynamic region. A cleaner implementation is to use the parameter map property against the taskflow binding. However, when using the parameter map, you need to do the housekeeping of changed parameter values yourself when you want the taskflow to refresh when parameters change. In other words, just specifying Refresh=ifNeeded on the taskflow binding no longer works because ADF does not detect changes in a parameter map.
Fortunately, you can address this complexity quite easily by creating some simple, yet powerful infrastructure classes that hide most of the complexity from your development team. (The full source of these classes can be found in the sample application, download links are at the bottom of this post)
- A DynamicRegionManager class that keeps track of the current task flow and current parameter map
- A TaskFlowConfigBean for each task flow that contains the actual task flow document path, the task flow parameters and a flag whether the parameter values have been changed.
- A RegionNavigationHandler that subclasses the standard navigation handler to provide JSF-like navigation to a region taskflow.
- A RegionXMLMenuModel class that subclasses the standard XMLMenuModel class to ensure the proper menu tab is selected based on the currently displayed taskflow in the dynamic region.
The following picture illustrates how this UIShell concept works at runtime.
The UIShell page (with extension .jsf in JDeveloper 11.1.2 and with extension .jspx in JDeveloper 11.1.1.x) contains a dynamic region. The taskflow binding in the page definition of UIShell gets the currently displayed taskflow from the DynamicRegionManager class that is registered as a managed bean under the name mainRegionManager. The actual task flow id and task flow parameters are supplied by the TaskFlowConfigBean. The DynamicRegionManager manages the current taskflow based on a logical name, for example Jobs. When method setCurrentTaskFlowName is called on the DynamicRegionManager with value Jobs (and we will later see how we use the RegionNavigationHandler to do this), the DynamicRegionManager looks up the corresponding TaskFlowConfigBean by suffixing the Jobs task flow name with TaskFlowConfig.he methods getCurrentTaskFlowId and getCurrentParamMap and currentParamMapChanged then obtain and return the correct values using the JobsTaskFlowConfig bean.
Using this technique, you can configure your dynamic region completely declarative, there is no need to write any Java code. All you need to do is configure the mainRegionManager and task flow config beans, as shown below.
In this sample, I configured the required managed beans in adfc-config.xml. When using ADF Libraries that contain task flows you want to show in the UIShell dynamic region, it is more elegant to define the TaskFlowConfigBean inside the ADF library. I usually define this bean in the adfc-config file of the task flow itself, below the <task-flow-definition/> section. It needs to be outside this section, otherwise the bean cannot be found by the DynamicRegionManager bean that is defined in the unbounded task together with the UIShell page. The advantage of this approach is that the config bean is placed in the same file as the task flow it refers to, the disadvantage is that beans defined outside the </task-flow-definition> section are not visible in the overview tab of a bounded task flow.
To set the current task flow name on the DynamicRegionManager, we use a custom RegionNavigationHandler class that you register in the faces-config.xml.
This class extends the default navigation handler, and overrides the handleNavigation method. The code is shown below. If the outcome contains a colon, the part after the colon contains the task flow name that should be set in the dynamic region.
With this class in place, we can use the action property on command components again to do region navigation, just like we are used to for normal JSF navigation, or navigation between page fragments inside a bounded task flow. The complete flow is as follows:
- The menu item has the action property set to uishell:Jobs.
- The region navigation handler set the current task flow name on the Dynamic region manager to Jobs (and navigates to UIShell page if needed)
- The dynamic region manager picks up the current task flow id and current parameters from the JobsTaskFlowConfig bean.
The last part of the puzzle is the RegionXMLMenuModel class that subclasses the standard XMLMenuModel class. This class overrides the getFocusRowKey method to return the focus path based on the current task flow region name.
With this class defined in the menu model managed bean, the menu will correctly display the selected tab.
In a future post I will discuss how the same concepts can be applied to a UIShell page with dynamic tabs.
- Sample application for JDeveloper 184.108.40.206 or 220.127.116.11
- Sample application for JDeveloper 11.1.2
- Slides of my ODTUG Kaleisdoscope 2011 presentation "Highly Reusable Task Flows". This presentation starts with a discussion of the above concepts, and continues with a number of additional samples on how to build reusable task flows and how to reuse them in various ways.