Skip to content

Commit

Permalink
Issue #1350 - Dynamic selection of the transport to use based on ALPN…
Browse files Browse the repository at this point in the history
… on the client side.

Added javadocs and small changes after review.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
  • Loading branch information
sbordet committed Mar 8, 2019
1 parent aa211b0 commit 29913f9
Show file tree
Hide file tree
Showing 14 changed files with 373 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,20 @@

package org.eclipse.jetty.client;

/**
* <p>A destination for those network transports that are duplex (e.g. HTTP/1.1 and FastCGI).</p>
*
* @see MultiplexHttpDestination
*/
public class DuplexHttpDestination extends HttpDestination
{
public DuplexHttpDestination(HttpClient client, Origin origin)
{
this(client, new Info(origin, null));
this(client, new Key(origin, null));
}

public DuplexHttpDestination(HttpClient client, Info info)
public DuplexHttpDestination(HttpClient client, Key key)
{
super(client, info);
super(client, key);
}
}
31 changes: 13 additions & 18 deletions jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public class HttpClient extends ContainerLifeCycle
public static final String USER_AGENT = "Jetty/" + Jetty.VERSION;
private static final Logger LOG = Log.getLogger(HttpClient.class);

private final ConcurrentMap<HttpDestination.Info, HttpDestination> destinations = new ConcurrentHashMap<>();
private final ConcurrentMap<HttpDestination.Key, HttpDestination> destinations = new ConcurrentHashMap<>();
private final ProtocolHandlers handlers = new ProtocolHandlers();
private final List<Request.Listener> requestListeners = new ArrayList<>();
private final Set<ContentDecoder.Factory> decoderFactories = new ContentDecoderFactorySet();
Expand Down Expand Up @@ -542,15 +542,9 @@ private URI checkHost(URI uri)
* @see #getDestinations()
*/
public Destination getDestination(String scheme, String host, int port)
{
return destinationFor(scheme, host, port);
}

@Deprecated
protected HttpDestination destinationFor(String scheme, String host, int port)
{
Origin origin = createOrigin(scheme, host, port);
return resolveDestination(new HttpDestination.Info(origin, null));
return resolveDestination(new HttpDestination.Key(origin, null));
}

private Origin createOrigin(String scheme, String host, int port)
Expand All @@ -566,15 +560,15 @@ private Origin createOrigin(String scheme, String host, int port)
return new Origin(scheme, host, port);
}

private HttpDestination resolveDestination(HttpDestination.Info info)
private HttpDestination resolveDestination(HttpDestination.Key key)
{
HttpDestination destination = destinations.get(info);
HttpDestination destination = destinations.get(key);
if (destination == null)
{
destination = getTransport().newHttpDestination(info);
destination = getTransport().newHttpDestination(key);
// Start the destination before it's published to other threads.
addManaged(destination);
HttpDestination existing = destinations.putIfAbsent(info, destination);
HttpDestination existing = destinations.putIfAbsent(key, destination);
if (existing != null)
{
removeBean(destination);
Expand All @@ -592,7 +586,7 @@ private HttpDestination resolveDestination(HttpDestination.Info info)
protected boolean removeDestination(HttpDestination destination)
{
removeBean(destination);
return destinations.remove(destination.getInfo(), destination);
return destinations.remove(destination.getKey(), destination);
}

/**
Expand All @@ -606,14 +600,15 @@ public List<Destination> getDestinations()
protected void send(final HttpRequest request, List<Response.ResponseListener> listeners)
{
Origin origin = createOrigin(request.getScheme(), request.getHost(), request.getPort());
HttpDestination.Protocol protocol = null;
HttpClientTransport transport = getTransport();
HttpDestination.Key destinationKey = null;
if (transport instanceof HttpClientTransport.Dynamic)
protocol = ((HttpClientTransport.Dynamic)transport).getProtocol(request);
destinationKey = ((HttpClientTransport.Dynamic)transport).newDestinationKey(request, origin);
if (destinationKey == null)
destinationKey = new HttpDestination.Key(origin, null);
if (LOG.isDebugEnabled())
LOG.debug("Selected {} for {}", protocol, request);
HttpDestination.Info destinationInfo = new HttpDestination.Info(origin, protocol);
HttpDestination destination = resolveDestination(destinationInfo);
LOG.debug("Selected {} for {}", destinationKey, request);
HttpDestination destination = resolveDestination(destinationKey);
destination.send(request, listeners);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,35 +43,28 @@ public interface HttpClientTransport extends ClientConnectionFactory
* Sets the {@link HttpClient} instance on this transport.
* <p>
* This is needed because of a chicken-egg problem: in order to create the {@link HttpClient}
* a {@link HttpClientTransport} is needed, that therefore cannot have a reference yet to the
* a HttpClientTransport is needed, that therefore cannot have a reference yet to the
* {@link HttpClient}.
*
* @param client the {@link HttpClient} that uses this transport.
*/
public void setHttpClient(HttpClient client);

public HttpDestination newHttpDestination(HttpDestination.Info info);

/**
* Creates a new, transport-specific, {@link HttpDestination} object.
* <p>
* {@link HttpDestination} controls the destination-connection cardinality: protocols like
* HTTP have 1-N cardinality, while multiplexed protocols like HTTP/2 have a 1-1 cardinality.
*
* @param origin the destination origin
* @param key the destination key
* @return a new, transport-specific, {@link HttpDestination} object
* @deprecated use {@link #newHttpDestination(HttpDestination.Info)} instead
*/
@Deprecated
public default HttpDestination newHttpDestination(Origin origin)
{
return newHttpDestination(new HttpDestination.Info(origin, null));
}
public HttpDestination newHttpDestination(HttpDestination.Key key);

/**
* Establishes a physical connection to the given {@code address}.
*
* @param address the address to connect to
* @param address the address to connect to
* @param context the context information to establish the connection
*/
public void connect(InetSocketAddress address, Map<String, Object> context);
Expand All @@ -86,9 +79,19 @@ public default HttpDestination newHttpDestination(Origin origin)
*/
public void setConnectionPoolFactory(ConnectionPool.Factory factory);

/**
* Specifies whether a {@link HttpClientTransport} is dynamic.
*/
@FunctionalInterface
public interface Dynamic
{
public HttpDestination.Protocol getProtocol(HttpRequest request);
/**
* Creates a new Key with the given request and origin.
*
* @param request the request that triggers the creation of the Key
* @param origin the origin of the server for the request
* @return a Key that identifies a destination
*/
public HttpDestination.Key newDestinationKey(HttpRequest request, Origin origin);
}
}
Loading

0 comments on commit 29913f9

Please sign in to comment.