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.
First, the following list details the JSP pages and presentation objects used in the application.
A list of the previously saved searches
Create a new search
View the results of a search
Delete a saved search
Request an existing search to be updated
Rudimentary stylesheet
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.
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.
<%@ 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"> </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>
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.
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.
|
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.
<%@ 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%"> </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>
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.
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.
<%@ 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>
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.
The code for this delete confirmation dialog is shown in Example 4-4.
<%@ 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>
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.
The code for the update confirmation page is shown in Example 4-5.
<%@ 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>