Debugging with Filters

 < Free Open Study > 



Filters give us the ability to intercept, in a non-intrusive way, servlet invocations as they happen. This means that we can configure the container to ensure that all inbound requests to one or more servlets are channelled through our filter, and all output responses are returned via our filter. We can add and remove filters without having to modify the servlets themselves.

If your debugging requirements are limited to discovering the usage pattern for servlet invocations from multiple remote clients (perhaps to investigate a scalability or performance problem) a filter offers a simple but effective approach.

Implementing the Debugging Filter

We'll implement just one filter, DebugFilter. As a generic invocation trapper it can be used with any web application:

    package debugging;    import java.io.*;    import javax.servlet.*;    import javax.servlet.http.*;    import java.util.*;    public class DebugFilter implements Filter {      private FilterConfig filterConfig = null;      public void init(FilterConfig config) {        this.filterConfig = config;      }      public void destroy() {}      public void setFilterConfig(FilterConfig filterConfig) {        this.filterConfig = filterConfig;      }      public FilterConfig getFilterConfig() {        return this.filterConfig;      } 

This is where our filter starts to get interesting. All incoming requests must pass through our filter's doFilter() method before arriving at one of the target servlet's own service() methods (either doGet() or doPost()). This method does the following:

  • It extracts information from the ServletRequest referenced by the request variable

  • It constructs an output message that incorporates tags of the form

     <invocation><sender>localhost</sender>...</invocation> 

  • It sends the message to the server log file

      public void doFilter(ServletRequest request, ServletResponse response,                           FilterChain chain)        throws IOException, ServletException { 

We only proceed if we have a FilterConfig object to get the ServletContext from:

        if (filterConfig != null) { 

The tagged output will be stored here:

          StringBuffer messageBuffer = new StringBuffer(); 

We record the sender of the request:

          messageBuffer.append("<invocation>");          messageBuffer.append("<sender>");          messageBuffer.append(request.getRemoteHost());          messageBuffer.append("</sender>"); 

We record the message (that is, the posted parameters):

          messageBuffer.append("<message>");          Enumeration parameterNames = request.getParameterNames();          boolean firstTime = true;          while (parameterNames.hasMoreElements()) {            String thisName = (String) parameterNames.nextElement();            String[] parameterValues = request.getParameterValues(thisName);            String thisValue = parameterValues[0];            if (firstTime) {              messageBuffer.append("?");            } else {              messageBuffer.append("&");            }            messageBuffer.append(thisName + "=" + thisValue);            firstTime = false;          }          messageBuffer.append("</message>"); 

We record the URL that the message was sent to:

          if (request instanceof HttpServletRequest) {            messageBuffer.append("<receiver>");            messageBuffer.append(((HttpServletRequest)request).getRequestURI());            messageBuffer.append("</receiver>");          } 

We time the servlet invocation and record it:

          long startTime = System.currentTimeMillis();          chain.doFilter(request,response);          long endTime = System.currentTimeMillis();          long duration = endTime - startTime;          messageBuffer.append("<duration>" + duration + "</duration>");          messageBuffer.append("</invocation>"); 

Finally, we write the result to the server log:

          filterConfig.getServletContext().log(messageBuffer.toString());        }      }    } 

We're writing an entry to the log file after the request has completed, which allows us to capture timing information. Later we'll investigate a side-effect of this approach.

For simplicity we're using the server log file to store our results. We could write the results into a dedicated text file, or to a database, or even send them to a remote monitoring process using RMI, CORBA, or raw sockets. We could also channel the output through the J2SE 1.4 Logging API (as we'll discuss later).

Using the Debugging Filter

As a test, we can apply our filter to the example servlets that come with Tomcat. First compile and copy DebugFilter into %CATALINA_HOME%/webapps/examples/WEB-INF/classes/debugging. Then add the following entry to the web.xml file in %CATALINA_HOME%/webapps/examples/WEB-INF (after the existing <filter> entries):

    <filter>      <filter-name>DebugFilter</filter-name>      <filter-class>debugging.DebugFilter</filter-class>    </filter> 

Add this element after the existing <filter-mapping> elements:

    <filter-mapping>      <filter-name>DebugFilter</filter-name>      <url-pattern>/*</url-pattern>    </filter-mapping> 

Restart Tomcat and access one of the example servlets. I accessed the SessionExample servlet at http://localhost:8080/examples/servlet/SessionExample.

The tagged output from the Debugging Filter can be found in the examples log file in the %CATALINA_HOME%/logs directory. I saw the following entry:

    <invocation>      <sender>127.0.0.1</sender>      <message></message>      <receiver>/examples/servlet/SessionExample</receiver>      <duration>140</duration>    </invocation>    ...    <invocation>      <sender>127.0.0.1</sender>      <message></message>      <receiver>/examples/images/code.gif</receiver>      <duration>10</duration>    </invocation>    ...    <invocation>      <sender>127.0.0.1</sender>      <message></message>      <receiver>/examples/images/return.gif</receiver>      <duration>10</duration>    </invocation> 

We now have the ability to record the sequence in which invocations of this servlet are made from various remote clients (the <sender> element) with various parameter lists (the <message> element). So we can determine a typical multi-user usage pattern for our web application and capture some performance data (the <duration> element).



 < Free Open Study > 



Professional Java Servlets 2.3
Professional Java Servlets 2.3
ISBN: 186100561X
EAN: 2147483647
Year: 2006
Pages: 130

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net