public boolean sendOutRequest(OutRequest outRequest) {
    boolean res = false;
    while (true) {
      if (!outRequest.shouldRetry()) {
        outRequest.setFuture();
        break;
      }

      if (sendOutRequest(outRequest, connect(outRequest))) {
        res = true;
        break;
      }
    }

    return res;
  }
  protected boolean sendOutRequest(OutRequest outRequest, Connection connection) {
    Request request = outRequest.getRequest();

    // Validate if the ArgScheme is set correctly
    if (request.getArgScheme() == null) {
      request.setArgScheme(ArgScheme.RAW);
      outRequest.setLastError(
          ErrorType.BadRequest, "Expect call request to have Arg Scheme specified");
      outRequest.setFuture();
      return false;
    }

    // Set the default retry flag if it is not set
    if (request.getRetryFlags() == null) {
      request.setRetryFlags("c");
    }

    long initTimeout = this.initTimeout;
    if (initTimeout <= 0) {
      initTimeout = request.getTimeout();
    }

    if (connection == null) {
      outRequest.setLastError(ErrorType.BadRequest, new TChannelNoPeerAvailable());
      outRequest.setFuture();
      return false;
    } else if (!connection.waitForIdentified(initTimeout)) {
      connection.clean();
      if (connection.lastError() != null) {
        outRequest.setLastError(ErrorType.NetworkError, connection.lastError());
      } else {
        outRequest.setLastError(ErrorType.NetworkError, new TChannelConnectionTimeout());
      }

      return false;
    }

    // Get a response router for our outbound channel
    ResponseRouter router = connection.channel().pipeline().get(ResponseRouter.class);
    return router.expectResponse(outRequest);
  }
  public SubPeer choosePeer(OutRequest outRequest) {
    SubPeer res = null;
    if (peers.size() == 0) {
      return null;
    }

    int start = new Random().nextInt(peers.size());
    int i = start;
    boolean stop = false;
    do {
      i = (i + 1) % peers.size();
      SubPeer peer = peers.get(i);
      stop = peer.updateScore(outRequest);
      if (stop || res == null) {
        res = peer;
      } else if (peer.getScore() > res.getScore()) {
        res = peer;
      }
    } while (!stop && i != start);

    outRequest.setUsedPeer(res.getRemoteAddress());
    return res;
  }
  protected <V extends Response> TFuture<V> sendRequest(
      Request request, InetAddress host, int port) {
    OutRequest<V> outRequest = new OutRequest<V>(this, request);
    if (host != null) {
      Connection conn = peerManager.findOrNew(new InetSocketAddress(host, port));
      // No retry for direct connections
      outRequest.disableRetry();
      if (!sendOutRequest(outRequest, conn)) {
        outRequest.setFuture();
      }
    } else if (peers.size() == 0) {
      outRequest.setLastError(ErrorType.BadRequest, new TChannelNoPeerAvailable());
      outRequest.setFuture();
    } else {
      sendOutRequest(outRequest);
    }

    return outRequest.getFuture();
  }