Java tutorial
//Copyright 2006 Mort Bay Consulting Pty. Ltd. //------------------------------------------------------------------------ //Licensed under the Apache License, Version 2.0 (the "License"); //you may not use this file except in compliance with the License. //You may obtain a copy of the License at //http://www.apache.org/licenses/LICENSE-2.0 //Unless required by applicable law or agreed to in writing, software //distributed under the License is distributed on an "AS IS" BASIS, //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //See the License for the specific language governing permissions and //limitations under the License. import java.io.File; import java.io.FileOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.StringTokenizer; import java.util.TimeZone; import java.util.Timer; import java.util.TimerTask; /** * RolloverFileOutputStream * * @author Greg Wilkins */ public class RolloverFileOutputStream extends FilterOutputStream { private static Timer __rollover; final static String YYYY_MM_DD = "yyyy_mm_dd"; private RollTask _rollTask; private SimpleDateFormat _fileBackupFormat = new SimpleDateFormat( System.getProperty("ROLLOVERFILE_BACKUP_FORMAT", "HHmmssSSS")); private SimpleDateFormat _fileDateFormat = new SimpleDateFormat( System.getProperty("ROLLOVERFILE_DATE_FORMAT", "yyyy_MM_dd")); private String _filename; private File _file; private boolean _append; private int _retainDays; /* ------------------------------------------------------------ */ public RolloverFileOutputStream(String filename) throws IOException { this(filename, true, Integer.getInteger("ROLLOVERFILE_RETAIN_DAYS", 31).intValue()); } /* ------------------------------------------------------------ */ public RolloverFileOutputStream(String filename, boolean append) throws IOException { this(filename, append, Integer.getInteger("ROLLOVERFILE_RETAIN_DAYS", 31).intValue()); } /* ------------------------------------------------------------ */ public RolloverFileOutputStream(String filename, boolean append, int retainDays) throws IOException { this(filename, append, retainDays, TimeZone.getDefault()); } /* ------------------------------------------------------------ */ public RolloverFileOutputStream(String filename, boolean append, int retainDays, TimeZone zone) throws IOException { super(null); _fileBackupFormat.setTimeZone(zone); _fileDateFormat.setTimeZone(zone); if (filename != null) { filename = filename.trim(); if (filename.length() == 0) filename = null; } if (filename == null) throw new IllegalArgumentException("Invalid filename"); _filename = filename; _append = append; _retainDays = retainDays; setFile(); synchronized (RolloverFileOutputStream.class) { if (__rollover == null) __rollover = new Timer(); _rollTask = new RollTask(); Calendar now = Calendar.getInstance(); now.setTimeZone(zone); GregorianCalendar midnight = new GregorianCalendar(now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH), 23, 0); midnight.setTimeZone(zone); midnight.add(Calendar.HOUR, 1); __rollover.scheduleAtFixedRate(_rollTask, midnight.getTime(), 1000L * 60 * 60 * 24); } } /* ------------------------------------------------------------ */ public String getFilename() { return _filename; } /* ------------------------------------------------------------ */ public String getDatedFilename() { if (_file == null) return null; return _file.toString(); } /* ------------------------------------------------------------ */ public int getRetainDays() { return _retainDays; } /* ------------------------------------------------------------ */ private synchronized void setFile() throws IOException { // Check directory File file = new File(_filename); _filename = file.getCanonicalPath(); file = new File(_filename); File dir = new File(file.getParent()); if (!dir.isDirectory() || !dir.canWrite()) throw new IOException("Cannot write log directory " + dir); Date now = new Date(); // Is this a rollover file? String filename = file.getName(); int i = filename.toLowerCase().indexOf(YYYY_MM_DD); if (i >= 0) { file = new File(dir, filename.substring(0, i) + _fileDateFormat.format(now) + filename.substring(i + YYYY_MM_DD.length())); } if (file.exists() && !file.canWrite()) throw new IOException("Cannot write log file " + file); // Do we need to change the output stream? if (out == null || !file.equals(_file)) { // Yep _file = file; if (!_append && file.exists()) file.renameTo(new File(file.toString() + "." + _fileBackupFormat.format(now))); OutputStream oldOut = out; out = new FileOutputStream(file.toString(), _append); if (oldOut != null) oldOut.close(); // if(log.isDebugEnabled())log.debug("Opened "+_file); } } /* ------------------------------------------------------------ */ private void removeOldFiles() { if (_retainDays > 0) { Calendar retainDate = Calendar.getInstance(); retainDate.add(Calendar.DATE, -_retainDays); int borderYear = retainDate.get(java.util.Calendar.YEAR); int borderMonth = retainDate.get(java.util.Calendar.MONTH) + 1; int borderDay = retainDate.get(java.util.Calendar.DAY_OF_MONTH); File file = new File(_filename); File dir = new File(file.getParent()); String fn = file.getName(); int s = fn.toLowerCase().indexOf(YYYY_MM_DD); if (s < 0) return; String prefix = fn.substring(0, s); String suffix = fn.substring(s + YYYY_MM_DD.length()); String[] logList = dir.list(); for (int i = 0; i < logList.length; i++) { fn = logList[i]; if (fn.startsWith(prefix) && fn.indexOf(suffix, prefix.length()) >= 0) { try { StringTokenizer st = new StringTokenizer( fn.substring(prefix.length(), prefix.length() + YYYY_MM_DD.length()), "_."); int nYear = Integer.parseInt(st.nextToken()); int nMonth = Integer.parseInt(st.nextToken()); int nDay = Integer.parseInt(st.nextToken()); if (nYear < borderYear || (nYear == borderYear && nMonth < borderMonth) || (nYear == borderYear && nMonth == borderMonth && nDay <= borderDay)) { // log.info("Log age "+fn); new File(dir, fn).delete(); } } catch (Exception e) { // if (log.isDebugEnabled()) e.printStackTrace(); } } } } } /* ------------------------------------------------------------ */ public void write(byte[] buf) throws IOException { out.write(buf); } /* ------------------------------------------------------------ */ public void write(byte[] buf, int off, int len) throws IOException { out.write(buf, off, len); } /* ------------------------------------------------------------ */ /** */ public void close() throws IOException { synchronized (RolloverFileOutputStream.class) { try { super.close(); } finally { out = null; _file = null; } _rollTask.cancel(); } } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ private class RollTask extends TimerTask { public void run() { try { RolloverFileOutputStream.this.setFile(); RolloverFileOutputStream.this.removeOldFiles(); } catch (IOException e) { e.printStackTrace(); } } } }