View Javadoc

1   /*
2    * SymmetricDS is an open source database synchronization solution.
3    *   
4    * Copyright (C) Keith Naas <knaas@users.sourceforge.net>
5    *               
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.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 }