package org.oddjob.logging; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; /** * An output stream that splits output into an existing * output stream if supplied, and a console archive. * <p> * The internal buffer is synchronised so this class is * thread safe, however no synchronisation occurs between writing * to the underlying stream and the log so output could be in * a different order. * */ abstract public class AbstractLoggingOutput extends OutputStream { private ByteArrayOutputStream buffer; /** The existing OutputStream to also write to. */ private final OutputStream existing; /** * Constructor. * * @param existing The output stream to also write to. May be null. * @param level The level to use when logging. * @param consoleArchiver The logger to write to. */ public AbstractLoggingOutput(OutputStream existing) { this.buffer = new ByteArrayOutputStream(); this.existing = existing; } public void write(int c) throws IOException { add(new byte[] { (byte) c }, 0, 1); if (existing != null) existing.write(c); } public void write(byte[] b) throws IOException { add(b, 0, b.length); if (existing != null) existing.write(b); } public void write(byte[] buf, int off, int len) throws IOException { add(buf, off, len); if (existing != null) existing.write(buf, off, len); } @Override public void flush() throws IOException { if (existing != null) { existing.flush(); } } public void close() throws IOException { next(); if (existing != null) existing.close(); } /** * Add bytes to the internal buffer. * * @param buf * @param off * @param length */ void add(byte[] buf, int off , int length) { synchronized (buffer) { for (int i = off; i < off + length; ++i) { if (buf[i] == '\n') { buffer.write(buf, off, i - off + 1); next(); add(buf, i+1, length - (i - off +1)); return; } } buffer.write(buf, off, length); } } /** * Called when a line is ready to be written to the LoagArchive. * */ void next() { String message = null; synchronized (buffer) { if (buffer.size() == 0) { return; } message = buffer.toString(); buffer.reset(); } dispatch(message); } abstract protected void dispatch(String message); }