Tutorial: Building a Worklist Application

     Previous  Next    Open TOC in new window    View as PDF - New Window  Get Adobe Reader - New Window
Content starts here

Advanced Topic: Adding a Customized User Interface

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:

 


Define Web Page Mock-Up and Flow

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).

Figure 7-1 Manager Review Mock-Up Page

Manager Review Mock-Up Page

Figure 7-2 Asset Summary Mock-Up Page

Asset Summary Mock-Up Page

Now that the mock-up is complete, proceed with defining the page flow as described in the following section.

 


Create the Page Flow

After determining the appearence of the customized user interface pages, define the logic and use of these pages as follows::

  1. In the Package Explorer pane, right-click the Loan_Web\src folder, and select NewArrow symbolOther. This will display the Select a Wizard dialog box.
  2. Select Web Page Flow and click Next (see Figure 7-3).
  3. Figure 7-3 Define Page Flow


    Define Page Flow

  4. The New Page Flow dialog box appears, enter manager in the Page Flow Folder name field and ManagerReview as the Controller name.
  5. Select the Make this a nested page flow check box and click Finish (see Figure 7-4).
  6. Figure 7-4 New Page Flow Dialog Box


    New Page Flow Dialog Box

    The Open Associated Perspective? dialog box is displayed.

  7. In the displayed Open Associated Perspective? dialog box, select the Remember my decision check box and click Yes. In doing so, you associate the project with the Page Flow perspective.
  8. The Page Flow Editor view appears (see Figure 7-5).
  9. Figure 7-5 Page Flow Editor


    Page Flow Editor

Edit the page flow as follows:

  1. Replace PageFlowController with com.bea.wli.worklist.TaskUIPageFlowController.
  2. Delete simpleActions = { @Jpf.SimpleAction(name = "begin", path = "index.jsp") })

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.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 WindowArrow symbolShow ViewArrow symbolProblems.

Define Form Beans

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:

Create Form Beans

  1. In the Page Flow Explorer, right-click Form Beans and select New Inner Class Form Bean ( see Figure 7-6).
  2. Figure 7-6 New Inner Class Form Bean


    New Inner Class Form Bean

  3. A new form bean with the default name NewFormBean is created.
  4. Right-click NewFormBeanArrow symbolRename, and name it as ManagerReviewForm.
  5. Repeat step 1 and step 3 and name it as AssetSummaryForm and AssetForm (see Figure 7-7).
  6. Figure 7-7 Form Beans


    Form Beans

Define ManagerReviewForm
  1. The ManagerReviewForm includes the following variables and data type:
    • Name (String)
    • SSN (String)
    • LoanAmount (Int)
    • NotesProp (PropertyInstanceHolder)
    • CollateralAssets (String)
  2. Select the above variables and place them in the ManagerReview.java source view.
  3. Select the variables and select SourceArrow symbolGenerate Getters and Setters.
  4. The Generate Getters and Setters dialog box appears.

  5. Select the properties variable variables (Figure 7-8).
  6. Figure 7-8 Generate Getters and Setters Dialog Box


    Generate Getters and Setters Dialog Box

  7. Click OK.

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.
Define AssetSummaryForm
  1. The AssetSummaryForm includes the following properties and data type:
    • Name (String)
    • Ssn (String)
    • Assets (SortedSet<AssetForm>)
    • CreditScore (int)
  2. Repeat step 2 and step 3 of ManagerReviewForm.
  3. Select the property variables listed above.
  4. Click Ok.
  5. Enter the follwing code into the AssetSummaryForm:
  6. 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 AssetForm
  1. The AssetForm will include the following properties and data type:
    • Name (String)
    • Value (int)
    • AmountOwed (int)
    • TotalValue (int)
  2. Repeat step 2 and step 3 of ManagerReviewForm..
  3. Select the property variables listed above.
  4. Click Ok.
  5. 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 errror, 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;

Define Support Asset Information Files

Define information to support a loan request for a person named John Smith (use spelling and case as given here) as follows:

  1. In the Package Explorer pane, expand Loan_Web.
  2. Right-click WebContentArrow symbolNewArrow symbolFolder.
  3. The New Folder dialog box appears (see Figure 7-9).

    Figure 7-9 New Folder


    New Folder

  4. Enter assets in the Folder Name and click Finish.
  5. Create another new folder, enter creditRatings in the Folder Name and click Finish.
  6. Right-click asset and select a new file.
  7. The New File dialog box appears.

  8. In the File Name enter John Smith.properties and click Finish.
  9. It appears in the editor.

  10. Enter the following details in the editor:
  11. assetList=Home, Car

    Home.value=300000

    Home.amountOwed=290000

    Car.value=20000.

    Car.amountOwed=19000

  12. Right-click creditRatings and select a new file.
  13. In the File Name enter CreditRating.properties and click Finish.
  14. Enter the following details (exactly as shown) on a single line in the properties file:
  15. John\ Smith=100.

Define Actions on the Page Flow

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.

Create an Action

  1. In the Page Flow Explorer, right-click Actions, new actions.
  2. The New Action dialog box appears (see Figure 7-10).

    Figure 7-10 New Action


    New Action

  3. Create five new action and enter the details as shown in Table 7-1.
    Table 7-1 New Action Settings
    Action Name
    Action Template
    Form Beans
    Forward To
    begin
    Basic...
    <none>
    <none>
    viewAssetSummaryAction
    Basic...
    ManagerReviewForm
    <none>
    returnToManagerReviewAction
    Basic...
    AssetSummaryForm
    <none>
    approveLoanAction
    Basic...
    ManagerReviewForm
    <none>
    rejectLoanAction
    Basic...
    ManagerReviewForm
    <none>

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.

Implement the Action Methods

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:

Action Methods, Form Beans and the UseFormBean Field

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 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 Property Editors and Actions

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-2
Action Name
Action Template
Form Bean
Forward To
editNotesPropAction
Basic...
ManagerReviewForm
<none>
okPropAction
Basic...
com.bea.wli.datatype.EditorValueHolder
<none>
cancelPropAction
Basic...
<none>
<none>
Define Action on the Page Flow
Notes: 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);
    }
Final Code for Page Flow
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();
        }
    }
}

Define JSP Pages

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.

Create JSP Files

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:

To create the JSP Files

  1. In the Page Flow Explorer, right-click Pages.
  2. Select GetManagerReview.jspArrow symbolCreate to create the new JSP file
  3. Repeat the above steps for AssetSummary.jsp.

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>

Create the Form and Associate it with an Action

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:

  1. If the JSP Design Palette is not visible, go to WindowArrow symbolShow ViewArrow symbolJSP Design Palette.
  2. The JSP Design Palette appears (see Figure 7-11).

    Figure 7-11 JSP Design Palette


    JSP Design Palette

  3. In the JSP Design Palette, expand NetUI and select form.
  4. Drag the form into your JSP source editor and drop it inside the <netui:body/> tag.
  5. 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.

GetManagerReview.jsp
  1. Double-click GetManagerReview.jsp and open it in the source editor.
  2. Drag the form from NetUI to the GetManagerReview.jsp and set the action for that form to approveLoanAction. The fact that approveLoanAction takes a form bean parameter of ManagerReviewForm type generates the association, within the form tag in GetManagerReview.jsp only, that:
  3. actionForm.<property> -> Call method ManagerReviewForm.get<property>
  4. The instance of ManagerReviewForm that is used to make this call is the instance passed in the Forward object that forwarded to this page. In the ManagerReview.java page flow code, the following happens from these actions:
    • begin()Add Data Binding Fields
    • returnToManagerReviewAction()
    • okPropAction()
    • cancelPropAction()
    • 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>
AssetSummary.JSP

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>
Add Data-binding Fields

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:

actionForm.<property>

If the attribute is anything else (e.g. value on <netui:label>) the syntax is:

${actionForm.<property>}

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:

Final Code GetManagerReview.jsp
<%@ 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.
Final Code Asset Summary.jsp

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 Command Links and Buttons

Add <netui:button> elements to navigate between forms and to take actions on the task they represent.

GetManagerReview.jsp

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).

Asset Summary.jsp

Insert the following code before the end table tag (</table>):

<tr>

<td colspan="2"><netui:button value="Back"/>

</tr>

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.

Final JSP Code

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

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 hostPage="GetManagerReview.jsp"

dataSource="actionForm.notesProp"

propName="Notes"

readOnly="false"

actionName="editNotesPropAction"/>

</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>

<tr>

<td colspan="2">

<netui:button value="Approve" action="approveLoanAction"/><p/>

<netui:button value="Reject" action="rejectLoanAction"/>

</td>

</tr>

</table>

</netui:form>

</netui:body>

</netui:html

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>

 


Register the Custom UI

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">
</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:

  1. In the Package Explorer, expand LoanWeb and go to /WebContent/WEB-INF/, and select task-ui-registry.xml.
  2. Right-click task-ui-registry.xml, and select Add ChildArrow symbolstep-override. This adds a new step-override element under the root element (see Figure 7-12).
  3. Figure 7-12 Adding Child


    Adding Child

  4. Expand the newly added step-override element. You'll see three elements under it called, respectively, task-type-id, step-name, and custom-task-ui-uri. These all are set to default values.
  5. For each of these three elements, click on the right-hand value column, and replace the default values with the l value discussed above (see Figure 7-13) .
  6. Figure 7-13 Edited XML


    Edited XML

 


Deploy the Custom Task UI

  1. On the Package Explorer pane, select and right-click on Loan_Web.
  2. Click Run AsArrow symbolRun On Server.
  3. In the Define a New Server dialog box, accept the default settings and click Next.
  4. Browse and select the myworklist domain, which you created using the Configuration Wizard. It is located at \user_projects\domains\myworklist.
  5. Click Finish.

 


Validate the Custom UI

To validate the Custom Task UI we use the following scenario:

Configure users and groups

See Configure Users and Groups for Loan Processing.

Create a Loan Approval Task

  1. Log in to the Loan_Web project using the following credentials:
  2. Username: weblogic

    Password: weblogic

  3. The Home page is displayed with the portlets for the Inbox of overdue, upcoming, and assigned tasks, along with the portlet that allows you to create a new task.
  4. Click the /Loan/loan_approval 1.0 option in the Create Task portlet. The Create New Task page is displayed.
  5. Enter the name Loan for John Smith as the Task Name.
  6. Enter the following information:
  1. Click Create Task. The task is created and shows up in the Upcoming Tasks portlet on the home page.
  2. Click Logout to close and log out as weblogic from the Worklist User Portal.

Assigned loanOfficer Forwards Loan to his Manager

  1. Log in to the Loan_Web project using the following credentials:
  2. Username: John

    Password: password

  3. Click Loan for John Smith in the Upcoming Tasks portlet. This will display the Task Work page with the task details, and the Action options available for user John (Figure 7-14).
  4. Figure 7-14 Task Detail Information


    Task Detail Information

  5. Select Request Manager Review in the Actions section to forward the request to the loan managers group for approval, and click Next.
  6. In the Key Action Properties of the refreshed web page that appears, enter the String Good Guy.
  7. Click Submit to complete the task.
  8. As the loan has been send to the manager for approval, the task instance will no longer appear in John's Inbox.
  9. Logout as user John from the Worklist User Portal.

Assigned loanManager Rejects the Loan.

Before creating a task instance for the new task plan, log into the Loan_web project using the following credentials:

Username: Mary

Password: password

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).

Figure 7-15 View Asset Summary

View Asset Summary

  1. From the Manager Review Page, click View Asset Summary.
  2. This displays John Smith's asset as shown in Figure 7-16.

    Figure 7-16 Asset Summary

    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:

  3. Click Back in the Asset Summary Page, to return to the Manager Review form.
  4. Enter Insufficient assets and low credit score in Reason for Action.
  5. Click Reject as shown in Figure 7-17, and the loan application is rejected by the manager. This puts the task in amn aborted state and removes it from Mary's Upcoming task portlets.
  6. Figure 7-17 Loan Reject


    Loan Reject


  Back to Top       Previous  Next