KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > quartz > jobs > LogCleanerJob


1 package org.quartz.jobs;
2
3 import java.io.File JavaDoc;
4 import java.io.FileFilter JavaDoc;
5 import java.text.ParseException JavaDoc;
6 import java.text.SimpleDateFormat JavaDoc;
7 import java.util.ArrayList JavaDoc;
8 import java.util.Calendar JavaDoc;
9 import java.util.Date JavaDoc;
10 import java.util.GregorianCalendar JavaDoc;
11 import java.util.Iterator JavaDoc;
12 import java.util.List JavaDoc;
13 import java.util.regex.Matcher JavaDoc;
14 import java.util.regex.Pattern JavaDoc;
15
16 import org.apache.commons.logging.Log;
17 import org.apache.commons.logging.LogFactory;
18 import org.quartz.Job;
19 import org.quartz.JobDataMap;
20 import org.quartz.JobExecutionContext;
21 import org.quartz.JobExecutionException;
22
23 /**
24  * This class implements a
25  * <a HREF="http://www.opensymphony.com/quartz/">Quartz</a>
26  * {@link Job} such that files older than a specified number
27  * of days get deleted.
28  * <p/>
29  * The file's date gets inferred from the filename.
30  * <p/>
31  * More details are to be found in the documentation of the
32  * {@link #execute(org.quartz.JobExecutionContext)} method.
33  *
34  * @author <a HREF="mailto:mirko.caserta@nexse.com">Mirko Caserta</a>
35  * @see #execute(org.quartz.JobExecutionContext)
36  */

37 public class LogCleanerJob implements Job {
38     private static final Log logWriter = LogFactory.getLog(LogCleanerJob.class);
39
40     public static final String JavaDoc DATAMAP_KEY_LOG_DIR = "log-dir";
41     public static final String JavaDoc DATAMAP_KEY_DELETE_IF_AGE_GREATER_THAN_DAYS = "delete-if-age-greater-than-days";
42     public static final String JavaDoc DATAMAP_KEY_DATE_IN_FILENAME_REGEX = "date-in-filename-regex";
43     public static final String JavaDoc DATAMAP_KEY_FILENAME_SIMPLE_DATE_FORMAT_PATTERN = "filename-simple-date-format-pattern";
44     public static final String JavaDoc DATAMAP_KEY_DELETE_EMPTY_DIRS = "delete-empty-dirs";
45
46     /**
47      * When invoked, this method deletes files found inside a given
48      * directory (and, recursively, into the the directory's subdirectories)
49      * based on criteria specified in the following parameters which
50      * have to be passed through the {@link JobDataMap} instance:
51      * <p/>
52      * <dl>
53      * <dt>{@link #DATAMAP_KEY_LOG_DIR}, type: String</dt>
54      * <dd>the absolute path to the log base directory</dd>
55      * <dt>{@link #DATAMAP_KEY_DELETE_IF_AGE_GREATER_THAN_DAYS}, type: int in a String</dt>
56      * <dd>if a file's age is older than the specified number of days, the
57      * file gets deleted</dd>
58      * <dt>{@link #DATAMAP_KEY_DATE_IN_FILENAME_REGEX}, type: String</dt>
59      * <dd>the regular expression to be used to infer the date from a filename;
60      * the date has to be matched such that <code>matcher.group(1)</code> returns
61      * the date as a {@link String}; see also: {@link Matcher#group(int)}</dd>
62      * <dt>{@link #DATAMAP_KEY_FILENAME_SIMPLE_DATE_FORMAT_PATTERN}, type: String</dt>
63      * <dd>the pattern to be used in {@link SimpleDateFormat#SimpleDateFormat(String)} to parse
64      * the date contained in the matching portion of a filename</dd>
65      * <dt>{@link #DATAMAP_KEY_DELETE_EMPTY_DIRS}, type: boolean in a String</dt>
66      * <dd>if set to <code>true</code>, after having deleted the matching files, a scan is made
67      * for empty directories and found ones will be deleted; please note that the log
68      * base dir itself won't get deleted even if it is found to be empty, this is
69      * intentional: you do not want to prune the log directory itself unless you want
70      * the application server and a bunch of Project Managers to get angry at you</dt>
71      * </dl>
72      * <p/>
73      * <h2>Practical example</h2>
74      * <p/>
75      * Suppose you have a log directory with an absolute path of:
76      * <code>/home/bea/user_projects/domains/mydomain/logs</code>
77      * <p/>
78      * The log files are named so that they end with the date
79      * the last time the log file was accessed. An example file
80      * name could be: <code>myserver.log.2005-12-02</code>
81      * <p/>
82      * The Grim Reaper should delete files older than 60 days.
83      * <p/>
84      * The following parameters should be used:
85      * <p/>
86      * <dl>
87      * <dt>log-dir</dt>
88      * <dd>/home/bea/user_projects/domains/myDomain/logs</dd>
89      * <dt>delete-if-age-greater-than-days</dt>
90      * <dd>60</dd>
91      * <dt>date-in-filename-regex</dt>
92      * <dd>^.+\.log\.(\d{4}-\d{2}-\d{2})$</dd>
93      * <dt>filename-simple-date-format-pattern</dt>
94      * <dd>yyyy-MM-dd</dd>
95      * <dt>delete-empty-dirs</dt>
96      * <dd>false</dd>
97      * </dl>
98      *
99      * @param context the Quartz context
100      * @throws JobExecutionException
101      */

102     public void execute(JobExecutionContext context) throws JobExecutionException {
103         final JobDataMap jobDataMap = context.getMergedJobDataMap();
104
105         if (jobDataMap == null || jobDataMap.isEmpty()) {
106             throw new JobExecutionException("the job data map is null or empty");
107         }
108
109         final String JavaDoc logDir = jobDataMap.getString(DATAMAP_KEY_LOG_DIR);
110
111         if (logDir == null || logDir.trim().length() == 0) {
112             throw new JobExecutionException(DATAMAP_KEY_LOG_DIR + " is null or empty");
113         }
114
115         final File JavaDoc logDirFile = new File JavaDoc(logDir);
116
117         if (!logDirFile.isDirectory()) {
118             throw new JobExecutionException(DATAMAP_KEY_LOG_DIR + " is not a directory");
119         }
120
121         final int deleteIfAgeGreaterThanDays = jobDataMap.getIntFromString(DATAMAP_KEY_DELETE_IF_AGE_GREATER_THAN_DAYS);
122
123         final GregorianCalendar JavaDoc gc = new GregorianCalendar JavaDoc();
124         gc.add(Calendar.DAY_OF_MONTH, - deleteIfAgeGreaterThanDays);
125         final Date JavaDoc deleteIfBeforeThisDate = gc.getTime();
126
127         final String JavaDoc dateInFileNameRegex = jobDataMap.getString(DATAMAP_KEY_DATE_IN_FILENAME_REGEX);
128
129         if (dateInFileNameRegex == null || dateInFileNameRegex.trim().length() == 0) {
130             throw new JobExecutionException(DATAMAP_KEY_DATE_IN_FILENAME_REGEX + " is null or empty");
131         }
132
133         final String JavaDoc dateFormatterPattern = jobDataMap.getString(DATAMAP_KEY_FILENAME_SIMPLE_DATE_FORMAT_PATTERN);
134
135         if (dateFormatterPattern == null || dateFormatterPattern.trim().length() == 0) {
136             throw new JobExecutionException(DATAMAP_KEY_FILENAME_SIMPLE_DATE_FORMAT_PATTERN + " is null or empty");
137         }
138
139         deleteSelectedFiles(logDirFile, deleteIfBeforeThisDate, dateInFileNameRegex, dateFormatterPattern);
140
141         if (jobDataMap.getBooleanValueFromString(DATAMAP_KEY_DELETE_EMPTY_DIRS)) {
142             deleteEmptyDirsRecursively(logDirFile);
143         }
144     }
145
146     private static void deleteSelectedFiles(File JavaDoc baseDir, Date JavaDoc deleteIfBeforeThisDate, String JavaDoc dateInFileNameRegex, String JavaDoc dateFormatterPattern) throws JobExecutionException {
147         logWriter.debug("deleteSelectedFiles: baseDir=" + baseDir + ", deleteIfBeforeThisDate=" + deleteIfBeforeThisDate + ", dateInFileNameRegex=" + dateInFileNameRegex + ", dateFormatterPattern=" + dateFormatterPattern);
148         final List JavaDoc fileList = getFileListRecursively(baseDir);
149         final Iterator JavaDoc fileListIterator = fileList.iterator();
150         final Pattern JavaDoc p = Pattern.compile(dateInFileNameRegex);
151         final SimpleDateFormat JavaDoc format = new SimpleDateFormat JavaDoc(dateFormatterPattern);
152         long successfullyDeletedFileCount = 0L;
153         long failedToDeleteFileCount = 0L;
154         long notToBeDeletedFileCount = 0L;
155
156         try {
157             while (fileListIterator.hasNext()) {
158                 final File JavaDoc f = (File JavaDoc) fileListIterator.next();
159                 final String JavaDoc fileName = f.getName();
160                 final Matcher JavaDoc m = p.matcher(fileName);
161
162                 if (m.matches() && m.groupCount() == 1) {
163                     logWriter.debug("fileName matches: fileName=" + fileName);
164                     final String JavaDoc dateString = m.group(1);
165                     logWriter.debug("inferred date from fileName: dateString=" + dateString);
166                     final Date JavaDoc parsedDate = format.parse(dateString);
167                     logWriter.debug("inferred date as parsed by SimpleDateFormat: parsedDate=" + parsedDate);
168
169                     if (parsedDate.before(deleteIfBeforeThisDate)) {
170                         logWriter.debug("file's date is before specified trigger date, file will be deleted: file=" + f + ", deleteIfBeforeThisDate=" + deleteIfBeforeThisDate);
171                         if (f.delete()) {
172                             successfullyDeletedFileCount++;
173                             logWriter.info("successfully deleted file because it was older than specified date: file=" + f + ", deleteIfBeforeThisDate=" + deleteIfBeforeThisDate);
174                         } else {
175                             failedToDeleteFileCount++;
176                             logWriter.warn("unable to delete file: file=" + f.toString());
177                         }
178                     } else {
179                         notToBeDeletedFileCount++;
180                         logWriter.debug("file's date is after specified trigger date, file will NOT be deleted: file=" + f + ", deleteIfBeforeThisDate=" + deleteIfBeforeThisDate);
181                     }
182                 }
183             }
184         } catch (ParseException JavaDoc ex) {
185             throw new JobExecutionException("error parsing file date", ex, false);
186         }
187         logWriter.debug("deleteSelectedFiles: successfullyDeletedFileCount=" + successfullyDeletedFileCount + ", failedToDeleteFileCount=" + failedToDeleteFileCount + ", notToBeDeletedFileCount=" + notToBeDeletedFileCount);
188     }
189
190     private static List JavaDoc getFileListRecursively(File JavaDoc baseDir) {
191         final List JavaDoc fileList = new ArrayList JavaDoc();
192         getFileListRecursively(baseDir, fileList);
193         return fileList;
194     }
195
196     private static void getFileListRecursively(File JavaDoc baseDir, List JavaDoc fileList) {
197         if (!baseDir.isDirectory()) {
198             return;
199         }
200
201         final File JavaDoc[] fileArray = baseDir.listFiles();
202
203         if (fileArray == null || fileArray.length == 0) {
204             return;
205         }
206
207         for (int i = 0; i < fileArray.length; i++) {
208             if (fileArray[i].isDirectory()) {
209                 getFileListRecursively(fileArray[i], fileList); // recurse
210
} else if (fileArray[i].isFile()) {
211                 fileList.add(fileArray[i]);
212             }
213         }
214     }
215
216     private static void deleteEmptyDirsRecursively(File JavaDoc baseDir) {
217         logWriter.debug("deleteEmptyDirsRecursively: baseDir=" + baseDir);
218
219         final List JavaDoc dirList = new ArrayList JavaDoc();
220         getDirListRecursively(baseDir, dirList);
221         final Iterator JavaDoc i = dirList.iterator();
222         long successfullyDeletedDirCount = 0L;
223         long failedToDeleteDirCount = 0L;
224         long notToBeDeletedDirCount = 0L;
225
226         while (i.hasNext()) {
227             final File JavaDoc dir = (File JavaDoc) i.next();
228             if (isEmptyDir(dir)) {
229                 if (dir.delete()) {
230                     successfullyDeletedDirCount++;
231                     logWriter.info("successfully deleted empty dir: dir=" + dir);
232                 } else {
233                     failedToDeleteDirCount++;
234                     logWriter.warn("unable to delete empty dir: dir=" + dir);
235                 }
236             } else {
237                 notToBeDeletedDirCount++;
238                 logWriter.debug("the directory is not empty and will not be deleted: dir=" + dir);
239             }
240         }
241         logWriter.debug("deleteEmptyDirsRecursively: successfullyDeletedDirCount=" + successfullyDeletedDirCount + ", failedToDeleteDirCount=" + failedToDeleteDirCount + ", notToBeDeletedDirCount=" + notToBeDeletedDirCount);
242     }
243
244     private static void getDirListRecursively(File JavaDoc baseDir, List JavaDoc dirList) {
245         if (!baseDir.isDirectory()) {
246             return;
247         }
248
249         final File JavaDoc[] dirArray = baseDir.listFiles(new FileFilter JavaDoc() {
250             public boolean accept(File JavaDoc pathname) {
251                 return pathname.isDirectory();
252             }
253         });
254
255         if (dirArray == null || dirArray.length == 0) {
256             return;
257         }
258
259         for (int i = 0; i < dirArray.length; i++) {
260             dirList.add(dirArray[i]);
261             getDirListRecursively(dirArray[i], dirList); // recurse
262
}
263     }
264
265     private static boolean isEmptyDir(File JavaDoc dir) {
266         if (!dir.isDirectory()) {
267             return false;
268         }
269         final File JavaDoc[] fileArray = dir.listFiles();
270         return fileArray != null && fileArray.length == 0;
271     }
272
273 }
274
Popular Tags