/** * Wait for all pending write operations to complete, then close the underlying output stream. * This method may block. */ @Override public void close() throws IOException { if (closed.getAndSet(true)) return; if (writerThread == null) { if (getBytesPosted() == getBytesWritten()) { return; } else { throw new IOException("Never connected; data never written"); } } Util.ensureInterruptible( new Util.Interruptible() { public void run() throws InterruptedException { pending.pushEOF(); } }); Util.ensureInterruptible( new Util.Interruptible() { public void run() throws InterruptedException { writerThread.join(); } }); checkStoredException(); if (getBytesPosted() != getBytesWritten()) throw new IOException("There were unwritten bytes"); }
@Override public void write(byte b[], int off, int len) throws IOException { Util.checkClosed(closed); checkStoredException(); pending.push(b, off, len); // Only do this if the push operation succeeds. bytesPosted.addAndGet(len); /* While it might be appropriate to send a notification to observers at this point, keep things simple and just wait until the writer thread gets around to do so instead. */ }
/** * Schedule a flush() to happen on the underlying output stream as soon as the I/O thread becomes * idle. This method intentionally never blocks, which is contrary to the traditional contract for * flush. */ @Override public void flush() throws IOException { Util.checkClosed(closed); flushPending.set(true); }