/**
  * 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);
 }