Mercurial Hosting > luan
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 } |