Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3) B25386-01 |
|
![]() Previous |
![]() Next |
If you have a set of pages that should be visited in a particular order, consider using the processTrain
and processChoiceBar
components to show the multipage process. In the SRDemo application, the SRCreate.jspx
and SRCreateConfirm.jspx
pages use a processTrain
and processChoiceBar
component to let a user create a new service request.
When rendered, the processTrain
component shows the total number of pages in the process as well as the page where the user is currently at, and allows the user to navigate between those pages. For example, Figure 11-13 shows the first page in the create service request process, where the user selects one appliance from a listbox and enters a description of the problem in a textbox. The number of nodes (circles) in the train indicates the total number of predefined pages in the process; the solid node indicates that the user is currently working on that page in the process.
The processChoiceBar
component renders a dropdown menu, and where applicable, buttons for navigating forward and backward in the process.
On the first page, when the user clicks Confirm or Continue (or selects Confirm from the dropdown menu), the application displays the second page of the create service request process, as shown in Figure 11-14.
From the second page, the user can return to the problem description page by clicking Basic Problem Details in the train or clicking the Back button, or by selecting Basic Problem Details from the dropdown menu.
If done the user clicks Submit Request, and the application displays the Request Submitted page, as shown in Figure 11-15.
To display a process train on each page, you bind the processTrain
component to a process train model. At runtime the train model dynamically creates the train for each page in the process.
To create and use a process train:
Create a process train model. (See Section 11.5.1.1, "Creating a Process Train Model")
Create the JSF page for each node in the train. (See Section 11.5.1.2, "Creating the JSF Page for Each Train Node")
Create a navigation rule that has navigation cases for each node. (See Section 11.5.1.3, "Creating the JSF Navigation Rules")
Use the oracle.adf.view.faces.model.MenuModel
class and the oracle.adf.view.faces.model.ProcessMenuModel
class to create a process train model that dynamically generates a process train. The MenuModel
class is the same menu model mechanism that is used for creating menu tabs and menu bars, as described in Section 11.2.1, "How to Create Dynamic Navigation Menus".
To create a process train model:
Create a class that can get and set the properties for each node in the process train.
Each node in the train needs to have a label
, a viewId
and an outcome
property. Example 11-37 shows part of the MenuItem
class used in the SRDemo application.
Example 11-37 MenuItem.java for Process Train Nodes
package oracle.srdemo.view.menu; ... public class MenuItem { private String _label = null; private String _outcome = null; private String _viewId = null; ... //extended security attributes private boolean _readOnly = false; private boolean _shown = true; public void setLabel(String label) { this._label = label; } public String getLabel() { return _label; } public void setOutcome(String outcome) { this._outcome = outcome; } public String getOutcome() { return _outcome; } public void setViewId(String viewId) { this._viewId = viewId; } public String getViewId() { return _viewId; } public void setReadOnly(boolean readOnly) { this._readOnly = readOnly; } public boolean isReadOnly() { return _readOnly; } public void setShown(boolean shown) { this._shown = shown; } public boolean isShown() { return _shown; } ... }
Configure a managed bean for each node in the train, with values for the properties that require setting at instantiation.
Each bean should be an instance of the class you create in step 1. Example 11-38 shows the managed bean code for the process train nodes in faces-config.xml
.
Example 11-38 Managed Beans for Process Train Nodes in the faces-config.xml File
<!--First train node --> <managed-bean> <managed-bean-name>createTrain_Step1</managed-bean-name> <managed-bean-class>oracle.srdemo.view.menu.MenuItem</managed-bean-class> <managed-bean-scope>application</managed-bean-scope> <managed-property> <property-name>label</property-name> <value>#{resources['srcreate.train.step1']}</value> </managed-property> <managed-property> <property-name>viewId</property-name> <value>/app/SRCreate.jspx</value> </managed-property> <managed-property> <property-name>outcome</property-name> <value>GlobalCreate</value> </managed-property> </managed-bean> <!-- Second train node--> <managed-bean> <managed-bean-name>createTrain_Step2</managed-bean-name> <managed-bean-class>oracle.srdemo.view.menu.MenuItem</managed-bean-class> <managed-bean-scope>application</managed-bean-scope> <managed-property> <property-name>label</property-name> <value>#{resources['srcreate.train.step2']}</value> </managed-property> <managed-property> <property-name>viewId</property-name> <value>/app/SRCreateConfirm.jspx</value> </managed-property> <managed-property> <property-name>outcome</property-name> <value>Continue</value> </managed-property> </managed-bean>
Configure a managed bean that is an instance of a list with application
as its scope.
The list entries are the train node managed beans you create in step 2, listed in the order that they should appear on the train. Example 11-39 shows the managed bean code for creating the process train list.
Example 11-39 Managed Bean for Process Train List in the faces-config.xml File
<!-- create the list to pass to the train model --> <managed-bean> <managed-bean-name>createTrainNodes</managed-bean-name> <managed-bean-class>java.util.ArrayList</managed-bean-class> <managed-bean-scope>application</managed-bean-scope> <list-entries> <value-class>oracle.srdemo.view.menu.MenuItem</value-class> <value>#{createTrain_Step1}</value> <value>#{createTrain_Step2}</value> </list-entries> </managed-bean>
Create a class to facilitate the construction of a ProcessMenuModel
instance. This class must have at least two properties, viewIdProperty
and instance
.
Example 11-40 shows the TrainModelAdapter
class used in the SRDemo application.
Example 11-40 TrainModelAdapter.java for Holding the Process Train Nodes
package oracle.srdemo.view.menu; import java.beans.IntrospectionException; import java.io.Serializable; import oracle.adf.view.faces.model.MenuModel; import oracle.adf.view.faces.model.ProcessMenuModel; public class TrainModelAdapter implements Serializable { private String _propertyName = null; private Object _instance = null; private transient MenuModel _model = null; private Object _maxPathKey = null; public MenuModel getModel() throws IntrospectionException { if (_model == null) { _model = new ProcessMenuModel(getInstance(), getViewIdProperty(), getMaxPathKey()); } return _model; } public String getViewIdProperty() { return _propertyName; } /** * Sets the property to use to get at view id * @param propertyName */ public void setViewIdProperty(String propertyName) { _propertyName = propertyName; _model = null; } public Object getInstance() { return _instance; } /** * Sets the treeModel * @param instance must be something that can be converted into a TreeModel */ public void setInstance(Object instance) { _instance = instance; _model = null; } public Object getMaxPathKey() { return _maxPathKey; } public void setMaxPathKey(Object maxPathKey) { _maxPathKey = maxPathKey; } }
If you wish to write your own menu model instead of using ProcessMenuModel
, you can use ProcessUtils
to implement the PlusOne or MaxVisited behavior for controlling page access. For information about how to control page access using those process behaviors, see Section 11.5.1.1.1, "What You May Need to Know About Controlling Page Access".
Configure a managed bean to reference the class you create in step 4. This is the bean to which the processTrain
component is bound.
The bean should be instantiated to have the instance
property value set to the managed bean that creates the train list (as configured in step 3). The instantiated bean should also have the viewIdProperty
value set to the viewId
property on the bean created in step 1. Example 11-41 shows the managed bean code for creating the process train model.
Example 11-41 Managed Bean for Process Train Model in the faces-config.xml File
<!-- create the train menu model --> <managed-bean> <managed-bean-name>createTrainMenuModel</managed-bean-name> <managed-bean-class> oracle.srdemo.view.menu.TrainModelAdapter</managed-bean-class> <managed-bean-scope>application</managed-bean-scope> <managed-property> <property-name>viewIdProperty</property-name> <value>viewId</value> </managed-property> <managed-property> <property-name>instance</property-name> <value>#{createTrainNodes}</value> </managed-property> </managed-bean>
When you want to control the pages users can access based on the page they are currently on, you can use one of two process scenarios provided by ADF Faces, namely Max Visited or Plus One.
Suppose there are five pages or nodes in a process train, and the user has navigated from page 1 to page 4 sequentially. At page 4 the user jumps back to page 2. Where the user can go next depends on which process scenario is used.
In the Max Visited process, from the current page 2 the user can go back to page 1, go ahead to page 3, or jump ahead to page 4. That is, the Max Visited process allows the user to return to a previous page or advance to any page up to the furthest page already visited. The user cannot jump ahead to page 5 from page 2 because page 5 has not yet been visited.
Given the same situation, in the Plus One process the user can only go ahead to page 3 or go back to page 1. That is, the Plus One process allows the user to return to a previous page or to advance one node in the train further than they are on currently. The user cannot jump ahead to page 4 even though page 4 has already been visited.
If you were to use the Max Visited process, you would add code similar to the next code snippet, for the createTrainMenuModel
managed bean (see Example 11-41) in faces-config.xml
:
<managed-property> <property-name>maxPathKey</property-name> <value>TRAIN_DEMO_MAX_PATH_KEY</value> </managed-property>
ADF Faces knows to use the Max Visited process because a maxPathKey
value is passed into the ProcessMenuModel
(see Example 11-40).
The Create New Service Request process uses the Plus One process because faces-config.xml
doesn't have the maxPathKey
managed-property setting, thus null
is passed for maxPathKey
. When null
is passed, ADF Faces knows to use the PlusOne process.
The process scenarios also affect the immediate
and readOnly
attributes of the command component used within a processTrain
component. For information, see Section 11.5.1.2.1, "What You May Need to Know About the Immediate and ReadOnly Attributes".
Each train node has its own page. To display the process train, on each page bind the processTrain
component to the process train model, as shown in Example 11-42.
A processTrain
component is usually inserted in the location
facet of a panelPage
or page
component. Like a menu component, a processTrain
component has a nodeStamp
facet that accepts one commandMenuItem
component. It is the commandMenuItem
component that provides the actual label you see below a train node, and the navigation outcome when the label is activated.
Example 11-42 ProcessTrain Component in the SRCreate.jspx File
<af:panelPage..> ... <f:facet name="location"> <af:processTrain var="train" value="#{createTrainMenuModel.model}"> <f:facet name="nodeStamp"> <af:commandMenuItem text="#{train.label}" action="#{train.getOutcome}" readOnly="#{createTrainMenuModel.model.readOnly}" immediate="false"/> </f:facet> </af:processTrain> </f:facet> ... </af:panelPage>
Note: You can use the same code for the process train on each page because the process train model dynamically determines the train node links, the order of the nodes, and whether the nodes are enabled, disabled, or selected. |
Typically, you use a processTrain
component with a processChoiceBar
component. The processChoiceBar
component, which is also bound to the same process train model, gives the user additional navigation choices for stepping through the multipage process. Example 11-43 shows the code for the processChoiceBar
component in the SRCreate.jspx
page. A processChoiceBar
component is usually inserted in the actions
facet of a panelPage
or page
component.
Example 11-43 ProcessChoiceBar Component in the SRCreate.jspx File
<af:panelPage ..> <f:facet name="actions"> <af:panelButtonBar> <af:commandButton text="#{res['srdemo.cancel']}" action="#{backing_SRCreate.cancelButton_action}" immediate="true"/> <af:processChoiceBar var="choice" value="#{createTrainMenuModel.model}"> <f:facet name="nodeStamp"> <af:commandMenuItem text="#{choice.label}" action="#{choice.getOutcome}" readOnly="#{createTrainMenuModel.model.readOnly}" immediate="false"/> </f:facet> </af:processChoiceBar> </af:panelButtonBar> </f:facet> ... </af:panelPage>
As illustrated in Figure 11-13 and Figure 11-14, the processChoiceBar
component automatically provides a Continue button and a Back button for navigating forward and backward in the process. You don't have to write any code for these buttons. If you want to provide additional buttons (such as the Cancel and Submit Request buttons in Figure 11-14), use a panelButtonBar
to lay out the button components and the processChoiceBar
component.
Note: If your multipage process has only two pages, ADF Faces uses Continue as the label for the button that navigates forward. If there is more than two pages in the process, the forward button label is Next. |
The two process scenarios provided by ADF Faces and described in Section 11.5.1.1.1, "What You May Need to Know About Controlling Page Access" have an effect on both the immediate
and readOnly
attributes of the commandMenuItem
component used within processTrain
. When binding processTrain
to a process train model, you can bind the node's immediate
or readOnly
attribute to the model's immediate
or readOnly
attribute. The ProcessMenuModel
class then uses logic to determine the value of the immediate
or readOnly
attribute.
When the data on the current page does not need to be validated, the immediate
attribute should be set to true
. For example, in the Plus One scenario described in Section 11.5.1.1.1, if the user is on page 4 and goes back to page 2, the user has to come back to page 4 again later, so that data does not need to be validated when going to page 1 or 3, but should be validated when going ahead to page 5.
The ProcessMenuModel
class uses the following logic to determine the value of the immediate
attribute:
Plus One: immediate
is set to true
for any previous step, and false
otherwise.
Max Visited: When the current page and the maximum page visited are the same, the behavior is the same as the Plus One scenario. If the current page is before the maximum page visited, then immediate
is set to false
.
The readOnly
attribute should be set to true
only if that page of the process cannot be reached from the current page. The ProcessMenuModel
class uses the following logic to determine the value of the readOnly
attribute:
Plus One: readOnly
will be true
for any page past the next available page.
Max Visited: When the current step and the maximum page visited are the same, the behavior is the same as the Plus One scenario. If the current page is before the maximum page visited, then readOnly
is set to true
for any page past the maximum page visited.
The <from-outcome>
and <to-view-id>
values in the navigation cases must match the properties set in the process train model.
In the SRDemo application, a global navigation rule is used for the first page of the Create New Service Request process because the SRCreate.jspx
page is accessible from any page in the application. The second page of the process, SRCreateConfirm.jspx
, is not included in the global navigation rule because it is only accessible from the SRCreate.jspx
page. Example 11-44 shows the navigation rules and cases for the process.
Example 11-44 Navigation Rules for Process Train Nodes in the faces.config.xml File
<navigation-rule> <from-view-id>*</from-view-id> <navigation-case> <from-outcome>GlobalCreate</from-outcome> <to-view-id>/app/SRCreate.jspx</to-view-id> </navigation-case> ... </navigation-rule> ... <navigation-rule> <from-view-id>/app/SRCreate.jspx</from-view-id> <navigation-case> <from-outcome>Continue</from-outcome> <to-view-id>/app/SRCreateConfirm.jspx</to-view-id> </navigation-case> ... </navigation-rule> <navigation-rule> <from-view-id>/app/SRCreateConfirm.jspx</from-view-id> <navigation-case> <from-outcome>Back</from-outcome> <to-view-id>/app/SRCreate.jspx</to-view-id> </navigation-case> <navigation-case> <from-outcome>Complete</from-outcome> <to-view-id>/app/SRCreateDone.jspx</to-view-id> </navigation-case> </navigation-rule>
Java automatically adds a no-arg constructor to TrainModelAdapter
because the TrainModelAdapter
class is used as a managed bean. TrainModelAdapter
constructs the process train model, which is a ProcessMenuModel
instance, via the createTrainMenuModel
managed bean. The createTrainNodes
managed bean creates and injects the train node list into the train model. The train model provides the model that correctly highlights and enables the nodes on the train as you step through the process.
The individual train node managed beans (for example, createTrain_Step1
) are instantiated with values for label
, viewId
, and outcome
that are used by the train model to dynamically generate the train nodes. The default JSF actionListener
mechanism uses the outcome values to handle the page navigation.
In the SRDemo application, the individual train node managed beans access String
resources in the resource bundle via the resources
managed bean, so that the correct node label is dynamically retrieved and display at runtime.
At runtime if maxPathKey
has a value (set in faces-config.xml
), ADF Faces knows to use the Max Visited process scenario. If maxPathKey
is null
(as in the SRDemo application), ADF Faces uses the Plus One process to control page access from the current page.
Like the menuTab
component, the processTrain
and processChoiceBar
components have a nodeStamp
facet, which takes one commandMenuItem
component. By using train
as the variable and binding the processTrain
component to the process train model, you need only one commandMenuItem
component to display all train node items using #{train.label}
as the text
value and #{train.getOutcome}
as the action
value on the command component. Similarly, by using choice
as the variable and binding the processChoiceBar
component to the process train model, you need only one commandMenuItem
component to display all items as menu options using #{choice.label}
as the text
value and #{choice.getOutcome}
as the action
value.
The enabling and disabling of a node is not controlled by the MenuItem
class, but by the process train model based on the current view using the EL expression #{createTrainMenuModel.model.readOnly}
on the readOnly
attribute of the processTrain
or processChoiceBar
component.
Tip: Disabled menu choices are not rendered on browsers that don't support disabled items in a dropdown menu. On browsers that support disabled items in a dropdown menu, the unreachable items will look disabled. |
The ProcessMenuModel
class extends the ViewIdPropertyMenuModel
class, which is used to create dynamic menus, as described in Section 11.2, "Using Dynamic Menus for Navigation". Like menus and menu items, each node on a train is defined as a menu item. But unlike menus where the menu items are gathered into the intermediate menu tree object (MenuTreeModelAdapter
), the complete list of train nodes is gathered into an ArrayList
that is then injected into the TrainModelAdapter
class. Note, however, that both ViewIdPropertyMenuModel
and ProcessMenuModel
can always take a List and turn it into a tree internally.
In the SRDemo application, the nodes on the train are not secured by user role as any user can create a new service request, which means that the train model can be stored as an application
scoped managed bean and shared by all users. The menu model is stored as a session
scoped managed bean because the menu tab items are secured by user role, as some tabs are not available to some user roles.
To add a new page to a process train, configure a new managed bean for the page (Example 11-38), add the new managed bean to the train list (Example 11-39), and add the navigation case for the new page (Example 11-44).