For example, with this configuration the filter will intercept all '/secure/' and '/services/' paths.
<filter> <filter-name>OneFilter</filter-name> <filter-class>com.MyFilterClass</filter-class> </filter> <filter-mapping> <filter-name>OneFilter</filter-name> <url-pattern>/secure/**</url-pattern> <url-pattern>/services/**</url-pattern> </filter-mapping>
But, what I need is to have a filter which intercepts all paths, except some ones.
I found this great solution in gitHub, https://gist.github.com/superbob/5005291, developed by this superbob guy ;), but it was quite specific. So I decided to enhanced it and give some more config options.
The idea is the same, one filter, wrapper, wich has inside a inner filter. The wrapper filter is responsible of instanciate and initialize the inner filter.
There is a special class called FilterWrapperCondition which evaluate if the inner filter should be called or not. This is in fact an interface, and the particular implementations are configured with the filter config of the wrapper.
These are the main classes. The complete code is in github: https://github.com/evazquezma/JEE6/tree/master/wrapperFilter
WrapperFilter
package es.pruebas.jee6.filter.wrapper;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This filter wrapp a inner filter and decides when invoke it.
*
* If you are using Spring, you can get Spring beans by using "WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());".
* In this way you will not need instanciate class by hand.
*
* @author SISIFO
*
*/
public class WrapperFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(WrapperFilter.class);
private static final String FILTER_PARAM_INNER_FILTER_CLASS = "wrapper.param.filterClass";
private static final String FILTER_PARAM_WRAPPER_CONDITION_CLASS = "wrapper.param.wrapperConditionClass";
private Filter innerFilter;
private FilterWrapperCondition filterWrapperCondition;
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
LOGGER.info("Initializing filter inhibitor");
this.innerFilter = createAndInitInnerFilter(filterConfig);
this.filterWrapperCondition = createAndInitFilterWrapperCondition(filterConfig);
LOGGER.info("Inhibitor engaged !");
}
private Filter createAndInitInnerFilter(final FilterConfig filterConfig) throws ServletException {
Filter filter = null;
try {
LOGGER.info("Loading inner filter: "+ filterConfig.getInitParameter(FILTER_PARAM_INNER_FILTER_CLASS));
filter = (Filter) Class.forName(filterConfig.getInitParameter(FILTER_PARAM_INNER_FILTER_CLASS)).newInstance();
} catch (InstantiationException | RuntimeException | ClassNotFoundException | IllegalAccessException e) {
LOGGER.error("exception while creating inner filter", e);
throw new RuntimeException(e);
}
filter.init(filterConfig);
return filter;
}
private FilterWrapperCondition createAndInitFilterWrapperCondition(FilterConfig filterConfig) {
FilterWrapperCondition wrapperCondition = null;
try {
LOGGER.info("Loading filter condition: "+ filterConfig.getInitParameter(FILTER_PARAM_WRAPPER_CONDITION_CLASS));
wrapperCondition = (FilterWrapperCondition) Class.forName(filterConfig.getInitParameter(FILTER_PARAM_WRAPPER_CONDITION_CLASS)).newInstance();
} catch (InstantiationException | RuntimeException | ClassNotFoundException | IllegalAccessException e) {
LOGGER.error("exception while creating filter condition", e);
throw new RuntimeException(e);
}
wrapperCondition.init(filterConfig);
return wrapperCondition;
}
@Override
public void destroy() {
LOGGER.info("Destroying wrapper filter");
LOGGER.info("Destroying inner filter");
innerFilter.destroy();
LOGGER.info("Destroyed !");
}
@Override
public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException {
if (filterWrapperCondition.allowInnerFilterCall(req, res)) {
innerFilter.doFilter(req, res, chain);
} else {
chain.doFilter(req, res);
}
}
}
ExclusionFilterWrapperCondition
package es.pruebas.jee6.filter.wrapper;
import javax.servlet.FilterConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
/**
* Example basic implementation.
*
* @author SISIFO
*
*/
public class ExclusionFilterWrapperCondition implements FilterWrapperCondition {
private static final String PARAM_EXCLUSION_PREFIX = "wrapper.exclusionFilterWrapperCondition.param";
private String[] exclusionsRules;
@Override
public void init(FilterConfig filterConfig) {
exclusionsRules = filterConfig.getInitParameter(PARAM_EXCLUSION_PREFIX).split(",");
for (int i=0; i<exclusionsRules.length; i++) {
exclusionsRules[i] = filterConfig.getServletContext().getContextPath() + exclusionsRules[i].trim();
}
}
@Override
public boolean allowInnerFilterCall(ServletRequest req, ServletResponse res) {
HttpServletRequest httpReq = (HttpServletRequest) req;
for (String pattern : exclusionsRules) {
if (httpReq.getRequestURI().startsWith(pattern)) {
return false;
}
}
return true;
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>wrapperFilter</display-name>
<filter>
<display-name>wrapperFilter</display-name>
<filter-name>wrapperFilter</filter-name>
<filter-class>es.pruebas.jee6.filter.wrapper.WrapperFilter</filter-class>
<init-param>
<param-name>wrapper.param.filterClass</param-name>
<param-value>es.pruebas.jee6.filter.SayHelloFilter</param-value>
</init-param>
<init-param>
<param-name>wrapper.param.wrapperConditionClass</param-name>
<param-value>es.pruebas.jee6.filter.wrapper.ExclusionFilterWrapperCondition</param-value>
</init-param>
<init-param>
<param-name>wrapper.exclusionFilterWrapperCondition.param</param-name>
<param-value>
/dontCallFilter/,
/neitherInThisURL/
</param-value>
</init-param>
<!-- Any other params for the inner filter -->
<!-- .... -->
</filter>
<filter-mapping>
<filter-name>wrapperFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<display-name>SayWorldFilter</display-name>
<filter-name>SayWorldFilter</filter-name>
<filter-class>es.pruebas.jee6.filter.SayWorldFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SayWorldFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>