All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.signalfx.shaded.jetty.client.HttpConversation Maven / Gradle / Ivy

//
//  ========================================================================
//  Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package com.signalfx.shaded.jetty.client;

import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedDeque;

import com.signalfx.shaded.jetty.client.api.Request;
import com.signalfx.shaded.jetty.client.api.Response;
import com.signalfx.shaded.jetty.util.AttributesMap;
import com.signalfx.shaded.jetty.util.log.Log;
import com.signalfx.shaded.jetty.util.log.Logger;

public class HttpConversation extends AttributesMap
{
    private static final Logger LOG = Log.getLogger(HttpConversation.class);

    private final Deque exchanges = new ConcurrentLinkedDeque<>();
    private volatile List listeners;

    public Deque getExchanges()
    {
        return exchanges;
    }

    /**
     * Returns the list of response listeners that needs to be notified of response events.
     * This list changes as the conversation proceeds, as follows:
     * 
    *
  1. * request R1 send => conversation.updateResponseListeners(null) *
      *
    • exchanges in conversation: E1
    • *
    • listeners to be notified: E1.listeners
    • *
    *
  2. *
  3. * response R1 arrived, 401 => conversation.updateResponseListeners(AuthenticationProtocolHandler.listener) *
      *
    • exchanges in conversation: E1
    • *
    • listeners to be notified: AuthenticationProtocolHandler.listener
    • *
    *
  4. *
  5. * request R2 send => conversation.updateResponseListeners(null) *
      *
    • exchanges in conversation: E1 + E2
    • *
    • listeners to be notified: E2.listeners + E1.listeners
    • *
    *
  6. *
  7. * response R2 arrived, 302 => conversation.updateResponseListeners(RedirectProtocolHandler.listener) *
      *
    • exchanges in conversation: E1 + E2
    • *
    • listeners to be notified: E2.listeners + RedirectProtocolHandler.listener
    • *
    *
  8. *
  9. * request R3 send => conversation.updateResponseListeners(null) *
      *
    • exchanges in conversation: E1 + E2 + E3
    • *
    • listeners to be notified: E3.listeners + E1.listeners
    • *
    *
  10. *
  11. * response R3 arrived, 200 => conversation.updateResponseListeners(null) *
      *
    • exchanges in conversation: E1 + E2 + E3
    • *
    • listeners to be notified: E3.listeners + E1.listeners
    • *
    *
  12. *
* Basically the override conversation listener replaces the first exchange response listener, * and we also notify the last exchange response listeners (if it's not also the first). * * This scheme allows for protocol handlers to not worry about other protocol handlers, or to worry * too much about notifying the first exchange response listeners, but still allowing a protocol * handler to perform completion activities while another protocol handler performs new ones (as an * example, the {@link AuthenticationProtocolHandler} stores the successful authentication credentials * while the {@link RedirectProtocolHandler} performs a redirect). * * @return the list of response listeners that needs to be notified of response events */ public List getResponseListeners() { return listeners; } /** * Requests to update the response listener, eventually using the given override response listener, * that must be notified instead of the first exchange response listeners. * This works in conjunction with {@link #getResponseListeners()}, returning the appropriate response * listeners that needs to be notified of response events. * * @param overrideListener the override response listener */ public void updateResponseListeners(Response.ResponseListener overrideListener) { // Create a new instance to avoid that iterating over the listeners // will notify a listener that may send a new request and trigger // another call to this method which will build different listeners // which may be iterated over when the iteration continues. HttpExchange firstExchange = exchanges.peekFirst(); HttpExchange lastExchange = exchanges.peekLast(); List listeners = new ArrayList<>(firstExchange.getResponseListeners().size() + lastExchange.getResponseListeners().size()); if (firstExchange == lastExchange) { // We don't have a conversation, just a single request. if (overrideListener != null) listeners.add(overrideListener); else listeners.addAll(firstExchange.getResponseListeners()); } else { // We have a conversation (e.g. redirect, authentication). // Order is important, we want to notify the last exchange first. listeners.addAll(lastExchange.getResponseListeners()); if (overrideListener != null) listeners.add(overrideListener); else listeners.addAll(firstExchange.getResponseListeners()); } if (LOG.isDebugEnabled()) LOG.debug("Exchanges in conversation {}, override={}, listeners={}", exchanges.size(), overrideListener, listeners); this.listeners = listeners; } /** *

Returns the total timeout for the conversation.

*

The conversation total timeout is the total timeout * of the first request in the conversation.

* * @return the total timeout of the conversation * @see Request#getTimeout() */ public long getTimeout() { HttpExchange firstExchange = exchanges.peekFirst(); return firstExchange == null ? 0 : firstExchange.getRequest().getTimeout(); } public boolean abort(Throwable cause) { HttpExchange exchange = exchanges.peekLast(); return exchange != null && exchange.abort(cause); } @Override public String toString() { return String.format("%s[%x]", HttpConversation.class.getSimpleName(), hashCode()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy