com.king.platform.net.http.netty.NettyHttpClientBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of king-http-client Show documentation
Show all versions of king-http-client Show documentation
A asyncronous http client built ontop of netty.
// Copyright (C) king.com Ltd 2015
// https://github.com/king/king-http-client
// Author: Magnus Gustafsson
// License: Apache 2.0, https://raw.github.com/king/king-http-client/LICENSE-APACHE
package com.king.platform.net.http.netty;
import com.king.platform.net.http.ConfKeys;
import com.king.platform.net.http.HttpClient;
import com.king.platform.net.http.netty.backpressure.BackPressure;
import com.king.platform.net.http.netty.backpressure.NoBackPressure;
import com.king.platform.net.http.netty.eventbus.DefaultEventBus;
import com.king.platform.net.http.netty.eventbus.RootEventBus;
import com.king.platform.net.http.netty.metric.MetricCallback;
import com.king.platform.net.http.netty.metric.MetricCollector;
import com.king.platform.net.http.netty.metric.RecordedTimeStamps;
import com.king.platform.net.http.netty.pool.ChannelPool;
import com.king.platform.net.http.netty.pool.PoolingChannelPool;
import com.king.platform.net.http.netty.util.SystemTimeProvider;
import com.king.platform.net.http.netty.util.TimeProvider;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* Builder for creating a Netty implementation of HttpClient.
*
* Example on how to use this builder.
*
{@code
* NettyHttpClientBuilder nettyHttpClientBuilder = new NettyHttpClientBuilder();
* HttpClient httpClient = nettyHttpClientBuilder.createHttpClient();
* httpClient.start();
* }
*/
public class NettyHttpClientBuilder {
private int nioThreads = 2;
private int httpCallbackExecutorThreads;
private ThreadFactory nioThreadFactory;
private Executor httpCallbackExecutor;
private Timer cleanupTimer;
private TimeProvider timeProvider;
private RootEventBus rootEventBus;
private BackPressure executionBackPressure;
private ChannelPool channelPool;
private MetricCallback metricCallback;
private int keepAliveTimeoutMS = 30_000;
private final Map optionsMap = new HashMap<>();
/**
* Set the amount of nio threads used for netty io reactor - defaults to two.
* @param nioThreads the number of nio threads
* @return the builder
*/
public NettyHttpClientBuilder setNioThreads(int nioThreads) {
this.nioThreads = nioThreads;
return this;
}
/**
* Set an metric callback which can be used to collect metrics of each calls and the state of the client.
* @param metricCallback the metric callback implementation
* @return the builder
*/
public NettyHttpClientBuilder setMetricCallback(MetricCallback metricCallback) {
this.metricCallback = metricCallback;
return this;
}
/**
* Set the amount of threads used for http callbacks. Defaults to two.
* Can only be set if httpCallbackExecutor has not been set.
* @param httpCallbackExecutorThreads the number of threads
* @return the builder
*/
public NettyHttpClientBuilder setHttpCallbackExecutorThreads(int httpCallbackExecutorThreads) {
if (httpCallbackExecutor != null) {
throw new IllegalStateException("Can't set callback dispatcher threads when httpCallbackExecutor has already been set.");
}
this.httpCallbackExecutorThreads = httpCallbackExecutorThreads;
return this;
}
/**
* Set an custom executor used for http callbacks.
* Can only be set if httpCallbackExecutorThreads has not been set.
* @param executor the executor used for callbacks
* @return the builder
*/
public NettyHttpClientBuilder setHttpCallbackExecutor(Executor executor) {
if (httpCallbackExecutorThreads != 0) {
throw new IllegalStateException("Can't set httpCallbackExecutor when httpCallbackExecutorThreads has already been set.");
}
this.httpCallbackExecutor = executor;
return this;
}
/**
* Set an custom thread factory for netty nio.
* @param nioThreadFactory the thread factory.
* @return the builder
*/
public NettyHttpClientBuilder setNioThreadFactory(ThreadFactory nioThreadFactory) {
this.nioThreadFactory = nioThreadFactory;
return this;
}
/**
* Set a custom timer used for cleanup jobs
* @param cleanupTimer the cleanup timer
* @return the builder
*/
public NettyHttpClientBuilder setCleanupTimer(Timer cleanupTimer) {
this.cleanupTimer = cleanupTimer;
return this;
}
/**
* Set a custom timeProvider implementation
* @param timeProvider the time provider
* @return the builder
*/
public NettyHttpClientBuilder setTimeProvider(TimeProvider timeProvider) {
this.timeProvider = timeProvider;
return this;
}
/**
* Set what back pressure should be used for executing requests.
* @param executionBackPressure the back pressure implementation
* @return the builder
*/
public NettyHttpClientBuilder setExecutionBackPressure(BackPressure executionBackPressure) {
this.executionBackPressure = executionBackPressure;
return this;
}
/**
* Set a custom root event bus
* @param rootEventBus the root event bus
* @return the builder
*/
public NettyHttpClientBuilder setRootEventBus(RootEventBus rootEventBus) {
this.rootEventBus = rootEventBus;
return this;
}
/**
* Set a custom socket channel pool. Defaults to {@link com.king.platform.net.http.netty.pool.PoolingChannelPool}
* If no pooling of connections is wanted, please provide {@link com.king.platform.net.http.netty.pool.NoChannelPool}
* @param channelPool the channel pool to use
* @return the builder
*/
public NettyHttpClientBuilder setChannelPool(ChannelPool channelPool) {
this.channelPool = channelPool;
return this;
}
/**
* Set the timeout time in ms for keep alive connections. Defaults to 30000 ms
* @param ms the time after which the connection will be closed (in ms)
* @return the builder
*/
public NettyHttpClientBuilder setKeepAliveTimeoutMs(int ms) {
if (channelPool != null) {
throw new IllegalStateException("Can't set keep-alive timeout when a non-default channel pool has already been set.");
}
this.keepAliveTimeoutMS = ms;
return this;
}
/**
* Configure global settings for the http client. Most of the settings can be overridden on each request.
*
* @param key The {@link ConfKeys} field
* @param value The value
* @param Option value type - Defined by the {@link ConfKeys} field.
* @return the builder
*/
public NettyHttpClientBuilder setOption(ConfKeys key, T value) {
optionsMap.put(key, value);
return this;
}
/**
* Create a HttpClient instance with the current settings.
* @return the built HttpClient
*/
public HttpClient createHttpClient() {
List shutdownJobs = new ArrayList<>();
if (httpCallbackExecutor == null) {
if (httpCallbackExecutorThreads == 0) {
httpCallbackExecutorThreads = 2;
}
final ExecutorService executorService = Executors.newFixedThreadPool(httpCallbackExecutorThreads, newThreadFactory("HttpClient-HttpCallback"));
httpCallbackExecutor = executorService;
shutdownJobs.add(new NettyHttpClient.ShutdownJob() {
@Override
public void onShutdown() {
executorService.shutdown();
}
});
}
if (nioThreadFactory == null) {
this.nioThreadFactory = newThreadFactory("HttpClient-nio-event-loop");
}
if (cleanupTimer == null) {
cleanupTimer = new HashedWheelTimer(newThreadFactory("HttpClient-timers"));
shutdownJobs.add(new NettyHttpClient.ShutdownJob() {
@Override
public void onShutdown() {
cleanupTimer.stop();
}
});
}
if (timeProvider == null) {
timeProvider = new SystemTimeProvider();
}
if (rootEventBus == null) {
rootEventBus = new DefaultEventBus();
}
if (metricCallback == null) {
metricCallback = EMPTY_METRIC_CALLBACK;
} else {
new MetricCollector().wireMetricCallbackOnEventBus(metricCallback, rootEventBus);
}
if (channelPool == null) {
channelPool = new PoolingChannelPool(cleanupTimer, timeProvider, keepAliveTimeoutMS, metricCallback);
}
if (executionBackPressure == null) {
executionBackPressure = new NoBackPressure();
}
NettyHttpClient nettyHttpClient = new NettyHttpClient(nioThreads, nioThreadFactory, httpCallbackExecutor, cleanupTimer, timeProvider, executionBackPressure,
rootEventBus, channelPool);
for (NettyHttpClient.ShutdownJob shutdownJob : shutdownJobs) {
nettyHttpClient.addShutdownJob(shutdownJob);
}
for (Map.Entry entry : optionsMap.entrySet()) {
nettyHttpClient.setOption(entry.getKey(), entry.getValue());
}
return nettyHttpClient;
}
private ThreadFactory newThreadFactory(final String name) {
return new ThreadFactory() {
private int threadId = 0;
@Override
public Thread newThread(Runnable runnable) {
Thread t = new Thread(runnable, name + " " + ++threadId);
t.setDaemon(true);
return t;
}
};
}
private final static MetricCallback EMPTY_METRIC_CALLBACK = new MetricCallback() {
@Override
public void onClosedConnectionTo(String host) {
}
@Override
public void onCreatedConnectionTo(String host) {
}
@Override
public void onReusedConnectionTo(String host) {
}
@Override
public void onError(String host, RecordedTimeStamps recordedTimeStamps) {
}
@Override
public void onCompletedRequest(String host, RecordedTimeStamps recordedTimeStamps) {
}
@Override
public void onCreatedServerPool(String host) {
}
@Override
public void onRemovedServerPool(String host) {
}
@Override
public void onServerPoolClosedConnection(String host, int poolSize) {
}
@Override
public void onServerPoolAddedConnection(String host, int poolSize) {
}
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy