protected void sendRequest(
      HttpRequest request,
      SendRequestResultListener listener,
      HttpResponseProcessor responseProcessor) {
    if (isClosingOrClosed()) {
      listener.onSendRequestFailure(request, new ClosedChannelException());
    } else if (!isConnected()) {
      listener.onSendRequestFailure(request, new RuntimeException("unable to send request"));
    } else {
      try {
        setResponseProcessor(responseProcessor, listener);
      } catch (DatabusException e) {
        listener.onSendRequestFailure(request, e.getCause());
        _channel.close();
        return;
      }

      // Send the HTTP request.
      if (_channel.isConnected()) {
        // ChannelFuture future = _channel.write(request);
        // future.addListener(new MySendRequestListener(request, listener));
        _channel.write(request);
      } else {
        _log.error("disconnect on request: " + request.getUri());
        listener.onSendRequestFailure(request, new ClosedChannelException());
      }
    }
  }
  @Override
  public DatabusRequest process(DatabusRequest request)
      throws IOException, RequestProcessingException {

    String command = request.getParams().getProperty(DatabusRequest.PATH_PARAM_NAME);
    if (null == command) {
      throw new InvalidRequestParamValueException(COMMAND_NAME, "command", "null");
    }

    String reply = "Command " + command + " completed ";
    LOG.info("got relayCommand = " + command);
    if (command.equals(SAVE_META_STATE_PARAM)) {
      _relay.saveBufferMetaInfo(true);
    } else if (command.equals(SHUTDOWN_RELAY_PARAM)) {
      String msg =
          "received shutdown curl request from: "
              + request.getRemoteAddress()
              + ". Shutting down\n";
      LOG.warn(msg);
      request.getResponseContent().write(ByteBuffer.wrap(msg.getBytes("UTF-8")));
      request.getResponseContent().close();
      _relay.shutdown();
    } else if (command.equals(VALIDATE_RELAY_BUFFER_PARAM)) {
      _relay.validateRelayBuffers();
    } else if (command.equals(DISCONNECT_CLIENTS)) {
      Channel rspChannel = request.getResponseContent().getRawChannel();
      _relay.disconnectDBusClients(rspChannel);
    } else if (command.equals(RUN_GC_PARAM)) {
      Runtime rt = Runtime.getRuntime();
      long mem = rt.freeMemory();
      LOG.info("mem before gc = " + rt.freeMemory() + " out of " + rt.totalMemory());
      long time = System.currentTimeMillis();
      System.gc();
      time = System.currentTimeMillis() - time;
      mem = rt.freeMemory() - mem;
      reply =
          new String(
              "GC run. Took "
                  + time
                  + " millsecs. Freed "
                  + mem
                  + " bytes out of "
                  + rt.totalMemory());
    } else if (command.startsWith(RESET_RELAY_BUFFER_PARAM)) {
      // We expect the request to be of the format:
      //   resetRelayBuffer/<dbName>/<partitionId>?prevScn=<long>&binlogOffset=<long>
      String[] resetCommands = command.split("/");
      if (resetCommands.length != 3) {
        throw new InvalidRequestParamValueException(COMMAND_NAME, "command", command);
      }
      String dbName = resetCommands[1];
      String dbPart = resetCommands[2];
      long prevScn = request.getRequiredLongParam(PREV_SCN_PARAM);
      long binlogOffset = request.getOptionalLongParam(BINLOG_OFFSET_PARAM, 0L);
      LOG.info("reset command = " + dbName + " part =" + dbPart);
      try {
        _relay.resetBuffer(
            new PhysicalPartition(Integer.parseInt(dbPart), dbName), prevScn, binlogOffset);
      } catch (BufferNotFoundException e) {
        reply = new String("command " + command + ":" + e.getMessage());
      }
    } else if (command.startsWith(GET_BINLOG_OFFSET_PARAM)) {
      String[] getOfsArgs = command.split("/");
      if (getOfsArgs.length != 2) {
        throw new InvalidRequestParamValueException(GET_BINLOG_OFFSET_PARAM, "Server ID", "");
      }
      int serverId;
      try {
        serverId = Integer.parseInt(getOfsArgs[1]);
        int[] offset = _relay.getBinlogOffset(serverId);
        if (offset.length != 2) {
          reply = "Error getting binlog offset";
        } else {
          reply = new String("RelayLastEvent(" + offset[0] + "," + offset[1] + ")");
        }
      } catch (NumberFormatException e) {
        throw new InvalidRequestParamValueException(
            GET_BINLOG_OFFSET_PARAM, "Server ID", getOfsArgs[1]);
      } catch (DatabusException e) {
        reply = new String("command " + command + "failed with:" + e.getMessage());
      }
    } else if (command.startsWith(PRINT_RELAY_INFO_PARAM)) {
      try {
        Map<String, String> infoMap = _relay.printInfo();
        reply = makeJsonResponse(infoMap, request);
      } catch (Exception e) {
        reply = new String("command " + command + " failed with:" + e.getMessage());
      }
    } else {
      // invalid command
      reply =
          new String(
              "command "
                  + command
                  + " is invalid. Valid commands are: "
                  + SAVE_META_STATE_PARAM
                  + "|"
                  + SHUTDOWN_RELAY_PARAM
                  + "|"
                  + VALIDATE_RELAY_BUFFER_PARAM
                  + "|"
                  + RUN_GC_PARAM
                  + "|"
                  + RESET_RELAY_BUFFER_PARAM
                  + "|"
                  + GET_BINLOG_OFFSET_PARAM
                  + "|"
                  + PRINT_RELAY_INFO_PARAM
                  + "|"
                  + DISCONNECT_CLIENTS);
    }

    byte[] responseBytes = new byte[(reply.length() + 2)];

    System.arraycopy(reply.getBytes("UTF-8"), 0, responseBytes, 0, reply.length());
    int idx = reply.length();
    responseBytes[idx] = (byte) '\r';
    responseBytes[idx + 1] = (byte) '\n';

    request.getResponseContent().write(ByteBuffer.wrap(responseBytes));

    return request;
  }