comparison src/org/eclipse/jetty/util/RolloverFileOutputStream.java @ 802:3428c60d7cfc

replace jetty jars with source
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 21:15:48 -0600
parents
children
comparison
equal deleted inserted replaced
801:6a21393191c1 802:3428c60d7cfc
1 //
2 // ========================================================================
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.util;
20
21 import java.io.File;
22 import java.io.FileOutputStream;
23 import java.io.FilterOutputStream;
24 import java.io.IOException;
25 import java.io.OutputStream;
26 import java.text.SimpleDateFormat;
27 import java.util.Calendar;
28 import java.util.Date;
29 import java.util.GregorianCalendar;
30 import java.util.Locale;
31 import java.util.TimeZone;
32 import java.util.Timer;
33 import java.util.TimerTask;
34
35 /**
36 * RolloverFileOutputStream
37 *
38 * This output stream puts content in a file that is rolled over every 24 hours.
39 * The filename must include the string "yyyy_mm_dd", which is replaced with the
40 * actual date when creating and rolling over the file.
41 *
42 * Old files are retained for a number of days before being deleted.
43 *
44 *
45 */
46 public class RolloverFileOutputStream extends FilterOutputStream
47 {
48 private static Timer __rollover;
49
50 final static String YYYY_MM_DD="yyyy_mm_dd";
51 final static String ROLLOVER_FILE_DATE_FORMAT = "yyyy_MM_dd";
52 final static String ROLLOVER_FILE_BACKUP_FORMAT = "HHmmssSSS";
53 final static int ROLLOVER_FILE_RETAIN_DAYS = 31;
54
55 private RollTask _rollTask;
56 private SimpleDateFormat _fileBackupFormat;
57 private SimpleDateFormat _fileDateFormat;
58
59 private String _filename;
60 private File _file;
61 private boolean _append;
62 private int _retainDays;
63
64 /* ------------------------------------------------------------ */
65 /**
66 * @param filename The filename must include the string "yyyy_mm_dd",
67 * which is replaced with the actual date when creating and rolling over the file.
68 * @throws IOException
69 */
70 public RolloverFileOutputStream(String filename)
71 throws IOException
72 {
73 this(filename,true,ROLLOVER_FILE_RETAIN_DAYS);
74 }
75
76 /* ------------------------------------------------------------ */
77 /**
78 * @param filename The filename must include the string "yyyy_mm_dd",
79 * which is replaced with the actual date when creating and rolling over the file.
80 * @param append If true, existing files will be appended to.
81 * @throws IOException
82 */
83 public RolloverFileOutputStream(String filename, boolean append)
84 throws IOException
85 {
86 this(filename,append,ROLLOVER_FILE_RETAIN_DAYS);
87 }
88
89 /* ------------------------------------------------------------ */
90 /**
91 * @param filename The filename must include the string "yyyy_mm_dd",
92 * which is replaced with the actual date when creating and rolling over the file.
93 * @param append If true, existing files will be appended to.
94 * @param retainDays The number of days to retain files before deleting them. 0 to retain forever.
95 * @throws IOException
96 */
97 public RolloverFileOutputStream(String filename,
98 boolean append,
99 int retainDays)
100 throws IOException
101 {
102 this(filename,append,retainDays,TimeZone.getDefault());
103 }
104
105 /* ------------------------------------------------------------ */
106 /**
107 * @param filename The filename must include the string "yyyy_mm_dd",
108 * which is replaced with the actual date when creating and rolling over the file.
109 * @param append If true, existing files will be appended to.
110 * @param retainDays The number of days to retain files before deleting them. 0 to retain forever.
111 * @throws IOException
112 */
113 public RolloverFileOutputStream(String filename,
114 boolean append,
115 int retainDays,
116 TimeZone zone)
117 throws IOException
118 {
119
120 this(filename,append,retainDays,zone,null,null);
121 }
122
123 /* ------------------------------------------------------------ */
124 /**
125 * @param filename The filename must include the string "yyyy_mm_dd",
126 * which is replaced with the actual date when creating and rolling over the file.
127 * @param append If true, existing files will be appended to.
128 * @param retainDays The number of days to retain files before deleting them. 0 to retain forever.
129 * @param dateFormat The format for the date file substitution. The default is "yyyy_MM_dd".
130 * @param backupFormat The format for the file extension of backup files. The default is "HHmmssSSS".
131 * @throws IOException
132 */
133 public RolloverFileOutputStream(String filename,
134 boolean append,
135 int retainDays,
136 TimeZone zone,
137 String dateFormat,
138 String backupFormat)
139 throws IOException
140 {
141 super(null);
142
143 if (dateFormat==null)
144 dateFormat=ROLLOVER_FILE_DATE_FORMAT;
145 _fileDateFormat = new SimpleDateFormat(dateFormat);
146
147 if (backupFormat==null)
148 backupFormat=ROLLOVER_FILE_BACKUP_FORMAT;
149 _fileBackupFormat = new SimpleDateFormat(backupFormat);
150
151 _fileBackupFormat.setTimeZone(zone);
152 _fileDateFormat.setTimeZone(zone);
153
154 if (filename!=null)
155 {
156 filename=filename.trim();
157 if (filename.length()==0)
158 filename=null;
159 }
160 if (filename==null)
161 throw new IllegalArgumentException("Invalid filename");
162
163 _filename=filename;
164 _append=append;
165 _retainDays=retainDays;
166 setFile();
167
168 synchronized(RolloverFileOutputStream.class)
169 {
170 if (__rollover==null)
171 __rollover=new Timer(RolloverFileOutputStream.class.getName(),true);
172
173 _rollTask=new RollTask();
174
175 Calendar now = Calendar.getInstance();
176 now.setTimeZone(zone);
177
178 GregorianCalendar midnight =
179 new GregorianCalendar(now.get(Calendar.YEAR),
180 now.get(Calendar.MONTH),
181 now.get(Calendar.DAY_OF_MONTH),
182 23,0);
183 midnight.setTimeZone(zone);
184 midnight.add(Calendar.HOUR,1);
185 __rollover.scheduleAtFixedRate(_rollTask,midnight.getTime(),1000L*60*60*24);
186 }
187 }
188
189 /* ------------------------------------------------------------ */
190 public String getFilename()
191 {
192 return _filename;
193 }
194
195 /* ------------------------------------------------------------ */
196 public String getDatedFilename()
197 {
198 if (_file==null)
199 return null;
200 return _file.toString();
201 }
202
203 /* ------------------------------------------------------------ */
204 public int getRetainDays()
205 {
206 return _retainDays;
207 }
208
209 /* ------------------------------------------------------------ */
210 private synchronized void setFile()
211 throws IOException
212 {
213 // Check directory
214 File file = new File(_filename);
215 _filename=file.getCanonicalPath();
216 file=new File(_filename);
217 File dir= new File(file.getParent());
218 if (!dir.isDirectory() || !dir.canWrite())
219 throw new IOException("Cannot write log directory "+dir);
220
221 Date now=new Date();
222
223 // Is this a rollover file?
224 String filename=file.getName();
225 int i=filename.toLowerCase(Locale.ENGLISH).indexOf(YYYY_MM_DD);
226 if (i>=0)
227 {
228 file=new File(dir,
229 filename.substring(0,i)+
230 _fileDateFormat.format(now)+
231 filename.substring(i+YYYY_MM_DD.length()));
232 }
233
234 if (file.exists()&&!file.canWrite())
235 throw new IOException("Cannot write log file "+file);
236
237 // Do we need to change the output stream?
238 if (out==null || !file.equals(_file))
239 {
240 // Yep
241 _file=file;
242 if (!_append && file.exists())
243 file.renameTo(new File(file.toString()+"."+_fileBackupFormat.format(now)));
244 OutputStream oldOut=out;
245 out=new FileOutputStream(file.toString(),_append);
246 if (oldOut!=null)
247 oldOut.close();
248 //if(log.isDebugEnabled())log.debug("Opened "+_file);
249 }
250 }
251
252 /* ------------------------------------------------------------ */
253 private void removeOldFiles()
254 {
255 if (_retainDays>0)
256 {
257 long now = System.currentTimeMillis();
258
259 File file= new File(_filename);
260 File dir = new File(file.getParent());
261 String fn=file.getName();
262 int s=fn.toLowerCase(Locale.ENGLISH).indexOf(YYYY_MM_DD);
263 if (s<0)
264 return;
265 String prefix=fn.substring(0,s);
266 String suffix=fn.substring(s+YYYY_MM_DD.length());
267
268 String[] logList=dir.list();
269 for (int i=0;i<logList.length;i++)
270 {
271 fn = logList[i];
272 if(fn.startsWith(prefix)&&fn.indexOf(suffix,prefix.length())>=0)
273 {
274 File f = new File(dir,fn);
275 long date = f.lastModified();
276 if ( ((now-date)/(1000*60*60*24))>_retainDays)
277 f.delete();
278 }
279 }
280 }
281 }
282
283 /* ------------------------------------------------------------ */
284 @Override
285 public void write (byte[] buf)
286 throws IOException
287 {
288 out.write (buf);
289 }
290
291 /* ------------------------------------------------------------ */
292 @Override
293 public void write (byte[] buf, int off, int len)
294 throws IOException
295 {
296 out.write (buf, off, len);
297 }
298
299 /* ------------------------------------------------------------ */
300 /**
301 */
302 @Override
303 public void close()
304 throws IOException
305 {
306 synchronized(RolloverFileOutputStream.class)
307 {
308 try{super.close();}
309 finally
310 {
311 out=null;
312 _file=null;
313 }
314
315 _rollTask.cancel();
316 }
317 }
318
319 /* ------------------------------------------------------------ */
320 /* ------------------------------------------------------------ */
321 /* ------------------------------------------------------------ */
322 private class RollTask extends TimerTask
323 {
324 @Override
325 public void run()
326 {
327 try
328 {
329 RolloverFileOutputStream.this.setFile();
330 RolloverFileOutputStream.this.removeOldFiles();
331
332 }
333 catch(IOException e)
334 {
335 // Cannot log this exception to a LOG, as RolloverFOS can be used by logging
336 e.printStackTrace();
337 }
338 }
339 }
340 }