I've created my first Java Servlet Filter!

I've created my first Java Servlet Filter!

Posted by Brad Wood
Jul 10, 2008 05:35:00 UTC
In the Java world, web requests are handled by servlets loaded within a servlet container. There is a servlet mapping which specifies a servlet class conforming to Sun's Servlet specification which has been part of the J2EE spec since version 2.2. When a request is sent to the servlet container, it is matched to the proper url pattern and passed to the appropriate servlet object via that objects service() method.Adobe ColdFusion is basically a collection of servlets running in a servlet container called JRUN. Requests made that look like *.cfm, *.cfml, or *.cfc are mapped to the CfmServlet servlet in web.xml which is handled by the coldfusion.bootstrap.BootstrapServlet class buried in the cfmx_bootstrap.jar Jar. Ok, big whoop-what does all that mean? What that means is you can write servlet filters in Java to intercept the request before it reaches the servlet (ColdFusion), modify the response before it returns to the browser (like applying compression), or to redirect the request as a form of security. Programs like SeeFusion work because they are a servlet filter. That is how it keeps track of each request made to the server. Based on URL mappings, you can define any number of servlet mappings that chain together to fiddle with the request-or simply log data about it. Each servlet mapping has its doFilter() method called before the request reaches the target servlet. Well, with all that in mind, I was spurred on by Charlie Arehart's comment on one of Jochem's recent blog entries talking about how rogue cookies being passed in the request header from the client by bots can trash your logs with meaningless errors. Charlie suggested someone could write a servlet filter that would remove these cookies from the request before ColdFusion got its hands on it. (Charlie did a nice article on Servlet Filters and ColdFusion in the CFDJ a while back) Well this caught my interest. I haven't actually done the cookie part yet, but I have created a "Hello World" filter and implemented it. It's pretty freakin' cool even though it's super basic. Below are the steps I followed using Eclipse 3 and my local developers edition of ColdFusion 8 standard. Some of the file paths will be different for you, but I'll let you figure that out. Please correct me if I did anything wrong. I promise I was making most of this up as I went via trial and error! YMMV Creating your very own servlet filter
  • In Eclipse open a new workspace.
  • Right click > New > Project
  • Choose Java > Java Project
  • Enter a name. I used "Test Filter"
  • Click Finish
  • Right click project name > New > Source Folder
  • Enter name. I used "src"
  • Right click source folder > New > package
  • Enter a name. I used "com.filters"
  • Right click package name > New > Class
  • Enter a name. I used "testFilter"
  • Copy jrun.jar from your server to your PC (<cf_root>\runtime\lib\jrun.jar)
    This is what contains the javax.servlet classes
  • Right click project name > Build Path > Add External Resource
  • Browse to and choose jrun.jar
  • Place following Java code in the testFilter.java file
[code]package com.filters;

import javax.servlet.*;
import java.io.IOException;
import javax.servlet.ServletException;

public class testFilter implements Filter 
	{
		private FilterConfig filterConfig = null;

		// This method is called once on server startup
		public void init(FilterConfig filterConfig) 
			{
				this.filterConfig = filterConfig;
			}
		
		// This method is called for every request and needs to be thread safe.
		public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
		  throws java.io.IOException, javax.servlet.ServletException 
		  	{
				// bef and aft are declared as local to this method so they will be specific to each request.
				long bef = System.currentTimeMillis();
			  	System.out.println("Entering Filter " + filterConfig.getFilterName() + ": " + bef);
			  	// This executes the next filter in line, or the target servlet.
			  	chain.doFilter(request,response);
			  	long aft = System.currentTimeMillis();
			  	System.out.println("Exiting Filter " + filterConfig.getFilterName() + ": " + aft + " Total Time: " + (aft - bef));
			}
		
		// This method is called once on server shut down
		public void destroy() 
			{
				this.filterConfig = null;
			}
	}


[/code]
  • Right click on project name > Export > Jar File
  • Name the jar. I called it testFilter.jar and placed it in my project directory
  • Click Finish
  • Now you have a compiled and jarred version of your new filter.
  • Copy testFilter.jar to server's classpath (<cf_root>\runtime\lib\testFilter.jar)
  • Open web.xml (<cf_root>\wwwroot\WEB-INF\web.xml)
  • Add the following servlet-filter with the other filter tags. The name is arbitrary, but the class needs to be your package name and class name.
[code]<filter>
	<filter-name>testFilter</filter-name>
	<filter-class>com.filters.testFilter</filter-class>
</filter>
[/code]
  • Add filter-mapping in front of all other mappings. (mappings are processed in the order they appear) The URL pattern "/*" will match ALL requests. "/test/*" would only match request to files in the test folder. "/test/*.html" would only apply to requests for html files in the test folder. "/test/index.cfm" would only apply to request specifically for index.cfm in the test folder. You get the picture.
[code]<filter-mapping>
	<filter-name>testFilter</filter-name>
	<url-pattern>&#47;*</url-pattern>
</filter-mapping>
[/code]
  • Restart your ColdFusion Server.
  • Hit a page on your server. (the request needs to match the URL pattern, obviously)
  • In ColdFusion's "out" log (<cf_root>/runtime/logs/coldfusion-out.log) There will be two entries at the end of the log:
[code]Entering Filter testFilter: 1215664939859
Exiting Filter testFilter: 1215664940171 Total Time: 312
[/code]
The first line was put there before the request was passed off to ColdFusion. The second line was placed there after ColdFusion had finished processing the request. Of course, this example just scratches the surface. Through the request and response wrapper classes one can change the way the request is presented to the servlet, or modify the response before the client receives it back. You have full access to the request headers, etc. Yes, a lot of this could also be accomplished with OnRequestStart.cfm and OnRequestEnd.cfm, but this is cooler and more powerful. For instance, you could use one of the many pre-written servlet filters out there to apply http compression to your pages. As soon as I get a servlet filter working that removes the cookies, I'll blog it. In the mean time let's observe a moment of silent awe for the mighty power of Java-- to which we owe the mighty power of ColdFusion.

 


Charlie Arehart

Good stuff, and thanks for mentioning the article. I want to point out to folks that in it, I also point you to places where you can find filters already written. There really are a lot of things that people want that are already done in filters. Sometimes the examples come with source, so you can learn from them, but even when they don't they can still be useful to solve a problem. At some point I plan to offer a followup that highlights some of the more interesting ones. Until then, folks spurred by Brad here should check them out.

Site Updates

Entry Comments

Entries Search