View Javadoc

1   /*
2    * SymmetricDS is an open source database synchronization solution.
3    *   
4    * Copyright (C) Chris Henson <chenson42@users.sourceforge.net>,
5    *               Eric Long <erilong@users.sourceforge.net>,
6    *               Keith Naas <knaas@users.sourceforge.net>
7    *
8    * This library is free software; you can redistribute it and/or
9    * modify it under the terms of the GNU Lesser General Public
10   * License as published by the Free Software Foundation; either
11   * version 3 of the License, or (at your option) any later version.
12   *
13   * This library is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   * Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public
19   * License along with this library; if not, see
20   * <http://www.gnu.org/licenses/>.
21   */
22  
23  package org.jumpmind.symmetric.web;
24  
25  import java.io.BufferedReader;
26  import java.io.ByteArrayInputStream;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.io.InputStreamReader;
30  import java.io.OutputStream;
31  import java.net.SocketException;
32  import java.util.zip.GZIPInputStream;
33  
34  import javax.servlet.ServletException;
35  import javax.servlet.http.HttpServlet;
36  import javax.servlet.http.HttpServletRequest;
37  import javax.servlet.http.HttpServletResponse;
38  
39  import org.apache.commons.lang.StringUtils;
40  import org.apache.commons.lang.math.NumberUtils;
41  import org.apache.commons.logging.Log;
42  import org.springframework.context.ApplicationContext;
43  import org.springframework.web.context.support.WebApplicationContextUtils;
44  
45  abstract public class AbstractServlet extends HttpServlet {
46  
47      protected abstract Log getLogger();
48  
49      protected OutputStream createOutputStream(HttpServletResponse resp) throws IOException {
50          return resp.getOutputStream();
51      }
52  
53      protected InputStream createInputStream(HttpServletRequest req) throws IOException {
54          InputStream is = null;
55          String contentType = req.getHeader("Content-Type");
56          boolean useCompression = contentType != null && contentType.equalsIgnoreCase("gzip");
57  
58          if (getLogger().isDebugEnabled()) {
59              StringBuilder b = new StringBuilder();
60              BufferedReader reader = null;
61              if (useCompression) {
62                  getLogger().debug("Received compressed stream");
63                  reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(req.getInputStream())));
64              } else {
65                  reader = req.getReader();
66              }
67  
68              String line = null;
69              do {
70                  line = reader.readLine();
71                  if (line != null) {
72                      b.append(line);
73                      b.append("\n");
74                  }
75              } while (line != null);
76  
77              getLogger().debug("Received: \n" + b);
78              is = new ByteArrayInputStream(b.toString().getBytes());
79          } else {
80              is = req.getInputStream();
81              if (useCompression) {
82                  is = new GZIPInputStream(is);
83              }
84          }
85  
86          return is;
87      }
88  
89      protected ApplicationContext getDefaultApplicationContext() {
90          return WebApplicationContextUtils.getWebApplicationContext(getServletContext());
91      }
92  
93      @Override
94      protected final void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
95          try {
96              handleGet(req, resp);
97          } catch (SocketException e) {
98              if (getLogger().isWarnEnabled()) {
99                  getLogger().warn("Socket issue while processing GET method ", e);
100             }
101         } catch (Exception e) {
102             if (getLogger().isErrorEnabled()) {
103                 getLogger().error("uncaught exception on GET method", e);
104             }
105             if (!resp.isCommitted()) {
106                 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
107             }
108         }
109     }
110 
111     /***
112      * Override me to do real work. Remember that a GET should be idempotent and
113      * safe. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html.
114      * 
115      * @param req
116      * @param resp
117      * @throws IOException
118      * @throws ServletException
119      * @throws Exception
120      *                 everything else that could go wrong!
121      * 
122      */
123     protected void handleGet(HttpServletRequest req, HttpServletResponse resp) throws Exception {
124         sendError(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED);
125     }
126 
127     @Override
128     protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
129         try {
130             handlePost(req, resp);
131         } catch (SocketException e) {
132             if (getLogger().isWarnEnabled()) {
133                 getLogger().warn("Socket issue while processing POST method ", e);
134             }
135         } catch (Exception e) {
136             if (getLogger().isErrorEnabled()) {
137                 getLogger().error("uncaught exception on POST method", e);
138             }
139             sendError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
140         }
141     }
142 
143     /***
144      * Override me to do real work. See
145      * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html.
146      * 
147      * @param req
148      * @param resp
149      * @throws IOException
150      * @throws ServletException
151      * @throws Exception
152      *                 everything else that could go wrong!
153      */
154     protected void handlePost(HttpServletRequest req, HttpServletResponse resp) throws Exception {
155         sendError(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED);
156     }
157 
158     @Override
159     protected final void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
160         try {
161             handlePut(req, resp);
162         } catch (SocketException e) {
163             if (getLogger().isWarnEnabled()) {
164                 getLogger().warn("Socket issue while processing PUT method ", e);
165             }
166         } catch (Exception e) {
167             if (getLogger().isErrorEnabled()) {
168                 getLogger().error("uncaught exception on PUT method", e);
169             }
170             sendError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
171         }
172     }
173 
174     /***
175      * Override me to do real work. Remember that a PUT should be idempotent.
176      * See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html.
177      * 
178      * @param req
179      * @param resp
180      * @throws IOException
181      * @throws ServletException
182      * @throws Exception
183      *                 everything else that could go wrong!
184      */
185     protected void handlePut(HttpServletRequest req, HttpServletResponse resp) throws Exception {
186         sendError(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED);
187     }
188 
189     @Override
190     protected final void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
191             IOException {
192         try {
193             handleDelete(req, resp);
194         } catch (SocketException e) {
195             if (getLogger().isWarnEnabled()) {
196                 getLogger().warn("Socket issue while processing DELETE method ", e);
197             }
198         } catch (Exception e) {
199             if (getLogger().isErrorEnabled()) {
200                 getLogger().error("uncaught exception on DELETE method", e);
201             }
202             sendError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
203         }
204     }
205 
206     /***
207      * Override me to do real work. Remember that a DELETE should be idempotent.
208      * See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html.
209      * 
210      * @param req
211      * @param resp
212      * @throws IOException
213      * @throws ServletException
214      * @throws Exception
215      *                 everything else that could go wrong!
216      */
217     protected void handleDelete(HttpServletRequest req, HttpServletResponse resp) throws Exception {
218         resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
219     }
220 
221     @Override
222     protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
223         try {
224             handleHead(req, resp);
225         } catch (SocketException e) {
226             if (getLogger().isWarnEnabled()) {
227                 getLogger().warn("Socket issue while processing HEAD method ", e);
228             }
229         } catch (Exception e) {
230             if (getLogger().isErrorEnabled()) {
231                 getLogger().error("uncaught exception on HEAD method", e);
232             }
233             sendError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
234         }
235     }
236 
237     /***
238      * Override me to do real work. Remember that a HEAD should be idempotent
239      * and safe. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html.
240      * 
241      * @param req
242      * @param resp
243      * @throws IOException
244      * @throws ServletException
245      * @throws Exception
246      *                 everything else that could go wrong!
247      */
248     protected void handleHead(HttpServletRequest req, HttpServletResponse resp) throws Exception {
249         sendError(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED);
250     }
251 
252     @Override
253     protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
254         try {
255             handleOptions(req, resp);
256         } catch (SocketException e) {
257             if (getLogger().isWarnEnabled()) {
258                 getLogger().warn("Socket issue while processing data ", e);
259             }
260         } catch (Exception e) {
261             if (getLogger().isErrorEnabled()) {
262                 getLogger().error("uncaught exception on OPTIONS method", e);
263             }
264             sendError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
265         }
266     }
267 
268     /***
269      * Override me to do real work. Remember that a OPTIONS should be idempotent
270      * and safe. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html.
271      * 
272      * @param req
273      * @param resp
274      * @throws IOException
275      * @throws ServletException
276      * @throws Exception
277      *                 everything else that could go wrong!
278      */
279     protected void handleOptions(HttpServletRequest req, HttpServletResponse resp) throws Exception {
280         sendError(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED);
281     }
282 
283     @Override
284     protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
285         try {
286             handleTrace(req, resp);
287         } catch (SocketException e) {
288             if (getLogger().isWarnEnabled()) {
289                 getLogger().warn("Socket issue while processing TRACE method ", e);
290             }
291         } catch (Exception e) {
292             if (getLogger().isErrorEnabled()) {
293                 getLogger().error("uncaught exception on TRACE method", e);
294             }
295             sendError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
296         }
297     }
298 
299     /***
300      * Override me to do real work. Remember that a TRACE should be idempotent.
301      * See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html.
302      * 
303      * @param req
304      * @param resp
305      * @throws IOException
306      * @throws ServletException
307      * @throws Exception
308      *                 everything else that could go wrong!
309      */
310     protected void handleTrace(HttpServletRequest req, HttpServletResponse resp) throws Exception {
311         sendError(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED);
312     }
313 
314     /***
315      * Because you can't send an error when the response is already committed,
316      * this helps to avoid unnecessary errors in the logs.
317      * 
318      * @param resp
319      * @param statusCode
320      * @throws IOException
321      */
322     protected boolean sendError(HttpServletResponse resp, int statusCode) throws IOException {
323         return ServletUtils.sendError(resp, statusCode);
324     }
325 
326     /***
327      * Because you can't send an error when the response is already committed,
328      * this helps to avoid unnecessary errors in the logs.
329      * 
330      * @param resp
331      * @param statusCode
332      * @param message
333      *                a message to put in the body of the response
334      * @throws IOException
335      */
336     protected boolean sendError(HttpServletResponse resp, int statusCode, String message) throws IOException {
337         return ServletUtils.sendError(resp, statusCode, message);
338     }
339 
340     /***
341      * Returns the parameter with that name, trimmed to null
342      * 
343      * @param request
344      * @param name
345      * @return
346      */
347     protected String getParameter(HttpServletRequest request, String name) {
348         return StringUtils.trimToNull(request.getParameter(name));
349     }
350 
351     /***
352      * Returns the parameter with that name, trimmed to null. If the trimmed
353      * string is null, defaults to the defaultValue.
354      * 
355      * @param request
356      * @param name
357      * @return
358      */
359     protected String getParameter(HttpServletRequest request, String name, String defaultValue) {
360         return StringUtils.defaultIfEmpty(StringUtils.trimToNull(request.getParameter(name)), defaultValue);
361     }
362 
363     protected long getParameterAsNumber(HttpServletRequest request, String name) {
364         return NumberUtils.toLong(StringUtils.trimToNull(request.getParameter(name)));
365     }
366 
367 }