In a simple search, customers search the catalog by entering text. For example, a customer could search for “air filter.” The customer input is searched as a complete string (for example, the above query would be based on “air filter” and not “air” or “filter”). We used the SearchFormHandler to create the query to the SQL Repository (Product Catalog) and to return a result set. It returns an empty set if no products are found. The result set is a collection of repository items that can be displayed in any format. Simple searches return both products and categories.

We used properties or configuration files to define the action a page performs and Boolean arguments to specify the type of searching to perform. Property names specify which catalog properties to search. The single configurable form handler simplifies catalog searching and should support all searching requirements. If your store requires custom searching beyond configuration changes, you can easily extend this form handler or write another one.

We implemented the search feature in Motorprise with a combination of JSPs, JSP fragments, and a Nucleus component configuration file (properties file). The properties file creates and configures a Nucleus component of class atg.commerce.catalog.SearchFormHandler to perform the search. The simple search functionality allows the user to enter a string and get products or categories that match the keywords as results.

Products have multiple properties such as keywords, description, longDescription, and displayName. The keywords property is a multi-valued property and the others are single-valued properties. Thus, for every product, there can be multiple keywords associated with it. A keyword search looks through all keyword properties for a string input. A text search looks through description and displayName for a string input, but does not search keyword properties. By default, a keyword and text search is done on each query. This means that both keywords as well as description and display name will be queried.

SimpleSearchFragment.jsp

We wanted customers to be able to search from other store pages besides the search page, simple_search.jsp. Therefore, we created this small search form fragment, /en/search/SimpleSearchFragment.jsp, that defines the search text entry field and the Search button to embed in any page that requires searching. We embedded this fragment in the Motorprise header so that users can search from every page.

This fragment imports the CatalogSearch component in order to configure its searchInput property and invoke its search handler.

Finally, the form redirects to the page name passed via the FormAction parameter. This page fragment declares a page parameter that is used as the action for the search form. In other words, the FormAction parameter is the file name of the page to which the user is redirected when the search form’s submit method is invoked.

The following example shows SimpleSearchFragment.jsp:

<%/* This page fragment is intended to be embedded on any page that
     requires a search capability.  */%>


<dsp:importbean bean="/atg/commerce/catalog/CatalogSearch"/>

<dsp:form action="simple_search.jsp" method="POST">
<table cellspacing="0" cellpadding="0" border="0" bgcolor="#999999" width=100%>

  <tr><td colspan=3><dsp:img src="../images/d.gif" vspace="0"/></td></td></tr>
  <tr>
    <td><dsp:img src="../images/d.gif" hspace="3"/></td>
    <td width=100>
    <!-- form elements -->
    <input name="repositoryKey" type="hidden" value="<dsp:valueof
      bean='/OriginatingRequest.requestLocale.locale'/>">
    <dsp:input bean="CatalogSearch.searchInput" size="15" type="text" value=""/>
    </td>
     <!--  use this hidden form tag to make sure the search handler is invoked if
       someone does not hit the submit button -->
     <td align=center>
    <dsp:input bean="CatalogSearch.search" type="hidden" value="Search"/>
    <dsp:input type="image" src="../images/motorprise-search.gif"
      bean="CatalogSearch.search" name="search" value="Search" border="0"/> </td>
    <!-- end form elements -->

  </tr>
  <tr>
    <td><dsp:img src="../images/d.gif" hspace="3"/></td>
    <td colspan=2><dsp:a href="advanced_search.jsp"><font color="#FFFFFF"><span
      class=smallw>Advanced search</span></font></dsp:a></td>
  </tr>
  <tr><td colspan=3><dsp:img src="../images/d.gif" vspace="0"/></td></tr>


</dsp:form>
</table>

The hidden input tag is an HTML workaround for forms with a single input field. The hidden input allows the user to invoke the submit method by typing the return key within the text input field.

Without this hidden tag, the user must click the Search button.

simple_search.jsp

The simple_search.jsp is a page built of several JSP code fragments that provide their own specific functionality. simple_search.jsp uses SearchResults.jsp to display the results of the search.

First, we display the search results at the top of the page by including SearchResults.jsp. The CatalogSearch component is used to perform the actual searching. When the user submits the search, the handler search method is invoked. This basically fills up the search results by ItemType property of catalogSearch.

The following example shows simple_search.jsp:

<%@ taglib uri="dsp" prefix="dsp" %>
<dsp:page>

<dsp:importbean bean="/atg/dynamo/droplet/ForEach"/>
<dsp:importbean bean="/atg/commerce/catalog/CatalogSearch"/>
<dsp:importbean bean="/atg/dynamo/droplet/Switch"/>

<DECLAREPARAM NAME="noCrumbs"
   CLASS="java.lang.String"
   DESCRIPTION="This is for deciding what kind of breadcrumbs to display.
   If this is true, then breadcrumbs will show: Store Home|Search,
   instead of nav history. Default is false."
   OPTIONAL>


<dsp:include page="../common/HeadBody.jsp" flush="true"><dsp:param
  name="pagetitle" value=" Simple Search"/></dsp:include>
<table border=0 cellpadding=0 cellspacing=0 width=800>
<tr>
  <td colspan=2><dsp:include page="../common/BrandNav.jsp"
    flush="true"></dsp:include></td>
</tr>
<tr bgcolor="#DBDBDB" >
  <td colspan=2 height=18>&nbsp;
  <!-- breadcrumbs -->
  <span class="small">
  <dsp:droplet name="Switch">
    <dsp:param name="value" param="noCrumbs"/>
      <dsp:oparam name="true"><dsp:a href="../home.jsp">Product Catalog</dsp:a>
        &nbsp; Simple Search</dsp:oparam>
      <dsp:oparam name="default"><dsp:param name="noCrumbs" value="false"/>
        <dsp:include page="../common/breadcrumbs.jsp" flush="true"><dsp:param
          name="displaybreadcrumbs" value="true"/><dsp:param name="no_new_crumb"
            value="true"/></dsp:include>
      </dsp:oparam>
  </dsp:droplet></span>
  </td>
</tr>


<tr>
  <td width=55><dsp:img src="../images/d.gif" hspace="27"/></td>
  <td valign="top" width=745><br><span class="big">Search</span></td>
</tr>

<tr>
  <td width="40"><dsp:img src="../images/d.gif"/></td>
  <td><br>
    <dsp:getvalueof id="pval0" bean="CatalogSearch.searchResultsByItemType">
      <dsp:include page="SearchResults.jsp" flush="true"><dsp:param
      name="ResultArray" value="<%=pval0%>"/></dsp:include></dsp:getvalueof>
  </td>
</tr>

<tr><td colspan=2><dsp:img src="../images/d.gif" vspace="6"/></td></tr>

<tr>
  <td width="40"><dsp:img src="../images/d.gif"/></td>
  <td><!-- simple search box -->
    <table bgcolor="#FFCC66" border=0 cellpadding=0 cellspacing=0>
      <tr>
        <td colspan=3>
          <table width=100% cellpadding=4 cellspacing=0 border=0>
          <tr><td class=box-top>&nbsp;Simple Search</td></tr>
          </table>
        </td>
      </tr>

      <tr><td bgcolor="#666666"><dsp:img src="../images/d.gif" width="1"/></td>
          <td>
            <dsp:form action="simple_search.jsp" method="POST">
            <table width=100% cellpadding=6 cellspacing=0 border=0>
            <tr>
              <td></td>
              <td bgcolor="#ffcc66">
              <input name="repositoryKey" type="hidden" value="<dsp:valueof
                bean="/OriginatingRequest.requestLocale.locale"/>">
              <dsp:input bean="CatalogSearch.searchInput" size="30" type="text"/>
              <input name="noCrumbs" type="hidden" value="<dsp:valueof
                param="noCrumbs"/>">
              <!--  use this hidden form tag to make sure the search handler is
                invoked if someone does not hit the submit button -->
              <dsp:input bean="CatalogSearch.search" type="hidden"
                value="Search"/>
              <dsp:input bean="CatalogSearch.search" type="submit"
                value="Search"/><br><!--<span class="help">Separate words or
                  phrases by <b>AND</b> or <b>OR</b></span>-->
              <p>
              <span class=smallb><dsp:a href="advanced_search.jsp">
                <dsp:param name="noCrumbs" param="noCrumbs"/>
                Use advanced search form</span></dsp:a>
              </td>
            </tr>
            <tr>
              <td></td>
              <td>
              <span class=smallb><dsp:a href="part_number_search.jsp">
               <dsp:param name="noCrumbs" param="noCrumbs"/>
                 Use part number search form</dsp:a></span>
              </td>
            </tr>
            </table>
            </dsp:form>
          </td>
          <td bgcolor="#666666"><dsp:img src="../images/d.gif" width="1"/></td>
      </tr>
      <tr><td bgcolor="#666666" colspan=3><dsp:img src=
        "../images/d.gif"/></td></tr>
      </table>
    </td>
  </tr>
  </table>


</body>
</html>
</dsp:page>
SearchResults.jsp

We used the SearchResults page fragment to iterate and display search results from simple_search.jsp. The ForEach component is sent the parameter array, which can take many kinds of multi-valued objects.

The type in this case is a java.util.Map that is the product of the SearchFormHandler component.

The map has one entry for each value specified in the itemTypes value of the component’s configuration file. In SimpleSearch, the itemTypes are category and product.

The map is a collection of search result arrays and their associated itemType identifiers. The value associated with category and product in the map is an array of category or product items, or null if no results are found for that key.

The category and product map elements are extracted by iterating through the map with the standard ForEach component in the outermost ForEach droplet tag. For each element of the map, the Switch component is then invoked to distinguish the category and product elements, and to affect the order in which they’re rendered on the page.

Once the category and product search result array is obtained, it is necessary to iterate through each element of that array to display the results. In order to detect an empty result array, we used another Switch component, this time for the unset dsp:oparam feature of Switch that identifies an empty input array and a message is rendered indicating that no items of the given type were found. When the array is non-null, the default dsp:oparam tag of Switch is rendered. In this case, another call to the ForEach component iterates through the array and displays each of its items.

<%@ taglib uri="dsp" prefix="dsp" %>
<dsp:page>


<%
/* ---------------------------------------------------------------
This JSP droplet displays the contents of search
that potentially returns both category and product repository items.
The one paramater, ResultArray, accepts a HashMap that contains
elements with the keys "category" and "product".  The values of these
keys are collections of category or product repository items found in
the search.
----------------------------------------------------------------*/
%>


<DECLAREPARAM NAME="ResultArray"
              CLASS="java.util.Map"
              DESCRIPTION="Array of Search Results">


<dsp:importbean bean="/atg/dynamo/droplet/Switch"/>
<dsp:importbean bean="/atg/dynamo/droplet/IsEmpty"/>
<dsp:importbean bean="/atg/dynamo/droplet/ForEach"/>
<dsp:importbean bean="/atg/dynamo/droplet/RQLQueryForEach"/>


<dsp:droplet name="ForEach">
  <dsp:param name="array" param="ResultArray"/>

  <%/*Each item in this array is a Collection of Categories or Products...*/%>
  <dsp:param name="elementName" value="ResultCollection"/>

  <dsp:oparam name="output">
    <dsp:droplet name="Switch">

      <%--The key tells us if this is a Collection of Products or Categories: --%>
      <dsp:param name="value" param="key"/>

      <%--For the list of CATEGORIES: --%>
      <dsp:oparam name="category">

        <blockquote>

        <dsp:droplet name="Switch">
          <dsp:param name="value" param="ResultCollection"/>
          <dsp:oparam name="default">
            <p>

            <%-- For each Category in the Collection: --%>
            <dsp:droplet name="ForEach">
              <dsp:param name="array" param="ResultCollection"/>
              <dsp:param name="sortProperties" value="+displayName"/>
              <dsp:param name="elementName" value="Category"/>
              <dsp:oparam name="outputStart">
                <b>We found these categories matching your search</b>
                <p>
              </dsp:oparam>
              <dsp:oparam name="output">

                <%-- Display a link to the Category: --%>
          <dsp:getvalueof id="urlStr" idtype="java.lang.String"
            param="Category.template.url">
                <dsp:a page="<%=urlStr%>">
                  <dsp:param name="id" param="Category.repositoryId"/>
                  <dsp:param name="navAction" value="jump"/>
                  <dsp:param name="Item" param="Category"/>
                  <dsp:valueof param="Category.displayName">No name</dsp:valueof>
          </dsp:a>
          </dsp:getvalueof>
                <br>
              </dsp:oparam>
              <dsp:oparam name="empty">
                <b>There are no categories matching your search</b>
                <p>
              </dsp:oparam>
            </dsp:droplet>
          </dsp:oparam>
          <%-- If NO Categories returned by the search: --%>
          <dsp:oparam name="unset">
            No category items in the catalog could be found that match your query
          </dsp:oparam>
        </dsp:droplet><%/*ForEach Category*/%>

        </blockquote>
        <P>
      </dsp:oparam>

      <%-- For the list of PRODUCTS: --%>
      <dsp:oparam name="product">
        <blockquote><p>

        <dsp:droplet name="Switch">
          <dsp:param name="value" param="ResultCollection"/>

          <dsp:oparam name="default">

            <%/*For each Product in the Collection: */%>
            <dsp:droplet name="ForEach">
              <dsp:param name="array" param="ResultCollection"/>
              <dsp:param name="sortProperties" value="+displayName"/>
              <dsp:param name="elementName" value="Product"/>
              <dsp:oparam name="outputStart">
                <p>
                <b>We found these products matching your search</b>
                <p>
              </dsp:oparam>
              <dsp:oparam name="output">
                <%-- Display a link to the Product: --%>
          <dsp:getvalueof id="urlStr" idtype="java.lang.String" param=
            "Product.template.url">
                <dsp:a page="<%=urlStr%>">
                  <dsp:param name="id" param="Product.repositoryId"/>
                  <dsp:param name="navAction" value="jump"/>
                  <dsp:param name="Item" param="Product"/>
                  <dsp:valueof param="Product.displayName">No name
                  </dsp:valueof>&nbsp;-&nbsp;<dsp:valueof
                    param="Product.description"/>
          </dsp:a>
          </dsp:getvalueof>
                <br>
              </dsp:oparam>
              <dsp:oparam name="empty">
                <b>There are no products matching your search</b>
                <p>
              </dsp:oparam>

            </dsp:droplet> <%/*ForEach Product*/%>

          </dsp:oparam>

          <%/*If NO Products returned by the search: */%>
          <dsp:oparam name="unset">
            No product items in the catalog could be found that match your
              query<p>
          </dsp:oparam>

        </dsp:droplet>
        </blockquote><P>
      </dsp:oparam>
    </dsp:droplet>

  </dsp:oparam>

</dsp:droplet> <%/*ForEach Item returned by Search */%>
</dsp:page>
 
loading table of contents...