Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add filters to servlet without modifying web.xml

I'd like the ability to modify/configure filters in a different way than web.xml. Here is a static configuration of 2 filters. I'd like the ability to have one filter statically configured and allow that filter to load additional filters. I just wanted to know if anyone knows of lib that already has this.

Using Servlet API 2.5

<web-app>   ...   <filter>     <filter-name>MyFilter1</filter-name>     <filter-class>com.me.MyFilter1</filter-class>   </filter>   <filter-mapping>     <filter-name>MyFilter1</filter-name>     <url-pattern>/*</url-pattern>   </filter-mapping>   ...   <filter>     <filter-name>MyFilter2</filter-name>     <filter-class>com.me.MyFilter2</filter-class>   </filter>   <filter-mapping>     <filter-name>MyFilter2</filter-name>     <url-pattern>/*</url-pattern>   </filter-mapping>   ... </web-app> 

I've seen this done in Guice with GuiceFilter where the Filters are configured at runtime.

like image 970
TJR Avatar asked Aug 25 '11 15:08

TJR


People also ask

Can we have multiple filters in web xml?

Yes. You can. The order you placed in web. xml will execute.

What is the method used for applying configuring web filters in servlets?

doFilter() method is invoked every time when user request to any resource, to which the filter is mapped.It is used to perform filtering tasks. This is invoked only once when filter is taken out of the service.

What is filter and filter mapping in web xml?

The filter-mapping element maps a URL pattern or servlet name to an instance of a filter. The filter-mapping always contains a filter-name element and a url-pattern element. The filter-name element must match a filter-name defined in a filter element elsewhere in the web. xml file.


Video Answer


2 Answers

Just do the same job as the container already does. I.e. reinvent the wheel of the chain of responsibility design pattern as is under the covers been used by servlet filters.

public class GodFilter implements Filter {      private Map<Pattern, Filter> filters = new LinkedHashMap<Pattern, Filter>();      @Override     public void init(FilterConfig config) throws ServletException {         Filter1 filter1 = new Filter1();         filter1.init(config);         filters.put(new Pattern("/foo/*"), filter1);          Filter2 filter2 = new Filter2();         filter2.init(config);         filters.put(new Pattern("*.bar"), filter2);          // ...     }      @Override     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {         HttpServletRequest hsr = (HttpServletRequest) request;         String path = hsr.getRequestURI().substring(hsr.getContextPath().length());         GodFilterChain godChain = new GodFilterChain(chain);          for (Entry<Pattern, Filter> entry : filters.entrySet()) {             if (entry.getKey().matches(path)) {                 godChain.addFilter(entry.getValue());             }         }          godChain.doFilter(request, response);     }      @Override     public void destroy() {         for (Filter filter : filters.values()) {             filter.destroy();         }     }  } 

with those little helper classes (which can if necessary be made private static nested classes of the above GodFilter):

public class Pattern {      private int position;     private String url;      public Pattern(String url) {         this.position = url.startsWith("*") ? 1                       : url.endsWith("*") ? -1                       : 0;         this.url = url.replaceAll("/?\\*", "");     }      public boolean matches(String path) {         return (position == -1) ? path.startsWith(url)              : (position == 1) ? path.endsWith(url)              : path.equals(url);     }  } 

and

public class GodFilterChain implements FilterChain {      private FilterChain chain;     private List<Filter> filters = new ArrayList<Filter>();     private Iterator<Filter> iterator;      public GodFilterChain(FilterChain chain) {         this.chain = chain;     }      @Override     public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {         if (iterator == null) {             iterator = filters.iterator();         }          if (iterator.hasNext()) {             iterator.next().doFilter(request, response, this);         } else {             chain.doFilter(request, response);         }     }      public void addFilter(Filter filter) {         if (iterator != null) {             throw new IllegalStateException();         }          filters.add(filter);     }  } 

You could if necessary also feed a XML config file with all possible filters so that you end up with easier configuration. You could use reflection to create filters in init() of your GodFilter.

Oh nevermind, that's what the web.xml and the container already is doing...

like image 141
BalusC Avatar answered Oct 03 '22 14:10

BalusC


Servlet 3.0 has the @WebFilter annotation to define a filter. No need to declare it in web.xml anymore.

But loading a filter from a filter is not supported. You could implement it yourself: it's "just" the chain of responsibility pattern, but why would you?

like image 21
JB Nizet Avatar answered Oct 03 '22 14:10

JB Nizet