- Monitoring Creation and Destruction of the Servlet Context
- Example: Initializing Commonly Used Data
- Detecting Changes in Servlet Context Attributes
- Example: Monitoring Changes to Commonly Used Data
- Packaging Listeners with Tag Libraries
- Example: Packaging the Company Name Listeners
- Recognizing Session Creation and Destruction
- Example: A Listener That Counts Sessions
- Watching for Changes in Session Attributes
- Example: Monitoring Yacht Orders
- Using Multiple Cooperating Listeners
- The Complete Events Deployment Descriptor
10.10 Example: Monitoring Yacht Orders
You're "promoted" to sales manager. (OK, ok, so that is too horrible a fate to contemplate. All right then, you are asked to help the sales manager.) You want to track buying patterns for a specific item (a yacht, in this case). Of course, you could try to find all servlets and JSP pages that process orders and change each one to record yacht purchases. That's an awful lot of work for what sounds like a simple request, though. Pretty hard to maintain, anyhow.
A much better option is to create a session attribute listener that monitors the attributes corresponding to order reservations or purchases and that records the information in the log file for later perusal by the sales manager.
The following steps summarize a listener that accomplishes this task.
Implement the HttpSessionAttributeListener interface. Listing 10.26 shows a class (YachtWatcher) that implements this interface.
Override attributeAdded, attributeReplaced, and attributeRemoved. The first of these (attributeAdded) is used to log the fact that a yacht was reserved (tentative) or purchased (permanent). The other two methods are used to print retractions of order reservations (but not purchasesall sales are final).
Obtain references to the attribute name, attribute value, session, and servlet context. Each of the three methods calls getName and getValueon its HttpSessionBindingEventargument to obtain the name and value of the modified attribute. The methods also call getServletContexton the session object (obtained with get-Session) to get a reference to the servlet context.
Use the objects. The attribute name is compared to "ordered-Item"(attribute addition, replacement, and removal) and "purchasedItem"(attribute addition only). If the name matches, then the attribute value is compared to "yacht". If that comparison also succeeds, then the logmethod of the servlet context is called.
Declare the listener. Listing 10.27 shows the web.xml file. It declares the listener with the listenerand listener-classele-ments, as below.
<listener> <listener-class> moreservlets.listeners.YachtWatcher </listener-class> </listener>
Listings 10.28 and 10.29 show a servlet that handles orders and an HTML form that sends it data, respectively. Figures 1016 through 1019 show the results. Listing 10.30 shows a portion of the resultant log file.
Figures 1016 The order form that sends data to the order handling servlet (Listing 10.28). That servlet adds, replaces, and removes values in the orderedItem and purchasedItem session attributes, which in turn triggers the yacht-watching listener (Listing 10.26).
Figures 1017 Result of reserving an order for a yacht. The yacht-watching listener makes an entry in the log file (Listing 10.30) saying that a customer ordered a yacht.
Figures 1018 Result of cancelling an order. If the user had previously reserved an order for a yacht, the yacht-watching listener makes an entry in the log file (Listing 10.30) saying that a customer replaced a yacht order with something else.
Figures 1019 Result of purchasing a yacht. The yacht-watching listener makes an entry in the log file (Listing 10.30) saying that a customer purchased a yacht.
Listing 10.26 YachtWatcher.java
package moreservlets.listeners; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; /** Listener that keeps track of yacht purchases by monitoring * the orderedItem and purchasedItem session attributes. */ public class YachtWatcher implements HttpSessionAttributeListener { private String orderAttributeName = "orderedItem"; private String purchaseAttributeName = "purchasedItem"; private String itemName = "yacht"; /** Checks for initial ordering and final purchase of * yacht. Records "Customer ordered a yacht" if the * orderedItem attribute matches "yacht". * Records "Customer finalized purchase of a yacht" if the * purchasedItem attribute matches "yacht". */ public void attributeAdded(HttpSessionBindingEvent event) { checkAttribute(event, orderAttributeName, itemName, " ordered a "); checkAttribute(event, purchaseAttributeName, itemName, " finalized purchase of a "); } /** Checks for order cancellation: was an order for "yacht" * cancelled? Records "Customer cancelled an order for * a yacht" if the orderedItem attribute matches "yacht". */ public void attributeRemoved(HttpSessionBindingEvent event) { checkAttribute(event, orderAttributeName, itemName, " cancelled an order for a "); } /** Checks for item replacement: was "yacht" replaced * by some other item? Records "Customer changed to a new * item instead of a yacht" if the orderedItem attribute * matches "yacht". */ public void attributeReplaced(HttpSessionBindingEvent event) { checkAttribute(event, orderAttributeName, itemName, " changed to a new item instead of a "); } private void checkAttribute(HttpSessionBindingEvent event, String orderAttributeName, String keyItemName, String message) { String currentAttributeName = event.getName(); String currentItemName = (String)event.getValue(); if (currentAttributeName.equals(orderAttributeName) && currentItemName.equals(keyItemName)) { ServletContext context = event.getSession().getServletContext(); context.log("Customer" + message + keyItemName + "."); } } }
Listing 10.27 web.xml (Excerpt for yacht-watching listener)
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <!-- ... --> <!-- Register the yacht-watching event listener. --> <listener> <listener-class> moreservlets.listeners.YachtWatcher </listener-class> </listener> <!-- ... --> <!-- Assign the name OrderHandlingServlet to moreservlets.OrderHandlingServlet. --> <servlet> <servlet-name>OrderHandlingServlet</servlet-name> <servlet-class> moreservlets.OrderHandlingServlet </servlet-class> </servlet> <!-- ... --> <!-- Assign the URL /HandleOrders to the servlet that is named OrderHandlingServlet. --> <servlet-mapping> <servlet-name>OrderHandlingServlet</servlet-name> <url-pattern>/HandleOrders</url-pattern> </servlet-mapping> <!-- ... --> </web-app>
Listing 10.28 OrderHandlingServlet.java
package moreservlets; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; /** Servlet that handles submissions from the order form. If the * user selects the "Reserve Order" button, the selected item * is put into the orderedItem attribute. If the user selects * the "Cancel Order" button, the orderedItem attribute is * deleted. If the user selects the "Purchase Item" button, * the selected item is put into the purchasedItem attribute. */ public class OrderHandlingServlet extends HttpServlet { private String title, picture; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(true); String itemName = request.getParameter("itemName"); if ((itemName == null) || (itemName.equals(""))) { itemName = "<B>MISSING ITEM</B>"; } String message; if (request.getParameter("order") != null) { session.setAttribute("orderedItem", itemName); message = "Thanks for ordering " + itemName + "."; } else if (request.getParameter("cancel") != null) { session.removeAttribute("orderedItem"); message = "Thanks for nothing."; } else { session.setAttribute("purchasedItem", itemName); message = "Thanks for purchasing " + itemName + "."; } response.setContentType("text/html"); PrintWriter out = response.getWriter(); String docType = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " + "Transitional//EN\">\n"; out.println (docType + "<HTML>\n" + "<HEAD><TITLE>" + message + "</TITLE></HEAD>\n" + "<BODY BGCOLOR=\"#FDF5E6\">\n" + "<H2 ALIGN=\"CENTER\">" + message + "</H2>\n" + "</BODY></HTML>"); } }
Listing 10.29 orders.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE>Orders</TITLE> <LINK REL=STYLESHEET HREF="events-styles.css" TYPE="text/css"> </HEAD> <BODY> <TABLE BORDER=5 ALIGN="CENTER"> <TR><TH CLASS="TITLE">Orders </TABLE> <P> Choose a valuable item below. <P> Select "Reserve Order" to hold the order for 30 days. Due to unprecedented demand, you can only reserve a single item: selecting another item will replace the previous choice. <P> Select "Purchase Item" to finalize your purchase. After finalizing a purchase, you can reserve a new item. <FORM ACTION="HandleOrders"> <DL> <DT><B>Item:</B> <DD><INPUT TYPE="RADIO" NAME="itemName" VALUE="yacht">Yacht <DD><INPUT TYPE="RADIO" NAME="itemName" VALUE="chalet">Chalet <DD><INPUT TYPE="RADIO" NAME="itemName" VALUE="car">Lamborghini <DD><INPUT TYPE="RADIO" NAME="itemName" VALUE="msajsp" CHECKED> <I>More Servlets and JavaServer Pages</I> <DD><INPUT TYPE="RADIO" NAME="itemName" VALUE="csajsp"> <I>Core Servlets and JavaServer Pages</I> </DL> <CENTER> <INPUT TYPE="SUBMIT" NAME="order" VALUE="Reserve Order"> <INPUT TYPE="SUBMIT" NAME="cancel" VALUE="Cancel Order"> <INPUT TYPE="SUBMIT" NAME="purchase" VALUE="Purchase Item"> </CENTER> </FORM> </BODY> </HTML>
Listing 10.30 Sample Log File Entries
2001-11-07 11:50:59 Customer ordered a yacht. 2001-11-07 11:51:06 Customer changed to a new item instead of a yacht. 2001-11-07 11:52:37 Customer cancelled an order for a yacht. 2001-11-07 11:53:05 Customer finalized purchase of a yacht. 2001-11-07 11:53:35 Customer ordered a yacht. 2001-11-07 11:53:50 Customer cancelled an order for a yacht. 2001-11-07 11:54:20 Customer changed to a new item instead of a yacht. 2001-11-07 11:54:27 Customer changed to a new item instead of a yacht. 2001-11-07 11:54:42 Customer cancelled an order for a yacht. 2001-11-07 11:54:44 Customer ordered a yacht. 2001-11-07 11:54:47 Customer changed to a new item instead of a yacht.