1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package net.sf.ehcache.constructs.web.filter;
18
19 import java.io.IOException;
20
21 import org.apache.commons.logging.LogFactory;
22 import org.apache.commons.logging.Log;
23
24 import javax.servlet.FilterChain;
25 import javax.servlet.FilterConfig;
26 import javax.servlet.ServletException;
27 import javax.servlet.ServletRequest;
28 import javax.servlet.ServletResponse;
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31 import java.lang.reflect.Method;
32 import java.util.Enumeration;
33 import java.util.HashMap;
34 import java.util.Map;
35
36
37
38
39
40
41
42
43
44 public abstract class Filter implements javax.servlet.Filter {
45
46
47
48 public static final String NO_FILTER = "NO_FILTER";
49 private static final Log LOG = LogFactory.getLog(Filter.class.getName());
50
51
52
53
54 protected FilterConfig filterConfig;
55
56
57
58
59 protected String exceptionsToLogDifferently;
60
61
62
63
64
65 protected String exceptionsToLogDifferentlyLevel;
66
67
68
69
70
71
72
73
74
75 protected boolean suppressStackTraces;
76
77
78
79
80
81
82
83
84
85 public final void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
86 throws ServletException, IOException {
87 final HttpServletRequest httpRequest = (HttpServletRequest) request;
88 final HttpServletResponse httpResponse = (HttpServletResponse) response;
89 try {
90
91 if (filterNotDisabled(httpRequest)) {
92 doFilter(httpRequest, httpResponse, chain);
93 } else {
94 chain.doFilter(request, response);
95 }
96 } catch (final Throwable throwable) {
97 logThrowable(throwable, httpRequest);
98 }
99 }
100
101
102
103
104
105
106
107
108 protected boolean filterNotDisabled(final HttpServletRequest httpRequest) {
109 return httpRequest.getAttribute(NO_FILTER) == null;
110 }
111
112
113
114
115 private void logThrowable(final Throwable throwable, final HttpServletRequest httpRequest)
116 throws ServletException, IOException {
117 StringBuffer messageBuffer = new StringBuffer("Throwable thrown during doFilter on request with URI: ")
118 .append(httpRequest.getRequestURI())
119 .append(" and Query: ")
120 .append(httpRequest.getQueryString());
121 String message = messageBuffer.toString();
122 boolean matchFound = matches(throwable);
123 if (matchFound) {
124 try {
125 if (suppressStackTraces) {
126 Method method = Log.class.getMethod(exceptionsToLogDifferentlyLevel, new Class[]{Object.class});
127 method.invoke(LOG, new Object[]{throwable.getMessage()});
128 } else {
129 Method method = Log.class.getMethod(exceptionsToLogDifferentlyLevel,
130 new Class[]{Object.class, Throwable.class});
131 method.invoke(LOG, new Object[]{throwable.getMessage(), throwable});
132 }
133 } catch (Exception e) {
134 LOG.fatal("Could not invoke Log method for " + exceptionsToLogDifferentlyLevel, e);
135 }
136 if (throwable instanceof IOException) {
137 throw (IOException) throwable;
138 } else {
139 throw new ServletException(message, throwable);
140 }
141 } else {
142
143 if (suppressStackTraces) {
144 LOG.warn(messageBuffer.append(throwable.getMessage()).append("\nTop StackTraceElement: ")
145 .append(throwable.getStackTrace()[0].toString()));
146 } else {
147 LOG.warn(messageBuffer.append(throwable.getMessage()), throwable);
148 }
149 if (throwable instanceof IOException) {
150 throw (IOException) throwable;
151 } else {
152 throw new ServletException(throwable);
153 }
154 }
155 }
156
157
158
159
160
161
162
163
164 private boolean matches(Throwable throwable) {
165 if (exceptionsToLogDifferently == null) {
166 return false;
167 }
168 if (exceptionsToLogDifferently.indexOf(throwable.getClass().getName()) != -1) {
169 return true;
170 }
171 if (throwable instanceof ServletException) {
172 Throwable rootCause = (((ServletException) throwable).getRootCause());
173 if (exceptionsToLogDifferently.indexOf(rootCause.getClass().getName()) != -1) {
174 return true;
175 }
176 }
177 if (throwable.getCause() != null) {
178 Throwable cause = throwable.getCause();
179 if (exceptionsToLogDifferently.indexOf(cause.getClass().getName()) != -1) {
180 return true;
181 }
182 }
183 return false;
184 }
185
186
187
188
189 public final void init(final FilterConfig config) throws ServletException {
190 try {
191
192 this.filterConfig = config;
193 processInitParams(config);
194
195
196 doInit();
197 } catch (final Exception e) {
198 LOG.fatal("Could not initialise servlet filter.", e);
199 throw new ServletException("Could not initialise servlet filter.", e);
200 }
201 }
202
203 private void processInitParams(final FilterConfig config) throws ServletException {
204 String exceptions = config.getInitParameter("exceptionsToLogDifferently");
205 String level = config.getInitParameter("exceptionsToLogDifferentlyLevel");
206 String suppressStackTracesString = config.getInitParameter("suppressStackTraces");
207 suppressStackTraces = Boolean.valueOf(suppressStackTracesString).booleanValue();
208 if (LOG.isDebugEnabled()) {
209 LOG.debug("Suppression of stack traces enabled for " + this.getClass().getName());
210 }
211
212 if (exceptions != null) {
213 validateMandatoryParameters(exceptions, level);
214 validateLevel(level);
215 exceptionsToLogDifferentlyLevel = level;
216 exceptionsToLogDifferently = exceptions;
217 if (LOG.isDebugEnabled()) {
218 LOG.debug("Different logging levels configured for " + this.getClass().getName());
219 }
220 }
221 }
222
223 private void validateMandatoryParameters(String exceptions, String level) throws ServletException {
224 if ((exceptions != null && level == null) || (level != null && exceptions == null)) {
225 throw new ServletException("Invalid init-params. Both exceptionsToLogDifferently"
226 + " and exceptionsToLogDifferentlyLevelvalue should be specified if one is"
227 + " specified.");
228 }
229 }
230
231 private void validateLevel(String level) throws ServletException {
232
233 if (!(level.equals("debug")
234 || level.equals("info")
235 || level.equals("warn")
236 || level.equals("error")
237 || level.equals("fatal"))) {
238 throw new ServletException("Invalid init-params value for \"exceptionsToLogDifferentlyLevel\"."
239 + "Must be one of debug, info, warn, error or fatal.");
240 }
241 }
242
243
244
245
246
247 public final void destroy() {
248 this.filterConfig = null;
249 doDestroy();
250 }
251
252
253
254
255 protected boolean acceptsEncoding(final HttpServletRequest request, final String name) {
256 final boolean accepts = headerContains(request, "Accept-Encoding", name);
257 return accepts;
258 }
259
260
261
262
263 private boolean headerContains(final HttpServletRequest request, final String header, final String value) {
264
265 logRequestHeaders(request);
266
267 final Enumeration accepted = request.getHeaders(header);
268 while (accepted.hasMoreElements()) {
269 final String headerValue = (String) accepted.nextElement();
270 if (headerValue.indexOf(value) != -1) {
271 return true;
272 }
273 }
274 return false;
275 }
276
277
278
279
280
281
282 protected void logRequestHeaders(final HttpServletRequest request) {
283 if (LOG.isDebugEnabled()) {
284 Map headers = new HashMap();
285 Enumeration enumeration = request.getHeaderNames();
286 StringBuffer logLine = new StringBuffer();
287 logLine.append("Request Headers");
288 while (enumeration.hasMoreElements()) {
289 String name = (String) enumeration.nextElement();
290 String headerValue = request.getHeader(name);
291 headers.put(name, headerValue);
292 logLine.append(": ").append(name).append(" -> ").append(headerValue);
293 }
294 LOG.debug(logLine);
295 }
296 }
297
298
299
300
301
302
303 protected abstract void doDestroy();
304
305
306
307
308
309
310 protected abstract void doFilter(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse,
311 final FilterChain chain) throws Throwable;
312
313
314
315
316
317 protected abstract void doInit() throws Exception;
318
319
320
321
322 public FilterConfig getFilterConfig() {
323 return filterConfig;
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348 protected boolean acceptsGzipEncoding(HttpServletRequest request) {
349 return acceptsEncoding(request, "gzip");
350 }
351
352 }
353