package org.netbeans.gradle.project.output; import java.io.IOException; import java.io.Writer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.jtrim.utils.ExceptionHelper; public final class LineOutputWriter extends Writer { public static interface Handler { public void writeLine(String line) throws IOException; public void flush() throws IOException; } private final Handler handler; private final Lock mainLock; private final StringBuilder lineBuffer; private final AtomicBoolean closed; private char lastChar; public LineOutputWriter(Handler handler) { ExceptionHelper.checkNotNullArgument(handler, "handler"); this.handler = handler; this.lineBuffer = new StringBuilder(256); this.mainLock = new ReentrantLock(); this.lastChar = '\0'; this.closed = new AtomicBoolean(false); } @Override public void write(char[] cbuf, int off, int len) throws IOException { ExceptionHelper.checkNotNullArgument(cbuf, "cbuf"); ExceptionHelper.checkArgumentInRange(off, 0, cbuf.length, "off"); ExceptionHelper.checkArgumentInRange(len, 0, cbuf.length - off, "len"); int currentOffset = off; int currentLength = len; while (currentLength > 0) { String line = null; mainLock.lock(); try { while (currentLength > 0) { char currentChar = cbuf[currentOffset]; char prevChar = lastChar; lastChar = currentChar; currentOffset++; currentLength--; if (prevChar == '\r' && currentChar == '\n') { continue; } if (currentChar == '\n' || currentChar == '\r') { line = lineBuffer.toString(); lineBuffer.setLength(0); break; } else { lineBuffer.append(currentChar); } } } finally { mainLock.unlock(); } if (line != null) { handler.writeLine(line); } } } @Override public void flush() throws IOException { handler.flush(); } @Override public void close() throws IOException { if (!closed.compareAndSet(false, true)) { return; } String line; mainLock.lock(); try { line = lineBuffer.toString(); lineBuffer.setLength(0); } finally { mainLock.unlock(); } handler.writeLine(line); handler.flush(); } }