4.1 Application Features

Here's the basic feature set:

  • User enters and saves search information for a book (the title and an ISBN).

  • User can create, view, delete, and run saved searches.

The application tracks the following data:

  • Amazon.com prices, availability, release date, and sales rank based on the supplied ISBN

  • Google rankings and top five search results for the book title

  • eBay search results for the book title, including number of matching listings, highest price, and number of bids

A few JSP pages can present the information and accept input from the user. These JSP pages rely on a simple Java class, Search. The Search class deals with connections to web services via a set of supporting classes: AmazonConnection, EbayConnection, and GoogleConnection. This relationship is shown in Figure 4-1.

Figure 4-1. Interaction between JSPs and Java support and connection classes
figs/rww_0401.gif


First, the following list details the JSP pages and presentation objects used in the application.


list.jsp

A list of the previously saved searches


new.jsp

Create a new search


view.jsp

View the results of a search


delete.jsp

Delete a saved search


update.jsp

Request an existing search to be updated


default.css

Rudimentary stylesheet

4.1.1 Listing Searches

The first JSP, list.jsp, is shown in Figure 4-2. This is the main page for the web application. Clicking View takes users to a report page showing the data retrieved from the various web services. Delete removes the selected search from the web application, and Update causes the web application to refresh the data from the various web services.

Figure 4-2. Listing searches
figs/rww_0402.gif


The code for list.jsp is shown in Example 4-1. It can conceptually be broken into three main sections. First, there are a few initialization lines, the normal JSP and HTML headers. Next, a JSP scriptlet retrieves data from our supporting Java classes and performs some housekeeping to more cleanly present the data in the JSP. Finally, the actual HTML formatting and JSP display variables appear.

Example 4-1. Main search results JSP
<%@ page contentType="text/html; charset=iso-8859-1" language="java"

 import="com.cascadetg.ch04.*" errorPage="" %>

<%



    boolean isUpdating = false;



    java.util.Hashtable mySearches 

        = com.cascadetg.ch04.Search.getAllSearches( );

    if(mySearches != null)

    {

        java.util.Enumeration mySearchEnum = mySearches.elements( );



        while(mySearchEnum.hasMoreElements( ))

        {

            Search current = 

                (com.cascadetg.ch04.Search)mySearchEnum.nextElement( );

            if(current.isUpdating( ))

                isUpdating = true;

        }

    }



%>

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<title>Chapter 4: Competitive Analysis, List</title>

<meta http-equiv="Content-Type" 

    content="text/html; charset=iso-8859-1" />

<% if (isUpdating) { %>

<meta http-equiv="refresh" content="15;url=list.jsp">

<% } %>

<link href="default.css" rel="stylesheet" type="text/css" />

</head>



<body>

<% if (isUpdating) { %>

<p align="right">Page will automatic refresh every 15 seconds 

while an update is in progress.</p>

<% } %>



<% if (mySearches == null) { %>

<p>No searches defined.</p>

<% } else { %>

<table width="100%"  border="0" cellspacing="3" cellpadding="3">

  <tr>

    <td><strong>Search</strong></td>

    <td width="200" nowrap="nowrap">&nbsp;</td>

  </tr>

<%

    java.util.Enumeration mySearchListing = mySearches.elements( );

    while(mySearchListing.hasMoreElements( )) 

    { 

        Search mySearch = (Search)mySearchListing.nextElement( );

        String productID = mySearch.getProductID( );

        %>

  <tr>

    <td class="list">

        <%= mySearch.getProductTitle( ) %> (<%= productID %>)</td>

    <td width="200" align="center" nowrap="nowrap" class="list">

    <a href="view.jsp?productID=<%=productID %>">View</a> - 

    <a href="delete.jsp?productID=<%=productID %>">Delete</a> - 

    <a href="update.jsp?productID=<%=productID %>">Update</a></td>

  </tr>

<% 

    }

%>

</table>

<% } %>

<p><a href="new.jsp">New Search</a></p>

</body>

</html>

4.1.2 Adding Searches

A user can click on the New Search link (as shown in Figure 4-2) to be brought to a form to add a new search. An example of this form is shown in Figure 4-3.

Figure 4-3. Adding a new search
figs/rww_0403.gif


The book title field is self-explanatory. The ISBN field is provided to allow entry of an International Standard Book Number (ISBN), a worldwide standard for providing a unique identifying number for any published book.

The ISBN number can typically be found on the back cover of a book. You can also find ISBN numbers for books by browsing the Amazon web site or consulting with the publisher. If you just want to try the application without finding a new ISBN, you can click on the provided link.

Another, different standard from ISBN is the Universal Product Code (UPC). Often, both the creator and distributors of a product introduce additional identifying codes for goods and services. Which codes to use is usually a business-driven question, but you'll want to be aware of what numbering systems are in place.

In this example, we're using the ISBN as the unique identifier for the books we're searching for, but in the "real world," you may want to use your own internal tracking system and then map that to the other systems. For example, if you carry both books (ISBN) and pickles (UPC), you're using two different numbering systems.

The code for new.jsp file is fairly straightforward, as shown in Example 4-2. If the creation of a new search is successful, users are returned to list.jsp.

Example 4-2. New search JSP
<%@ page contentType="text/html; charset=iso-8859-1" 

language="java" errorPage="" %>

<%

    boolean success = false;

    boolean submitted = (request.getParameter("Submit") != null);

    if(submitted)

    {

        String productID = request.getParameter("productID");

        String productTitle = request.getParameter("productTitle");

        

        success = 

              com.cascadetg.ch04.Search.addSearch(productID, productTitle);

        if(success)

        {

            response.sendRedirect("list.jsp");

            return;

        }

    }

%>

<head>

<title>Chapter 4: Competitive Analysis</title>

<meta http-equiv="Content-Type" 

    content="text/html; charset=iso-8859-1" />

<link href="default.css" rel="stylesheet" type="text/css" />

</head>

<body>

<% if(submitted) { %>

<p>Error submitting. Try again.</p>

<% } %>

<form name="new_item"  method="post" action="new.jsp">

  <table width="60%"  border="0" cellspacing="0" cellpadding="0">

    <tr>

      <td width="50%">Book ISBN :</td>

      <td><input name="productID" type="text" /></td>

    </tr>

    <tr>

      <td width="50%">Book Title :</td>

      <td><input name="productTitle" type="text" /></td>

    </tr>

    <tr>

      <td width="50%">&nbsp;</td>

      <td><input type="submit" name="Submit" value="Submit" /></td>

    </tr>

  </table>

  <p><a href="new.jsp?productID=0596004001&productTitle=

                       Mac%20OS%20X%20for%20Java%20Geeks&Submit=Submit">

  Add Mac OS X for Java Geeks</a> </p>

</form>

</body>

</html>

4.1.3 Viewing a Search

Figure 4-4 shows an example of the results of a search. The user can click the "Return to list" link in the upper-right corner to return to the search list.

Figure 4-4. Viewing search results
figs/rww_0404.gif


As you can see from Example 4-3, view.jsp retrieves the results from the Search object. The results are then formatted into a HTML table. The heavy lifting is performed by the Search.update( ) method, as described later in this chapter.

Example 4-3. Search results JSP
<%@ page contentType="text/html; charset=iso-8859-1" 

language="java" errorPage="" %>

<%

    String productID = request.getParameter("productID");

    com.cascadetg.ch04.Search mySearch 

        = com.cascadetg.ch04.Search.getSearch(productID);

    Object[] attributeKeys = null;

    if(mySearch != null)

    {    

        java.util.Map myAttributes = mySearch.getAttributes( );

        if(myAttributes != null)

        {

            attributeKeys = myAttributes.keySet( ).toArray( );

        }

    };

%>

<head>

<title>Chapter 4: Competitive Analysis</title>

<meta http-equiv="Content-Type" 

    content="text/html; charset=iso-8859-1" />

<link href="default.css" rel="stylesheet" type="text/css" />

</head>



<body>

<p align="right"><a href="list.jsp">Return to list</a></p>

<% if(mySearch == null)

    { %>

    <p>Unable to find this product ID (<%=productID%>)</p>

<%    } else { %>

    

<h2>Book Title: <%= mySearch.getProductTitle( ) %>

    (ISBN: <%= mySearch.getProductID( ) %>)</h2>

<p>Is Updating: <%= mySearch.isUpdating( ) %></p>

<table width="100%"  border="0" cellspacing="3" cellpadding="3">

  <tr>

    <td nowrap="nowrap">Attribute</td>

    <td>Value</td>

  </tr>

  <%

  if(attributeKeys != null)

      for(int i = 0; i < attributeKeys.length; i++)

    {

        String key = (String)attributeKeys[i];

  %>

  <tr>

    <td nowrap="nowrap" class="list"><%= key %></td>

    <td class="list"><%= mySearch.getAttribute(key) %></td>

  </tr>

  <% } %>

</table>

<% } %>

<p><a href="list.jsp">Return to list</a></p>

<p><a href="new.jsp">New search</a></p>

</body>

</html>

4.1.4 Removing a Search

If we allow people to add searches, we also should allow them to remove them. When a user clicks delete from the main JSP (as shown in Figure 4-2), a simple form (as shown in Figure 4-5) prompts the user to confirm the deletion before processing the request.

Figure 4-5. Delete confirmation web page
figs/rww_0405.gif


The code for this delete confirmation dialog is shown in Example 4-4.

Example 4-4. Delete confirmation JSP code
<%@ page contentType="text/html; charset=iso-8859-1" 

language="java" errorPage="" %>

<%

    boolean delete = false;

    String productID = request.getParameter("productID");

    if(request.getParameter("Delete") != null)

        delete = true;

    

    boolean deleted = false;

    if(delete)

    {        

        deleted = 

            com.cascadetg.ch04.Search.removeSearch(productID);

    };

%>

<head>

<title>Chapter 4: Competitive Analysis</title>

<meta http-equiv="Content-Type" 

    content="text/html; charset=iso-8859-1" />

<link href="default.css" 

    rel="stylesheet" type="text/css" />

</head>

<body><% 

if (delete)

{ 

    if(deleted)

    {

%>

        <p>The item has been deleted.</p>

<%    } else {

%>        

        <p>Item not found.</p>

<%    }

} else{ %>

        <p>Are you sure you want to delete the 

            item "<%= productID %>"?</p>        

        <form name="deleteForm"  

            method="post" action="delete.jsp">

          <input type="hidden" name="productID" 

            value="<%= productID %>"/>

          <input name="Delete" type="submit" 

             value="Delete" />

         </form>

        <%

} 

%>

<p><a href="list.jsp">Return to list.</a></p>

</body>

</html>

4.1.5 Updating a Search

The Search object caches the data returned from the various web services in memory, but a user may wish to force the system to immediately refresh the data. Clicking on the update link on the main page (Figure 4-2) allows a user to do just that, after a confirmation web page, as shown in Figure 4-6.

Figure 4-6. Confirming an update request
figs/rww_0406.gif


The code for the update confirmation page is shown in Example 4-5.

Example 4-5. Update confirmation JSP
<%@ page contentType="text/html; charset=iso-8859-1" 

language="java" import="com.cascadetg.ch04.*" errorPage="" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<%

    boolean updateProduct = false;

    String productID = request.getParameter("productID");

    if(productID != null)

    {

        updateProduct = true;

        Search.getSearch(productID).update( );

    }



%>

<title>Chapter 4: Competitive Analysis</title>

<meta http-equiv="Content-Type" 

content="text/html; charset=iso-8859-1" />

<link href="default.css" rel="stylesheet" type="text/css" />

</head>



<body>

<% if (updateProduct) { %>

<p>Product updated.</p>

<% } else { %>



<p>Unknown product.</p>

<% } %>

<p><a href="list.jsp">Return to list.</a> </p>

</body>

</html>