![]() ![]() ![]() ![]() ![]() ![]() |
This chapter describes how to create a customized task user interface (for use in the Worklist user portal. Worklist provides a default task user interface (shown in the Work on Task page of the user portal). This user interface dynamically creates forms based on the task plan metadata. For example, the default task user interface consults the current step for a task before deciding what actions to make available on the ‘take action’ page, and consults the properties defined for an action before deciding what properties to show on the ‘complete task action’ page. This allows you to perform most human interaction in Worklist without any custom user interface development.
However, there may be instances where you need to customize the interface and control what is displayed for a given step, or for the entire task plan. Worklist enables you to provide a customized user interface for tasks based on a given task plan (and optionally a specific step within a task plan). This allows you to integrate custom business logic, external systems, etc. into the processing of task actions and property settings.
Your custom task user interface is used in place of the default Worklist-supplied task user interface when viewing tasks based on task plans (or steps of those plans) you designate. It will appear in place of the default task user interface on the ‘Work on Task’ page of the Worklist user portal. This granular replacement of the default task user interface allows you to specify a custom task user interface only where it is needed, and use the default task user interface everywhere else.
For example, a Loan Manager may need to check the credit rating of the customer before approving or rejecting the loan. Using the custom task UI, you can customize the user portal to display information that will empower the Loan Manager to make a well informed decision.
The following topics are covered in this chapter:
Before you start creating a customized user interface, define the appearance of the page by creating a mock-up. For this tutorial, create mock-up pages for the “Manager Review Page” and the “Asset Summary Page” (See Figure 7-1 and Figure 7-2).
Now that the mock-up is complete, proceed with defining the page flow as described in the following section.
After determining the appearance of the customized user interface pages, define the logic and use of these pages as follows:
The Open Associated Perspective? dialog box is displayed.
Edit the page flow as follows:
The initial view in the page flow was as follows:
@Jpf.Controller(nested = true, simpleActions = { @Jpf.SimpleAction(name = "begin", path = "index.jsp") })
After editing it, it should be:
@Jpf.Controller(nested = true)
public class ManagerReview extends com.bea.wli.worklist.portal.TaskUIPageFlowController{
Note: | This change will result in some compilation errors saying ‘Action "begin" was not found.’ This error will be resolved in subsequent steps.You can view the compilation error in the ‘Problems’ view in the bottom part of the IDE. Make sure ‘Problems’ view is opened. To open the Problems view from the menu, go to Window![]() ![]() |
You must define form beans to support the two web pages mocked up (see Define Web Page Mock-Up and Flow on page 7-2).
We create three form beans as inner classes of the Manager Review Pane, they are as follows:
The Generate Getters and Setters dialog box appears.
After you defined the variables, the class should look as the follows:
@Jpf.FormBean
public static class ManagerReviewForm implements java.io.Serializable {
rivate static final long serialVersionUID = 746621147L;
private String _name;
private String _ssn;
private int _loanAmount;
private PropertyInstanceHolder _notesProp;
private String _collateralAssets;
public int getLoanAmount() { return _loanAmount; }
public void setLoanAmount(int loanAmount) { _loanAmount = loanAmount; }
public String getName() { return _name; }
public void setName(String name) { _name = name; }
public String getSsn() { return _ssn; }
public void setSsn(String ssn) { _ssn = ssn; }
public PropertyInstanceHolder getNotesProp() { return _notesProp; }
public void setNotesProp(PropertyInstanceHolder notesProp) {
_notesProp = notesProp; }
public String getCollateralAssets() { return _collateralAssets; }
public void setCollateralAssets(String collateralAssets) {
_collateralAssets = collateralAssets; }
}
Note: | The serialVersionUID value will differ. It is auto-generated and can be different from the one shown here. |
After you defined the variables, the class should look as the following:
@Jpf.FormBean
public static class AssetForm
implements java.io.Serializable, Comparable {
private static final long serialVersionUID = 1491696939L;
private String _name;
private int _value;
private int _amountOwed;
public int getAmountOwed() {
return _amountOwed;
}
public void setAmountOwed(int lienValue) {
_amountOwed = lienValue;
}
public String getName() {
return _name;
}
public void setName(String name) {
_name = name;
}
public int getValue() {
return _value;
}
public void setValue(int value) {
_value = value;
}
public int getActualValue() {
return _value - _amountOwed;
}
}
Note: | The serialVersionUID value will differ. It is auto-generated and can be different from the one shown here. |
After completing the above steps, there will be a compilation error stating that AssetForm class must implement the inherited abstract method Comparable.compareTo(Object)
. To resolve this error, copy the following method and paste it inside the AssetForm class. The code allows the asset summary web page to collate the individual asset items in descending total asset value.
public int compareTo(Object o) {
if (!(o instanceof AssetForm)) {
return 0;
}
AssetForm other = (AssetForm)o;
int otherActualValue = other._value - other._amountOwed;
return otherActualValue - getActualValue();
}
Add the following method to the end of the AssetForm class. This method will be used to retrieve an ‘actual’ asset value from the JSP pages we define later.
public int getActualValue() }
return _value - _amountOwed;
public java.util.SortedSet<AssetForm> getAssets() { return _assets; }
public int getCreditScore() { return _creditScore; }
After you defined the variables, the class should look as the following:
@Jpf.FormBean
public static class AssetSummaryForm
implements java.io.Serializable {
private static final long serialVersionUID = 1517513921L;
private java.util.SortedSet<AssetForm> _assets;
private int _creditScore;
private String _name;
private String _ssn;
public AssetSummaryForm() {
_assets = new java.util.TreeSet<AssetForm>();
}
public String getName() { return _name; }
public void setName(String name) { _name = name; }
public String getSsn() { return _ssn; }
public void setSsn(String ssn) { _ssn = ssn; }
public java.util.SortedSet<AssetForm> getAssets() { return _assets; }
public int getCreditScore() { return _creditScore; }
}
Note: | The serialVersionUID value will differ. It is auto-generated and can be different from the one shown here. |
In the AssetSummaryForm, add the following code to allow the form bean to load asset and credit score information.
This information is loaded in a very simplistic way (properties files) that is sufficient for the purposes of this tutorial. In a real application, this information would likely come by way of a Java API or web service to an external system.
The page flow action implementations use the loadSummaryInfo method included in the following code to initialize the AssetSummaryForm object with asset and credit score information for the user given by the name variable.
public void loadSummaryInfo(HttpSession session) {
loadCreditScore(session);
loadAssets(session);
}
public int getTotalActualAssetValue() {
int total = 0;
for (AssetForm asset: _assets) {
total = asset.getActualValue();
}
return total;
}
protected void loadCreditScore(HttpSession session) {
// Load the credit scores as properties
String resourceName = "/creditRatings/creditRatings.properties";
java.util.Properties props =
loadProperties(resourceName, session);
_creditScore = getIntProperty(props, _name);
}
protected void loadAssets(HttpSession session) {
// Load the assets as properties
String resourceName = "/assets/" + _name + ".properties";
java.util.Properties props =
loadProperties(resourceName, session);
String assetList = props.getProperty("assetList");
if (assetList != null) {
java.util.StringTokenizer st = new java.util.StringTokenizer(assetList, ",");
while (st.hasMoreTokens()) {
String assetName = st.nextToken().trim();
AssetForm asset = new AssetForm();
asset.setName(assetName);
int value =
getIntProperty(props, assetName + "." + "value");
asset.setValue(value);
int amountOwed =
getIntProperty(props, assetName + "." + "amountOwed");
asset.setAmountOwed(amountOwed);
_assets.add(asset);
}
}
}
protected java.util.Properties
loadProperties(String resourceName, HttpSession session) {
// Load the resources as properties
java.io.InputStream is = null;
try {
is = session.getServletContext().
getResourceAsStream(resourceName);
java.util.Properties props = new java.util.Properties();
if (is != null) {
props.load(is);
}
return props;
} catch (Exception e) {
// TODO: Better handling
e.printStackTrace();
} finally {
if (is != null) {
try { is.close(); } catch (Exception e) { e.printStackTrace(); }
}
}
return new java.util.Properties();
}
private int getIntProperty(java.util.Properties props, String key) {
String value = props.getProperty(key);
if (value == null) {
return 0;
}
return Integer.valueOf(value);
}
After completing the above steps, there will be a compilation error regarding the missing begin()method in the page flow.
Define information to support a loan request for a person named John Smith (use spelling and case as given here) as follows:
The New Folder dialog box appears (see Figure 7-9).
The New File dialog box appears.
Define actions on the page flow to move between the Manager Review and Asset Summary pages, and to take the Approve and Reject actions on the task. Page flow actions are methods on the page flow controller that allow the UI to forward to new pages, optionally calculating results and passing form beans to the pages to which you forward.
Form beans are passed from an action to a web page in order to populate display fields on the page. Then, values from fields on the web page are collected and placed into properties on the form bean when the web page is submitted back to the server for processing.
Action methods can accept a form bean populated as the result of clicking a submit button on a web page, by defining the form bean as a parameter to the action method. For an example of this, see the ‘approve’ action below. Action methods can also pass a form bean on to a target web page to which the action is forwarding. This is done by passing a Forward object that has a form bean object set on it. For an example of this, see the ‘show asset summary’ action below.
Define the following actions for initialization:
Define the following actions for page navigation:
Note: | The above two actions are natural reciprocals of each other. This reflects their purpose to navigate between two pages in a cyclic fashion. |
Define the following actions to handle user actions on the task:
The following describes how to add new actions. You can follow the steps below and use the page flow action wizard to add all of the above actions (and then copy/paste the action method body code as given in the section ‘Implement Action Methods’). Or you can just copy and paste the complete code for the action declarations and methods as given in ‘Implement Action Methods’ below and skip the next step completely.
The New Action dialog box appears (see Figure 7-10).
Next we need to implement a method body for the action methods we just defined.
The code for the all action methods is given below. Make sure you copy the action signature along with the @Jpf.Action annotation for each action method.
For each action method described in the above section:
If you didn’t create the action methods using the action wizard, you should:
If you did create the action methods using the action wizard you should:
/**
* Initialize this controller, and call the super class
* helper to initialize stuff we get for free. This includes
* task context, standard form beans for a task and action,
* and property editing support.
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name="success", path="GetManagerReview.jsp")
})
public Forward begin() throws Exception {
// Initialize our base class helpers so we can use them
// throughout this controller
beginActionHelper();
// Create our ManagerReviewForm, and load it with property
// values given by our base class helpers
_managerReviewForm = new ManagerReviewForm();
_managerReviewForm.setName(
(String)getTaskPropertiesMap().
get("Name").getValue());
_managerReviewForm.setSsn(
(String)getTaskPropertiesMap().
get("SSN").getValue());
_managerReviewForm.setLoanAmount(
((Long)getTaskPropertiesMap().
get("LoanAmt").getValue()).intValue());
// Get the editable notes property, because we'll
// use this PropertyInstanceHolder to edit the notes
// property via Worklist-provided helpers
com.bea.wli.worklist.portal.PropertyInstanceHolder notesProp =
getTaskEditablePropertiesMap().
get("Notes");
_managerReviewForm.setNotesProp(notesProp);
return new Forward("success", _managerReviewForm);
}
/**
* Forward to the assets sub form and display the assets
* we find for the loan applicant.
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
path = "AssetSummary.jsp")
}, useFormBean = "_managerReviewForm"
)
public Forward viewAssetSummaryAction(ManagerReviewForm form) {
AssetSummaryForm assetSummaryForm = new AssetSummaryForm();
assetSummaryForm.setName(form.getName());
assetSummaryForm.setSsn(form.getSsn());
assetSummaryForm.loadSummaryInfo(getSession());
return new Forward("success", assetSummaryForm);
}
/**
* Return to the main form after looking at assets.
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
path = "GetManagerReview.jsp")
})
public Forward returnToManagerReviewAction(AssetSummaryForm form) {
Forward forward = new Forward("success", _managerReviewForm);
return forward;
}
/**
* Approve the loan, using the super class helpers. and the properties we
* stored in ManagerReviewForm. We
* specify the useFormBean attr to keep a single copy
* of ManagerReviewForm.
* NOTE: We could have designed this action to forward to an 'action props'
* page to collect the properties for the action (instead of putting
* fields directly on the main form. If we did want a separate page,
* we could call showStepActionActionHelper to prepare a
* TakeStepActionActionForm for us to obtain these properties from.
* This form is well suited to use with propertyEditor tags in the
* action props form.
* @see TaskUIPageFlowController#showStepActionActionHelper(com.bea.wli.worklist.api.taskplan.StepAction)
* @see TaskUIPageFlowController#takeStepActionActionHelper(com.bea.wli.worklist. portal.TakeStepActionActionForm)
* @see TaskUIPageFlowController#isPostActionInteractiveAssignment(java.lang.String)
* @see TaskUIPageFlowController#takeStepActionAndClaimActionHelper(com.bea.wli.worklist.portal.TakeStepActionActionForm, java.lang.String)
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
action = "stepDoneAction")
}, useFormBean="_managerReviewForm")
public Forward approveLoanAction(ManagerReviewForm form)
throws Exception {
// Build a map of the property values we'll pass for the action
java.util.Map<String, String> propMap
= new java.util.HashMap<String, String>();
propMap.put("Notes", form.getNotesProp().getEditorValueAsString());
propMap.put("CollateralAssets", form.getCollateralAssets());
// Now take the action
this.takeStepAction(getCurrentStep().getName(),
"Approve",
propMap);
Forward forward = new Forward("success");
return forward;
}
/**
* Reject the loan, using the super class helpers. We
* specify the useFormBean attr to keep a single copy
* of ManagerReviewForm.
* NOTE: We could have designed this action to forward to an 'action props'
* page to collect the properties for the action (instead of putting
* fields directly on the main form. If we did want a separate page,
* we could call showStepActionActionHelper to prepare a
* TakeStepActionActionForm for us to obtain these properties from.
* This form is well suited to use with propertyEditor tags in the
* action props form.
* @see TaskUIPageFlowController#showStepActionActionHelper(com.bea.wli.worklist.api.taskplan.StepAction)
* @see TaskUIPageFlowController#takeStepActionActionHelper(com.bea.wli.worklist.portal.TakeStepActionActionForm)
* @see TaskUIPageFlowController#isPostActionInteractiveAssignment(java.lang.String)
* @see TaskUIPageFlowController#takeStepActionAndClaimActionHelper(com.bea.wli.worklist.portal.TakeStepActionActionForm, java.lang.String)
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
action = "stepDoneAction")
}, useFormBean="_managerReviewForm")
public Forward rejectLoanAction(ManagerReviewForm form)
throws Exception {
// Build a map of the property values we'll pass for the action
java.util.Map<String, String> propMap
= new java.util.HashMap<String, String>();
propMap.put("Notes", form.getNotesProp().getEditorValueAsString());
// Now take the action
this.takeStepAction(getCurrentStep().getName(),
"Reject",
propMap);
Forward forward = new Forward("success");
return forward;
}
Action methods can accept form beans, and forward to pages using form beans. When submitting a web form, and in the process of calling the action associated with the submit, the NetUI framework, by default, will create a new form bean instance (using the no-arg public constructor for the form bean class). This new bean instance is then populated via Java reflection with data from data binding tags in the submitted web page form.
This process has some limitations. For example, if your form bean contains transient, hidden information that is not represented in the web pages JSP tags, the form bean that actually gets passed to the action method (the bean that is created by the NetUI framework) will be missing this information.
To avoid the overhead and possible behavioral problems of creating new beans each time an action method is called, you can specify a useFormBean field on the @Jpf.Action
annotation for an action method. This allows the controller to hold a single copy of the form bean in the page flow controller’s state, and the action method then just fetches the object from that state instead of creating a new form bean object.
We make use of the useFormBean facility in the action method code given in the previous section. To make this code work, you need to define a member variable on the page flow controller to hold the form bean we’ll be passing around.
Add the following member variable to the top of your ManagerReview class:
private ManagerReviewForm _managerReviewForm; // To preserve the form between requests
.
If you haven’t already done so, make sure your action methods that take a ManagerReviewForm parameter include a useFormBean attribute in the @Jpf.Action annotation. For example, the @Jpf.Action annotation for the rejectLoanAction is:
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
action = "stepDoneAction")
}, useFormBean="_managerReviewForm")
The text you need to add is highlighted in the above code.
Worklist provides some built-in support for editing properties in your custom task UI. It includes a JSP tag, default editors, and some helper methods in the base TaskUIPageFlowController. These facilities allow you to easily edit the following types of properties using out-of-box UI:
In addition, the property editor facility allows you to easily support editing properties using an inline editor (simple form field) as well as a stand-alone editor for the complex types mentioned above. This facility makes robust editing of properties a fairly simple matter. The manager review web page defined in this tutorial edits two properties; Notes and CollateralAssets. We edit the Notes property using the property editor facilities of Worklist, and the CollateralAssets property using simple NetUI data binding tags.
The property editor facility usage in this tutorial spans several constructs:
We define the following actions to handle task’s user property editor:
Using the steps described for adding the actions in Define Actions on the Page Flow section, add the following actions as shown in Table 7-2.
Table 7-2Notes: | For adding com.bea.wli.datatype.EditorValueHolder you will have to click Add button next to the form bean input field. It will open up a search window. Type EditorValueHolder and it should find this class. Click on the entry and press Ok. |
Insert the following code for the three actions mentioned above into your ManagerReview page flow controller.
private transient com.bea.wli.datatype.EditorValueHolder _editorValue; // For efficiency
/**
* This action handles an 'initiate stand-alone editor' call
* that comes from the GetManagerReview.jsp and the worklist
* propertyEditor tag. It (via editPropActionHelper) calculates
* the stand-alone editor's URI, and then forwards to that URI.
* This editor is a nested page flow, and returns to this
* controller (the caller) via well-known return actions
* okPropAction, and cancelPropAction. We pass the managerReviewForm
* form bean to avoid it getting recreated in this call.
*/
@Jpf.Action(useFormBean="_managerReviewForm")
public Forward editNotesPropAction(ManagerReviewForm form)
throws com.bea.wli.worklist.api.ManagementException,
com.bea.wli.datatype.DataTypeException {
// Get editable properties from the super class. Note
// that we could also get these from the UpdateActionForm
// contained in the super class. The UpdateActionForm is
// maintained for us by our super
// class, and contains the editable properties for the
// task (these are represented as PropertyInstanceHolder)
// General-purpose task UI can simply use the UpdateActionForm
// as the form bean for their main page.
com.bea.wli.worklist.portal.PropertyInstanceHolder[] properties =
getTaskEditablePropertiesMap().
values().toArray(new com.bea.wli.worklist.portal.PropertyInstanceHolder[0]);
// NOTE: We might store attrs off the propertyEditor tag
// here (e.g. hostPage) that would help us to
// navigate back to an appropriate page when the edit
// is completed (via okPropAction) or aborted (via
// cancelPropAction
// This begins the edit on the property we selected
// in the JSP page (and the name is set into the HTTP
// request coming in on this method.
Forward forward = editPropActionHelper(properties);
return forward;
}
/**
* The stand-alone editor (forwarded to in editNotesPropAction)
* returns to this action when you click 'Ok' to apply the edit.
* It returns on this action passing an EditorValueHolder holding
* the value that was created/edited in the editor. We pass
* this _editorValue in useFormBean to avoid creating a copy
* of this potentially large form bean.
*/
@Jpf.Action(loginRequired = true,
forwards = {
@Jpf.Forward(name = "backToManagerReview",
path = "GetManagerReview.jsp")
},
useFormBean = "_editorValue")
protected Forward okPropAction(com.bea.wli.datatype.EditorValueHolder value)
throws Exception {
okPropActionHelper(value);
return new Forward("backToManagerReview", _managerReviewForm);
}
/**
* This is the action the stand-alone editor (launched from
* editNotesPropAction) calls when the user clicks Cancel in
* the editor.
* @return
* @throws Exception
*/
@Jpf.Action(loginRequired = true,
forwards = {
@Jpf.Forward(name = "backToManagerReview",
path = "GetManagerReview.jsp")
})
protected Forward cancelPropAction()
throws Exception {
cancelPropActionHelper();
return new Forward("backToManagerReview", _managerReviewForm);
}
After completing the above mentioned steps the code for the Page Flow will be as follows:
package manager;
import javax.servlet.http.HttpSession;
import org.apache.beehive.netui.pageflow.Forward;
import org.apache.beehive.netui.pageflow.annotations.Jpf;
import com.bea.wli.worklist.portal.PropertyInstanceHolder;
import com.bea.wli.worklist.portal.TaskUIPageFlowController;
@Jpf.Controller(nested = true)
public class ManagerReview extends TaskUIPageFlowController {
private static final long serialVersionUID = -1579985639L;
private ManagerReviewForm _managerReviewForm; // To preserve the form between requests.
@Jpf.Action(forwards = { @Jpf.Forward(name = "done", returnAction = "managerDone") })
protected Forward done() {
return new Forward("done");
}
/**
* Initialize this controller, and call the super class
* helper to initialize stuff we get for free. This includes
* task context, standard form beans for a task and action,
* and property editing support.
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name="success", path="GetManagerReview.jsp")
})
public Forward begin() throws Exception {
// Initialize our base class helpers so we can use them
// throughout this controller
beginActionHelper();
// Create our ManagerReviewForm, and load it with property
// values given by our base class helpers
_managerReviewForm = new ManagerReviewForm();
_managerReviewForm.setName(
(String)getTaskPropertiesMap().
get("Name").getValue());
_managerReviewForm.setSsn(
(String)getTaskPropertiesMap().
get("SSN").getValue());
_managerReviewForm.setLoanAmount(
((Long)getTaskPropertiesMap().
get("LoanAmt").getValue()).intValue());
// Get the editable notes property, because we'll
// use this PropertyInstanceHolder to edit the notes
// property via Worklist-provided helpers
PropertyInstanceHolder notesProp =
getTaskEditablePropertiesMap().
get("Notes");
_managerReviewForm.setNotesProp(notesProp);
return new Forward("success", _managerReviewForm);
}
/**
* Forward to the assets sub form and display the assets
* we find for the loan applicant.
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
path = "AssetSummary.jsp")
}, useFormBean = "_managerReviewForm"
)
public Forward viewAssetSummaryAction(ManagerReviewForm form) {
AssetSummaryForm assetSummaryForm = new AssetSummaryForm();
assetSummaryForm.setName(form.getName());
assetSummaryForm.setSsn(form.getSsn());
assetSummaryForm.loadSummaryInfo(getSession());
return new Forward("success", assetSummaryForm);
}
/**
* Return to the main form after looking at assets.
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
path = "GetManagerReview.jsp")
})
public Forward returnToManagerReviewAction(AssetSummaryForm form) {
Forward forward = new Forward("success", _managerReviewForm);
return forward;
}
/**
* Approve the loan, using the super class helpers. and the properties we
* stored in ManagerReviewForm. We
* specify the useFormBean attr to keep a single copy
* of ManagerReviewForm.
* NOTE: We could have designed this action to forward to an 'action props'
* page to collect the properties for the action (instead of putting
* fields directly on the main form. If we did want a separate page,
* we could call showStepActionActionHelper to prepare a
* TakeStepActionActionForm for us to obtain these properties from.
* This form is well suited to use with propertyEditor tags in the
* action props form.
* @see TaskUIPageFlowController#showStepActionActionHelper(com.bea.wli.worklist.api.tasktype.StepAction)
* @see TaskUIPageFlowController#takeStepActionActionHelper(com.bea.wli.worklist.portal.TakeStepActionActionForm)
* @see TaskUIPageFlowController#isPostActionInteractiveAssignment(java.lang.String)
* @see TaskUIPageFlowController#takeStepActionAndClaimActionHelper(com.bea.wli.worklist.portal.TakeStepActionActionForm, java.lang.String)
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
action = "stepDoneAction")
}, useFormBean="_managerReviewForm")
public Forward approveLoanAction(ManagerReviewForm form)
throws Exception {
// Build a map of the property values we'll pass for the action
java.util.Map<String, String> propMap
= new java.util.HashMap<String, String>();
propMap.put("Notes", form.getNotesProp().getEditorValueAsString());
propMap.put("CollateralAssets", form.getCollateralAssets());
// Now take the action
this.takeStepAction(getCurrentStep().getName(),
"Approve",
propMap);
Forward forward = new Forward("success");
return forward;
}
/**
* Reject the loan, using the super class helpers. We
* specify the useFormBean attr to keep a single copy
* of ManagerReviewForm.
* NOTE: We could have designed this action to forward to an 'action props'
* page to collect the properties for the action (instead of putting
* fields directly on the main form. If we did want a separate page,
* we could call showStepActionActionHelper to prepare a
* TakeStepActionActionForm for us to obtain these properties from.
* This form is well suited to use with propertyEditor tags in the
* action props form.
* @see TaskUIPageFlowController#showStepActionActionHelper(com.bea.wli.worklist.api.tasktype.StepAction)
* @see TaskUIPageFlowController#takeStepActionActionHelper(com.bea.wli.worklist.portal.TakeStepActionActionForm)
* @see TaskUIPageFlowController#isPostActionInteractiveAssignment(java.lang.String)
* @see TaskUIPageFlowController#takeStepActionAndClaimActionHelper(com.bea.wli.worklist.portal.TakeStepActionActionForm, java.lang.String)
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
action = "stepDoneAction")
}, useFormBean="_managerReviewForm")
public Forward rejectLoanAction(ManagerReviewForm form)
throws Exception {
// Build a map of the property values we'll pass for the action
java.util.Map<String, String> propMap
= new java.util.HashMap<String, String>();
propMap.put("Notes", form.getNotesProp().getEditorValueAsString());
// Now take the action
this.takeStepAction(getCurrentStep().getName(),
"Reject",
propMap);
Forward forward = new Forward("success");
return forward;
}
/**
* Callback that is invoked when this controller instance is created.
*/
@Override
protected void onCreate() {
}
/**
* Callback that is invoked when this controller instance is destroyed.
*/
@Override
protected void onDestroy(HttpSession session) {
}
private transient com.bea.wli.datatype.EditorValueHolder _editorValue; // For efficiency
/**
* This action handles an 'initiate stand-alone editor' call
* that comes from the GetManagerReview.jsp and the worklist
* propertyEditor tag. It (via editPropActionHelper) calculates
* the stand-alone editor's URI, and then forwards to that URI.
* This editor is a nested page flow, and returns to this
* controller (the caller) via well-known return actions
* okPropAction, and cancelPropAction. We pass the managerReviewForm
* form bean to avoid it getting recreated in this call.
*/
@Jpf.Action(useFormBean="_managerReviewForm")
public Forward editNotesPropAction(ManagerReviewForm form)
throws com.bea.wli.worklist.api.ManagementException,
com.bea.wli.datatype.DataTypeException {
// Get editable properties from the super class. Note
// that we could also get these from the UpdateActionForm
// contained in the super class. The UpdateActionForm is
// maintained for us by our super
// class, and contains the editable properties for the
// task (these are represented as PropertyInstanceHolder)
// General-purpose task UI can simply use the UpdateActionForm
* we could call showStepActionActionHelper to prepare a
* TakeStepActionActionForm for us to obtain these properties from.
* This form is well suited to use with propertyEditor tags in the
* action props form.
* @see TaskUIPageFlowController#showStepActionActionHelper(com.bea.wli.worklist.api.tasktype.StepAction)
* @see TaskUIPageFlowController#takeStepActionActionHelper(com.bea.wli.worklist.portal.TakeStepActionActionForm)
* @see TaskUIPageFlowController#isPostActionInteractiveAssignment(java.lang.String)
* @see TaskUIPageFlowController#takeStepActionAndClaimActionHelper(com.bea.wli.worklist.portal.TakeStepActionActionForm, java.lang.String)
*/
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
action = "stepDoneAction")
}, useFormBean="_managerReviewForm")
public Forward rejectLoanAction(ManagerReviewForm form)
throws Exception {
// Build a map of the property values we'll pass for the action
java.util.Map<String, String> propMap
= new java.util.HashMap<String, String>();
propMap.put("Notes", form.getNotesProp().getEditorValueAsString());
// Now take the action
this.takeStepAction(getCurrentStep().getName(),
"Reject",
propMap);
Forward forward = new Forward("success");
return forward;
}
/**
* Callback that is invoked when this controller instance is created.
*/
@Override
protected void onCreate() {
}
/**
* Callback that is invoked when this controller instance is destroyed.
*/
@Override
protected void onDestroy(HttpSession session) {
}
private transient com.bea.wli.datatype.EditorValueHolder _editorValue; // For efficiency
/**
* This action handles an 'initiate stand-alone editor' call
* that comes from the GetManagerReview.jsp and the worklist
* propertyEditor tag. It (via editPropActionHelper) calculates
* the stand-alone editor's URI, and then forwards to that URI.
* This editor is a nested page flow, and returns to this
* controller (the caller) via well-known return actions
* okPropAction, and cancelPropAction. We pass the managerReviewForm
* form bean to avoid it getting recreated in this call.
*/
@Jpf.Action(useFormBean="_managerReviewForm")
public Forward editNotesPropAction(ManagerReviewForm form)
throws com.bea.wli.worklist.api.ManagementException,
com.bea.wli.datatype.DataTypeException {
// Get editable properties from the super class. Note
// that we could also get these from the UpdateActionForm
// contained in the super class. The UpdateActionForm is
// maintained for us by our super
// class, and contains the editable properties for the
// task (these are represented as PropertyInstanceHolder)
// General-purpose task UI can simply use the UpdateActionForm
public String getSsn() { return _ssn; }
public void setSsn(String ssn) { _ssn = ssn; }
public PropertyInstanceHolder getNotesProp()
{ return _notesProp; }
public void setNotesProp(PropertyInstanceHolder notesProp)
{ _notesProp = notesProp; }
public String getCollateralAssets() { return _collateralAssets; }
public void setCollateralAssets(String collateralAssets) {
_collateralAssets = collateralAssets; }
}
@Jpf.FormBean
public static class AssetSummaryForm implements java.io.Serializable {
private static final long serialVersionUID = 1517513921L;
private java.util.SortedSet<AssetForm> _assets;
private int _creditScore;
private String _name;
private String _ssn;
public AssetSummaryForm() {
_assets = new java.util.TreeSet<AssetForm>();
}
public String getName() { return _name; }
public void setName(String name) { _name = name; }
public String getSsn() { return _ssn; }
public void setSsn(String ssn) { _ssn = ssn; }
public java.util.SortedSet<AssetForm> getAssets() { return _assets; }
// NOTE: No setter for assets property. We’ll load this internally.
public int getCreditScore() { return _creditScore; }
// NOTE: No setter for creditScore, we’ll load this internally.
public void loadSummaryInfo(HttpSession session) {
loadCreditScore(session);
loadAssets(session);
}
public int getTotalActualAssetValue() {
int total = 0;
for (AssetForm asset: _assets) {
total = asset.getActualValue();
}
return total;
}
protected void loadCreditScore(HttpSession session) {
// Load the credit scores as properties
String resourceName = "/creditRatings/creditRatings.properties";
java.util.Properties props =
loadProperties(resourceName, session);
_creditScore = getIntProperty(props, _name);
}
protected void loadAssets(HttpSession session) {
// Load the assets as properties
String resourceName = "/assets/" + _name + ".properties";
java.util.Properties props =
loadProperties(resourceName, session);
String assetList = props.getProperty("assetList");
if (assetList != null) {
java.util.StringTokenizer st = new java.util.StringTokenizer(assetList, ",");
while (st.hasMoreTokens()) {
String assetName = st.nextToken().trim();
AssetForm asset = new AssetForm();
asset.setName(assetName);
int value =
getIntProperty(props, assetName + "." + "value");
asset.setValue(value);
int amountOwed =
getIntProperty(props, assetName + "." + "amountOwed");
asset.setAmountOwed(amountOwed);
_assets.add(asset);
}
}
}
protected java.util.Properties
loadProperties(String resourceName, HttpSession session) {
// Load the resources as properties
java.io.InputStream is = null;
try {
is = session.getServletContext().
getResourceAsStream(resourceName);
java.util.Properties props = new java.util.Properties();
if (is != null) {
props.load(is);
}
return props;
} catch (Exception e) {
// TODO: Better handling
e.printStackTrace();
} finally {
if (is != null) {
try { is.close(); } catch (Exception e) { e.printStackTrace(); }
}
}
return new java.util.Properties();
}
private int getIntProperty(java.util.Properties props, String key) {
String value = props.getProperty(key);
if (value == null) {
return 0;
}
return Integer.valueOf(value);
}
}
@Jpf.FormBean
public static class AssetForm implements java.io.Serializable, Comparable {
private static final long serialVersionUID = 1491696939L;
private String _name;
private int _value;
private int _amountOwed;
public int getAmountOwed() {
return _amountOwed;
}
public void setAmountOwed(int lienValue) {
_amountOwed = lienValue;
}
public String getName() {
return _name;
}
public void setName(String name) {
_name = name;
}
public int getValue() {
return _value;
}
public void setValue(int value) {
_value = value;
}
public int getActualValue() {
return _value - _amountOwed;
}
public int compareTo(Object o) {
if (!(o instanceof AssetForm)) {
return 0;
}
AssetForm other = (AssetForm)o;
int otherActualValue = other._value - other._amountOwed;
return otherActualValue - getActualValue();
}
}
}
According to the screen mockups in Define Web Page Mock-Up and Flow, define two JSP pages for the custom task UI using Beehive NetUI data binding JSP tags to render web forms that can read data from and write data into form beans. The use of these tags greatly simplifies the process of writing a data-driven JSP page.
The page flow perspective in Workshop give us a starting point for defining the correct pages. With the actions we defined in previous sections, your ManagerReview page flow controller should show two grayed out JSP pages under the ‘Pages’ node in the page flow explorer:
The default JSP code is as follows:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
<netui:html>
<head>
<netui:base/>
</head>
<netui:body>
<p>Beehive NetUI JavaServer Page - ${pageContext.request.requestURI}</p>
</netui:body>
</netui:html>
Fill out these pages by inserting the correct text for our forms in between the<netui:body/> tag.
It is recommended that you use HTML<table>
tags to help organize and align these form fields.
Delete the following code from the JSP:
<p>Beehive NetUI JavaServer Page - ${pageContext.request.requestURI}</p>
In this step, create a <netui:form>
element to hold all our JSP data items, then associate that form with an action from our ManagerReview page flow controller. This will associate the form with the form bean referenced in the action method. This association will bind the data from our form bean to the data items we’ll add to the JSP form.
The general process for adding a NetUI form to a JSP is as follows:
The JSP Design Palette appears (see Figure 7-11).
<netui:body/>
tag.
When you drop it, the form element is added, something like this:<netui:form action=""></netui:form>
Associate the form with an action on your page flow controller For this tutorial, you’ll associate the form element with an action on our ManagerReview page flow controller that takes a form bean as a parameter. This association is very important, as it establishes the action method that will be called when the form is submitted and the Java type of the form bean to associate with the form. The associated form bean then becomes accessible to the NetUI tags in the JSP code by using the value and dataSource attributes of those tags. These attributes refer to properties on the form bean via JSP expressions like this:
actionForm.<property on form bean>
and the form bean defines a pair of methods of the form:
<Java type for property> get<Property name>()
void set<Property name>(<Java type for property> value)
We’ll show examples of this for the individual web pages we define.
actionForm.<property> -> Call method ManagerReviewForm.get<property>
All of these actions should return a Forward containing a ManagerReviewForm instance.
The JSP Code should be as shown below:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
<netui:html>
<head>
<netui:base/>
</head>
<netui:body>
<netui:form action="approveLoanAction"></netui:form>
</netui:body>
</netui:html>
We’ll create a <netui:form> and set the action for that form to be returnToManagerReviewAction. Remember that returnToManagerReviewAction looks like this:
@Jpf.Action(forwards = {
@Jpf.Forward(name = "success",
path = "GetManagerReview.jsp"),
@Jpf.Forward(name = "success2",
path = "GetManagerReview2.jsp")
})
public Forward returnToManagerReviewAction(AssetSummaryForm form) {
Forward forward = new Forward("success", _managerReviewForm);
return forward;
}
The fact that returnToManagerReviewAction takes a form bean parameter of AssetSummaryForm type generates the association, within the form tag in AssetSummary.jsp only, that:
actionForm.<property> -> Call method AssetSummaryForm.get<property>
The instance of AssetSummaryForm that is used to make this call is the instance passed in the Forward object that forwarded to this page. In our ManagerReview.java page flow code, the AssetSummary.jsp is reached from these actions:
The JSP Code should be as shown below:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
<netui:html>
<head>
<netui:base/>
</head>
<netui:body>
<netui:form action="returnToManagerReviewAction"></netui:form>
</netui:body>
</netui:html>
NetUI data binding JSP tags automate the work needed to fetch data out of a form bean for display in a JSP page, and to set data into a form bean as a result of submitting a <netui:form>
. All NetUI data binding tags have an attribute that associates them with a property on a form bean. In some tags (e.g. <netui:label>
) the attribute is named ‘value’. On others (e.g. <netui-data:repeater>
the attribute is named ‘dataSource’. These attributes use a different syntax for defining the property expression. If the attribute is dataSource, the syntax is:
If the attribute is anything else (e.g. value on <netui:label>) the syntax is:
We use actionForm references in the following JSP code to bind properties from our ManagerReviewForm to the JSP page. You can drag and drop the appropriate tags from the JSP Designer palette to the JSP code to arrive at these results. Note that some of the tags come from the NetUI menu, and others from the NetUI-Data menu (e.g. repeater). The final code for our JSP files are given in the sections below:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
<netui:html>
<head>
<netui:base/>
</head>
<netui:body>
<netui:form action="approveLoanAction">
<table>
<tr>
<td><netui:label value="Customer Name:"/></td>
<td><netui:label value="${actionForm.name}"/></td>
</tr>
<tr>
<td><netui:label value="SSN:"/></td>
<td><netui:label value="${actionForm.ssn}"/></td>
</tr>
<tr>
<td><netui:label value="Loan Amount:"/></td>
<td><netui:label value="${actionForm.loanAmount}"/></td>
</tr>
<tr>
<td colspan="2">
<!-- We'll edit this property using a plain-old
NetUI actionForm binding (Note the netui:textBox
tag) -->
<netui:label value="Collateral Assets:"/>
<netui:textBox dataSource="actionForm.collateralAssets"/>
</td>
</tr>
</table>
</netui:form>
</netui:body>
</netui:html>
Notice that we don’t have any tags to handle the Notes property. We cover this separately here because we’ll use a custom Worklist tag called propertyEditor to allow us to use the property editing framework offered by Worklist. Insert the following code before the last <tr> element in the table above (the one that holds the CollateralAssets property elements)
<tr>
<td colspan="2">
<!-- This shows how to use the propertyEditor tag.
It will show a label, a summary value, and a
link to a stand-alone editor if available. This
tag also allows editing the property value
in-place.
NOTE: We set the hostPage attr to facilitate
navigating back to this page after editing
a property
NOTE: We need an action defined on the controller
that has the name given in the actionName attr
-->
<netui:label value="Reason for Action:"/>
<worklist:propertyEditor dataSource="actionForm.notesProp"
propName="Notes"
readOnly="false"
hostPage="GetManagerReview.jsp"
actionName="editNotesPropAction"/>
</td>
</tr>
To make the <worklist:propertyEditor> tag reference legal, we must define the worklist prefix to map to the correct URI for the Worklist tags. Add this to the end of the taglib statements at the top of the JSP file:
<%@taglib uri="http://bea.com/wli/worklist/tags-worklist-1.0" prefix="worklist"%>
The propertyEditor tag is bound to actionForm.notesProp which is of type PropertyInstanceHolder. This binding allows the propertyEditor tag to retrieve an editable property value for the property, determine its property type (one of the Worklist-defined types), find the registered stand-alone editor for that type, and pass the editable value to the stand-alone editor.
Note: | The propertyEditor tag refers to our editNotesPropAction. This action will be called when launching the stand-alone editor for the property. It is not apparent here, but our code in the ManagerReview page flow controller also includes two ‘return’ action methods that allow the stand-alone editor to return to the calling page flow when its Ok and Cancel buttons are clicked. These actions are okPropAction, and cancelPropAction, respectively. |
The final code for Asset Summary.jsp is as follows:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
<netui:html>
<head>
<netui:base/>
</head>
<netui:body>
<netui:form action="returnToManagerReviewAction">
<table>
<tr>
<td colspan="2"><netui:label value="Assets for ${actionForm.name}"/></td>
</tr>
<tr>
<netui-data:repeater dataSource="actionForm.assets">
<netui-data:repeaterHeader>
<table border="1">
<tr>
<td>Name</td>
<td>Value</td>
<td>Amount Owed</td>
<td>Actual Value</td>
</tr>
</netui-data:repeaterHeader>
<netui-data:repeaterItem>
<tr>
<td><netui:label value="${container.item.name}"/></td>
<td><netui:label value="${container.item.value}"/></td>
<td><netui:label value="${container.item.amountOwed}"/></td>
<td><netui:label value="${container.item.actualValue}"/></td>
</tr>
</netui-data:repeaterItem>
<netui-data:repeaterFooter>
</table>
</netui-data:repeaterFooter>
</netui-data:repeater>
</tr>
<tr>
<td><netui:label value="Credit Score:"/></td>
<td><netui:label value="${actionForm.creditScore}"/></td>
</tr>
</table>
</netui:form>
</netui:body>
</netui:html>
Add <netui:button> elements to navigate between forms and to take actions on the task they represent.
Insert the following code before/above the <tr> element containing the <worklist:propertyEditor> tag. This code renders an action button in our GetManagerReview page that when clicked, will call the viewAssetSummary action, and forward the user to the AssetSummary page.
<tr>
<td colspan="2">
<netui:button value="View Asset Summary"
action="viewAssetSummaryAction"/>
</td>
</tr>
and then insert this code before the ending </table> tag
<tr>
<td colspan="2">
<netui:button value="Approve" action="approveLoanAction"/>
<p/>
<netui:button value="Reject" action="rejectLoanAction"/>
</td>
</tr>
This renders buttons that allow the Loan Manager to take the Approve and Reject actions on the task (via the approveLoanAction and rejectLoanAction action methods on the page flow).
Insert the following code before the end table tag (</table>):
<td colspan="2"><netui:button value="Back"/>
This renders a ‘Back’ button to take the Loan Manager back to the Manager Review page. Note that there is no action attribute here. In this case, the action from the form (returnToManagerReviewAction) is taken.
The final jsp code for GetManagerReview.jsp is shown below:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
<%@taglib uri="http://bea.com/wli/worklist/tags-worklist-1.0" prefix="worklist"%>
<netui:html>
<head>
<netui:base/>
</head>
<netui:body>
<netui:form action="approveLoanAction">
<table>
<tr>
<td><netui:label value="Customer Name:"/></td>
<td><netui:label value="${actionForm.name}"/></td>
</tr>
<tr>
<td><netui:label value="SSN:"/></td>
<td><netui:label value="${actionForm.ssn}"/></td>
</tr>
<tr>
<td><netui:label value="Loan Amount:"/></td>
<td><netui:label value="${actionForm.loanAmount}"/></td>
</tr>
<tr>
<td colspan="2">
<netui:button value="View Asset Summary" action="viewAssetSummaryAction"/>
</td>
</tr>
<tr>
<td colspan="2">
<!-- This shows how to use the propertyEditor tag.
It will show a label, a summary value, and a
link to a stand-alone editor if available. This
tag also allows editing the property value
NOTE: We set the hostPage attr to facilitate
navigating back to this page after editing
NOTE: We need an action defined on the controller
that has the name given in the actionName attr
<netui:label value="Reason for Action:"/>
<worklist:propertyEditor hostPage="GetManagerReview.jsp"
dataSource="actionForm.notesProp"
actionName="editNotesPropAction"/>
<!-- We'll edit this property using a plain-old
NetUI actionForm binding (Note the netui:textBox
<netui:label value="Collateral Assets:"/>
<netui:textBox dataSource="actionForm.collateralAssets"/>
<netui:button value="Approve" action="approveLoanAction"/><p/>
<netui:button value="Reject" action="rejectLoanAction"/>
The final jsp code for AssetSummary.jsp is shown below:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%>
<%@taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%>
<netui:html>
<head>
<netui:base/>
</head>
<netui:body>
<netui:form action="returnToManagerReviewAction">
<table>
<tr>
<td colspan="2"><netui:label value="Assets for ${actionForm.name}"/></td>
</tr>
<tr>
<netui-data:repeater dataSource="actionForm.assets">
<netui-data:repeaterHeader>
<table border="1">
<tr>
<td>Name</td>
<td>Value</td>
<td>Amount Owed</td>
<td>Actual Value</td>
</tr>
</netui-data:repeaterHeader>
<netui-data:repeaterItem>
<tr>
<td><netui:label value="${container.item.name}"/></td>
<td><netui:label value="${container.item.value}"/></td>
<td><netui:label value="${container.item.amountOwed}"/></td>
<td><netui:label value="${container.item.actualValue}"/></td>
</tr>
</netui-data:repeaterItem>
<netui-data:repeaterFooter>
</table>
</netui-data:repeaterFooter>
</netui-data:repeater>
</tr>
<tr>
<td><netui:label value="Credit Score:"/></td>
<td><netui:label value="${actionForm.creditScore}"/></td>
</tr>
<tr>
<td colspan="2"><netui:button value="Back"/>
</tr>
</table>
</netui:form>
</netui:body>
</netui:html>
After designing the custom task UI for the Manager Review Pending step of the Loan Approval task plan.You need to register the custom task UI to be applied under those circumstances, by adding mapping entries to a registry file located in our LoanWeb web project, at the following location:
LoanWeb/WebContent/WEB-INF/task-ui-registry.xml
This XML file is associated with the schema for the Worklist Task UI Registry, and this schema is registered with Workshop.You w have to edit this file in Workshop. Open the file, and you’ll see an editor with Design and Source tabs. In the source tab, the initial contents should look something like this:
<task-ui-registry xmlns="http://www.bea.com/wli/worklist/taskuiregistry">
<step-override>
<task-plan-id>/Loans/Loan Approval:1.0</task-plan-id>
<step-name>Manager Review Pending</step-name>
<custom-task-ui-uri>/manager/ManagerReview.jpf</custom-task-ui-uri>
</step-override>
</task-ui-registry>
In the design tab, you can right-click any node in the tree view to act on it. You can delete nodes, and add children to nodes.
To register our custom task UI, we need the following information:
For this tutorial, the required information is:
The URI ends with .jpf, even though our page flow controller file is really ManagerReview.java. This is needed to allow servlet filters in the LoanApp web application to fire correctly. To finish editing task-ui-registry.xml first switch to the Package Explorer view and then do the following in the design tab of the editor:
\user_projects\domains\myworklist.
To validate the Custom Task UI we use the following scenario:
See Configure Users and Groups for Loan Processing.
Before creating a task instance for the new task plan, log into the Loan_web project using the following credentials:
Mary will see the ‘Loan for John Smith’ task in her Inbox.Click this task, the resulting page is the custom task UI page flow we defined above (see Figure 7-15).
This displays John Smith’s asset as shown in Figure 7-16.
This table lists John Smith’s assets, and their actual value (in descending order). Mary looks at this information, and realizes John Smith has only $10,000 in assets, and low credit score (100). Mary decides to reject this loan by performing the following steps:
![]() ![]() ![]() |