public void send(Request request, List<Response.ResponseListener> listeners) {
    if (!scheme.equals(request.getScheme()))
      throw new IllegalArgumentException(
          "Invalid request scheme " + request.getScheme() + " for destination " + this);
    if (!getHost().equals(request.getHost()))
      throw new IllegalArgumentException(
          "Invalid request host " + request.getHost() + " for destination " + this);
    int port = request.getPort();
    if (port >= 0 && getPort() != port)
      throw new IllegalArgumentException(
          "Invalid request port " + port + " for destination " + this);

    HttpConversation conversation = client.getConversation(request.getConversationID(), true);
    HttpExchange exchange = new HttpExchange(conversation, this, request, listeners);

    if (client.isRunning()) {
      if (exchanges.offer(exchange)) {
        if (!client.isRunning() && exchanges.remove(exchange)) {
          throw new RejectedExecutionException(client + " is stopping");
        } else {
          LOG.debug("Queued {}", request);
          requestNotifier.notifyQueued(request);
          Connection connection = acquire();
          if (connection != null) process(connection, false);
        }
      } else {
        throw new RejectedExecutionException(
            "Max requests per destination "
                + client.getMaxRequestsQueuedPerDestination()
                + " exceeded");
      }
    } else {
      throw new RejectedExecutionException(client + " is stopped");
    }
  }
  /**
   * Processes a new connection making it idle or active depending on whether requests are waiting
   * to be sent.
   *
   * <p>A new connection is created when a request needs to be executed; it is possible that the
   * request that triggered the request creation is executed by another connection that was just
   * released, so the new connection may become idle.
   *
   * <p>If a request is waiting to be executed, it will be dequeued and executed by the new
   * connection.
   *
   * @param connection the new connection
   */
  public void process(final C connection) {
    HttpClient client = getHttpClient();
    final HttpExchange exchange = getHttpExchanges().poll();
    if (LOG.isDebugEnabled())
      LOG.debug("Processing exchange {} on {} of {}", exchange, connection, this);
    if (exchange == null) {
      if (!connectionPool.release(connection)) connection.close();

      if (!client.isRunning()) {
        if (LOG.isDebugEnabled()) LOG.debug("{} is stopping", client);
        connection.close();
      }
    } else {
      final Request request = exchange.getRequest();
      Throwable cause = request.getAbortCause();
      if (cause != null) {
        if (LOG.isDebugEnabled()) LOG.debug("Aborted before processing {}: {}", exchange, cause);
        // It may happen that the request is aborted before the exchange
        // is created. Aborting the exchange a second time will result in
        // a no-operation, so we just abort here to cover that edge case.
        exchange.abort(cause);
      } else {
        send(connection, exchange);
      }
    }
  }
Example #3
0
  protected void send(HttpRequest request, List<Response.ResponseListener> listeners) {
    if (!getScheme().equals(request.getScheme()))
      throw new IllegalArgumentException(
          "Invalid request scheme " + request.getScheme() + " for destination " + this);
    if (!getHost().equals(request.getHost()))
      throw new IllegalArgumentException(
          "Invalid request host " + request.getHost() + " for destination " + this);
    int port = request.getPort();
    if (port >= 0 && getPort() != port)
      throw new IllegalArgumentException(
          "Invalid request port " + port + " for destination " + this);

    HttpExchange exchange = new HttpExchange(this, request, listeners);

    if (client.isRunning()) {
      if (enqueue(exchanges, exchange)) {
        if (!client.isRunning() && exchanges.remove(exchange)) {
          request.abort(new RejectedExecutionException(client + " is stopping"));
        } else {
          if (LOG.isDebugEnabled()) LOG.debug("Queued {} for {}", request, this);
          requestNotifier.notifyQueued(request);
          send();
        }
      } else {
        if (LOG.isDebugEnabled())
          LOG.debug(
              "Max queue size {} exceeded by {} for {}",
              client.getMaxRequestsQueuedPerDestination(),
              request,
              this);
        request.abort(
            new RejectedExecutionException(
                "Max requests per destination "
                    + client.getMaxRequestsQueuedPerDestination()
                    + " exceeded for "
                    + this));
      }
    } else {
      request.abort(new RejectedExecutionException(client + " is stopped"));
    }
  }
 public void release(Connection connection) {
   LOG.debug("{} released", connection);
   if (client.isRunning()) {
     boolean removed = activeConnections.remove(connection);
     if (removed) process(connection, false);
     else LOG.debug("{} explicit", connection);
   } else {
     LOG.debug("{} is stopped", client);
     remove(connection);
     connection.close();
   }
 }
 @Override
 public void release(Connection c) {
   @SuppressWarnings("unchecked")
   C connection = (C) c;
   if (LOG.isDebugEnabled()) LOG.debug("Released {}", connection);
   HttpClient client = getHttpClient();
   if (client.isRunning()) {
     if (connectionPool.isActive(connection)) {
       if (connectionPool.release(connection)) send();
       else connection.close();
     } else {
       if (LOG.isDebugEnabled()) LOG.debug("Released explicit {}", connection);
     }
   } else {
     if (LOG.isDebugEnabled()) LOG.debug("{} is stopped", client);
     connection.close();
   }
 }
  /**
   * Processes a new connection making it idle or active depending on whether requests are waiting
   * to be sent.
   *
   * <p>A new connection is created when a request needs to be executed; it is possible that the
   * request that triggered the request creation is executed by another connection that was just
   * released, so the new connection may become idle.
   *
   * <p>If a request is waiting to be executed, it will be dequeued and executed by the new
   * connection.
   *
   * @param connection the new connection
   * @param dispatch whether to dispatch the processing to another thread
   */
  protected void process(Connection connection, boolean dispatch) {
    // Ugly cast, but lack of generic reification forces it
    final HttpConnection httpConnection = (HttpConnection) connection;

    final HttpExchange exchange = exchanges.poll();
    if (exchange == null) {
      LOG.debug("{} idle", httpConnection);
      if (!idleConnections.offer(httpConnection)) {
        LOG.debug("{} idle overflow");
        httpConnection.close();
      }
      if (!client.isRunning()) {
        LOG.debug("{} is stopping", client);
        remove(httpConnection);
        httpConnection.close();
      }
    } else {
      final Request request = exchange.getRequest();
      Throwable cause = request.getAbortCause();
      if (cause != null) {
        abort(exchange, cause);
        LOG.debug("Aborted before processing {}: {}", exchange, cause);
      } else {
        LOG.debug("{} active", httpConnection);
        if (!activeConnections.offer(httpConnection)) {
          LOG.warn("{} active overflow");
        }
        if (dispatch) {
          client
              .getExecutor()
              .execute(
                  new Runnable() {
                    @Override
                    public void run() {
                      httpConnection.send(exchange);
                    }
                  });
        } else {
          httpConnection.send(exchange);
        }
      }
    }
  }