KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > j2biz > blogunity > web > filter > AccessLogFilter


1 /*
2  * $Id: AccessLogFilter.java,v 1.7 2005/01/17 21:36:06 michelson Exp $
3  *
4  * Copyright (c) 2004 j2biz Group, http://www.j2biz.com
5  * Koeln / Duesseldorf , Germany
6  *
7  * @author Max Kalina
8
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  *
24  *
25  * Portions of code in this class are copyrighted
26  * by Apache Software Foundation and licensed under Apache License, Version 2.0 (the "License").
27  *
28  * You may obtain a copy of the License at
29  *
30  * http://www.apache.org/licenses/LICENSE-2.0
31  *
32  *
33  */

34
35 package com.j2biz.blogunity.web.filter;
36
37 import java.io.File JavaDoc;
38 import java.io.FileWriter JavaDoc;
39 import java.io.IOException JavaDoc;
40 import java.io.PrintWriter JavaDoc;
41 import java.text.SimpleDateFormat JavaDoc;
42 import java.util.Date JavaDoc;
43 import java.util.TimeZone JavaDoc;
44
45 import javax.servlet.Filter JavaDoc;
46 import javax.servlet.FilterChain JavaDoc;
47 import javax.servlet.FilterConfig JavaDoc;
48 import javax.servlet.ServletException JavaDoc;
49 import javax.servlet.ServletRequest JavaDoc;
50 import javax.servlet.ServletResponse JavaDoc;
51 import javax.servlet.http.HttpServletRequest JavaDoc;
52 import javax.servlet.http.HttpServletResponse JavaDoc;
53 import javax.servlet.http.HttpSession JavaDoc;
54
55 import org.apache.commons.lang.StringUtils;
56 import org.apache.commons.logging.Log;
57 import org.apache.commons.logging.LogFactory;
58
59 import com.j2biz.blogunity.BlogunityManager;
60 import com.j2biz.blogunity.IConstants;
61 import com.j2biz.blogunity.dao.BlogDAO;
62 import com.j2biz.blogunity.dao.RefererDAO;
63 import com.j2biz.blogunity.dao.VisitedPageDAO;
64 import com.j2biz.blogunity.exception.BlogunityException;
65 import com.j2biz.blogunity.pojo.Blog;
66 import com.j2biz.blogunity.pojo.Referer;
67 import com.j2biz.blogunity.pojo.User;
68 import com.j2biz.blogunity.pojo.VisitedPage;
69
70 /**
71  * This filter logs requestes to blog(s) in combined log format.
72  */

73 public class AccessLogFilter implements Filter JavaDoc {
74     /**
75      * Logger for this class
76      */

77     private static final Log log = LogFactory.getLog(AccessLogFilter.class);
78
79     /**
80      * The set of month abbreviations for log messages.
81      */

82     protected static final String JavaDoc months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
83             "Aug", "Sep", "Oct", "Nov", "Dec"};
84
85     private Date JavaDoc currentDate;
86
87     private String JavaDoc timeZone;
88
89     private SimpleDateFormat JavaDoc timeFormatter;
90
91     private SimpleDateFormat JavaDoc monthFormatter;
92
93     private SimpleDateFormat JavaDoc yearFormatter;
94
95     private SimpleDateFormat JavaDoc dayFormatter;
96
97     private PrintWriter JavaDoc writer = null;
98
99     private SimpleDateFormat JavaDoc dateFormatter;
100
101     private String JavaDoc dateStamp;
102
103     private String JavaDoc space = " ";
104
105     private boolean rotatable = true;
106
107     private String JavaDoc prefix = "access_";
108
109     private String JavaDoc suffix = ".log";
110
111     private long rotationLastChecked = 0L;
112
113     /*
114      * (non-Javadoc)
115      *
116      * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
117      */

118     public void init(FilterConfig JavaDoc arg0) throws ServletException JavaDoc {
119         currentDate = new Date JavaDoc();
120
121         TimeZone JavaDoc tz = TimeZone.getDefault();
122         timeZone = calculateTimeZoneOffset(tz.getRawOffset());
123
124         dateFormatter = new SimpleDateFormat JavaDoc("yyyy-MM-dd");
125         dateFormatter.setTimeZone(tz);
126
127         dateStamp = dateFormatter.format(currentDate);
128
129         dayFormatter = new SimpleDateFormat JavaDoc("dd");
130         dayFormatter.setTimeZone(tz);
131         monthFormatter = new SimpleDateFormat JavaDoc("MM");
132         monthFormatter.setTimeZone(tz);
133         yearFormatter = new SimpleDateFormat JavaDoc("yyyy");
134         yearFormatter.setTimeZone(tz);
135
136         timeFormatter = new SimpleDateFormat JavaDoc("HH:mm:ss");
137         timeFormatter.setTimeZone(tz);
138
139         currentDate = new Date JavaDoc();
140
141     }
142
143     /*
144      * (non-Javadoc)
145      *
146      * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
147      * javax.servlet.ServletResponse, javax.servlet.FilterChain)
148      */

149     public void doFilter(ServletRequest JavaDoc req, ServletResponse JavaDoc res, FilterChain JavaDoc chain)
150             throws IOException JavaDoc, ServletException JavaDoc {
151
152         HttpServletRequest JavaDoc request = (HttpServletRequest JavaDoc) req;
153         HttpServletResponse JavaDoc response = (HttpServletResponse JavaDoc) res;
154
155         // first resolve the name of the requested blog
156
String JavaDoc requestUri = request.getRequestURI();
157         requestUri = requestUri.substring(request.getContextPath().length() + 6, requestUri
158                 .length());
159         if (requestUri.length() == 0) {
160             requestUri = "/";
161         }
162         int indx = requestUri.indexOf("/", 1);
163         if (indx == -1) {
164             indx = requestUri.length();
165         }
166
167         // get blogname here
168
String JavaDoc blogName = requestUri.substring(1, indx);
169
170         if (StringUtils.isEmpty(blogName)) {
171             chain.doFilter(req, res);
172             return;
173         }
174
175         // check, if this blog already exists!
176
File JavaDoc blogDataDir = new File JavaDoc(BlogunityManager.getSystemConfiguration().getBlogsDirectory(),
177                 blogName);
178         if (!blogDataDir.exists()) {
179             // requested blog not exists -> return
180
chain.doFilter(req, res);
181             return;
182         }
183
184         try {
185             logToDatabase(request, response, blogName);
186         } catch (BlogunityException e) {
187             log.error("Unable to log access to database for blog '" + blogName + "'!");
188         }
189
190         chain.doFilter(req, res);
191
192         if (BlogunityManager.getSystemConfiguration().isAccessLoggingEnabled()) {
193             logToFile(request, response, blogName);
194         }
195
196     }
197
198     /**
199      * @param request
200      * @param response
201      * @param chain
202      * @param blogName
203      * @throws BlogunityException
204      */

205     private void logToDatabase(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
206             String JavaDoc blogName) throws BlogunityException {
207
208         BlogDAO dao = new BlogDAO();
209         Blog blog = dao.getBlogByUrlName(blogName);
210
211         String JavaDoc page = request.getRequestURL().toString();
212
213         String JavaDoc referer = request.getHeader("referer");
214         if (StringUtils.isEmpty(referer)) referer = null;
215         else {
216             //TODO test this code!!!!
217
// don't log referers from itself!
218
if (page.startsWith(BlogunityManager.getBase())) {
219                 String JavaDoc temp = StringUtils.substringAfter(page, BlogunityManager.getBase());
220                 if (temp.startsWith("/my") || temp.startsWith("/exec")
221                         || temp.startsWith("/blogs/" + blogName)) {
222                     referer = null;
223                 }
224             }
225
226         }
227
228         String JavaDoc host = null;
229
230         if (isResolveHosts()) host = request.getRemoteHost();
231         else
232             host = request.getRemoteAddr();
233
234         Date JavaDoc d = new Date JavaDoc();
235
236         if (request.getQueryString() != null) {
237             page += "?" + request.getQueryString();
238         }
239
240         Referer refObj = new Referer(blog, referer, host, d);
241         VisitedPage pageObj = new VisitedPage(blog, page, host, d);
242
243         (new RefererDAO()).createReferer(refObj);
244         (new VisitedPageDAO()).createVisitedPage(pageObj);
245
246     }
247
248     /**
249      * @param request
250      * @param response
251      * @throws ServletException
252      * @throws IOException
253      */

254     private void logToFile(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, String JavaDoc blogName)
255             throws IOException JavaDoc, ServletException JavaDoc {
256
257         // check, if this blog already exists!
258
File JavaDoc blogDataDir = new File JavaDoc(BlogunityManager.getSystemConfiguration().getBlogsDirectory(),
259                 blogName);
260
261         if (!blogDataDir.exists()) { return; }
262
263         File JavaDoc logsDir = new File JavaDoc(blogDataDir, "logs");
264         // if "logs"-directory not yet exists, create new one
265
if (!logsDir.exists()) {
266             try {
267                 boolean result = logsDir.mkdir();
268                 if (!result) {
269                     log.error("Unable to create 'logs'-directory for blog '" + blogName + "'!");
270                     return;
271                 }
272             } catch (Throwable JavaDoc t) {
273                 log.error("Unable to create 'logs'-directory for blog '" + blogName + "'!", t);
274                 return;
275             }
276         }
277
278         open(logsDir);
279         log(getLogMessage(request, response), logsDir);
280         close();
281
282     }
283
284     private String JavaDoc calculateTimeZoneOffset(long offset) {
285         StringBuffer JavaDoc tz = new StringBuffer JavaDoc();
286         if ((offset < 0)) {
287             tz.append("-");
288             offset = -offset;
289         } else {
290             tz.append("+");
291         }
292
293         long hourOffset = offset / (1000 * 60 * 60);
294         long minuteOffset = (offset / (1000 * 60)) % 60;
295
296         if (hourOffset < 10) tz.append("0");
297         tz.append(hourOffset);
298
299         if (minuteOffset < 10) tz.append("0");
300         tz.append(minuteOffset);
301
302         return tz.toString();
303     }
304
305     private boolean isResolveHosts() {
306         return true;
307     }
308
309     /**
310      * Return the month abbreviation for the specified month, which must be a
311      * two-digit String.
312      *
313      * @param month
314      * Month number ("01" .. "12").
315      */

316     private String JavaDoc lookup(String JavaDoc month) {
317
318         int index;
319         try {
320             index = Integer.parseInt(month) - 1;
321         } catch (Throwable JavaDoc t) {
322             index = 0; // Can not happen, in theory
323
}
324         return (months[index]);
325
326     }
327
328     private String JavaDoc getLogMessage(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) {
329
330         Date JavaDoc date = getDate();
331         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
332
333         String JavaDoc value = null;
334
335         if (isResolveHosts()) result.append(request.getRemoteHost());
336         else
337             result.append(request.getRemoteAddr());
338
339         result.append(" - ");
340
341         value = null;
342
343         //try ti get username from HttpSession
344
HttpSession JavaDoc s = request.getSession(false);
345         if (s != null) {
346             User u = (User) s.getAttribute(IConstants.Session.USER);
347             if (u != null) value = u.getNickname();
348         }
349
350         if (value == null) value = "guest";
351
352         result.append(value);
353         result.append(space);
354
355         result.append("[");
356         result.append(dayFormatter.format(date)); // Day
357
result.append('/');
358         result.append(lookup(monthFormatter.format(date))); // Month
359
result.append('/');
360         result.append(yearFormatter.format(date)); // Year
361
result.append(':');
362         result.append(timeFormatter.format(date)); // Time
363
result.append(space);
364         result.append(timeZone); // Time Zone
365
result.append("] \"");
366
367         result.append(request.getMethod());
368         result.append(space);
369         result.append(request.getRequestURI());
370         if (request.getQueryString() != null) {
371             result.append('?');
372             result.append(request.getQueryString());
373         }
374         result.append(space);
375         result.append(request.getProtocol());
376         result.append("\" ");
377
378         //FIXME we return here always status OK, that is wrong
379
result.append(HttpServletResponse.SC_OK);
380
381         result.append(space);
382
383         // i'm not sure, this is the right value for "bytes sent"-field
384
int length = response.getBufferSize();
385
386         if (length <= 0) value = "-";
387         else
388             value = "" + length;
389         result.append(value);
390
391         result.append(space);
392         result.append("\"");
393         String JavaDoc referer = request.getHeader("referer");
394         if (referer != null) result.append(referer);
395         else
396             result.append("-");
397         result.append("\"");
398
399         result.append(space);
400         result.append("\"");
401         String JavaDoc ua = request.getHeader("user-agent");
402         if (ua != null) result.append(ua);
403         else
404             result.append("-");
405         result.append("\"");
406
407         return result.toString();
408
409     }
410
411     /**
412      * This method returns a Date object that is accurate to within one second.
413      * If a thread calls this method to get a Date and it's been less than 1
414      * second since a new Date was created, this method simply gives out the
415      * same Date again so that the system doesn't spend time creating Date
416      * objects unnecessarily.
417      *
418      * @return Date
419      */

420     private Date JavaDoc getDate() {
421         if (currentDate == null) {
422             currentDate = new Date JavaDoc();
423         } else {
424             // Only create a new Date once per second, max.
425
long systime = System.currentTimeMillis();
426             if ((systime - currentDate.getTime()) > 1000) {
427                 currentDate = new Date JavaDoc(systime);
428             }
429         }
430
431         return currentDate;
432     }
433
434     /*
435      * (non-Javadoc)
436      *
437      * @see javax.servlet.Filter#destroy()
438      */

439
440     public void destroy() {
441     }
442
443     /**
444      * Close the currently open log file (if any)
445      */

446     private synchronized void close() {
447
448         if (writer == null) return;
449         writer.flush();
450         writer.close();
451         writer = null;
452
453     }
454
455     /**
456      * Log the specified message to the log file, switching files if the date
457      * has changed since the previous log call.
458      *
459      * @param message
460      * Message to be logged
461      */

462     public void log(String JavaDoc message, File JavaDoc dir) {
463
464         if (rotatable) {
465             // Only do a logfile switch check once a second, max.
466
long systime = System.currentTimeMillis();
467             if ((systime - rotationLastChecked) > 1000) {
468
469                 // We need a new currentDate
470
currentDate = new Date JavaDoc(systime);
471                 rotationLastChecked = systime;
472
473                 // Check for a change of date
474
String JavaDoc tsDate = dateFormatter.format(currentDate);
475
476                 // If the date has changed, switch log files
477
if (!dateStamp.equals(tsDate)) {
478                     synchronized (this) {
479                         if (!dateStamp.equals(tsDate)) {
480                             close();
481                             dateStamp = tsDate;
482                             open(dir);
483                         }
484                     }
485                 }
486             }
487         }
488
489         // Log this message
490
if (writer != null) {
491             writer.println(message);
492         }
493
494     }
495
496     /**
497      * Open the new log file for the date specified by <code>dateStamp</code>.
498      */

499     private synchronized void open(File JavaDoc dir) {
500
501         // Open the current log file
502
try {
503             String JavaDoc pathname;
504             // If no rotate - no need for dateStamp in fileName
505
if (rotatable) {
506                 pathname = dir.getAbsolutePath() + File.separator + prefix + dateStamp + suffix;
507             } else {
508                 pathname = dir.getAbsolutePath() + File.separator + prefix + suffix;
509             }
510             writer = new PrintWriter JavaDoc(new FileWriter JavaDoc(pathname, true), true);
511         } catch (IOException JavaDoc e) {
512             writer = null;
513         }
514
515     }
516 }
Popular Tags