Servlet Filters and Event
Listeners
This
chapter describes the following servlet features:
Servlet
filters are used for preprocessing Web application requests and postprocessing
responses, as described in the following sections:
Overview of Servlet Filters
When
the servlet container calls a method in a servlet on behalf of the client, the
HTTP request that the client sent is, by default, passed directly to the
servlet. The response that the servlet generates is, by default, passed
directly back to the client, with its content unmodified by the container. In
this scenario, the servlet must process the request and generate as much of the
response as the application requires.
But
there are many cases in which some preprocessing of the request for servlets
would be useful. In addition, it is sometimes useful to modify the response
from a class of servlets. One example is encryption. A servlet, or a group of
servlets in an application, may generate response data that is sensitive and
should not go out over the network in clear-text form, especially when the
connection has been made using a nonsecure protocol such as HTTP. A filter can
encrypt the responses. Of course, in this case the client must be able to
decrypt the responses.
A
common scenario for a filter is one in which you want to apply preprocessing or
postprocessing to requests or responses for a group of servlets, not just a
single servlet. If you need to modify the request or response for just one
servlet, there is no need to create a filter—just do what is required directly
in the servlet itself.
Note
that filters are not servlets. They do not implement and override HttpServlet methods such as doGet() or doPost(). Rather, a filter implements the methods of the javax.servlet.Filter interface. The methods are:
- init()
- destroy()
- doFilter()
How the Servlet Container Invokes Filters
Figure 3-1 shows how the
servlet container invokes filters. On the left is a scenario in which no
filters are configured for the servlet being called. On the right, several
filters (1, 2, ..., N) have been configured in a chain to be invoked by the
container before the servlet is called and after it has responded. The web.xml file specifies which servlets cause the container to invoke
the filters.
Figure 3-1 Servlet Invocation with and without
Filters
The
order in which filters are invoked depends on the order in which they are
configured in the web.xml file. The first filter in web.xml is the first one invoked during the request, and the last
filter in web.xml is the first one invoked during the
response. Note the reverse order during the response.
Note:
Be careful in
coordinating any use of multiple filters, in case of possible overlap in
functionality or in what the filters are overwriting.
|
Filtering of Forward
or Include Targets
In
the OC4J 10.1.2 implementation, when a servlet is filtered, any servlets that
are forwarded to or included from the filtered servlet are not filtered
by default. You can change this behavior, however, through the following
environment setting:
oracle.j2ee.filter.on.dispatch=true
This
flag is set to false by default.
Note:
This flag is a
temporary mechanism for the current release. Future releases will adhere to
version 2.4 of the servlet specification, which directs that servlets that
are forwarded to or included from a filtered servlet are not filtered by
default. But in compliance with the specification, you can configure this
behavior through the web.xml file.
|
This
section lists and describes three servlet filter examples.
This
section provides a simple filter example. Any filter must implement the three
methods in the javax.servlet.Filter interface or must extend a class that
implements them. So the first step is to write a class that implements these
methods. This class, which we will call MyGenericFilter, can be extended by other filters.
Here
is the generic filter code. Assume that this generic filter is part of a
package com.example.filter and set up a corresponding directory
structure.
This
is an elementary example of an empty (or "pass-through") filter and
could be used as a template.
package com.example.filter;
import javax.servlet.*;
public class MyGenericFilter implements javax.servlet.Filter {
public FilterConfig
filterConfig;
//1
public void doFilter(final
ServletRequest request, //2
final ServletResponse response,
FilterChain chain)
throws
java.io.IOException, javax.servlet.ServletException {
chain.doFilter(request,response); //3
}
public void init(final FilterConfig
filterConfig) { //4
this.filterConfig =
filterConfig;
}
public void destroy()
{
//5
}
}
Save
this code in a file called MyGenericFilter.java in the package directory. The numbered code notes refer to
the following:
- This code declares a variable
to save the filter configuration object.
- The doFilter() method contains the code that implements the
filter.
- In the generic case, just call
the filter chain.
- The init() method saves the filter configuration in a
variable.
- The destroy() method can be overridden to accomplish any
required finalization.
Filter Code: HelloWorldFilter.java
This
filter overrides the doFilter() method
of the MyGenericFilter class above. It prints a message on the
console when it is called on entrance, then adds a new attribute to the servlet
request, then calls the filter chain. In this example there is no other filter
in the chain, so the container passes the request directly to the servlet. Enter
the following code in a file called HelloWorldFilter.java:
package com.acme.filter;
import javax.servlet.*;
public class HelloWorldFilter extends MyGenericFilter {
private FilterConfig
filterConfig;
public void doFilter(final
ServletRequest request,
final
ServletResponse response,
FilterChain chain)
throws
java.io.IOException, javax.servlet.ServletException {
System.out.println("Entering Filter");
request.setAttribute("hello","Hello World!");
chain.doFilter(request,response);
System.out.println("Exiting HelloWorldFilter");
}
}
To
keep the example simple, the "servlet" to process the filter output
is written as a JSP page. Here it is:
<HTML>
<HEAD>
<TITLE>Filter Example 1</TITLE>
</HEAD>
<BODY>
<HR>
<P><%=request.getAttribute("hello")%></P>
<P>Check your console output!</P>
<HR>
</BODY>
</HTML>
The
JSP page gets the new request attribute, hello, that the filter added, and prints its value on the console. Put
the filter.jsp page in the root directory of the OC4J
standalone default Web application, and make sure your console window is
visible when you invoke filter.jsp from
your browser.
To
test the filter examples in this chapter, use the OC4J standalone default Web
application. Configure the filter in the web.xml file in the default Web application /WEB-INF directory (j2ee/home/default-web-app/WEB-INF, by default).
You
will need the following entries in the <web-app> element:
<!-- Filter Example 1
-->
<filter>
<filter-name>helloWorld</filter-name>
<filter-class>com.acme.filter.HelloWorldFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>helloWorld</filter-name>
<url-pattern>/filter.jsp</url-pattern>
</filter-mapping>
<!-- end Filter Example
1 -->
The <filter> element defines the name of the filter and the Java class
that implements the filter. The <filter-mapping> element defines the URL pattern that specifies which targets
the <filter-name> element should apply to. In this simple
example, the filter applies to only one target: the JSP code in filter.jsp.
Invoke filter.jsp from your Web browser. The console output should look like
this:
hostname% Entering Filter
Exiting HelloWorldFilter
The
Web browser output is similar to that shown in Figure 3-2, which follows.
Figure 3-2 Example 1 Output
You
can configure a filter with initialization parameters in the web.xml file. This section provides a filter example that uses the
following web.xml entry, which demonstrates a parameterized
filter:
<!-- Filter Example 2
-->
<filter>
<filter-name>message</filter-name>
<filter-class>com.acme.filter.MessageFilter</filter-class>
<init-param>
<param-name>message</param-name>
<param-value>A
message for you!</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>message</filter-name>
<url-pattern>/filter2.jsp</url-pattern>
</filter-mapping>
<!-- end Filter Example
2 -->
Here,
the filter named message has been configured with an initialization
parameter, also called message. The value of the message parameter is "A message for you!"
Filter Code: MessageFilter.java
Following
is the code to implement the message filter example.
Note that it uses the MyGenericFilter class from "Filter Example 1".
package com.acme.filter;
import javax.servlet.*;
public class MessageFilter extends MyGenericFilter {
public void doFilter(final
ServletRequest request,
final
ServletResponse response,
FilterChain chain)
throws
java.io.IOException, javax.servlet.ServletException {
System.out.println("Entering MessageFilter");
String message =
filterConfig.getInitParameter("message");
request.setAttribute("message",message);
chain.doFilter(request,response);
System.out.println("Exiting MessageFilter");
}
}
This
filter uses the filterConfig object that was saved in the generic
filter. The filterConfig.getInitParameter() method returns the value of the
initialization parameter.
As
in the first example, this example uses a JSP page to implement the
"servlet" that tests the filter. The filter named in the <url-pattern> tag above is filter2.jsp. Here is the code, which you can enter into a file filter2.jsp in the OC4J standalone default Web application root
directory:
<HTML>
<HEAD>
<TITLE>Lesson 2</TITLE>
</HEAD>
<BODY>
<HR>
<P><%=request.getAttribute("message")%></P>
<P>Check your console output!</P>
<HR>
</BODY>
</HTML>
Verify
that the filter configuration has been entered in the web.xml file, as shown above. Then access the JSP page with your
browser. The console output is similar to the following:
Auto-deploying file:/private/tssmith/appserver/default-web-app/
(Assembly had been updated)...
Entering MessageFilter
Exiting MessageFilter
Note
the message from the server showing that it redeployed the default Web
application after the web.xml file was edited,
and note the messages from the filter as it was entered and exited. The Web
browser output is similar to that shown in Figure 3-3, which follows.
Figure 3-3 Example 2 Output
A
particularly useful function for a filter is to manipulate the response to a
request. To accomplish this, use the standard javax.servlet.http.HttpServletResponseWrapper class, a custom javax.servlet.ServletOutputStream object, and a filter. To test the filter,
you also need a target to be processed by the filter. In this example, the
target that is filtered is a JSP page.
Create
three new classes to implement this example:
- FilterServletOutputStream: This class is a new implementation of ServletOutputStream for response wrappers.
- GenericResponseWrapper: This class is a basic implementation of the response
wrapper interface.
- PrePostFilter: This class implements the filter.
This
example uses the HttpServletResponseWrapper class to wrap the response before it is
sent to the target. This class is an object that acts as a wrapper for the ServletResponse object (using a Decorator design pattern, as described in
software design textbooks). It is used to wrap the real response so that it can
be modified after the target of the request has delivered its response.
The
HTTP servlet response wrapper developed in this example uses a custom servlet
output stream that lets the wrapper manipulate the response data after the
servlet (or JSP page, in this example) is finished writing it out. Normally,
this cannot be done after the servlet output stream has been closed (essentially,
after the servlet has committed it). That is the reason for implementing a
filter-specific extension to the ServletOutputStream class in this example.
Output Stream: FilterServletOutputStream.java
The FilterServletOutputStream class is used to manipulate the response
of another resource. This class overrides the three write() methods of the standard java.io.OutputStream class.
Here
is the code for the new output stream:
package com.acme.filter;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class FilterServletOutputStream extends ServletOutputStream
{
private DataOutputStream
stream;
public
FilterServletOutputStream(OutputStream output) {
stream = new
DataOutputStream(output);
}
public void write(int b)
throws IOException {
stream.write(b);
}
public void write(byte[]
b) throws IOException {
stream.write(b);
}
public void write(byte[]
b, int off, int len) throws IOException
{
stream.write(b,off,len);
}
}
Save
this code in the following directory, under the default Web application root
directory (j2ee/home/default-web-app by default), and compile it:
/WEB-INF/classes/com/acme/filter
Servlet Response Wrapper:
GenericResponseWrapper.java
To
use the custom ServletOutputStream class, implement a class that can act as a
response object. This wrapper object is sent back to the client in place of the
original response that was generated.
The
wrapper must implement some utility methods, such as to retrieve the type and
length of its content. The GenericResponseWrapper class accomplishes this:
package com.acme.filter;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class GenericResponseWrapper extends HttpServletResponseWrapper
{
private
ByteArrayOutputStream output;
private int contentLength;
private String
contentType;
public
GenericResponseWrapper(HttpServletResponse response) {
super(response);
output=new
ByteArrayOutputStream();
}
public byte[] getData() {
return
output.toByteArray();
}
public ServletOutputStream
getOutputStream() {
return new
FilterServletOutputStream(output);
}
public PrintWriter
getWriter() {
return new
PrintWriter(getOutputStream(),true);
}
public void
setContentLength(int length) {
this.contentLength =
length;
super.setContentLength(length);
}
public int
getContentLength() {
return contentLength;
}
public void
setContentType(String type) {
this.contentType = type;
super.setContentType(type);
}
public String
getContentType() {
return contentType;
}
}
Save
this code in the following directory, under the default Web application root directory
(j2ee/home/default-web-app by default), and compile it:
/WEB-INF/classes/com/acme/filter
This
filter adds content to the response after that target is invoked. This filter
extends the filter from "Generic Filter".
Here
is the filter code, PrePostFilter.java:
package com.acme.filter;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class PrePostFilter extends MyGenericFilter {
public void doFilter(final
ServletRequest request,
final
ServletResponse response,
FilterChain chain)
throws IOException,
ServletException {
OutputStream out =
response.getOutputStream();
out.write("<HR>PRE<HR>".getBytes());
GenericResponseWrapper
wrapper =
new
GenericResponseWrapper((HttpServletResponse) response);
chain.doFilter(request,wrapper);
out.write(wrapper.getData());
out.write("<HR>POST<HR>".getBytes());
out.close();
}
}
Save
this code in the following directory, under the default Web application root
directory (j2ee/home/default-web-app by default), and compile it:
/WEB-INF/classes/com/acme/filter
As
in the previous examples, create a simple JSP page:
<HTML>
<HEAD>
<TITLE>Filter Example 3</TITLE>
</HEAD>
<BODY>
This is a testpage. You should see<br>
this text when you invoke filter3.jsp, <br>
as well as the additional material added<br>
by the PrePostFilter.
<br>
</BODY>
</HTML>
Save
this JSP code in filter3.jsp in the root directory of the default Web
application.
Add
the following <filter> element to web.xml, after the configuration of the message filter:
<!-- Filter Example 3
-->
<filter>
<filter-name>prePost</filter-name>
<display-name>prePost</display-name>
<filter-class>com.acme.filter.PrePostFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>prePost</filter-name>
<url-pattern>/filter3.jsp</url-pattern>
</filter-mapping>
<!-- end Filter Example
3 -->
Invoke
the servlet in your Web browser. You will see a page that looks similar to the
page in Figure 3-4, which follows.
Figure 3-4 Example 3 Output
The
servlet specification includes the capability to track key events in your Web
applications through event listeners. This functionality allows
more efficient resource management and automated processing based on event
status. The following sections describe servlet event listeners:
Event Categories and Listener Interfaces
There
are two levels of servlet events:
- Servlet context-level
(application-level) event
This event involves resources or state held at the level of the
application servlet context object.
This event involves resources or state associated with the series
of requests from a single user session; that is, associated with the HTTP
session object.
Each
of these two levels has two event categories:
- Lifecycle changes
- Attribute changes
You
can create one or more event listener classes for each of the four event
categories. A single listener class can monitor multiple event categories.
Create
an event listener class by implementing the appropriate interface or interfaces
of the javax.servlet package or javax.servlet.http package. Table 3-1 summarizes the
four categories and the associated interfaces.
Table 3-1 Event
Listener Categories and Interfaces
Event Category
|
Event Descriptions
|
Java Interface
|
Servlet context lifecycle changes
|
Servlet context creation, at which point the first request can
be serviced
Imminent shutdown of the servlet context
|
javax.servlet. ServletContextListener
|
Servlet context attribute changes
|
Addition of servlet context attributes
Removal of servlet context attributes
Replacement of servlet context attributes
|
javax.servlet. ServletContextAttributeListener
|
Session lifecycle changes
|
Session creation
Session invalidation
Session timeout
|
javax.servlet.http. HttpSessionListener
|
Session attribute changes
|
Addition of session attributes
Removal of session attributes
Replacement of session attributes
|
javax.servlet.http. HttpSessionAttributeListener
|
Typical Event Listener Scenario
Consider
a Web application comprising servlets that access a database. A typical use of
the event listener mechanism would be to create a servlet context lifecycle
event listener to manage the database connection. This listener may function as
follows:
- The listener is notified of
application startup.
- The application logs in to the
database and stores the connection object in the servlet context.
- Servlets use the database
connection to perform SQL operations.
- The listener is notified of
imminent application shutdown (shutdown of the Web server or removal of
the application from the Web server).
- Prior to application shutdown,
the listener closes the database connection.
Event Listener Declaration and Invocation
Event
listeners are declared in the application web.xml deployment descriptor through <listener> elements under the top-level <web-app> element. Each listener has its own <listener> element, with a <listener-class> subelement specifying the class name. Within each event
category, event listeners should be specified in the order in which you would
like them to be invoked when the application runs.
After
the application starts up and before it services the first request, the servlet
container creates and registers an instance of each listener class that you
have declared. For each event category, listeners are registered in the order
in which they are declared. Then, as the application runs, event listeners for
each category are invoked in the order of their registration. All listeners
remain active until after the last request is serviced for the application.
Upon
application shutdown, session event listeners are notified first, in reverse
order of their declarations, then application event listeners are notified, in
reverse order of their declarations.
Here
is an example of event listener declarations, from the Sun Microsystems Java
Servlet Specification, Version 2.3:
<web-app>
<display-name>MyListeningApplication</display-name>
<listener>
<listener-class>com.acme.MyConnectionManager</listenerclass>
</listener>
<listener>
<listener-class>com.acme.MyLoggingModule</listener-class>
</listener>
<servlet>
<display-name>RegistrationServlet</display-name>
...
</servlet>
</web-app>
Assume
that MyConnectionManager and MyLoggingModule both implement the ServletContextListener interface, and that MyLoggingModule also implements the HttpSessionListener interface.
When
the application runs, both listeners are notified of servlet context lifecycle
events, and the MyLoggingModule listener is also notified of session
lifecycle events. For servlet context lifecycle events, the MyConnectionManager listener is notified first, because of the
declaration order.
Event
Listener Coding and Deployment Guidelines
Be
aware of the following rules and guidelines for event listener classes:
- In a multithreaded application,
attribute changes may occur simultaneously. There is no requirement for
the servlet container to synchronize the resulting notifications; the
listener classes themselves are responsible for maintaining data integrity
in such a situation.
- Each listener class must have a
public zero-argument constructor.
- Each listener class file must
be packaged in the application WAR file, either under /WEB-INF/classes or in a JAR file in /WEB-INF/lib.
Note:
In a distributed
environment, the scope of event listeners is one for each deployment
descriptor declaration for each JVM. There is no requirement for distributed
Web containers to propagate servlet context events or session events to
additional JVMs. The servlet specification discusses this.
|
Event
Listener Methods and Related Classes
This
section contains event listener methods that are called by the servlet
container when a servlet context event or session event occurs. These methods
take different types of event objects as input, so these event classes and
their methods are also discussed.
ServletContextListener Methods, ServletContextEvent Class
The ServletContextListener interface specifies the following methods:
- void
contextInitialized(ServletContextEvent sce)
The servlet container calls this method to notify the listener
that the servlet context has been created and the application is ready to
process requests.
- void
contextDestroyed(ServletContextEvent sce)
The servlet container calls this method to notify the listener
that the application is about to be shut down.
The
servlet container creates a javax.servlet.ServletContextEvent object that is input for calls to ServletContextListener methods. The ServletContextEvent class includes the following method, which
your listener can call:
- ServletContext
getServletContext()
Use this method to retrieve the servlet context object that was
created or is about to be destroyed, from which you can obtain information as
desired. See "Introduction to Servlet
Contexts" for information about the javax.servlet.ServletContextinterface.
ServletContextAttributeListener Methods, ServletContextAttributeEvent
Class
The ServletContextAttributeListener interface specifies the following methods:
- void
attributeAdded(ServletContextAttributeEvent scae)
The servlet container calls this method to notify the listener
that an attribute was added to the servlet context.
- void
attributeRemoved(ServletContextAttributeEvent scae)
The servlet container calls this method to notify the listener
that an attribute was removed from the servlet context.
- void
attributeReplaced(ServletContextAttributeEvent scae)
The servlet container calls this method to notify the listener
that an attribute was replaced in the servlet context.
The
container creates a javax.servlet.ServletContextAttributeEvent object that is input for calls to ServletContextAttributeListener methods. The ServletContextAttributeEvent class includes the following methods,
which your listener can call:
Use method this to get the name of the attribute that was added,
removed, or replaced.
Use this method to get the value of the attribute that was added,
removed, or replaced. In the case of an attribute that was replaced, this
method returns the old value, not the new value.
HttpSessionListener Methods, HttpSessionEvent Class
The HttpSessionListener interface specifies the following methods:
- void
sessionCreated(HttpSessionEvent hse)
The servlet container calls this method to notify the listener
that a session was created.
- void
sessionDestroyed(HttpSessionEvent hse)
The servlet container calls this method to notify the listener
that a session was destroyed.
The
container creates a javax.servlet.http.HttpSessionEvent object that is input for calls to HttpSessionListener methods. The HttpSessionEvent class includes the following method, which your listener can
call:
Use this method to retrieve the session object that was created or
destroyed, from which you can obtain information as desired. See "Introduction to Servlet
Sessions" for information about the javax.servlet.http.HttpSession interface.
HttpSessionAttributeListener Methods, HttpSessionBindingEvent Class
The HttpSessionAttributeListener interface specifies the following methods:
- void
attributeAdded(HttpSessionBindingEvent hsbe)
The servlet container calls this method to notify the listener
that an attribute was added to the session.
- void
attributeRemoved(HttpSessionBindingEvent hsbe)
The servlet container calls this method to notify the listener
that an attribute was removed from the session.
- void
attributeReplaced(HttpSessionBindingEvent hsbe)
The servlet container calls this method to notify the listener
that an attribute was replaced in the session.
The
container creates a javax.servlet.http.HttpSessionBindingEvent object that is input for calls to HttpSessionAttributeListener methods. The HttpSessionBindingEvent class includes the following methods,
which your listener can call:
Use this method to get the name of the attribute that was added,
removed, or replaced.
Use this method to get the value of the attribute that was added,
removed, or replaced. In the case of an attribute that was replaced, this
method returns the old value, not the new value.
Use this method to retrieve the session object that had the
attribute change.
This
section provides code for a sample that uses a servlet context lifecycle and
session lifecycle event listener. This includes the following components:
- SessionLifeCycleEventExample: This is the event listener class, implementing the ServletContextListener and HttpSessionListener interfaces.
- SessionCreateServlet: This servlet creates an HTTP session.
- SessionDestroyServlet: This servlet destroys an HTTP session.
- index.jsp: This is the application welcome page (the user
interface), from which you can invoke SessionCreateServlet or SessionDestroyServlet.
- web.xml: This is the deployment descriptor, in which the
servlets and listener class are declared.
To
download and run this application, refer to the Use Servlet Lifecycle Events
example at the following link:
(These
examples were written for older versions of OC4J, but the functionality is
similar for the 10.1.2 implementation.)
You
must be a member of the Oracle Technology Network, but memberships are free of
charge.
Here
is the welcome page, the user interface that enables you to invoke the
session-creation servlet by clicking the Create New Session link,
or to invoke the session-destruction servlet by clicking the Destroy
Current Session link.
<%@page session="false" %>
<H2>OC4J - HttpSession Event Listeners </H2>
<P>
This example demonstrates the use of the HttpSession Event and
Listener that is
new with the Java Servlet 2.3 API.
</P>
<P>
[<a href="servlet/SessionCreateServlet">Create New
Session</A>]
[<a href="servlet/SessionDestroyServlet">Destroy
Current Session</A>]
</P>
<P>
Click the Create link above to start a new HttpSession. An HttpSession
listener has been configured for this application. The servler
container
will send an event to this listener when a new session is created
or
destroyed. The output from the event listener will be visible in
the
console window from where OC4J was started.
</P>
Note:
No new session object
is created if you click the Create New Session link again
after having already created a session from the same client, unless the
session has reached a timeout limit or you have explicitly destroyed it in
the meantime.
|
Deployment Descriptor: web.xml
The
servlets and the event listener are declared in the web.xml file. This results in SessionLifeCycleEventExample being instantiated and registered upon
application startup. Because of this, the servlet container automatically calls
its methods, as appropriate, upon the occurrence of servlet context or session
lifecycle events. Here are the web.xml entries:
<web-app>
<listener>
<listener-class>SessionLifeCycleEventExample</listener-class>
</listener>
<servlet>
<servlet-name>sessioncreate</servlet-name>
<servlet-class>SessionCreateServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>sessiondestroy</servlet-name>
<servlet-class>SessionDestroyServlet</servlet-class>
</servlet>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Listener Class: SessionLifeCycleEventExample
This
section shows the listener class. Its sessionCreated() method is called by the servlet container when an HTTP
session is created, which occurs when you click the Create New Session link
in index.jsp. When sessionCreated() is called, it calls the log() method to print a "CREATE" message indicating the
ID of the new session.
The sessionDestroyed() method is called when the HTTP session is
destroyed, which occurs when you click the Destroy Current Session link.
When sessionDestroyed() is called, it calls the log() method to print a "DESTROY" message indicating the
ID and duration of the terminated session.
import javax.servlet.http.*;
import javax.servlet.*;
public class SessionLifeCycleEventExample
implements
ServletContextListener, HttpSessionListener
{
/* A listener class must
have a zero-argument constructor: */
public
SessionLifeCycleEventExample()
{
}
ServletContext
servletContext;
/* Methods from the
ServletContextListener */
public void
contextInitialized(ServletContextEvent sce)
{
servletContext =
sce.getServletContext();
}
public void
contextDestroyed(ServletContextEvent sce)
{
}
/* Methods for the
HttpSessionListener */
public void sessionCreated(HttpSessionEvent
hse)
{
log("CREATE",hse);
}
public void
sessionDestroyed(HttpSessionEvent hse)
{
HttpSession
_session = hse.getSession();
long _start =
_session.getCreationTime();
long _end =
_session.getLastAccessedTime();
String _counter =
(String)_session.getAttribute("counter");
log("DESTROY,
Session Duration:"
+ (_end -
_start) + "(ms) Counter:" + _counter, hse);
}
protected void log(String
msg, HttpSessionEvent hse)
{
String _ID =
hse.getSession().getId();
log("SessionID:" + _ID + " " + msg);
}
protected void log(String
msg)
{
System.out.println("[" + getClass().getName() + "] "
+ msg);
}
}
Session Creation Servlet:
SessionCreateServlet.java
This
servlet is invoked when you click the Create New Session link
in index.jsp. Its invocation results in the servlet
container creating a request object and associated session object. Creation of
the session object results in the servlet container calling the sessionCreated() method of the event listener class.
import java.io.*;
import java.util.Enumeration;
import java.util.Date;
import javax.servlet.*;
import javax.servlet.http.*;
public class SessionCreateServlet extends HttpServlet {
public void doGet
(HttpServletRequest req, HttpServletResponse res)
throws
ServletException, IOException
{
//Get the session
object
HttpSession session
= req.getSession(true);
// set content type
and other response header fields first
res.setContentType("text/html");
// then write the
data of the response
PrintWriter out =
res.getWriter();
String _sval =
(String)session.getAttribute("counter");
int _counter=1;
if(_sval!=null)
{
_counter=Integer.parseInt(_sval);
_counter++;
}
session.setAttribute("counter",String.valueOf(_counter));
out.println("<HEAD><TITLE> " + "Session
Created Successfully ..
Look at OC4J
Console to see whether the HttpSessionEvent invoked "
+
"</TITLE></HEAD><BODY>");
out.println("<P>[<A HREF=\"SessionCreateServlet\">Reload</A>] ");
out.println("[<A
HREF=\"SessionDestroyServlet\">Destroy
Session</A>]");
out.println("<h2>Session created
Successfully</h2>");
out.println("Look
at the OC4J Console to see whether the HttpSessionEvent
was
invoked");
out.println("<h3>Session Data:</h3>");
out.println("New
Session: " + session.isNew());
out.println("<br>Session ID: " + session.getId());
out.println("<br>Creation Time: " + new
Date(session.getCreationTime()));
out.println("<br>Last Accessed Time: " +
new
Date(session.getLastAccessedTime()));
out.println("<BR>Number of Accesses: " +
session.getAttribute("counter"));
}
}
Session Destruction Servlet:
SessionDestroyServlet.java
This
servlet is invoked when you click the Destroy Current Session link
in index.jsp. Its invocation results in a call to the invalidate() method of the session object. This, in turn, results in the
servlet container calling the sessionDestroyed() method of the event listener class.
import java.io.*;
import java.util.Enumeration;
import javax.servlet.*;
import javax.servlet.http.*;
public class SessionDestroyServlet extends HttpServlet {
public void doGet
(HttpServletRequest req, HttpServletResponse res)
throws
ServletException, IOException
{
//Get the session
object
HttpSession session
= req.getSession(true);
// Invalidate
Session
session.invalidate();
// set content type
and other response header fields first
res.setContentType("text/html");
// then write the
data of the response
PrintWriter out =
res.getWriter();
out.println("<HEAD><TITLE> " + "Session
Destroyed Successfully ..
Look at OC4J
Console to see whether the HttpSessionEvent invoked "
+
"</TITLE></HEAD><BODY>");
out.println("<P>[<A
HREF=\"../index.jsp\">Restart</A>]");
out.println("<h2> Session Destroyed
Successfully</h2>");
out.println("Look at the OC4J Console to see whether the
HttpSessionEvent was invoked");
out.close();
}
}