Realization of Search NPO Use Cases


Realization of Search NPO Use Cases

The following subsections will explain the use case realization for the use cases in the Search NPO package. Please refer to Chapter 1 for use case descriptions.

Search NPO Use Case

The search facility is a generic facility that can seamlessly plug into the navigation scheme of any functionality desiring to use the NPO search function. Plugging of a search function into the navigation scheme of other functions is accomplished by using a combination of three techniques:

  • The request handler calling the search function does so by rendering a search function-related view that transfers control to the request handler of the search facility.

  • The search facility's request handler remembers the request handler that invoked the search facility.

  • After the search is completed, the search facility transfers the control back to the calling request handler by rendering.

This use case is realized using the class structure depicted in Figure 5-23. The complete semantics will be are explained later in the section "Create the Campaign Use Case." Observe that the SearchAndListNPOAction is subclassed from DispatchAction.

click to expand
Figure 5-23: Search NPO class diagram

SearchAndListNPOForm uses a Collection object searchResult, which is a coarse-grained object consisting of NPOViewDTO objects. The business tier uses the value list handler pattern [Core] to provide this collection; this pattern is explained in Chapter 7.



Realization of Manage Campaigns Use Cases

The following subsections provide the use case realization for use cases in the Manage Campaigns package. Please refer to Chapter 1 for use case descriptions.

Create the Campaign Use Case

The campaign management function requires the ability to search and select an NPO for which a campaign has to be created. In order to accomplish this, the Create Campaign function will chain itself to the Search function. The Shared Request Handler pattern discussed in this section is used in demonstrating how we can accomplish this using the Struts framework. Figure 5-24 illustrates a class diagram for realizing this use case.

click to expand
Figure 5-24: Create Campaign clas diagram

Shared Request Handler Pattern

A use case may include or depend on other use cases. Often a common set of functionality is shared between several use cases. A navigation scheme can be conditionally altered by injecting new services in the process flow. In the sample application, the search-related functionality (search parameter page and search result page) and the associated request handlers can be invoked by both the NPO administrators as well as the donors. An NPO administrator (or a Site admin as stand-in) will require search services for creating campaigns based on NPOs selected using the search process. A donor will require the search service to find a desired NPO prior to making a donation. In both cases, the same search functionality is invoked. Upon invocation, the search facility will provide a search parameters page, whose submission will provide a list of NPOs from which the administrators or donors can select the desired NPO. Selection of an NPO during the campaign creation process will take the administrator to a page for entering campaign details, whereas selection of an NPO during the donation process will take a donor to the donation cart.

Structure Figure 5-25 illustrates the class diagram of the Shared Request Handler pattern. There are several dynamic views to demonstrate the campaign creation function, as such, the associated sequence diagrams are discussed progressively through the section.

click to expand
Figure 5-25: Shared Request Handler Pattern

Note 

From Figure 5-25, we observe that the Multi-Page pattern will be a foundational for implementing the Shared Request Handler pattern. We would have had significant difficultly implementing Shared Request Handler pattern without this foundational pattern. This demonstrates that the process of harvesting and documenting pattern is a continuous process. Over time, creating large-scale solutions implies looking at the catalog of design patterns whose implementation is already proven and the vocabulary well understood, and applying these pattern within the context of the problem domain to create a highly modular, scalable, maintenable, and extensible solution.

Configuration Semantics The struts-config.xml declarations are shown in this section. The Create Campaign use case employs the multi-page pattern. The view associated with page 1 is 2_3C_EnterPortalID.jsp, and the view associated with page 2 is 2_3_4_2_CampaignDetails.jsp; this is shown in the following struts-config.xml declaration. However, please note that the views 2_3C_EnterPortalID.jsp and 2_3_4_2_CampaignDetails.jsp need intervening views provided by the search function to search and select the NPO. Therefore, we should transfer control to the search function from the Create Campaign function. CreateCampaignAction request handler accomplishes this by creating an ActionForward with name="ShowSearch" for displaying the view 2_3_4_NewCampaignSearch.jsp after successfully processing the view 2_3C_EnterPortalID.jsp and before processing the view 2_3_4_2_CampaignDetails.jsp.

<!-- Use Case: Create Campaigns (Use Case Package: Manage Campaigns)-->
<action path="/CreateCampaignStep1" forward="/2_3C_EnterPortalID.jsp"/>
<action path="/CreateCampaignStep2"
   type="com.gc.prez.managecampaigns.CreateCampaignAction"
   name="ManageCampaignsForm" scope="session"
   validate="false">
   <forward name="EnterPortalID" path="/2_3C_EnterPortalID.jsp"/>
   <forward name="ShowSearch" path="/2_3_4_NewCampaignSearch.jsp"/>
   <forward name="CreateNewCampaign" path="/2_3_4_2_CampaignDetails.jsp"/>
   <forward name="success" path="/2_SiteAdministratorServicesMainPage.jsp"/>
</action>
 

The view 2_3_4_NewCampaignSearch.jsp includes a generic search parameter view G_AdvancedSearchForNPO.jsp whose HTML form's action parameter attribute has the URL "/SearchAndListNPO.do?method=advanceSearch". Submitting this form will cause the search parameter page to invoke ActionMapping identified by the path "/SearchAndListNPO", which in turn will be used for invoking the SearchAndListNPOAction.advanceSearch method of the request handler, therefore accomplishing a transfer of control from the campaign function to the SearchAndListNPOAction request handler. This transfer of control also includes transfer of application state from the action property stored in the forms ManageCampaignsForm to the action property of SearchAndListNPOForm. The action property informs the SearchAndListNPOAction request handler, whose function must be returned control when the search function exits after completing NPO selection. The action property provides a kind of callback facility when the SearchAndListNPOAction request handler is ready to transfer control back to the calling request handler. For example, in the sample application, when the action property is set to createNewCampaign, the SearchAndListNPOAction request handler will return control to the campaign function's next view (page 2 of campaign process) using the <forward> specification identified by the name="CreateNewCampaign"; the action property can also be set to "Donate", in which case the SearchAndListNPOAction request handler will return control to the donate function's next view using the <forward> specification identified by the name="Donate". This is shown here by the forward declarations "Create New Campaign" and "Donate". Note that the SearchAndListNPOAction is subclassed from DispatchAction.

<!-- Use Case: Search NPO (Use Case Package: Search NPO) -->
<action path="/SearchAndListNPO"
   type="com.gc.prez.searchnpo.SearchAndListNPOAction"
   name="SearchAndListNPOForm"
   scope="session"
   parameter="method"
   validate="false">
   <forward name="ShowSearchForCampaign" path="/2_3_4_NewCampaignSearch.jsp"/>
   <forward name="ShowSearchForDonation" path="P_3_DonorServicesAndSearch.jsp"/>
   <forward name="SelectNPOForNewCampaign" path="/2_3_4_1_SelectNPO.jsp"/>
   <forward name="SelectNPOForDonation" path="/P_3_1_SelectNPO.jsp"/>
   <forward name="CreateNewCampaign" path="/2_3_4_2_CampaignDetails.jsp"/>
   <forward name="Donate" path="/P_3_1_1_DonationCart.jsp"/>
   <forward name="failure" path="/2_SiteAdministratorServicesMainPage.jsp"/>
</action>
 

In the preceding struts-config.xml declaration, observe that the views selected by the SearchAndListNPOAction are specific to the calling function (Create Campaign or Donor Search); the "ShowSearchFor" and "selectNPOFor " <forward> specifications are associated with caller-specific views that embed a generic search form G_AdvancedSearchForNPO.jsp, and a generic select NPO form G_NPOSearchList.jsp, respectively. This embedding of search-related forms inside of other views is necessary to maintain the look and feel of the calling function and provide a consistent user experience.

View Semantics The following snippet is from the dynamic navigation bar 2_AdministrationServicesNavBar that is included with all administrator JSPs. This is just another case of multi-page pattern where the site administrator has an extra step "/CreateCampaignStep1"; this will invoke the view 2_4B_EnterEIN.jsp shown next:

<gc:hasAccess role="SiteAdminRole">
   <html:link page="/CreateCampaignStep1.do">
      <bean:message key="PortalAdminServices.CreateNewCampaign"/>
   </html:link><br>
</gc:hasAccess>
<gc:hasAccess role="PortalAdminRole">
   <html:link page="/CreateCampaignStep2.do">
      <bean:message key="PortalAdminServices.CreateNewCampaign"/>
   </html:link><br>
</gc:hasAccess>
 

The view 2_3C_EnterPortalID.jsp will invoke the request handler CreateCampaignAction using the ActionMapping identified by the path "/CreateCampaignStep2" (refer to struts-config .xml shown earlier) with the page attribute property of the corresponding form-bean set to 1. The request handler CreateCampaignAction may also be directly invoked from the navigation bar using the ActionMapping identified by the path "/CreateCampaignStep2" when the user is a portal-alliance administrator. The view 2_3C_EnterPortalID.jsp is shown next; the corresponding page is shown in Figure 5-26, and the multi-page pattern semantics are depicted in Figure 5-27.

click to expand
Figure 5-26: Enter Portal ID page

click to expand
Figure 5-27: Multi-page Pattern sequence diagram

<html:form method="POST" action="/CreateCampaignStep2.do" focus="portalID">
 <html:hidden property="page" value="1"/>
<table border="0" cellspacing="0" cellpadding="5">
         <tr>
            <td ><bean:message
               key="SiteAdminServices.EnterPortalID"/></td>
            <td><html:text property="portalID" size="16" maxlength="16"/></td>
         </tr>
         <tr>
            <td>&nbsp;</td>
            <td><html:submit><bean:message key="prompt.Submit"/></html:submit>
         </td>
      </tr>
   </table>
</html:form>
 

Once invoked, the CreateCampaignAction request handler will in turn invoke the search facility–related view 2_3_4_NewCampaignSearch.jsp using the <forward> specification identified by name="ShowSearch" in the method SearchandSelectNPO; the corresponding page is shown in Figure 5-28. Figure 5-29 is a sequence diagram for the method CreateCampaignAction.searchAndSelectNPO that depicts the flow of events for invoking the search facility page 2_3_4_ NewCampaignSearch.jsp. Observe that this page has an embedded view /G_AdvancedSearchForNPO.jsp that will invoke the SearchAndListNPOAction request handler. This is how the Create New Campaign function manages to transfer control to the search function.

click to expand
Figure 5-28: Enter Search Parameters page

click to expand
Figure 5-29: Invoke the search facility view using ActionForward

As mentioned earlier, the view 2_3_4_NewCampaignSearch.jsp includes the search function–related view G_AdvancedSearchForNPO.jsp. A condensed version of G_AdvancedSearchForNPO.jsp is shown next. When this form is submitted, it will result in the invocation of the SearchAndListNPOAction request handler. The SearchAndListNPOAction request handler is subclassed from DispatchAction, therefore the method invoked for this request handler is the one specified by the request time parameter method specified in the query portion of HTML form's action attribute URL.

<html:form method="POST"
   action="/SearchAndListNPO.do?method=advanceSearch"
   focus="keywords">
   ... rest of the JSP containing search parameters...
</html:form>
 

After successfully processing the parameters of the view 2_3_4_NewCampaignSearch.jsp, the request handler will list the results of the search by invoking the view 2_3_4_1_SelectNPO.jsp; the corresponding page is shown in Figure 5-29. The SearchAndListNPOAction request handler SearchandListNPOAction invokes this view by creating the ActionForward object related to the <forward> specification identified by name="SelectNPOForNewCampaign" (refer to struts-config.xml declarations specified in the preceding discussion). This view is selected because the state maintained in the SearchAndListForm form-bean identifies that the search is being performed on behalf of the Create Campaign function and therefore the look-and-feel of this function is desired.

The view 2_3_4_1_SelectNPO.jsp includes the generic view G_NPOSearchList.jsp for selecting an NPO from the selection list; the corresponding page is shown in Figure 5-30.

click to expand
Figure 5-30: Select NPO from the selection list

The specification action="/SearchAndListNPO.do?method=selectNPO" in the following HTML form (generated with view 2_3_4_1_Select.jsp) will use the ActionMapping object identified by the path "/SearchAndListNPO" to invoke SearchAndListNPOAction. The selection is applied to the corresponding form-bean, and the controller then calls the method SearchAndListNPOAction .selectNPO() of the request handler; this method is identified by the request time parameter method specified in the query portion of HTML form's action attribute URL.

<html:form method="POST"
   action="/SearchAndListNPO.do?method=selectNPO">
   ... rest of the JSP for displaying search results...
</html:form>
 

The SearchAndListNPOAction.selectNPO method will re-invoke the calling CreateCampaignAction by exiting with an ActionForward that invokes the next view 2_3_4_2_CampaignDetails.jsp (with the page property set to 2) in the campaign creation process using the <forward> declaration identified by name="CreateNewCampaign". This is how the search function manages to transfer control back to the Create Campaign function.This is shown in the Figure 5-31.

click to expand
Figure 5-31: Transfer control to the caller

The SearchAndListNPOAction.selectNPO method, prior to exiting, will first transfer the information on the selected NPO to the form-bean associated with the calling request handler. This is illustrated in Figure 5-32. The resulting page (based on 2_3_4_2_ CampaignDetails.jsp) is shown in Figure 5-33. The rest of the process is similar to the multi-page pattern.

click to expand
Figure 5-32: Set properties in the form-bean of the calling request handler

click to expand
Figure 5-33: Create New Campaign page

Successful submission of the Campaign page will result in the creation of a campaign for the corresponding Portal ID. This is illustrated in Figure 5-34, which shows the flow of events for the final step in campaign creation.

click to expand
Figure 5-34: Final step in campaign creation

Request Handler In the following abridged version of the CreateCampaignAction request handler, when the searchAndSelectNPO method is called from the execute method, the request handler initializes the action property of the search form-bean SearchAndListNPOForm with a value that informs the SearchAndListNPOAction of the ActionForward that it will have to create when the search function has completed selecting the desired NPO. The CreateCampaignAction request handler transfers control to the search function by creating an ActionForward relating to the <forward> specification identified by name="ShowSearch". This is illustrated using the following code fragment:

public class CreateCampaignAction extends Action {
    public ActionForward execute( ActionMapping mapping,
    ActionForm form, HttpServletRequest req,
    HttpServletResponse res ) throws Exception {
        /* The logic here is similar to multi-page pattern */
... rest of the code ...
    }

    public ActionForward searchAndSelectNPO( ActionMapping mapping,
    ActionForm form, HttpServletRequest req,
    HttpServletResponse res ) {
        ManageCampaignsForm campaignForm = ( ManageCampaignsForm )form;
        /* Find or create a new search form-bean */
        SearchAndListNPOForm searchForm =
        ( SearchAndListNPOForm )req.getSession().getAttribute(
                    "SearchAndListNPOForm" );
        if ( searchForm == null ) {
            searchForm = new SearchAndListNPOForm();
            req.getSession().setAttribute( "SearchAndListNPOForm", searchForm );
        }
        /* Store information on the calling module in search form-bean */
        searchForm.setAction( "createNewCampaign" );
        campaignForm.setAction( "createNewCampaign" );
        /* Display the search page for transferring control to the
         * search function */
        return mapping.findForward( "ShowSearch" );
    }
    /* Process page 2 after the NPO is selected by the search facility */
    public ActionForward createNewCampaign( ActionMapping mapping,
    ActionForm form, HttpServletRequest req,
    HttpServletResponse res ) throws Exception {
       ...rest of the code...
       /* The logic here is similar to multi-page pattern */
       return mapping.findForward( "success" );
    }
}
 

In the following SearchAndListNPOAction request handler, the advanceSearch method will set the searchResult property of the SearchAndListNPOForm; this property is a Collection object consisting of NPOViewDTO objects the SearchAndListNPOAction.selectNPO method will invoke the view of the calling function that was responsible for instantiating the search service; before transferring control to the Create Campaign view, the request handler will transfer information about the selected EIN from the search form-bean to the campaign form-bean.

public class SearchAndListNPOAction extends DispatchAction {
   public ActionForward advanceSearch( ActionMapping mapping,
   ActionForm form, HttpServletRequest req,
   HttpServletResponse res ) throws Exception {
      SearchAndListNPOForm searchForm = ( SearchAndListNPOForm )form;
...rest of the code...
      int resultCount =
      SearchAndListDelegate.getInstance().search( req, searchParameters );
      /* Get a Collection object from the business tier */
if ( resultCount > 0 ) {
            searchForm.setSearchResult(
            ( SearchAndListDelegate.getInstance() ).searchNext(
                       req, Constants.PageSize ) );
      }
      ...rest of the code...
      /* Show custom selection view related to the calling function */
      if ( action.equals( "createNewCampaign" ) ) {
         return mapping.findForward( "SelectNPOForNewCampaign" );
      }
      else if ( action.equals( "donate" ) )
      { return mapping.findForward( "SelectNPOForDonation" ); }
      else { return null; }
   }
   /* Based on action property value, transfer control to the caller */
   public ActionForward selectNPO( ActionMapping mapping,
   ActionForm form, HttpServletRequest req,
   HttpServletResponse res ) {
      SearchAndListNPOForm searchForm = ( SearchAndListNPOForm )form;
      String action                   = searchForm.getAction();
      ...rest of the code...
      /* Invoke post-search page of the calling function */
      if ( action.equals( "createNewCampaign" ) ) {
         return createNewCampaign( mapping, form, req, res );
      }
      else if ( action.equals( "donate" ) ) {
         return donate( mapping, form, req, res ); }
      else { return null; }
   }
   /* Initialize calling function's form-bean with selected NPO */
   public ActionForward createNewCampaign( ActionMapping mapping,
   ActionForm form, HttpServletRequest req, HttpServletResponse res ) {
      SearchAndListNPOForm searchForm = ( SearchAndListNPOForm )form;
      String action                   = searchForm.getAction();
      ManageCampaignsForm campaignsForm = ( ManageCampaignsForm )
         req.getSession().getAttribute( "ManageCampaignsForm" );
      String selectedEIN = searchForm.getEin();
      Iterator iterator =
      ( ( Collection )searchForm.getSearchResult() ).iterator();
      while ( iterator.hasNext() ) {
         NPOViewDTO dto = ( NPOViewDTO )iterator.next();
         if ( dto.getEin().equals( selectedEIN ) ) {
            /* Transfer the information on selected NPO
             * to campaign form-bean */
            campaignsForm.setEin( selectedEIN );
            campaignsForm.setNpoName( dto.getNpoName() );
            campaignsForm.setAction( action );
            req.getSession().removeAttribute( "SearchAndListNPOForm" );
            break;
         }
      }
      saveToken( req );
      return mapping.findForward( "CreateNewCampaign" );
   }
   public ActionForward donate( ActionMapping mapping,
   ActionForm form, HttpServletRequest req,
   HttpServletResponse res ) {
      ... donor search function related code ...
   }
}
 

Update Campaigns Use Case

A site administrator or a portal-alliance administrator can modify existing campaigns by altering the start and end dates of the campaigns. The implementation of this use case employs the multi-page pattern. Figures 5-35 and 5-36 illustrate the static and dynamic aspects of the Update Campaigns use case.

click to expand
Figure 5-35: Update Campaigns class diagram

click to expand
Figure 5-36: Update Campaigns sequence diagram

The use of nested indexed properties in realizing this use case is explained in Chapter 4, which demonstrates the ability to map request time parameters to properties of JavaBean objects contained in a Collection object. The declarations in the struts-config.xml file are depicted here:

<action path="/UpdateCampaignsStep1" forward="/2_3_5_EnterRegionCode.jsp"/>

<action path="/UpdateCampaignsStep2"
   type="com.gc.prez.managecampaigns.UpdateCampaignsAction"
   name="ManageCampaignsForm"
   scope="session"
   validate="false">
   <forward name="EnterRegionCode"
            path="/2_3_5_EnterRegionCode.jsp"/>
   <forward name="ShowUpdateCampaigns"
            path="/2_3_5_1_UpdateCampaigns.jsp"/>
   <forward name="success"
            path="/2_SiteAdministratorServicesMainPage.jsp"/>
</action>
 

The ActionMapping identified by the path "/UpdateCampaignsStep1" will render the view 2_3_5_EnterRegionCode.jsp; the corresponding page is shown in Figure 5-37. In turn, this view will use the ActionMapping identified by the path "/UpdateCampaignsStep2" to invoke the UpdateCampaignsAction request handler which in turn will render the view 2_3_5_1_UpdateCampaigns.jsp using the <forward> specification identified by name= "ShowUpdateCampaigns". The corresponding page is shown in Figure 5-38. Readers are urged to review the implementation provided in the accompanying source distribution.

click to expand
Figure 5-37: Enter region code page

click to expand
Figure 5-38: Update Campaigns page