Monday, June 08, 2009

Fetching Servlet Filter init parameters from a properties file with Spring

A while ago I wrote some code and thought it a neat trick but totally forgot about it until recently. I am writing this blog entry, firstly to share the idea and secondly to see if somebody can give an alternative using only Spring classes (which would deepen my understanding). Using Spring's DelegatingFilterProxy it is possible to hand off creation of servlet filters to a bean defined in Spring's application context. This is very useful if you want to inject Spring managed beans into a your servlet filters.

I am using the DelegatingFilterProxy mechanism to configure my servlet filter init parameters and in conjunction using PreferencesPlaceholderConfigurer so these come from a properties file. This means I can easily switch between prod and dev environments without having to modify web.xml (I could even change the authenticationFilter implementation to something else but that is a different story!). My aim here is to minimize the number of files I need to edit when moving between prod and dev environments. I hope somebody else finds this approach useful.

As an example I am using the Yale CAS Filter, which is considered a little long in the tooth now (but I'm still using it). It makes for a good example because there are numerous filter properties that you might want to change. Even the most up to date version of the JA-SIG CAS Filter could potentially benefit from using my approach.

web.xml


...
<filter>
<filter-name>authenticationFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>authenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...

applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="location" value="/WEB-INF/dev.properties" />
</bean>

<bean id="authenticationFilter" class="edu.bristol.web.ParameterPassingFilterProxy">
<property name="parameters">
<map>
<entry key="edu.yale.its.tp.cas.client.filter.loginUrl" value="${cas.loginUrl}" />
<entry key="edu.yale.its.tp.cas.client.filter.validateUrl" value="${cas.validateUrl}" />
<entry key="edu.yale.its.tp.cas.client.filter.wrapRequest" value="${cas.wrapRequest}" />
<entry key="edu.yale.its.tp.cas.client.filter.serverName" value="${cas.serverName}" />
<entry key="edu.yale.its.tp.cas.client.filter.renew" value="${cas.renew}" />
</map>
</property>
<property name="targetBeanName" value="casFilter" />
</bean>

<bean id="casFilter" class="edu.yale.its.tp.cas.client.filter.CASFilter"/>

</beans>

The extra class that I added to make this work is available from ParameterPassingFilterProxy.java you are free to use it as you wish.