1 16 package org.mortbay.util; 17 18 import java.io.File ; 19 import java.io.FileOutputStream ; 20 import java.io.FilterOutputStream ; 21 import java.io.IOException ; 22 import java.io.OutputStream ; 23 import java.lang.ref.WeakReference ; 24 import java.text.SimpleDateFormat ; 25 import java.util.ArrayList ; 26 import java.util.Calendar ; 27 import java.util.Date ; 28 import java.util.GregorianCalendar ; 29 import java.util.ListIterator ; 30 import java.util.StringTokenizer ; 31 32 import org.apache.commons.logging.Log; 33 import org.mortbay.log.LogFactory; 34 35 36 41 public class RolloverFileOutputStream extends FilterOutputStream 42 { 43 static Log log = LogFactory.getLog(RolloverFileOutputStream.class); 44 static Rollover __rollover; 45 final static String YYYY_MM_DD="yyyy_mm_dd"; 46 final static ArrayList __rollovers = new ArrayList (); 47 48 private SimpleDateFormat _fileBackupFormat = 49 new SimpleDateFormat (System.getProperty("ROLLOVERFILE_BACKUP_FORMAT","HHmmssSSS")); 50 private SimpleDateFormat _fileDateFormat = 51 new SimpleDateFormat (System.getProperty("ROLLOVERFILE_DATE_FORMAT","yyyy_MM_dd")); 52 53 private String _filename; 54 private File _file; 55 private boolean _append; 56 private int _retainDays; 57 private WeakReference _ref; 58 59 60 public RolloverFileOutputStream(String filename) 61 throws IOException 62 { 63 this(filename,true,Integer.getInteger("ROLLOVERFILE_RETAIN_DAYS",31).intValue()); 64 } 65 66 67 public RolloverFileOutputStream(String filename, boolean append) 68 throws IOException 69 { 70 this(filename,append,Integer.getInteger("ROLLOVERFILE_RETAIN_DAYS",31).intValue()); 71 } 72 73 74 public RolloverFileOutputStream(String filename, 75 boolean append, 76 int retainDays) 77 throws IOException 78 { 79 super(null); 80 81 if (filename!=null) 82 { 83 filename=filename.trim(); 84 if (filename.length()==0) 85 filename=null; 86 } 87 if (filename==null) 88 throw new IllegalArgumentException ("Invalid filename"); 89 90 _filename=filename; 91 _append=append; 92 _retainDays=retainDays; 93 _ref=new WeakReference (this); 94 setFile(); 95 96 synchronized(__rollovers) 97 { 98 if (__rollover==null) 99 { 100 __rollover=new Rollover(); 101 __rollover.start(); 102 } 103 __rollovers.add(_ref); 104 } 105 } 106 107 108 public String getFilename() 109 { 110 return _filename; 111 } 112 113 114 public String getDatedFilename() 115 { 116 if (_file==null) 117 return null; 118 return _file.toString(); 119 } 120 121 122 public int getRetainDays() 123 { 124 return _retainDays; 125 } 126 127 128 private synchronized void setFile() 129 throws IOException 130 { 131 File file = new File (_filename); 133 _filename=file.getCanonicalPath(); 134 file=new File (_filename); 135 File dir= new File (file.getParent()); 136 if (!dir.isDirectory() || !dir.canWrite()) 137 throw new IOException ("Cannot write log directory "+dir); 138 139 Date now=new Date (); 140 141 String filename=file.getName(); 143 int i=filename.toLowerCase().indexOf(YYYY_MM_DD); 144 if (i>=0) 145 { 146 file=new File (dir, 147 filename.substring(0,i)+ 148 _fileDateFormat.format(now)+ 149 filename.substring(i+YYYY_MM_DD.length())); 150 } 151 152 if (file.exists()&&!file.canWrite()) 153 throw new IOException ("Cannot write log file "+file); 154 155 if (out==null || !file.equals(_file)) 157 { 158 _file=file; 160 if (!_append && file.exists()) 161 file.renameTo(new File (file.toString()+"."+_fileBackupFormat.format(now))); 162 OutputStream oldOut=out; 163 out=new FileOutputStream (file.toString(),_append); 164 if (oldOut!=null) 165 oldOut.close(); 166 if(log.isDebugEnabled())log.debug("Opened "+_file); 167 } 168 } 169 170 171 private void removeOldFiles() 172 { 173 if (_retainDays>0) 174 { 175 Calendar retainDate = Calendar.getInstance(); 176 retainDate.add(Calendar.DATE,-_retainDays); 177 int borderYear = retainDate.get(java.util.Calendar.YEAR); 178 int borderMonth = retainDate.get(java.util.Calendar.MONTH) + 1; 179 int borderDay = retainDate.get(java.util.Calendar.DAY_OF_MONTH); 180 181 File file= new File (_filename); 182 File dir = new File (file.getParent()); 183 String fn=file.getName(); 184 int s=fn.toLowerCase().indexOf(YYYY_MM_DD); 185 if (s<0) 186 return; 187 String prefix=fn.substring(0,s); 188 String suffix=fn.substring(s+YYYY_MM_DD.length()); 189 190 String [] logList=dir.list(); 191 for (int i=0;i<logList.length;i++) 192 { 193 fn = logList[i]; 194 if(fn.startsWith(prefix)&&fn.indexOf(suffix,prefix.length())>=0) 195 { 196 try 197 { 198 StringTokenizer st = new StringTokenizer (fn.substring(prefix.length(), prefix.length()+YYYY_MM_DD.length()), "_."); 199 int nYear = Integer.parseInt(st.nextToken()); 200 int nMonth = Integer.parseInt(st.nextToken()); 201 int nDay = Integer.parseInt(st.nextToken()); 202 203 if (nYear<borderYear || 204 (nYear==borderYear && nMonth<borderMonth) || 205 (nYear==borderYear && 206 nMonth==borderMonth && 207 nDay<=borderDay)) 208 { 209 log.info("Log age "+fn); 210 new File (dir,fn).delete(); 211 } 212 } 213 catch(Exception e) 214 { 215 if (log.isDebugEnabled()) 216 e.printStackTrace(); 217 } 218 } 219 } 220 } 221 } 222 223 224 public void write (byte[] buf) 225 throws IOException 226 { 227 out.write (buf); 228 } 229 230 231 public void write (byte[] buf, int off, int len) 232 throws IOException 233 { 234 out.write (buf, off, len); 235 } 236 237 238 240 public void close() 241 throws IOException 242 { 243 synchronized(__rollovers) 244 { 245 __rollovers.remove(_ref); 246 _ref=null; 247 try{super.close();} 248 finally 249 { 250 out=null; 251 _file=null; 252 } 253 254 if ( __rollovers.size() == 0 ) { 256 __rollover.timeToStop(); 257 __rollover.interrupt(); 258 __rollover = null; 259 } 260 } 261 } 262 263 264 265 266 267 private class Rollover extends Thread 268 { 269 private boolean timeToStop = false; 270 271 Rollover() 272 { 273 setName("Rollover"); 274 setDaemon(true); 275 } 276 277 synchronized void timeToStop() 278 { 279 timeToStop = true; 280 } 281 282 public void run() 283 { 284 while(!timeToStop) 285 { 286 try 287 { 288 Calendar now = Calendar.getInstance(); 290 GregorianCalendar midnight = 291 new GregorianCalendar (now.get(Calendar.YEAR), 292 now.get(Calendar.MONTH), 293 now.get(Calendar.DAY_OF_MONTH), 294 23,0); 295 midnight.add(Calendar.HOUR,1); 296 long sleeptime= 297 midnight.getTime().getTime()- 298 now.getTime().getTime(); 299 if(log.isDebugEnabled())log.debug("Rollover sleep until "+midnight.getTime()); 300 Thread.sleep(sleeptime); 301 } 302 catch(InterruptedException e) 303 { 304 if (!timeToStop) 305 e.printStackTrace(); 306 } 307 308 synchronized(__rollovers) 309 { 310 ListIterator iter = __rollovers.listIterator(); 311 while (iter.hasNext()) 312 { 313 WeakReference ref = 314 (WeakReference )iter.next(); 315 RolloverFileOutputStream rfos = 316 (RolloverFileOutputStream)ref.get(); 317 318 if (rfos==null) 319 iter.remove(); 320 else 321 { 322 try 323 { 324 rfos.setFile(); 325 rfos.removeOldFiles(); 326 } 327 catch(IOException e) 328 { 329 if (!timeToStop) 330 e.printStackTrace(); 331 } 332 } 333 } 334 } 335 } 336 } 337 } 338 } 339 340 341 342 343 344 | Popular Tags |