View Javadoc

1   /*
2    * SymmetricDS is an open source database synchronization solution.
3    *   
4    * Copyright (C) Chris Henson <chenson42@users.sourceforge.net>,
5    *               Keith Naas <knaas@users.sourceforge.net>
6    *
7    * This library is free software; you can redistribute it and/or
8    * modify it under the terms of the GNU Lesser General Public
9    * License as published by the Free Software Foundation; either
10   * version 3 of the License, or (at your option) any later version.
11   *
12   * This library is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this library; if not, see
19   * <http://www.gnu.org/licenses/>.
20   */
21  package org.jumpmind.symmetric.web;
22  
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Map;
27  
28  import javax.servlet.Filter;
29  import javax.servlet.FilterChain;
30  import javax.servlet.FilterConfig;
31  import javax.servlet.ServletContext;
32  import javax.servlet.ServletException;
33  import javax.servlet.ServletRequest;
34  import javax.servlet.ServletResponse;
35  
36  import org.apache.commons.logging.Log;
37  import org.apache.commons.logging.LogFactory;
38  import org.jumpmind.symmetric.ext.IExtensionPoint;
39  import org.springframework.context.ApplicationContext;
40  import org.springframework.web.context.support.WebApplicationContextUtils;
41  
42  /***
43   * This filter allows us simplify the configuration of symmetric by defining
44   * filters directly within spring configuration files.
45   * 
46   * Configured within web.xml
47   * 
48   * <pre>
49   *  &lt;filter&gt;
50   *    &lt;filter-name&gt;SymmetricFilter&lt;/filter-name&gt;
51   *    &lt;filter-class&gt;
52   *      org.jumpmind.symmetric.web.SymmetricFilter
53   *    &lt;/filter-class&gt;
54   *  &lt;/filter&gt;
55   * 
56   *  &lt;filter-mapping&gt;
57   *    &lt;filter-name&gt;SymmetricFilter&lt;/filter-name&gt;
58   *    &lt;url-pattern&gt;*&lt;/url-pattern&gt;
59   *  &lt;/filter-mapping&gt;
60   * </pre>
61   * 
62   * @since 1.4.0
63   * 
64   */
65  public class SymmetricFilter implements Filter {
66  
67      private static final Log logger = LogFactory.getLog(SymmetricFilter.class);
68  
69      private ServletContext servletContext;
70  
71      private List<Filter> filters;
72  
73      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
74              ServletException {
75          new SymmetricFilterChain(chain).doFilter(request, response);
76      }
77  
78      @SuppressWarnings("unchecked")
79      public void init(FilterConfig filterConfig) throws ServletException {
80          servletContext = filterConfig.getServletContext();
81          filters = new ArrayList<Filter>();
82          ApplicationContext ctx = getContext();
83          Map<String, Filter> filterBeans = ctx.getBeansOfType(Filter.class);
84          if (filterBeans.size() == 0) {
85              filterBeans = ctx.getParent().getBeansOfType(Filter.class);
86          }
87          // they will need to be sorted somehow, right now its just the order
88          // they appear in the spring file
89          for (final Map.Entry<String, Filter> filterEntry : filterBeans.entrySet()) {
90              if (logger.isDebugEnabled()) {
91                  logger.debug(String.format("Initializing filter %s", filterEntry.getKey()));
92              }
93              final Filter filter = filterEntry.getValue();
94              if (filter instanceof IExtensionPoint) {
95                  filter.init(filterConfig);
96                  filters.add(filter);
97              } else {
98                  logger
99                          .info("Found a Spring filter that does not implement IExtensionPoint.  NOT adding it as a SymmetricFilter.");
100             }
101         }
102     }
103 
104     public void destroy() {
105         for (final Filter filter : filters) {
106             filter.destroy();
107         }
108 
109     }
110 
111     protected ApplicationContext getContext() {
112         return WebApplicationContextUtils.getWebApplicationContext(getServletContext());
113     }
114 
115     public ServletContext getServletContext() {
116         return servletContext;
117     }
118 
119     /***
120      * The chain will visit each filter in turn. When done, it will pass along
121      * to the original chain. The chain skips disabled filters. I'm wondering if
122      * this should be moved to the {@link SymmetricFilter#init(FilterConfig)}.
123      * 
124      * @author Keith
125      * 
126      */
127     private class SymmetricFilterChain implements FilterChain {
128 
129         private FilterChain chain;
130         private int index;
131 
132         public SymmetricFilterChain(FilterChain chain) {
133             this.chain = chain;
134             index = 0;
135         }
136 
137         public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
138             if (!response.isCommitted()) {
139                 if (index < filters.size()) {
140                     final Filter filter = filters.get(index++);
141                     if (filter instanceof AbstractFilter) {
142                         final AbstractFilter builtinFilter = (AbstractFilter) filter;
143                         if (!builtinFilter.isDisabled() && builtinFilter.matches(request)) {
144                             builtinFilter.doFilter(request, response, this);
145                         } else {
146                             this.doFilter(request, response);
147                         }
148                     } else {
149                         filter.doFilter(request, response, this);
150                     }
151                 } else {
152                     chain.doFilter(request, response);
153                 }
154             }
155         }
156     }
157 
158 }