My friend Google said there were a number of others who wanted to do the same thing but they were being pointed to servlet 3.0. Unfortunately, servlet 3.0 and J2EE 6 were not an option for me, so it was looking like a tough nut to crack.
Then it struck me, what if I created a generic, conditional servlet filter that took the name of the class of the real filter as an init param? And, what if I passed in the condition that was to be evaluated to determine whether or not to create and/or invoke the real filter? Then, in the conditional filter, I could examine the condition and, as necessary, dynamically create an instance of the wrapped filter class.
Turns out it worked like a charm. Here's how. First the filter definition in web.xml:
CAS Authentication Filter my.org.security.servlet.ConditionalFilter condition cas/enabled wrapped-class org.jasig.cas.client.authentication.AuthenticationFilter
public class ConditionalFilter implements Filter {
// instance of the actual filter being wrapped
private Filter _wrappedFilter;
// are we to ignore the wrapped filter?
private boolean _ignore = true;
public ConditionalFilter() {
} // constructor
public void init(FilterConfig filterConfig) throws ServletException {
// the 'condition' init param tells us whether or not
// the wrapped filter is active
_ignore = !checkCondition(filterConfig.getInitParameter("condition"));
try {
if (!_ignore) {
// the wrapped filter is active so we create an instance
// of it and initialize it
_wrappedFilter = getFilterInstance(
filterConfig.getInitParameter("wrapped-class")
);
_wrappedFilter.init(filterConfig);
}
} catch (Exception e) {
throw new ServletException(e);
}
} // init()
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain filterChain)
throws IOException, ServletException {
if (!_ignore) {
// the wrapped filter is active so we let it do its work
_wrappedFilter.doFilter(request, response, filterChain);
} else {
// wrapped filter is inactive so simply move on to the next filter
filterChain.doFilter(request, response);
}
} // doFilter()
public void destroy() {
if (_ignore) {
_wrappedFilter.destroy();
}
} // destroy()
private Filter getFilterInstance(String className)
throws ClassNotFoundException, InvalidClassException,
InvocationTargetException, IllegalAccessException,
InstantiationException, NoSuchMethodException {
// try to create an instance of the wrapped filter
// with the given class name
Class filterClass = Class.forName(className);
java.lang.reflect.Constructor constructor = filterClass.getConstructor();
Object filter = constructor.newInstance();
if (!(filter instanceof Filter)) {
throw new InvalidClassException(
String.format("'%s' is not an instance of Filter", className)
);
}
return (Filter)filter;
} // getFilterInstance()
/*
* looks up the configured 'condition' via JNDI to determine
* whether or not the wrapped filter is active
*/
private boolean checkCondition(String condition) {
boolean result = false;
try {
InitialContext context = new InitialContext();
String path = String.format("java:comp/env/%s", condition);
result =(Boolean)context.lookup(path);
} catch (final NamingException e) {
System.out.println(
"unable to load condition from JNDI"
);
}
return result;
} // checkCondition()
} // class ConditionalFilter