|
Related Reading
|
Sun Microsystems released the proposed final draft of the Servlet 2.3 specification on October 20, 2000. Although the Servlet 2.3 specification is not in its final version yet, we do not have to wait any longer to play with the exciting new features defined by it. Apache's Tomcat has released a build, version 4.0 beta 1 that fully supports the Servlet 2.3 proposed final draft specification.
My last article was an introduction to Servlet concepts (for those new to this area) and then it was an overview of two new additions to the specification, the application lifecycle events and Servlet filters. This article is going to go into detail about writing the application lifecycle events.
All the code that will be shown in this article has been tested on Apache's Tomcat version 4.0 beta 1 on a Windows platform. This version of Tomcat has full support of the new Servlet 2.3 specification and the JSP 1.2 specification. If you need help installing and setting up Tomcat refer to James Goodwill's article Installing and Configuring Tomcat for an easy to follow guide on installing and configuring Apache's Tomcat version 4.0 beta 1.
All the code is part of a Web Application called demo.
The Servlet 2.3 proposed final draft specification has defined application lifecycle events to provide Web Application developers more interaction with the ServletContext object and HttpSession objects. Web Application developers write event listeners so they can now be notified when lifecycle events happen (such as creation or destruction) or when attributes are modified in the ServletContext object or HttpSession objects.
Event listeners are Java classes that follow the JavaBeans design and are provided by the Web Application developer in the Web archive (.war) file. There are two types of event listeners, and both types apply to the ServletContext object and HttpSession objects. The two types are lifecycle events and changes to attributes events. Table 1 shows the types of events, a brief description, and the listener interface to implement. This table is taken from the Servlet 2.3 proposed final draft specification.
| Table 1: Supported Event Types | ||
| Event Type | Description | Listener Interface |
| Servlet Context Events | ||
| Lifecycle | The Servlet context has just been created and is available to service its first request, or the Servlet context is about to be shutdown. | javax.Servlet.ServletContextListener |
| Changes to Attributes | Attributes on the Servlet context has been added, removed, or replaced. | javax.Servlet.ServletContextAttributesListener |
| Http Session Events | ||
| Lifecycle | An HttpSession has just been created, or has been invalidated or timed out. | javax.Servlet.http.HttpSessionListener |
| Changes to Attributes | Attributes have been added, removed or replaced in an HttpSession object. | javax.Servlet.http.HttpSessionAttributesListener |
An interesting point is that there can be multiple listener classes listening to each event type and the Web application developer has the flexibility to define the order the event listener objects are invoked.
The container manages the lifecycle of event listeners. It is the containers responsibility to instantiate each of the listener classes in a Web Application before the execution of the first request into the Web Application. Also, each of the listener classes must be referenced until the Web Application services the last request.
For more details on the container's responsibilities, refer to my last article.
|
When a web application is deployed a servlet context object,
ServletContext, is created and associated with the web
application. There is a one-to-one relationship between a servlet
context object and the web application. All resources within the web
application, such as servlets and JSPs, can retrieve any information
stored in the servlet context.
As a web application programmer, you may want to initialize objects and place them in the servlet context when it is created and destroy the objects when the servlet context is destroyed. For example, you may decide to create a connection to a database when the servlet context is created and close the connection when the servlet context is destroyed.
To write an application lifecycle event listener that executes when
the servlet context is created and destroyed, write a Java class that
implements the javax.Servlet.ServletContextListener
class. This class has two methods with the following signatures (taken
from the JavaDocs):
void contextDestroyed (ServletContextEvent sce)
Notification that the Servlet context is about to be shut down.
void contextInitialized (ServletContextEvent sce)
Notification that the Web Application is ready to process requests.
Let's write a simple application lifecycle event listener that writes a message to the console of the server when the web application is ready to accept requests and when it is going to be removed. Listing 1 shows the code for a simple application event listener class.
Listing 1: An application lifecycle event listener that
outputs messages to the console when the web application is ready to
service requests and when it is going to be
removed. (MyContextListener.java)
package com.listeners;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributesListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public final class MyContextListener
implements ServletContextListener {
private ServletContext context = null;
public MyContextListener() {}
//This method is invoked when the Web Application
//has been removed and is no longer able to accept
//requests
public void contextDestroyed(ServletContextEvent event)
{
//Output a simple message to the server's console
System.out.println("The Simple Web App. Has Been Removed");
this.context = null;
}
//This method is invoked when the Web Application
//is ready to service requests
public void contextInitialized(ServletContextEvent event)
{
this.context = event.getServletContext();
//Output a simple message to the server's console
System.out.println("The Simple Web App. Is Ready");
}
}
|
Application lifecycle event listeners are deployed within the web
archive (.war) file and are defined in the deployment
descriptor, web.xml, for the web application. The
lifecycle event listeners are defined using
<listener> tags. The order you define the listener
classes does matter;, they will be executed in the order you
specify. Listing 2 shows the web.xml file that defines
the application lifecycle event listener that was shown in Listing
1.
Listing 2: The web.xml file that defines the application lifecycle event listener listed above (MyContextListener.java)
<?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/j2ee/dtds/web-app_2_3.dtd">
<web-app>
<!-- Define application events listeners -->
<listener>
<listener-class>
com.listeners.MyContextListener
</listener-class>
</listener>
<!-- Define servlets that are included in the example application -->
<servlet>
<servlet-name>
simple
</servlet-name>
<servlet-class>
com.servlets.SimpleServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>
bank
</servlet-name>
<servlet-class>
com.servlets.BankBalance
</servlet-class>
</servlet>
<!-- Define servlet mappings to urls -->
<servlet-mapping>
<servlet-name>
simple
</servlet-name>
<url-pattern>
/simple
</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>
bank
</servlet-name>
<url-pattern>
/bank
</url-pattern>
</servlet-mapping>
</web-app>
There are a few items to notice. The listener tag comes before the
servlet definitions in the web.xml file. Also, the
<listener> tag has a child element,
<listener-class>, that defines the application
lifecycle event listener.
|
Figure 1 shows the console for Tomcat when it starts up and the above web application is deployed.
|
Figure 2 is a snapshot of the directory structure to give you a good idea of how the demo web application is set up.
|
The Servlet 2.3 specification allows for more interaction between
the web application programmer and ServletContext. The
programmer can now write an application lifecycle event listener that
executes when the attributes of the ServletContext object
have been modified. If you want to execute some code when the
attributes of the ServletContext object has been
modified, write a Java class that implements the
javax.Servlet.ServletContextAttributesListener
interface. This interface defines three methods with the following
signatures (this is taken from the JavaDocs):
void attributeAdded (ServletContextAttributeEvent
scab)
Notification that a new attribute was
added to the servlet context.
void attributeRemoved
(ServletContextAttributeEvent scab)
Notification that an existing attribute has been removed
from the servlet context.
void attributeReplaced
(ServletContextAttributeEvent scab)
Notification that an attribute on the servlet context has
been replaced.
Listing 3 is an example of writing an application event
listener for getting notifications of changes to the
ServletContext object.
Listing 3: An application event
listener that writes messages to the console when attributes of the
ServletContext object have been
modified. (ServletContextAttribListener.java)
package com.listeners;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributesListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ServletContextAttribListener
implements ServletContextAttributesListener {
//This method is invoked when an attribute
//is added to the ServletContext object
public void attributeAdded (ServletContextAttributeEvent scab)
{
System.out.println("An attribute was added to the " +
"ServletContext object");
}
//This method is invoked when an attribute
//is removed from the ServletContext object
public void attributeRemoved (ServletContextAttributeEvent scab)
{
System.out.println("An attribute was removed from " +
"the ServletContext object");
}
//This method is invoked when an attribute
//is replaced in the ServletContext object
public void attributeReplaced (ServletContextAttributeEvent scab)
{
System.out.println("An attribute was replaced in the " +
"ServletContext object");
}
}
This code is well and good, but what about testing it? Listing 4 is
for an HTML document that allows the user to add name-value pairs as
an object to the ServletContext object. You can also
remove items and replace items in the ServletContext
object. Listing 5 is the code for the Servlet that parses the request
from the HTML document and actually does the manipulation of the
ServletContext object.
Listing 4: An HTML document that
allows users to play with the ServletContext
object. (servletcontextattrib.html)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Working With Attributes Of the ServletContext Object</title>
</head>
<body>
<center>
<font size="6" color="navy">
Playing With The ServletContext Object
</font>
</center>
<form name="MyForm" action="./servletcontextattrib" method="POST">
<table width="75%" bgcolor="silver" align="center">
<tr><td rowspan="3">Select an Action</td>
<td><input type="radio" name="action" value="add">
Add Item To ServletContext
</td>
</tr>
<tr>
<td><input type="radio" name="action" value="remove">
Remove Item From ServletContext
</td>
</tr>
<tr>
<td><input type="radio" name="action" value="replace">
Replace Item In ServletContext
</td>
</tr>
<tr><td>Servlet Context Attribute Name</td>
<td><input type="text" name="name" value=""></td>
</tr>
<tr><td>Servlet Context Attribute Value</td>
<td><input type="text" name="value" value=""></td>
</tr>
<tr><td colspan="2" align="center">
<input type="submit" name="btnSubmit" value="Submit">
</td>
</tr>
</table>
</form>
</body>
</html>
|
Listing 5: The code for the servlet
that takes the HTML form information and does the actual manipulation
of the ServletContext
object. (ServletContextAttrib.java)
package com.servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ServletContextAttrib extends HttpServlet
{
public void service(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
ServletOutputStream out = response.getOutputStream();
out.print("<?xml version='1.0' encoding='UTF-8'?>");
out.print("<!DOCTYPE html");
out.print("PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'");
out.print("'DTD/xhtml1-strict.dtd'>");
out.print("<html>");
out.print("<head>");
out.print("<title>ServletContext Attributes</title>");
out.print("</head>");
out.print("<body>");
ServletContext context = getServletContext();
String action = request.getParameter("action");
String name = request.getParameter("name");
String value = request.getParameter("value");
if (action == null) {}
else {
if (action.equals("add"))
{
String test = (String) context.getAttribute(name);
if (test == null)
{
context.setAttribute(name, value);
out.print("Added Item To ServletContext object");
} else {
context.setAttribute(name, value);
out.print("Replaced Item in ServletContext");
}
}
else if (action.equals("remove"))
{
String test = (String) context.getAttribute(name);
if (test == null) {
out.print("Item does not exist");
} else {
context.removeAttribute(name);
out.print("Removed Item From ServletContext");
}
}
else
{
String test = (String) context.getAttribute(name);
if (test == null)
{
context.setAttribute(name, value);
out.print("Added Item To ServletContext object");
} else {
context.setAttribute(name, value);
out.print("Replaced Item in ServletContext");
}
}
}
out.print("<center> <br /> <br />");
out.print("<a href='./servletcontextattrib.html'>");
out.print("Back To Home Page");
out.print("</a>");
out.print("</center>");
out.print("</body>");
out.print("</html>");
}
}
|
Listing 6: The deployment descriptor,
web.xml, which contains the definitions for the listener
classes and Servlet defined above.
<?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/j2ee/dtds/web-app_2_3.dtd">
<web-app>
<!-- Define application events listeners -->
<listener>
<listener-class>
com.listeners.MyContextListener
</listener-class>
</listener>
<listener>
<listener-class>
com.listeners.ServletContextAttribListener
</listener-class>
</listener>
<!-- Define servlets that are included in the example application -->
<servlet>
<servlet-name>
simple
</servlet-name>
<servlet-class>
com.servlets.SimpleServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>
bank
</servlet-name>
<servlet-class>
com.servlets.BankBalance
</servlet-class>
</servlet>
<servlet>
<servlet-name>
context attribs
</servlet-name>
<servlet-class>
com.servlets.ServletContextAttrib
</servlet-class>
</servlet>
<!-- Define servlet mappings to urls -->
<servlet-mapping>
<servlet-name>
simple
</servlet-name>
<url-pattern>
/simple
</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>
bank
</servlet-name>
<url-pattern>
/bank
</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>
context attribs
</servlet-name>
<url-pattern>
/servletcontextattrib
</url-pattern>
</servlet-mapping>
</web-app>
The application event listeners can also make notifications when an
HttpSession object is created, destroyed, or has its
attributes modified. This is another way the Servlet 2.3 specification
is empowering the web application programmer.
It is possible to write one application event listener that handles
all notifications for changes to the HttpSession
objects. This could be done with ServletContext
notifications, but the earlier examples kept them separate to show
that method.
To receive lifecycle notifications for HttpSession
objects write a Java class that implements the
javax.Servlet.http.HttpSessionListener interface. This
interface defines two methods and their signatures are (taken from the
JavaDocs):
void sessionCreated (HttpSessionEvent se)
Notification that a session was created.
void sessionDestroyed (HttpSessionEvent se)
Notification that a session was invalidated.
To receive notifications that the attributes of an
HttpSession object have been modified implement the
javax.servlet.http.HttpSessionAttributesListener
interface. This interface defines three methods and their signatures
are (taken from the JavaDocs):
void attributeAdded (HttpSessionBindingEvent se)
Notification that an attribute has been added to a session.
void attributeRemoved (HttpSessionBindingEvent se)
Notification that an attribute has been removed from a session.
void attributeReplaced (HttpSessionBindingEvent se)
Notification that an attribute has been replaced in a session.
|
Listing 7 is an example of an application event listener that
receives all notifications of HttpSession objects;
whether the HttpSession object was created or destroyed
and if an attribute was added or removed.
Listing 7: An application event listener that handles all notifications of HttpSession objects. (MySessionListener.java)
package com.listeners;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionAttributesListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public final class MySessionListener
implements HttpSessionAttributesListener, HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
System.out.println("HttpSession object has been created");
}
public void sessionDestroyed(HttpSessionEvent event) {
System.out.println("HttpSession object has been removed");
}
public void attributeAdded(HttpSessionBindingEvent event) {
System.out.println("An attribute has been added " +
"to an HttpSession object");
}
public void attributeRemoved(HttpSessionBindingEvent event) {
System.out.println("An attribute has been removed " +
"to an HttpSession object");
}
public void attributeReplaced(HttpSessionBindingEvent event) {
System.out.println("An attribute has been replaced " +
"to an HttpSession object");
}
}
It's good to see the code for the application event listener, but
let's test it. Listing 8 is the code for a Servlet that maintains a
"bank balance" for an individual in an HttpSession
object. You can withdraw and deposit money into the account, in
increments of $50.
Listing 8: A Servlet that works with an HttpSession object. (BankBalance.java)
package com.servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class BankBalance extends HttpServlet
{
public void service(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
ServletOutputStream out = response.getOutputStream();
out.print("<?xml version='1.0' encoding='UTF-8'?>");
out.print("<!DOCTYPE html");
out.print("PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'");
out.print("'DTD/xhtml1-strict.dtd'>");
out.print("<html>");
out.print("<head>");
out.print("<title>Maintaining Session State</title>");
out.print("</head>");
out.print("<body>");
out.print("<center>");
HttpSession session = request.getSession();
String action = request.getParameter("action");
Double balance = (Double) session.getAttribute("Balance");
if (balance == null)
{
balance = new Double(500);
session.setAttribute("Balance", balance);
out.print(balance.doubleValue());
out.print("<br />");
} else {
double bal = balance.doubleValue();
if (action.equals("withdraw"))
{
bal -= 50;
} else {
bal += 50;
}
balance = new Double(bal);
session.setAttribute("Balance", balance);
out.print("Your new balance is: ");
out.print(bal);
out.print("<br />");
}
out.print("<a href='./bank?action=deposit'>");
out.print("Deposit $50");
out.print("</a>");
out.print("<br />");
out.print("<a href='./bank?action=withdraw'>");
out.print("Withdraw $50");
out.print("</a>");
out.print("</center>");
out.print("</body>");
out.print("</html>");
}
}
The web.xml deployment descriptor that defines this
Servlet and the application event listener is shown in Listing 9.
Listing 9: The web.xml deployment descriptor showing the
BankBalance Servlet definition and the
MySessionListener application event listener
definition.
<?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/j2ee/dtds/web-app_2_3.dtd">
<web-app>
<!-- Define application events listeners -->
<listener>
<listener-class>
com.listeners.MyContextListener
</listener-class>
</listener>
<listener>
<listener-class>
com.listeners.ServletContextAttribListener
</listener-class>
</listener>
<listener>
<listener-class>
com.listeners.MySessionListener
</listener-class>
</listener>
<!-- Define servlets that are included in the example application -->
<servlet>
<servlet-name>
simple
</servlet-name>
<servlet-class>
com.servlets.SimpleServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>
bank
</servlet-name>
<servlet-class>
com.servlets.BankBalance
</servlet-class>
</servlet>
<servlet>
<servlet-name>
context attribs
</servlet-name>
<servlet-class>
com.servlets.ServletContextAttrib
</servlet-class>
</servlet>
<!-- Define servlet mappings to urls -->
<servlet-mapping>
<servlet-name>
simple
</servlet-name>
<url-pattern>
/simple
</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>
bank
</servlet-name>
<url-pattern>
/bank
</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>
context attribs
</servlet-name>
<url-pattern>
/servletcontextattrib
</url-pattern>
</servlet-mapping>
</web-app>
This article shows you how to write application event listeners to
handle notifications about changes to the ServletContext
object and HttpSession objects. Application event
listeners give web application programmers greater control over the
ServletContext and HttpSession
objects. Although the examples in this article were simplistic, they
lay the groundwork for examining these event listeners. Now that you
can write listener classes, adding more advanced programming within
the notification methods is easy.
Stephanie Fesler is a BEA Systems expert on implementing various Java 2EE API.
Return to ONJava.com.
Copyright © 2007 O'Reilly Media, Inc.