The Category Class

I l @ ve RuBoard

The Category Class

Now that you have products to put in it, you can create your Category object (see Listing 9.11). Again, most of it will look very familiar.

Listing 9.11 The Category Class
 package com.bfg.product; import java.util.Vector; import java.util.Set; import java.util.HashMap; import java.util.Iterator; import java.text.NumberFormat; import java.text.SimpleDateFormat; import org.apache.turbine.services.db.TurbineDB; import org.apache.turbine.util.db.pool.DBConnection; import org.apache.turbine.util.TurbineConfig; import com.bfg.exceptions.ProductActivityException; import java.sql.*; import java.util.ResourceBundle; import org.apache.turbine.util.Log; public class Category {     private static ResourceBundle sql_bundle =       ResourceBundle.getBundle("com.bfg.product.SQLQueries");     protected int pID;     protected Product pFeaturedProduct;     protected Vector pProducts = new Vector();     protected String pName;     protected static HashMap categories = new HashMap();     public int getID() {      return pID;     }     public void setID(int ID) {      pID = ID;     }     public String getName() {      return pName;     }     public void setName(String Name) {      pName = Name;     }     public Product getFeaturedProduct() {      return pFeaturedProduct;     }     public void setFeaturedProduct(Product Product) {      pFeaturedProduct = Product;     }     public Vector getProducts() {      return pProducts;     }     public void setProducts(Vector Products) {      pProducts = Products;     }     public static Set getCategories() {      return categories.keySet();     }     public static Category findCategory(String Name)      throws ProductActivityException {          if (categories.get(Name) != null) {          return (Category) categories.get(Name);                  }          DBConnection dbConn = null;          Category cat = null;          try              {                   dbConn = TurbineDB.getConnection();                   if (dbConn == null) {                       Log.error("jdbc", "Can't get database connection");                       throw new ProductActivityException();                   }                   PreparedStatement pstmt =                       dbConn.prepareStatement(sql_bundle. getString("findCatQuery"));                   pstmt.setString(1, Name);                   ResultSet rs = pstmt.executeQuery();                   if (rs.next()) {                       cat = new Category();                        cat.setName(rs.getString("CATEGORY_NAME"));                       cat.setID(rs.getInt("CATEGORY_ID"));                       String feat = rs.getString("FEATURED_PRODUCT");                       if (!rs.wasNull()) {                            cat.setFeaturedProduct(Product.findProduct(feat));                       }                   }                   rs.close();                   pstmt.close();                   if (cat != null) {                       pstmt = dbConn.prepareStatement(sql_bundle.[ic:ccc]getString("catProdQuery"));                       pstmt.setInt(1, cat.getID());                       rs = pstmt.executeQuery();                       while (rs.next()) {                           cat.getProducts().add( Product.findProduct(rs.getString( graphics/ccc.gif "PRODUCT_ISBN")));                       }                       rs.close();                       pstmt.close();                       categories.put(Name, cat);                   }               }           catch (Exception e)               {                   Log.error("jdbc", "Error during findCategory", e);                   e.printStackTrace();                   throw new ProductActivityException();               }           finally               {                   try                        {                           TurbineDB.releaseConnection(dbConn);                        }                    catch (Exception e)                        {                           Log.error("jdbc", "Error during releaseConnection", e);                        }               }           return cat;       } static boolean allLoaded = false;     public static void loadAllCategories()      throws ProductActivityException {      if (allLoaded) return;      allLoaded = true;      DBConnection dbConn = null;      Category cat = null;      try          {              dbConn = TurbineDB.getConnection();              if (dbConn == null) {                  lcat.error("Can't get database connection");                  throw new ProductActivityException();              }              PreparedStatement pstmt = dbConn.prepareStatement(sql_bundle.getString("findAllCats"));               ResultSet rs = pstmt.executeQuery();               while (rs.next()) {                    findCategory(rs.getString("CATEGORY_NAME"));               }               rs.close();               pstmt.close();          }          catch (Exception e)              {                  lcat.error("Error during loadAllCategories", e);                  e.printStackTrace();                  throw new ProductActivityException();              }          finally              {                   try                        {                             TurbineDB.releaseConnection(dbConn);                        }                   catch (Exception e)                        {                           lcat.error("Error during releaseConnection", e);                        }              }       }       public static void main(String[] args) {           TurbineConfig tc =               new TurbineConfig("com/bfg/props/",                                  "TurbineResources.properties");           tc.init();           try {               Category.loadAllCategories();               Category c =                   findCategory("JDBC");               if (c != null) {                   System.out.println("Good Test: Find Real Category");               }  else {                    System.out.println("Failed Test: Find Real Category");               }           }  catch (Exception e) {                System.out.println("Failed Test: Find Real Category");                e.printStackTrace();           }           try {               Category c =                   findCategory("notancat");               if (c != null) {                   System.out.println("Bad Test: Find Fake Category");               }  else {                    System.out.println("Good Test: Find Fake Category");                }           }  catch (Exception e) {                System.out.println("Failed Test: Find Fake Category");                e.printStackTrace();           }       } } 

Among the highlights of Listing 9.11: When a category is loaded from the database, a subquery is run to find all the products and then load them because the category needs to have a pointer to all its products. You also must load the featured product.

As you can see, when you have objects that depend on other objects, you need to make sure that they're loaded in the right order. For example, if a category loads the featured product and the product has a pointer to the category (which isn't the case here), you would need to be sure to avoid an infinite recursion. To do this, you would need to make sure that the product and the category registered themselves in the appropriate cache before they tried to find the contained objects.

In the application as written, there are no such dependencies because everything is referenced from the top down, following this path :

 Category -> Product -> Author 

Because categories are at the top of the hierarchy, you need to have some way to get a list of them ”for example, to present a sidebar menu. The loadAllCategories method loads all the categories in the database. After that, you can use getCategories to get the set and then iterate over it to get a list of categories. Listing 9.12 shows the modification to the bfgheader .jsp code to use this.

Listing 9.12 Additions to bfgheader.jsp
 <%@ page import="com.bfg.product.Category" %> <%@ page import="java.util.Set" %> <%@ page import="java.util.Iterator" %> . . .     <p>Departments</p>     <blockquote>       <h5>     <% Category.loadAllCategories(); Iterator it = Category.getCategories().iterator(); while (it.hasNext()) {     String catName = (String) it.next(); %>     <a href="/bfg/jsp/product/Category.jsp?category<%= catName %>"><%= catName %></a><br>        <%        } %>     </h5>     </blockquote> 

The code gets the iterator of category names and creates HREFs for each one, calling Category.jsp with the category name as the argument.

So, now you should write Category.jsp. You can find it in Listing 9.13.

Listing 9.13 Category.jsp
 <%@ page import="com.bfg.product.Product" %> <%@ page import="com.bfg.product.Category" %> <%@ page import="java.util.Iterator" %> <% Category cat = null; if (((request.getParameter("category") != null) &&      (cat = Category.findCategory(request.getParameter("category"))) != null)) { %> <head> <title>Books About <%= cat.getName() %></title> </head> <%@ include file="/jsp/includes/bfgheader.jsp" %>     <h2 align="center">Books About <%= cat.getName() %></h2>       <% if (cat.getFeaturedProduct() != null) {     Product feat = cat.getFeaturedProduct(); %> <table border="0" cellpadding="0" cellspacing="0" bordercolor="#111111" width="639">       <tr>         <td width="128">         <img border="0" src="/bfg/jsp/images/products/<%= feat.getISBN() %>.jpg"              align="left" width="113" height="140"></td>         <td valign="top" width="511">         <h3 align="center">         <span style="font-size: 10.0pt; font-family: Times New Roman">       <%= feat.getTitle() %>       </span></h3>         <p align="center">         <span style="font-size: 10.0pt; font-family: Times New Roman">       By <%= feat.getAuthorString() %>       </span></p>         <p align="center"><font size="2" face="Times New Roman">Publication         date: </font>         <span style="font-size: 10.0pt; font-family: Times New Roman">      <%= feat.getPubDateString() %>, <%= feat.getPriceString() %>       </span></td>       </tr>     </table>     <p><span style="font-size: 10.0pt">     <%= feat.getDescription() %>     </span></p>     <p><font size="2">     <a href="index.htm">[Buy It!]</a></font></p>     <p align="center">&nbsp;</td>   </tr> </table>     <% }  %> <table border="0" cellpadding="0" cellspacing="0"        style="border-collapse: collapse" bordercolor="#111111"        width="100%" id="AutoNumber4" height="253">   <tr>     <th width="38%" height="23" align="left">Title</th>     <th width="23%" height="23" align="left">Author</th>     <th width="11%" height="23" align="left">Price</th>     <td width="28%" height="23" align="left">&nbsp;</td>   </tr>     <%     Iterator iter = cat.getProducts().iterator();     while (iter.hasNext()) {      Product prod = (Product) iter.next(); %>   <tr>     <td width="38%" height="38" bgcolor="#00FFFF">     <span style="font-size: 10.0pt; font-family: Times New Roman">        <%= prod.getTitle() %>     </span></td>     <td width="23%" height="38" bgcolor="#00FFFF">     <span style="font-size: 10.0pt; font-family: Times New Roman">        <%= prod.getAuthorString() %>     </span></td>     <td width="11%" height="38" bgcolor="#00FFFF">     <span style="font-size: 10.0pt; font-family: Times New Roman">     <%= prod.getPriceString() %>     </span></td>     <td width="28%" height="38" bgcolor="#00FFFF">     <p align="center"><font size="2">        <a href="Product.jsp?ISBN=<%= prod.getISBN()%>">        [More Information] </A>     [Buy It!]</font></td>   </tr>        <% } }  else { %> <head> <title>Category Not Found</title> </head> <%@ include file="/jsp/includes/bfgheader.jsp" %> <H1>The requested Category was not found.</H1> If you believe you have reached this page in error, please contact <A HREF="mailto: info@bfgbooks.com">info@bfgbooks.com</A> <% }  %> <%@ include file="/jsp/includes/bfgfooter.jsp" %> 

Here you can really start mining the database for information. First, the code checks to see if it has been handed in a valid category name; otherwise , it splashes up the error page.

Assuming that it has a valid category name, the code generates a title based on the category name and checks whether there is a featured product for the category. If there is, the code creates a detailed product information listing with a link to the product information page.

After starting the table that will contain the list of books in the category, you can use an iterator over the vector of products and generate a line for each book. The More Information link is actually live; clicking on it takes the customer to the product detail page for that book. All this isn't bad for a day's work, as Figure 9.4 shows. But don't rest on your laurels just yet; you might as well go that last mile, so to speak, and implement the "list all books by an author" function.

Figure 9.4. The finished category page.

graphics/09fig04.jpg

Listing all the books by a particular author is actually simpler than it sounds. To start, change the getAuthorString method of Product (see Listing 9.14).

Listing 9.14 Enhanced getAuthorString()
 private String getAuthorHREF(Author author) { return "<A HREF=\"/bfg/jsp/product/ByAuthor.jsp?author=" +      author.getName() + "\">" + author.getName() + "</A>"; } public String getAuthorString() { Vector authors = getAuthors(); if (authors.size() == 1) {      return (getAuthorHREF((Author)authors.elementAt(0))); } StringBuffer s = new StringBuffer(); Iterator i = authors.iterator(); while (i.hasNext()) {      Author author = (Author) i.next();      if (author == authors.firstElement()) {          s.append(getAuthorHREF(author));      }  else {           s.append("; " + getAuthorHREF(author));      }  }  return(s.toString()); } 

Basically, the string returned has simply been changed from a plain piece of text to a piece of HTML with links to a new page. Without modifying any of the JSP already written, you suddenly get this new functionality for free. To make things more general, you should probably place the absolute path portion of the URL in a resource bundle so that it can be changed without having to recompile the code.

Luckily, unlike some products such as Dynamo, you don't have to do anything special when you want to pass HTML back to a JSP page using <%= . JSP just sends whatever is returned out to the browser.

Now you can do a ByAuthor.jsp, which is nearly identical to Category.jsp (see Listing 9.15).

Listing 9.15 ByAuthor.jsp
 <%@ page import="com.bfg.product.Product" %> <%@ page import="com.bfg.product.Author" %> <%@ page import="java.util.Iterator" %> <% Author author = null; if (((request.getParameter("author") != null) &&      (author = Author.findAuthor(request.getParameter("author"))) != null)) { %> <head> <title>Books By <%= author.getName() %></title> </head> <%@ include file="/jsp/includes/bfgheader.jsp" %>     <h2 align="center">Books By <%= author.getName() %></h2> <table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" graphics/ccc.gif bordercolor="#111111" width="100%" id="AutoNumber4" height="253">   <tr>     <th width="38%" height="23" align="left">Title</th>     <th width="23%" height="23" align="left">Author</th>     <th width="11%" height="23" align="left">Price</th>     <td width="28%" height="23" align="left">&nbsp;</td>   </tr>     <%     Iterator iter = author.getBooks().iterator();     while (iter.hasNext()) {      Product prod = (Product) iter.next(); %>   <tr>     <td width="38%" bgcolor="#00FFFF">     <span style="font-size: 10.0pt; font-family: Times New Roman">        <A HREF="Product.jsp?ISBN=<%= prod.getISBN() %>">         <%= prod.getTitle() %></A>     </span></td>     <td width="23%" bgcolor="#00FFFF">     <span style="font-size: 10.0pt; font-family: Times New Roman">        <%= prod.getAuthorString() %>     </span></td>     <td width="11%" bgcolor="#00FFFF">     <span style="font-size: 10.0pt; font-family: Times New Roman">     <%= prod.getPriceString() %>     </span></td>     <td width="28%" bgcolor="#00FFFF">     <p align="center"><font size="2"><a href="Product.jsp?ISBN=<%= prod.getISBN()%>">        [More Information] </A>     [Buy It!]</font></td>   </tr>        <% } }  else { %> <head> <title>Author Not Found</title> </head> <%@ include file="/jsp/includes/bfgheader.jsp" %> <H1>The requested Author was not found.</H1> If you believe you have reached this page in error, please contact <A HREF="mailto: info@bfgbooks.com">info@bfgbooks.com</A> <% }  %> <%@ include file="/jsp/includes/bfgfooter.jsp" %> 

Other than removing the featured product ”which isn't applicable for authors ”and doing the lookup for the iterator based on the author's books rather than the category's books, this is relatively much the same code as in Category.jsp. It produces the page shown in Figure 9.5.

Figure 9.5. The ByAuthor page.

graphics/09fig05.jpg

I l @ ve RuBoard


MySQL and JSP Web Applications. Data-Driven Programming Using Tomcat and MySQL
MySQL and JSP Web Applications: Data-Driven Programming Using Tomcat and MySQL
ISBN: 0672323095
EAN: 2147483647
Year: 2002
Pages: 203
Authors: James Turner

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net