public void stop() {
   try {
     channel.close();
     logger.debug("~~ [CLOSE]");
   } catch (IOException e) {
     throw new ClientException("Unable to close socket connection properly." + e.getMessage(), e);
   }
 }
    public static ByteChannel create(String host, int port, Logger logger) throws IOException {
      SocketChannel channel = SocketChannel.open();
      channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
      channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
      channel.connect(new InetSocketAddress(host, port));

      if (logger.isTraceEnabled()) {
        return new LoggingByteChannel(new AllOrNothingChannel(channel), logger);
      } else {
        return new AllOrNothingChannel(channel);
      }
    }
  private SocketProtocol negotiateProtocol() throws IOException {
    // TODO make this not so hard-coded
    logger.debug("~~ [HANDSHAKE] [1, 0, 0, 0].");
    // Propose protocol versions
    ByteBuffer buf =
        ByteBuffer.wrap(
            new byte[] {
              0, 0, 0, 1,
              0, 0, 0, 0,
              0, 0, 0, 0,
              0, 0, 0, 0
            });

    channel.write(buf);

    // Read back the servers choice
    buf.clear();
    buf.limit(4);

    channel.read(buf);

    // Choose protocol, or fail
    buf.flip();
    final int proposal = buf.getInt();

    switch (proposal) {
      case 1:
        logger.debug("~~ [HANDSHAKE] 1");
        return new SocketProtocolV1(channel);
      case 0:
        throw new ClientException(
            "The server does not support any of the protocol versions supported by "
                + "this driver. Ensure that you are using driver and server versions that "
                + "are compatible with one another.");
      default:
        throw new ClientException(
            "Protocol error, server suggested unexpected protocol version: " + proposal);
    }
  }
  public void start() {
    try {
      logger.debug("~~ [CONNECT] {0}:{1}.", host, port);
      channel = SocketChannelFactory.create(host, port, logger);

      protocol = negotiateProtocol();
      reader = protocol.reader();
      writer = protocol.writer();
    } catch (ConnectException e) {
      throw new ClientException(
          String.format(
              "Unable to connect to '%s' on port %s, "
                  + "ensure the database is running and that there is a working "
                  + "network "
                  + "connection to it.",
              host, port));
    } catch (IOException e) {
      throw new ClientException("Unable to process request: " + e.getMessage(), e);
    }
  }
 @Override
 public void handleIgnoredMessage() {
   super.handleIgnoredMessage();
   logger.debug(DEFAULT_DEBUG_LOGGING_FORMAT, IGNORED);
 }
 @Override
 public void handleFailureMessage(String code, String message) {
   super.handleFailureMessage(code, message);
   logger.debug("S: [FAILURE %s \"%s\"]", code, message);
 }
 @Override
 public void handleRecordMessage(Value[] fields) {
   super.handleRecordMessage(fields);
   logger.debug("S: RecordMessage{%s}", Arrays.asList(fields));
 }
 @Override
 public void handleSuccessMessage(Map<String, Value> meta) {
   super.handleSuccessMessage(meta);
   logger.debug("S: [SUCCESS %s]", meta);
 }
 @Override
 public void handleAckFailureMessage() {
   super.handleAckFailureMessage();
   logger.debug(DEFAULT_DEBUG_LOGGING_FORMAT, ACK_FAILURE);
 }
 @Override
 public void handleDiscardAllMessage() {
   super.handleDiscardAllMessage();
   logger.debug(DEFAULT_DEBUG_LOGGING_FORMAT, DISCARD_ALL);
 }
 @Override
 public void handlePullAllMessage() {
   super.handlePullAllMessage();
   logger.debug(DEFAULT_DEBUG_LOGGING_FORMAT, PULL_ALL);
 }
 @Override
 public void handleRunMessage(String statement, Map<String, Value> parameters) {
   super.handleRunMessage(statement, parameters);
   logger.debug("S: [RUN \"%s\" %s]", statement, parameters);
 }
 @Override
 public void handleInitializeMessage(String clientNameAndVersion) {
   super.handleInitializeMessage(clientNameAndVersion);
   logger.debug("S: [INITIALIZE \"%s\"]", clientNameAndVersion);
 }