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.Collections;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.regex.Pattern;
29
30 import javax.servlet.ServletContext;
31 import javax.servlet.ServletRequest;
32 import javax.servlet.ServletResponse;
33 import javax.servlet.http.HttpServletRequest;
34
35 import org.apache.commons.lang.ArrayUtils;
36 import org.apache.commons.lang.StringUtils;
37 import org.jumpmind.symmetric.service.IParameterService;
38 import org.springframework.context.ApplicationContext;
39 import org.springframework.web.context.support.WebApplicationContextUtils;
40
41 /***
42 * All symmetric servlets and filters (other than {@link SymmetricFilter} and
43 * {@link SymmetricServlet}) should extend this class. It it managed by Spring.
44 */
45 public class ServletResourceTemplate implements IServletResource {
46 protected ServletContext servletContext;
47
48 private boolean disabled;
49 protected String[] uriPatterns;
50 private String[] regexPatterns;
51 protected Pattern[] compiledRegexPatterns;
52 protected IParameterService parameterService;
53
54 public void init(ServletContext servletContext) {
55 this.servletContext = servletContext;
56 compileRegexPatterns();
57 }
58
59 public void refresh() {
60 compileRegexPatterns();
61 }
62
63 protected void compileRegexPatterns() {
64 final List<Pattern> compiledRegexPatterns;
65 if (!ArrayUtils.isEmpty(regexPatterns)) {
66 compiledRegexPatterns = new ArrayList<Pattern>(regexPatterns.length);
67 for (String regexPattern : regexPatterns) {
68 compiledRegexPatterns.add(Pattern.compile(regexPattern));
69 }
70 } else {
71 compiledRegexPatterns = Collections.emptyList();
72 }
73 this.compiledRegexPatterns = compiledRegexPatterns.toArray(new Pattern[compiledRegexPatterns.size()]);
74 }
75
76 public void setDisabled(boolean disabled) {
77 this.disabled = disabled;
78 }
79
80 public void setUriPattern(String uriPattern) {
81 this.uriPatterns = new String[] { uriPattern };
82 }
83
84 public void setUriPatterns(String[] uriPatterns) {
85 this.uriPatterns = uriPatterns;
86 }
87
88 public void setRegexPattern(String regexPattern) {
89 this.regexPatterns = new String[] { regexPattern };
90 }
91
92 public void setRegexPatterns(String[] regexPatterns) {
93 this.regexPatterns = regexPatterns;
94 }
95
96 public boolean isDisabled() {
97 return disabled;
98 }
99
100 public String[] getUriPatterns() {
101 return uriPatterns;
102 }
103
104 public String[] getRegexPatterns() {
105 return regexPatterns;
106 }
107
108 protected boolean matchesRegexPatterns(String uri) {
109 boolean retVal = false;
110 for (int i = 0; !retVal && i < compiledRegexPatterns.length; i++) {
111 retVal = matchesRegexPattern(uri, compiledRegexPatterns[i]);
112 }
113 return retVal;
114 }
115
116 protected boolean matchesRegexPattern(String uri, Pattern compiledRegexPattern) {
117 return compiledRegexPattern.matcher(uri).matches();
118 }
119
120 protected boolean matchesUriPatterns(String uri) {
121 boolean retVal = false;
122 for (int i = 0; !retVal && i < uriPatterns.length; i++) {
123 retVal = matchesUriPattern(uri, uriPatterns[i]);
124 }
125 return retVal;
126 }
127
128 protected boolean matchesUriPattern(String uri, String uriPattern) {
129
130 boolean retVal = false;
131 String path = StringUtils.defaultIfEmpty(uri, "/");
132 final String pattern = StringUtils.defaultIfEmpty(uriPattern, "/");
133 if ("/".equals(pattern) || "/*".equals(pattern) || pattern.equals(path)) {
134 retVal = true;
135 } else {
136 final String[] patternParts = StringUtils.split(pattern, "/");
137 final String[] pathParts = StringUtils.split(path, "/");
138 boolean matches = true;
139 for (int i = 0; i < patternParts.length && i < pathParts.length && matches; i++) {
140 final String patternPart = patternParts[i];
141 matches = "*".equals(patternPart) || patternPart.equals(pathParts[i]);
142 }
143 retVal = matches;
144 }
145 return retVal;
146 }
147
148 protected ServletContext getServletContext() {
149 return servletContext;
150 }
151
152 public void destroy() {
153
154 }
155
156 public boolean matches(ServletRequest request) {
157 boolean retVal = true;
158 if (request instanceof HttpServletRequest) {
159 final HttpServletRequest httpRequest = (HttpServletRequest) request;
160 final String uri = normalizeRequestUri(httpRequest);
161 if (!ArrayUtils.isEmpty(uriPatterns)) {
162 retVal = matchesUriPatterns(uri);
163 } else if (!ArrayUtils.isEmpty(compiledRegexPatterns)) {
164 retVal = matchesRegexPatterns(uri);
165 }
166 }
167 return retVal;
168 }
169
170 /***
171 * Returns the part of the path we are interested in when doing pattern
172 * matching. This should work whether or not the servlet or filter is
173 * explicitly mapped inside of the web.xml since it always strips off the
174 * contextPath.
175 *
176 * @param httpRequest
177 * @return
178 */
179 protected String normalizeRequestUri(HttpServletRequest httpRequest) {
180 String retVal = httpRequest.getRequestURI();
181 String contextPath = httpRequest.getContextPath();
182 if (retVal.startsWith(contextPath)) {
183 retVal = retVal.substring(contextPath.length());
184 }
185 return retVal;
186 }
187
188 /***
189 * Because you can't send an error when the response is already committed,
190 * this helps to avoid unnecessary errors in the logs.
191 *
192 * @param resp
193 * @param statusCode
194 * @throws IOException
195 */
196 protected boolean sendError(ServletResponse resp, int statusCode) throws IOException {
197 return ServletUtils.sendError(resp, statusCode);
198 }
199
200 /***
201 * Because you can't send an error when the response is already committed,
202 * this helps to avoid unnecessary errors in the logs.
203 *
204 * @param resp
205 * @param statusCode
206 * @param message
207 * a message to put in the body of the response
208 * @throws IOException
209 */
210 protected boolean sendError(ServletResponse resp, int statusCode, String message) throws IOException {
211 return ServletUtils.sendError(resp, statusCode, message);
212 }
213
214 protected ApplicationContext getDefaultApplicationContext() {
215 return WebApplicationContextUtils.getWebApplicationContext(getServletContext());
216 }
217
218 /***
219 * Returns true if this is a spring managed resource.
220 *
221 * @return
222 */
223 public boolean isSpringManaged() {
224 return getDefaultApplicationContext().getBeansOfType(this.getClass()).values().contains(this);
225 }
226
227 /***
228 * Returns true if this is a container managed resource.
229 *
230 * @return
231 */
232 @SuppressWarnings("unchecked")
233 public IServletResource getSpringBean() {
234 IServletResource retVal = this;
235 if (!isSpringManaged()) {
236 Iterator iterator = getDefaultApplicationContext().getBeansOfType(this.getClass()).values().iterator();
237 if (iterator.hasNext()) {
238 retVal = (IServletResource) iterator.next();
239 }
240 }
241 return retVal;
242 }
243
244 /***
245 * Returns true if this should be container compatible
246 *
247 * @return
248 */
249 public boolean isContainerCompatible() {
250 return false;
251 }
252
253 protected void setServletContext(ServletContext servletContext) {
254 this.servletContext = servletContext;
255 }
256
257 public void setParameterService(IParameterService parameterService) {
258 this.parameterService = parameterService;
259 }
260 }