Using Listeners
You also must know how to use the servlet context attribute listener and the session attribute listener. You can write code that responds to servlet events by defining listener objects. These objects have methods that the container invokes when life-cycle events occur. The event is triggered by a change in the application. For example, the session listener is invoked by the container when a session attribute changes. Also, this happens if an attribute in the application object changes and when the context or session is created and destroyed. You take advantage of this event model by defining a listener class that implements a listener interface. The container invokes the listener method and passes it information about that event. Notice that the methods in the HttpSessionListener interface are passed an HttpSessionEvent.
You can expect to see four listener interfaces on the exam. The following two tables describe them. Table 3.1 lists the context (Web application) events and the interface/method that your class must implement to respond to the event.
Table 3.1 Servlet Context Events
Event |
Interface |
Method |
Servlet context has just been created |
javax.servlet.ServletContextListener |
contextInitialized() |
Just before killing servlet context |
ServletContextListener |
contextDestroyed() |
Adding an attribute |
javax.servlet.ServletContextAttributesListener |
attributeAdded() |
Removing an attribute |
ServletContextAttributesListener |
attributeRemoved() |
Replacing an attribute |
ServletContextAttributesListener |
attributeReplaced() |
Table 3.2 lists the session events and the interface/method that your class must implement to respond to the event.
Table 3.2 Servlet Session Events
Event |
Interface |
Method |
Session has just been created |
javax.servlet.http sessionCreated() |
HttpSessionListener |
Just before passivating session |
HttpSessionListener |
sessionDestroyed() |
Adding an attribute |
javax.servlet.http.HttpSessionAttributesListener |
attributeAdded() |
Removing an attribute |
HttpSessionAttributesListener |
attributeRemoved() |
Replacing an attribute |
HttpSessionAttributesListener |
attributeReplaced() |
The following is a short commentary on the methods mentioned previously:
-
When a servlet is initialized or destroyed, you listen with javax.servlet.ServletContextListener:
-
contextDestroyed(ServletContextEvent sce)Notification that the servlet context is about to be shut down
-
contextInitialized(ServletContextEvent sce)Notification that the Web application is ready to process requests
-
When a session is initialized or destroyed, you listen with javax.servlet.http.HttpSessionListener:
-
sessionCreated(HttpSessionEvent se)Notification that a session was created
-
sessionDestroyed(HttpSessionEvent se)Notification that a session became invalid or timed out
-
When a context attribute is added, removed, or replaced you listen with javax.servlet.ServletContextAttributeListener:
-
attributeAdded(ServletContextAttributeEvent scab)Notifica-tion that a new attribute was added to the servlet context
-
attributeRemoved(ServletContextAttributeEvent scab)Notification that an existing attribute was removed from the servlet context
-
attributeReplaced(ServletContextAttributeEvent scab)Notification that an attribute on the servlet context was replaced
-
When a session attribute is added, removed, or replaced you listen with HttpSessionAttributeListener:
-
attributeAdded(HttpSessionBindingEvent se)Notification that an attribute was added to a session
-
attributeRemoved(HttpSessionBindingEvent se)Notification that an attribute was removed from a session
-
attributeReplaced(HttpSessionBindingEvent se)Notification that an attribute was replaced in a session
Obvious similarities exist between context and session interfaces and methods. Use javax.servlet.ServletContextAttributeListener when a context attribute is added, removed, or replaced. On the other hand, use HttpSessionAttributeListener when the same is done in a session. Both of these are public interfaces (they extend java.util.EventListener) and have the same method names but different parameters.
Suppose that you wanted to mark the times when your Web application started and ended. The following code snippet shows how you could use the initialization and destruction events to do that:
public final class ContextListener implements ServletContextListener { public void contextInitialized( ServletContextEvent event) { ServletContext context = event.getServletContext(); String IP = "209.83.3.142"; context.setAttribute("DefaultAddress", IP); } public void contextDestroyed(ServletContextEvent event) { ServletContext context = event.getServletContext(); String IP = context.getAttribute("DefaultAddress"); //do something with IP //context.removeAttribute("DefaultAddress"); } }
The attribute DefaultAddress is set when the container initializes the application. Of course, you could dynamically get the IP. Then when the application quits, the same attribute is retrieved. When you have this IP, you could log it and then delete it, for example. For an excellent article that provides an overview of application life-cycle events, see "Servlet App Event Listeners," by Stephanie Fesler (April 12, 2001, http://www.onjava.com/pub/a/onjava/2001/04/12/listeners.html).
For a better example, Listing 3.2 demonstrates a simplified approach to how you could listen to an application and record what is going on.
Listing 3.2 Listening to Context and Session Events
package com.companyname.listening; import java.io.*; import java.util.Date; import javax.servlet.*; import javax.servlet.http.*; /** * A custom listener for session events. * All events that occur are monitored. */ public class MySessionListener implements HttpSessionListener, HttpSessionAttributeListener { private StringBuffer log = new StringBuffer("MySessionListener log\n"); public void attributeAdded(HttpSessionBindingEvent event) { log.append(event.getName() + "," + event.getValue() + "," + new Date() + "\n"); } public void attributeRemoved(HttpSessionBindingEvent event) { log.append(event.getName() + "," + event.getValue() + "," + new Date() + "\n"); } public void attributeReplaced(HttpSessionBindingEvent event) { log.append(event.getName() + "," + event.getValue() + "," + new Date() + "\n"); } public void sessionCreated(HttpSessionEvent event) { log.append("sessionCreated: " + new Date() + "\n"); } public void sessionDestroyed(HttpSessionEvent event) { HttpSession session = event.getSession(); if (session!=null) { log.append("Session Id:" + session.getId()); log.append("Current Time: " + new Date()); log.append("Created Time: " + session.getCreationTime()); log.append("Last Accessed: " + session.getLastAccessedTime()); } //permanently record the events; something like: //myLogger.record( log.toString() ); } }
TIP
The listener architecture in servlets is based on the event model. The container automatically calls certain methods when an event occurs. For example, the container calls attributeRemoved in a servlet that implements HttpSessionAttributeListener when an attribute is removed from a session object.
Before you can listen to events, you must configure your Web application to have an event listener. Most containers have default listeners already configured, so most likely you don't have to change the configuration. However, you should understand the steps involved. You would edit the web.xml (located in the WEB-INF) deployment descriptor of the Web application for which you are creating an event listener; you would add the <listener> element. Among containers, the required order of top-level elements varies. I recommend placing the <listener> element directly after the <filter> and <filter-mapping> elements and before the <servlet> element. You can specify many listeners, and usually the container invokes the event listeners in the order in which they appear in the deployment descriptor. Conversely, most containers invoke these events in the reverse order during shutdown. The following snippet is an example of two listener declarations:
<listener> <listener-class>myContextListener</listener-class> </listener> <listener> <listener-class> mySessionAttributeListener </listener-class> </listener>
Remember that the listener element indicates the deployment properties for a Web application listener bean. The listener-class element declares that a class in the application must be registered as a Web application listener bean. The value is the fully qualified class name of the listener class.