/**
   * Attempts to read a buffered message from the underlying connection. This is more efficient than
   * attempting to actually read from the underlying connection for each message, when ends up
   * making a final "empty" read from the non-blocking connection, rather than simply consuming all
   * buffered data.
   *
   * <p>TODO: It would be ideal if there was a way to consume data as we go, instead of buffering it
   * all then consuming it. However, this only matters for streams of medium-sized messages with a
   * huge backlog, which should be rare? The C++ implementation has a similar issue.
   *
   * @param builder message builder to be parsed
   * @return true if a message was read, false if there is not enough buffered data to read a
   *     message.
   */
  public boolean readBufferedMessage(MessageLite.Builder builder) {
    try {
      if (nextMessageLength == -1) {
        if (connection.available() < 4) {
          return false;
        }

        input.setLimit(4);
        nextMessageLength = codedInput.readRawLittleEndian32();
      }
      assert nextMessageLength >= 0;

      if (connection.available() < nextMessageLength) {
        assert 0 <= connection.available() && connection.available() < nextMessageLength;
        return false;
      }

      // Parse the response for the next RPC
      // TODO: Add .available() to CodedInputStream to avoid many copies to internal buffer?
      // or make CodedInputStream wrap a non-blocking interface like C++?
      input.setLimit(nextMessageLength);
      builder.mergeFrom(codedInput);
      assert codedInput.isAtEnd();
      codedInput.resetSizeCounter();
      nextMessageLength = -1;
      return true;
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
 public ProtoConnection(NonBlockingConnection connection) {
   this.connection = connection;
   input = connection.getInputStream();
   output = connection.getOutputStream();
   codedInput = CodedInputStream.newInstance(input);
   codedOutput = CodedOutputStream.newInstance(output);
 }
  public boolean tryWrite(MessageLite message) {
    try {
      codedOutput.writeRawLittleEndian32(message.getSerializedSize());
      message.writeTo(codedOutput);
      // writes to the underlying output stream
      codedOutput.flush();

      return connection.tryFlush();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
 /**
  * See {@link NIOReadStream#readAllAvailable()}.
  *
  * @see NIOReadStream#readAllAvailable()
  */
 public boolean readAllAvailable() {
   return connection.readAllAvailable();
 }
 public void close() {
   connection.close();
 }
 public boolean writeAvailable() {
   return connection.writeAvailable();
 }
 public SelectableChannel getChannel() {
   return connection.getChannel();
 }