[ Team LiB ] Previous Section Next Section

Recipe 11.11 Using a Filter to Monitor Session Attributes

Problem

You want to use a filter to check a session attribute prior to the request reaching a servlet.

Solution

Create a Java class that implements javax.servlet.Filter, write session-related code in the class's doFilter( ) method, then configure the filter in your deployment descriptor.

Discussion

Filters, as their name suggests, are semipermeable barriers through which requests to your web application must pass before they reach servlets, JSPs, or even static content. Filters are technically Java classes that implement the javax.servlet.Filter interface. A filter can have a look at the ServletRequest and ServletResponse objects before these objects find their way to a servlet's service methods (which include service( ), doGet( ), and doPost( )). Filters can initiate authentication, logging, encryption, database actions, caching, and just about any other task that passes through request and response objects.

Filters are configured in web.xml. In Example 11-18, a filter checks a logged-in HttpSession attribute, and logs its activities by calling the ServletContext object's log( ) method. This filter is mapped to a servlet registered in web.xml as MyServlet. Any requests to the MyServlet servlet cause the SessionFilter.doFilter( ) method to be called. Example 11-17 shows the relevant entries in web.xml.

Example 11-17. Configuring a filter in web.xml
<!-- the beginning of web.xml goes here -->

<filter>
        <filter-name>SessionFilter</filter-name>
        <filter-class>com.jspservletcookbook.SessionFilter</filter-class>
</filter>

<filter-mapping>
        <filter-name>SessionFilter</filter-name>
        <servlet-name>MyServlet</servlet-name>
</filter-mapping>
<!-- more filters or listener classes added here -->

<servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>com.jspservletcookbook.MyServlet</servlet-class>
</servlet>

<!-- deployment descriptor continues ...-->

The filter element specifies the filter's registered name and its fully qualified Java class. You package the filter class with the rest of the web application by placing the class in WEB-INF/classes or in a JAR file in WEB-INF/lib. The filter-mapping element maps the filter to the servlet registered in the deployment descriptor as MyServlet. Filters can also be mapped to URL patterns (Chapter 20 explains this syntax in detail). Example 11-18 is the source code for com.jspservletcookbook.SessionFilter.

Example 11-18. A filter that snoops on session information
package com.jspservletcookbook;

import javax.servlet.*;
import javax.servlet.http.*;

public class SessionFilter implements Filter {
    
   private FilterConfig config;
    
   //Creates new SessionFilter
   public SessionFilter( ) {}
    
  public void  init(FilterConfig filterConfig)  throws ServletException{
        
      System.out.println("Instance created of "+getClass( ).getName( ));
      this.config = filterConfig;
    }
    
  public void  doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws java.io.IOException, ServletException {
        
      HttpSession session = ((HttpServletRequest) request).getSession( );

      ServletContext context = config.getServletContext( );

      /* use the ServletContext.log method to log 
        filter messages */
      context.log("doFilter called in: " + config.getFilterName( ) +  
        " on " + (new java.util.Date( )));
  
      // log the session ID
      context.log("session ID: " + session.getId( ));

      // Find out whether the logged-in session attribute is set
      String logged = (String) session.getAttribute("logged-in");
      if (logged == null)
          session.setAttribute("logged-in","no");

      //log a message about the log-in status
      context.log("log-in status: "+
          (String)session.getAttribute("logged-in"));

      context.log("");

      chain.doFilter(request,response);
  }
    
  public void destroy( ){
        /*called before the Filter instance is removed 
        from service by the web container*/
  }
}

Every filter has to have a zero-argument constructor, just like listener classes.


The init( ) method displays a console message when its instance is created by the web container. The javax.servlet.FilterConfig object is used to get the ServletContext object for this filter (by calling FilterConfig.getServletContext( )). The ServletContext.log( ) method is used to log messages from the filter. These messages can then be read in the server logs. In Tomcat, look in the <Tomcat-install-directory>/logs directory for log files with names such as localhost_home_log.2003-01-24.txt. Here is an example of the log entries for this filter:

2003-01-24 11:56:09 doFilter called in: SessionFilter on Fri Jan 24 11:56:09 EST 2003
2003-01-24 11:56:09 session ID: E04DE93D9B88A974ED2350BCF7945F34
2003-01-24 11:56:09 log-in status: no

The filter gets access to the session with this code:

HttpSession session = ((HttpServletRequest) request).getSession( );

Since the doFilter( ) method has a ServletRequest parameter type, and not a HttpServletRequest type, the request parameter has to be cast to the latter type so that the code can call the request.getSession( ) method.

Beware of doing this blindly in environments where you are not positive that all servlets are HttpServlets. If you aren't sure, a simple class check before casting can solve this problem.


Once the filter has access to the session object, it looks for a certain session attribute (logged-in). If session.getAttribute("logged-in") returns null, this attribute is added to the session with the value "no". The code then calls chain.doFilter(request,response) inside of the filter's doFilter( ) method.

This method call on the FilterChain object ensures that the request and response are passed along to the next filter on the chain, or, in the absence of any more mapped filters, to the targeted web resource. Example 11-19 shows the doGet( ) method of the MyServlet servlet that the filter in Example 11-18 is mapped to.

Example 11-19. doGet method of a servlet to which a filter is mapped
public void doGet(HttpServletRequest request, 
  HttpServletResponse response)
    throws ServletException, java.io.IOException {
        
        response.setContentType("text/html");
        java.io.PrintWriter out = response.getWriter( );

        HttpSession session = request.getSession( );

        String logged = (String) session.getAttribute("logged-in");

        out.println("<html>");
        out.println("<head>");
        out.println("<title>Filter Servlet</title>");
        out.println("</head>");
        out.println("<body>");
        
        out.println("<h2>Session Logged in Info</h2>");

        out.println("logged in : " + logged+ "<br><br>");
        
        out.println("</body>");
        out.println("</html>");
        
    }

This servlet checks the logged-in session attribute and displays its value, as shown in Figure 11-7.

A filter is mapped to a servlet's registered name like this:

<filter-mapping>
  <filter-name>SessionFilter</filter-name>
  <servlet-name>MyServlet</servlet-name>
</filter-mapping>

The requests for this servlet will not pass through the mapped filter first, however, if the servlet is requested with an "invoker"-style URL of the form http://localhost:8080/servlet/com.jspservletcookbook.MyServlet. If this causes problems for the web application, consider disabling or overriding the URL mapping of /servlet/* in your web application. Recipe 3.6 describes how to do this.


Figure 11-7. Checking a session object after a filter has altered it
figs/jsjc_1107.gif

A filter can take a number of actions with a session object before it reaches a servlet or JSP that does session tracking, such as add, remove, or change session attributes. It can also alter the session's timeout period (with the HttpSession.setMaxInactiveInterval(int seconds) method) based on an attribute of the session or request.

See Also

Chapter 19 on using filters; Recipe 11.4 on checking the validity of a session; Chapter 1 on web.xml; Chapter 7 of the Servlet v2.3 and 2.4 specifications on sessions; the javax.servlet.http.HttpSession API at http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/HttpSession.html; Chapter 1 on web.xml; Chapter 6 of the Servlet v 2.3 and 2.4 specifications on filtering.

    [ Team LiB ] Previous Section Next Section