Taming your Tomcat: Filtering tricks for Tomcat 5
Designing maintainable high-performance systems
The new Tomcat 5 server takes filters to a new level of deployment flexibility. Tomcat 5’s support for the upcoming Servlet 2.4 and JSP 2.0 specifications gives filter writers a new way to integrate and deploy these flexible components — tapping directly into the request dispatcher’s operations. In this article, Sing Li takes you on a guided tour of the new enhancement and gives you some hands-on training. See how Tomcat 5 can benefit Web application frameworks and lead ultimately to the design of maintainable high-performance systems.
Back in June 2001, I wrote an article that previewed the (then) brand-new Servlet 2.3 feature called filtering (see Resources). The Tomcat 4.x server supported this feature, and filters enabled Web application developers to create flexible application components that could be inserted and chained into the application server’s request flow — before and after the actual request was processed. And because filters are packaged as application-level components, on a par with JSP pages and servlets, they can easily be bundled in the same WAR file for deployment on any Servlet 2.3-compliant server. Since then, major application server vendors have embraced the Servlet 2.3 standard to support filtering, and filters have become a cornerstone component of many Web applications.
Readers who are unfamiliar with filtering operations — or who would like a refresher on how to construct filters and how filters work — are encouraged to read the first Tomcat filtering article.
Servlet 2.4 filter enhancements
Based on actual “in-the-field” feedback from the Web development community, the Servlet 2.4 specification — now being finalized — gives filters a single, highly important new capability. This new capability finally enables filters to play on completely level ground with servlets and JSP pages, enabling Web application designers to add major application functionality using filters. This new capability also facilitates a highly popular new style of Web application design called JSP Model 2, or Model View Controller (MVC) Web application design. (See Resources for more information on JSP Model 2 or MVC-styled Web application design.)
Filters in the request dispatcher’s processing flow
The new filtering feature in Servlet 2.4 basically alleviates the restriction that filters can only operate in the request flow before and after the actual request processing by the application server. Instead, Servlet 2.4 filters can now interact with the request dispatcher at every dispatch point. This means that when a Web resource forwards a request to another resource (for instance, a servlet forwarding the request to a JSP page in the same application), a filter can be operating before the request is handled by the targeted resource. It also means that should a Web resource include the output or function from other Web resources (for instance, a JSP page including the output from multiple other JSP pages), Servlet 2.4 filters can work before and after each of the included resources. Figure 1 illustrates the difference between Servlet 2.3 and Servlet 2.4’s dispatcher interactions.
Figure 1. Servlet 2.3 and Servlet 2.4 filter differences
Controlling filter dispatcher interactions
The interaction of filters with the container’s request processing flow is configured through the
element definition in the deployment descriptor (web.xml file). This is the convention established in the Servlet 2.3 specification, and it has not changed in Servlet 2.4. Instead, the new ability to interact with the dispatcher is controlled through a new optional
sub-element. Listing 1 shows a
element in a deployment descriptor that uses the
sub-element to apply a filter called “Blue Filter” to any JSP page that may be included (assuming that all the JSP pages in the application are mapped to the
/jsp/* URL pattern):
To apply the same filter to dispatcher-forwarded resources as well as included resources, we simply add another
sub-element, as shown in Listing 2:
The values that a
sub-element can contain are shown in Table 1:
Table 1. Possible values for a
|REQUEST||Apply filter to request originating from the client — exactly the same as the default behavior in Servlet 2.3-compliant containers.|
|FORWARD||Apply filter to request as it is being forwarded using the
|INCLUDE||Apply filter to request as Web resources are being included through
|ERROR||Apply filter to an error processing resource (essentially a container-managed forward mechanism when an error occurs).|
All of the values in Table 1, of course, are still subjected to the match specified by the
. Essentially, only the URLs that match the
sub-element will be filtered.
To better appreciate the operation of the new filter/dispatcher interactions, let’s put some filters to work in a Tomcat server.
|Downloading and installing Tomcat 5 plus JSTL
All code has been fully tested under Tomcat 5.0 alpha, the latest release build available at the time this article was written. In addition to installing Tomcat, you need to download the JSTL 1.0 binaries. Place standard.jar and jstl.jar into the webapps/dvworks/web-inf/lib directory, and all the TLD files under the webapps/dvworks/web-inf directory. (See Resources) for more information on installing Tomcat and downloading the JSTL 1.0 binaries.)
Configuring Tomcat 5 filters
Assuming you have Tomcat 5 installed and running with the JSP Standard Tag Library 1.0 (see the sidebar “Downloading and installing Tomcat 5 plus JSTL”), we can now work with some actual filter examples. Download the source code to get our sample Web application.
Let’s look at the coding of a couple of JSP pages and filters. The resources we’ll work with initially are:
The filtercount.jsp resource is quite simple, and consists of the code shown in Listing 3:
This JSP page calls the dispatcher to include another JSP page called
/jsp/included.jsp. It also uses the JSTL Expression Language to print out the value of two counters (
BlueCounter) that are attached as attributes to the incoming request, if the counter exists, and if the count is greater than zero.
In fact, each counter is used to count the number of times that either
BlueCounter is called during request processing. Table 2 shows the filters we will use and what they actually do.
Table 2. Names and functions of filters in experiment scenarios
||Increment the value of the
||Increment the value of the
All of the filters in Table 2 are part of the
The code for
com.ibm.dvworks.filters.AddAttributesFilter is presented in Listing 4. Note that it simply creates the two counter attributes as
java.lang.Integer type, which has a value of 0.
Listing 4. Code for AddAttributesFilter.java
The construction of this filter follows the basic filter coding pattern. Again, refer to the first article for more details on coding filters.
com.ibm.dvworks.filters.RedFilter has the code shown in Listing 5. Note that the code simply looks for the
RedCounter attribute and increments it if found.
com.ibm.dvworks.filters.BlueFilter class has identical code to
RedFilter, except the constant
COUNTER_ATTRIB is defined to be
BlueFilter, as shown in Listing 6:
The filtercount.jsp file uses the dispatcher to include the included.jsp file. The included.jsp file simply creates a table that is filled with the color specified by the input parameter called
BoxColor. Note the use of the Expression Language (EL) in rendering the color in the table, as shown in Listing 7:
With these filters and JSP pages, we are ready to begin our exploration of five different filter configuration scenarios.
Scenario 1: Standard Servlet 2.3 filter interaction — REQUEST only
In this first scenario, we will configure our filters to work in a manner supported by older Servlet 2.3 containers.
element that we will use is shown in Listing 8:
Edit your web.xml to reflect the Listing 8 configuration. Here, we are not specifying a
sub-element. This means that the filters will be applied on a REQUEST-only basis, as it did in Servlet 2.3 containers. The configuration in Listing 8 is operationally identical to the code in Listing 9:
Start Tomcat 5, and access the Web application using the
http:// URL. Figure 2 shows the response generated by filtercount.jsp:
According to the filtercount.jsp response,
RedFilter has been called only once in this scenario. Figure 3 is a detailed interaction diagram showing the request flow through the request processors:
In Figure 3, the filter chain is called only once — as the request enters the system from the client.
The filter chain, of course, consists of
RedFilter, as shown in Figure 4:
In this Servlet 2.3-styled configuration,
RedFilter is applied only once on the incoming request directly from the client.
Scenario 2: Combining REQUEST and INCLUDE interactions
The filter mapping we will use for this scenario is shown in Listing 10. Note the use of the Servlet 2.4 syntax and the addition of the INCLUDE dispatcher sub-element to
Restart Tomcat 5 and access the application again with the
http:// URL. The response shown in Figure 5 displays the filter count.
RedFilter has been called twice — once during the incoming request, and the second time with the inclusion of included.jsp. The two calls are detailed in the interaction diagram shown in Figure 6. Note that we have simplified the diagram by showing only the flow of the request into the system (and not the detailed return flow as was done previously).
Scenario 3: Combining REQUEST, INCLUDE, and FORWARD interactions
Next, we will bring in another simple JSP page, called forwarder.jsp, shown in Listing 11. It simply uses the dispatcher to forward the incoming request to filtercount.jsp.
Now we can add
BlueFilter to the deployment descriptor, as shown in Listing 12:
BlueFilter is configured to handle forwarded requests only, while the rest of the filter mapping remains unchanged.
Restart Tomcat 5 and access the application with the
http:// URL. Figure 7 shows the response.
In this case, we see that
BlueFilter is actually called once — during the forwarding of the request from forwarder.jsp to filtercount.jsp. The interaction diagram in Figure 8 shows the flow.
Scenario 4: Combining REQUEST, INCLUDE, FORWARD, and legacy Servlet 2.3 interactions
In this scenario, we are adding a filter from the previous filtering article (see Resources). You can use
ReplaceTextFilter to replace text in the response. We configure it using initial parameters in the
definition shown in Listing 13:
We then add the following
to the ones used in the previous scenario, as shown in Listing 14:
Note that we are not specifying a
sub-element here, and therefore this filter is defaulting to REQUEST-only processing.
Restart Tomcat 5 and access the
http:// URL. You should see something similar to Figure 9. Unlike the previous configuration, now the included box is green.
The interaction diagram shown in Figure 10 illustrates how
ReplaceTextFilter is handed the response for final processing before passing it back to the client. It is here that the color of the table is changed from red to green.
Servlet 2.4 containers are completely backward compatible with Servlet 2.3 filters, definitions, and mappings.
Scenario 5: Filtering on ERROR dispatch
For the final scenario, we will briefly examine the application of a filter when dispatching to an error-handling page. The filter mapping that we will use is in Listing 15. Make sure you remove all other filter mappings in web.xml.
To purposely generate an error, we create a JSP page, called errorgen.jsp, which sets up a page called errorhdlr.jsp to handle an error, and then throws an exception, as shown in Listing 16:
When an error is caught by the page, the container forwards the request to the
/jsp/errorhdlr.jsp page, as specified in the
@page directive. The errorhdlr.jsp page contains the code shown in Listing 17:
The errorhdlr.jsp prints out the filter counter values, then prints out the message of the exception being caught using the EL.
Restart Tomcat 5 and access the
http:// URL. Even though you attempt to access errorgen.jsp, it is errorhdlr.jsp that will be displayed (because an exception is explicitly thrown). The error page that you will see is shown in Figure 11:
RedFilter has been called twice — once at the REQUEST level and a second time when the container forwards to the error page.
You can apply Servlet 2.4 filters just before the processing of a custom error-handling Web resource.
Filters and Model 2 Web application frameworks
The enhanced filtering capability in Tomcat 5 provides new deployment opportunities when using popular application frameworks. Frameworks such as Struts and Turbine (see Resources) use a JSP Model 2 architecture to separate data operations (the Model in an MVC pattern) from the business logic operations, and the presentation operations (the View). Their functionality centers around the use of a switching servlet (the Controller servlet) that forwards incoming requests to different user-created Action components, either according to a static XML directive file or using runtime introspection. These requests are typically further forwarded between components, until the response is complete. The Model 2 architecture enables designers to componentize their server-side coding for adaptability to change and easier long-term maintenance.
Because the dispatcher is used extensively to forward requests between the controller servlet and the application components, as well as between application components, you can readily add filters to the processing flow. With the Servlet 2.4 enhancements, filters can now become an integral part of a Web application’s components mix — when using Model 2 application frameworks.
|An architectural pattern from the hardware domain
A novel way of thinking of a cluster of servers running a maximally scaled Web application is through the analogy of a microprocessor. Incoming requests span a finite set of possible operations like a CPU’s instruction set. Processing of requests by the servers is analogous to the execution of instructions by the hardware core.
Pipelining your application toward a high-performance future
Pipelining is a request flow-centric view of componentized request processing. It focuses on the multistage processing of a single request as it flows through the application server.
In the pipeline model, a request flows through an assembly line (the pipeline) while at each stage being modified/transformed/processed by a series of processors, until finally the response is generated and expedited back to the client. Popular Web application frameworks such as Jakarta Struts and Turbine, through the virtue of their JSP Model 2 architecture, already componentize the server-side logic in a pipelined fashion.
Figure 12 shows the typical pipeline stages that a Web application or service request may flow through when displaying a page of data:
In summary, the request is passed through the three pipeline stages shown in Table 3:
Table 3. Pipeline model stages
|Name of pipeline stage||Description of typical operation performed|
|Data fetch||Fetches data from external systems (such as JDBC datasource), based on information from the incoming request|
|Processing||Validates or transforms data elements using the value of the data element to look up further data, such as from internal or external sources|
|Rendering||Creates the output response based on the processed data, typically in a visual format (such as HTML) or an interchange format (such as XML)|
By placing design focus on the request processing pipeline, Web application design is entering a new era of performance tuning and optimization possibilities. Many of the same techniques being exploited in modern microprocessor hardware design — in the optimization of pipelines — can be leveraged in the near future for optimization of Web application server software and hardware.
For example, in a Web application that has similar requirements for every request flowing through the data fetch stage of processing, the optimized application server/hardware platform can prefetch and locally cache the most commonly accessed data — completely eliminating the data fetch overhead for most incoming requests. Another example — for requests that demand significant CPU processing resources in the rendering stage, such as XSLT transformation or other XML parsing — a parallel bank of hardware-accelerated XML processors can be configured in the rendering stage of the pipeline. While these optimizations are still slightly futuristic in terms of practical ability to implement them today, designing Web applications with consideration for the pipeline model is a necessary element to make them reality.
Tomcat 5’s new filtering feature enables us to tap into every stage of the Web application’s request-processing flow. This capability facilitates the use of filters with application frameworks and opens up new performance optimization and tuning possibilities.
the Web application, filters, and JSP source code for this article.
- For an introduction to Tomcat filters, how they work, and how to code them,
tricks for your Tomcat“, also by Sing Li (developerWorks, June 2001).
- Download the latest version of Apache Tomcat at the official
Tomcat Web site. You can download the alpha
release of the Tomcat 5.0 server.
- Download the latest version of JSTL at the Apache
Jakarta Taglib site. You can obtain the specification at JSR-52.
- At the time of publication, Mark Kolb is in the process of writing a four-part
series on JSTL. Part 1, “The
expression language” (developerWorks, February 2003), introduces JSTL
and the EL; Part 2, “Getting
down to the core” (developerWorks, March 2003), details flow control
and URL management through custom tags.
- Filtering enhancements are described in the Servlet 2.4 specification. You
can find the latest in JSR-154.
- The latest status and more information on the JavaServer Pages 2.0 specification,
including coverage of the proposed Expression Language (EL), can be found in JSR-152.
- Learn more about Model 2 Web application development using the Struts application
framework. See the official
Struts Web site for detailed information and the latest developments.
- Learn how to use
JSP and custom tags within VisualAge for Java and WebSphere Studio in this
tutorial from WebSphere
- Discover how to create “Advanced
JSP Tag Libraries using Apache Tomcat and VisualAge for Java” (WebSphere
Developer Technical Journal, July 2001).
- You’ll find hundreds of articles about every aspect of Java programming in
Java technology zone.
First published IBM developerWorks (http://www-106.ibm.com/developerworks/java/library/j-tomcat2).
Sing Li is the author of Early Adopter JXTA and Professional Jini, as well as numerous other books with Wrox Press. He is a regular contributor to technical magazines and is an active evangelist of the P2P evolution. Sing is a consultant and freelance writer and can be reached at firstname.lastname@example.org.