1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 * <filter>
50 * <filter-name>SymmetricFilter</filter-name>
51 * <filter-class>
52 * org.jumpmind.symmetric.web.SymmetricFilter
53 * </filter-class>
54 * </filter>
55 *
56 * <filter-mapping>
57 * <filter-name>SymmetricFilter</filter-name>
58 * <url-pattern>*</url-pattern>
59 * </filter-mapping>
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
88
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 }