/** * */ package com.trendrr.oss.appender; import java.util.Date; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.trendrr.oss.concurrent.LazyInit; import com.trendrr.oss.exceptions.TrendrrIOException; /** * @author Dustin Norlander * @created Oct 3, 2011 * */ class RollingFileThread implements Runnable{ protected static Log log = LogFactory.getLog(RollingFileThread.class); public RollingFileThread(RollingFileAppender cacheAppender){ this.appender = cacheAppender; this.queue = new LinkedBlockingQueue<AppendItem>(); } private RollingFileAppender appender; private class AppendItem { Date d; String c; public AppendItem(Date d, String c) { this.d = d; this.c = c; } } private LinkedBlockingQueue<AppendItem> queue; private int maxQueueSize = 200; private AppendItem eofSignal = new AppendItem(null, "eof"); //we use a special queue item to let us know we are done. (Maybe slightly hacky, but it works) private LazyInit lazyInit = new LazyInit(); private AtomicBoolean stopped = new AtomicBoolean(false); private Thread t = null; private void exception(Exception e) { RollingFileCallback cb = this.appender.getCallback(); if (cb != null) { cb.onError(e); } else { log.error("CAught", e); } } @Override public void run() { while(true){ if (this.stopped.get() && this.queue.isEmpty()) { return; } AppendItem next = null; try { next = this.queue.take(); } catch (InterruptedException e) { if (this.stopped.get()) return; this.exception(e); continue; } if (this.eofSignal.equals(next)) { return; } try { this.appender.doAppend(next.d, next.c); } catch (Exception e) { this.exception(e); } } } private void startThreadIfNeeded() { if (lazyInit.start()) { try { this.t = new Thread(this); this.t.setDaemon(true); this.t.start(); } finally { lazyInit.end(); } } } public void append(Date d, String s){ if (this.stopped.get()) { Exception e = new TrendrrIOException("This file appendar is no longer active. Dropping this task: \n\n" + s); this.exception(e); return; } if (this.queue.size() > this.maxQueueSize) { Exception e = new TrendrrIOException("Error file queue size is growing faster then I can write to disk. Dropping this task: \n\n" + s); this.exception(e); return; } this.startThreadIfNeeded(); try { if (d == null) d = new Date(); this.queue.put(new AppendItem(d, s)); } catch (InterruptedException e) { this.exception(e); } } public void close() { this.stopped.set(true); this.queue.add(this.eofSignal); } }