com.signalfx.shaded.jetty.client.HttpConversation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of signalfx-codahale Show documentation
Show all versions of signalfx-codahale Show documentation
Dropwizard Codahale metrics plugin for signalfx
The newest version!
//
// ========================================================================
// 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:
*
* -
* request R1 send => conversation.updateResponseListeners(null)
*
* - exchanges in conversation: E1
* - listeners to be notified: E1.listeners
*
*
* -
* response R1 arrived, 401 => conversation.updateResponseListeners(AuthenticationProtocolHandler.listener)
*
* - exchanges in conversation: E1
* - listeners to be notified: AuthenticationProtocolHandler.listener
*
*
* -
* request R2 send => conversation.updateResponseListeners(null)
*
* - exchanges in conversation: E1 + E2
* - listeners to be notified: E2.listeners + E1.listeners
*
*
* -
* response R2 arrived, 302 => conversation.updateResponseListeners(RedirectProtocolHandler.listener)
*
* - exchanges in conversation: E1 + E2
* - listeners to be notified: E2.listeners + RedirectProtocolHandler.listener
*
*
* -
* request R3 send => conversation.updateResponseListeners(null)
*
* - exchanges in conversation: E1 + E2 + E3
* - listeners to be notified: E3.listeners + E1.listeners
*
*
* -
* response R3 arrived, 200 => conversation.updateResponseListeners(null)
*
* - exchanges in conversation: E1 + E2 + E3
* - listeners to be notified: E3.listeners + E1.listeners
*
*
*
* 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