Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.lontime.exthttp.provider.AbstractProvider Maven / Gradle / Ivy
package com.github.lontime.exthttp.provider;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import com.github.lontime.base.commonj.components.AbstractComponentLifecycle;
import com.github.lontime.base.commonj.components.ComponentInterfaceHelper;
import com.github.lontime.base.commonj.langs.Prioritized;
import com.github.lontime.base.commonj.utils.CollectionHelper;
import com.github.lontime.exthttp.common.ConfigKey;
import com.github.lontime.exthttp.common.Response;
import com.github.lontime.exthttp.configuration.ClientOption;
import com.github.lontime.exthttp.configuration.ConnectionOption;
import com.github.lontime.exthttp.configuration.OptionResolver;
import com.github.lontime.exthttp.configuration.WiretapSpec;
import com.github.lontime.exthttp.container.DisposableServerWrapper;
import com.github.lontime.exthttp.container.HttpInterceptorInterface;
import com.github.lontime.exthttp.container.ServerContainer;
import com.github.lontime.extjson.JSONInstance;
import com.github.lontime.extjson.TypeReference;
import io.netty.channel.ChannelOption;
import io.netty.channel.epoll.EpollChannelOption;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.util.AttributeKey;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.ByteBufFlux;
import reactor.netty.http.Http11SslContextSpec;
import reactor.netty.http.Http2SslContextSpec;
import reactor.netty.http.HttpProtocol;
import reactor.netty.http.client.HttpClient;
import reactor.netty.http.client.HttpClientResponse;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.tcp.DefaultSslContextSpec;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
import static reactor.netty.resources.ConnectionProvider.LEASING_STRATEGY_LIFO;
/**
* AbstractProvider.
* @author lontime
* @since 1.0
*/
public abstract class AbstractProvider extends AbstractComponentLifecycle implements Provider {
private Map clientMap = new ConcurrentHashMap<>();
private Map connectionMap = new ConcurrentHashMap<>();
private final ServerContainer serverContainer;
public AbstractProvider() {
this.serverContainer = new ServerContainer();
}
@Override
public void initialize() {
serverContainer.initialize();
}
@Override
public void start() {
serverContainer.start();
}
@Override
public void stop() {
serverContainer.stop();
}
@Override
public void destroy() {
serverContainer.destroy();
}
@Override
public HttpClient get(String name) {
return clientMap.computeIfAbsent(name, this::loadHttpClient);
}
@Override
public Mono> asyncPostForObject(String name, HttpHeaders headers, String uri, Object body, Class clazz) {
return asyncRequestForObject(name, HttpMethod.POST, headers, uri, body, clazz);
}
@Override
public Mono> asyncDeleteForObject(String name, HttpHeaders headers, String uri, Object body, Class clazz) {
return asyncRequestForObject(name, HttpMethod.DELETE, headers, uri, body, clazz);
}
@Override
public Mono> asyncPatchForObject(String name, HttpHeaders headers, String uri, Object body, Class clazz) {
return asyncRequestForObject(name, HttpMethod.PATCH, headers, uri, body, clazz);
}
@Override
public Mono> asyncGetForObject(String name, HttpHeaders headers, String uri, Class clazz) {
return asyncRequestForObject(name, HttpMethod.GET, headers, uri, null, clazz);
}
@Override
public Mono> asyncPostForObject(String name, HttpHeaders headers, String uri, Object body, TypeReference clazz) {
return asyncRequestForObject(name, HttpMethod.POST, headers, uri, body, clazz);
}
@Override
public Mono> asyncDeleteForObject(String name, HttpHeaders headers, String uri, Object body, TypeReference clazz) {
return asyncRequestForObject(name, HttpMethod.DELETE, headers, uri, body, clazz);
}
@Override
public Mono> asyncPatchForObject(String name, HttpHeaders headers, String uri, Object body, TypeReference clazz) {
return asyncRequestForObject(name, HttpMethod.PATCH, headers, uri, body, clazz);
}
@Override
public Mono> asyncGetForObject(String name, HttpHeaders headers, String uri, TypeReference clazz) {
return asyncRequestForObject(name, HttpMethod.GET, headers, uri, null, clazz);
}
private Mono> asyncRequestForObject(String name, HttpMethod method, HttpHeaders headers, String uri,
Object body, Class clazz) {
return request(name, method, headers, uri, body).map(s -> {
final T newBody = JSONInstance.get().parse(s.getT2(), clazz);
return buildResponse(s.getT1(), newBody);
});
}
private Mono> asyncRequestForObject(String name, HttpMethod method, HttpHeaders headers, String uri,
Object body, TypeReference reference) {
return request(name, method, headers, uri, body).map(s -> {
final T newBody = JSONInstance.get().parse(s.getT2(), reference);
return buildResponse(s.getT1(), newBody);
});
}
private Mono> request(String name, HttpMethod method, HttpHeaders headers, String uri, Object body) {
if (!headers.contains(HttpHeaderNames.CONTENT_TYPE)) {
headers.add(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
}
if (body == null) {
return get(name).headers(h -> h.add(headers))
.request(method).uri(uri)
.responseSingle((res, content) -> content.asString().map(s -> Tuples.of(res, s)));
}
final String string;
if (body instanceof String) {
string = (String) body;
} else {
string = JSONInstance.get().toJSONString(body);
}
final HttpClient httpClient = get(name);
return httpClient.headers(h -> h.add(headers))
.request(method).uri(uri)
.send(ByteBufFlux.fromString(Flux.just(string)))
.responseSingle((res, content) -> content.asString().map(s -> Tuples.of(res, s)));
}
private Response buildResponse(HttpClientResponse clientResponse, T body) {
final HttpHeaders entries = clientResponse.responseHeaders();
final Map map = new HashMap<>(Math.max(entries.size(), 4));
for (Map.Entry entry : entries) {
map.put(entry.getKey(), entry.getValue());
}
return Response.builder().status(clientResponse.status().code())
.headers(map).body(body).build();
}
@Override
public DisposableServerWrapper getServer(String name) {
return serverContainer.getServer(name);
}
@Override
public void close() {
reentrantStopAndRemoveHooklet();
}
private HttpClient loadHttpClient(String name) {
final ClientOption option = OptionResolver.getInstance().getClientOption(name);
final ConnectionProvider connection = getConnection(option.getConnectionName());
HttpClient httpClient = (connection == null) ? HttpClient.create() : HttpClient.create(connection);
if (CollectionHelper.isNotEmpty(option.getProtocols())) {
final int size = option.getProtocols().size();
final HttpProtocol[] protocols = new HttpProtocol[size];
for (int i = 0; i < size; i++) {
protocols[i] = option.getProtocols().get(0);
}
httpClient = httpClient.protocol(protocols);
}
if (option.getBaseUrl() != null) {
httpClient = httpClient.baseUrl(option.getBaseUrl());
}
if (option.getHost() != null) {
httpClient = httpClient.host(option.getHost());
}
if (option.getPort() != null) {
httpClient = httpClient.port(option.getPort());
}
if (option.getKeepAlive() != null) {
httpClient = httpClient.keepAlive(option.getKeepAlive());
}
if (option.getCompress() != null) {
httpClient = httpClient.compress(option.getCompress());
}
if (option.getDisableRetry() != null) {
httpClient = httpClient.disableRetry(option.getDisableRetry());
}
if (option.getSecure() != null && option.getSecure()) {
final DefaultSslContextSpec defaultSslContextSpec = DefaultSslContextSpec.forClient()
.configure(builder -> builder.trustManager(InsecureTrustManagerFactory.INSTANCE));
httpClient = httpClient.secure(spec -> spec.sslContext(defaultSslContextSpec));
}
if (option.getHttp11Secure() != null && option.getHttp11Secure()) {
final Http11SslContextSpec http11SslContextSpec = Http11SslContextSpec.forClient()
.configure(builder -> builder.trustManager(InsecureTrustManagerFactory.INSTANCE));
httpClient = httpClient.secure(spec -> spec.sslContext(http11SslContextSpec));
}
if (option.getHttp2Secure() != null && option.getHttp2Secure()) {
final Http2SslContextSpec http2SslContextSpec = Http2SslContextSpec.forClient()
.configure(builder -> builder.trustManager(InsecureTrustManagerFactory.INSTANCE));
httpClient = httpClient.secure(spec -> spec.sslContext(http2SslContextSpec));
}
if (option.getNoSSL() != null && option.getNoSSL()) {
httpClient = httpClient.noSSL();
}
if (option.getNoProxy() != null && option.getNoProxy()) {
httpClient = httpClient.noProxy();
}
if (option.getWiretapEnabled() != null) {
httpClient = httpClient.wiretap(option.getWiretapEnabled());
}
if (option.getResponseTimeout() != null) {
httpClient = httpClient.responseTimeout(option.getResponseTimeout());
}
if (option.getFollowRedirect() != null) {
if (option.getRedirect() != null) {
httpClient = httpClient.followRedirect(option.getFollowRedirect(), r -> {
final ClientOption.Redirect redirectOpts = option.getRedirect();
if (redirectOpts.getResponseTimeout() != null) {
r.responseTimeout(redirectOpts.getResponseTimeout());
}
if (CollectionHelper.isNotEmpty(redirectOpts.getHeaders())) {
redirectOpts.getHeaders().forEach((k, v) -> r.addHeader(k, v));
}
if (redirectOpts.getIsFollowRedirect() != null && redirectOpts.getIsFollowRedirect()) {
r.isFollowRedirect();
}
if (redirectOpts.getCookie() != null) {
r.addCookie(redirectOpts.getCookie());
}
});
} else {
httpClient = httpClient.followRedirect(option.getFollowRedirect());
}
}
if (option.getWiretapSpec() != null) {
final WiretapSpec wiretapSpec = option.getWiretapSpec();
httpClient = httpClient.wiretap(wiretapSpec.getCategory(), wiretapSpec.getLevel(),
wiretapSpec.getFormat(), wiretapSpec.getCharset());
}
if (CollectionHelper.isNotEmpty(option.getHeaders())) {
for (Map.Entry entry : option.getHeaders().entrySet()) {
final ConfigKey configKey = entry.getKey();
httpClient = httpClient.headers(h -> h.set(configKey.getKey(), configKey.parseValue(entry.getValue())));
}
}
if (CollectionHelper.isNotEmpty(option.getCookies())) {
for (Cookie cookie : option.getCookies()) {
httpClient = httpClient.cookie(cookie);
}
}
if (option.getCookieEncoder() != null && option.getCookieDecoder() != null) {
httpClient = httpClient.cookieCodec(option.getCookieEncoder().toCookieEncoder(), option.getCookieDecoder().toCookieDecoder());
} else if (option.getCookieEncoder() != null) {
httpClient = httpClient.cookieCodec(option.getCookieEncoder().toCookieEncoder());
}
if (option.getResponseDecoder() != null) {
httpClient = httpClient.httpResponseDecoder(s -> {
final ClientOption.ResponseDecoder decoder = option.getResponseDecoder();
if (decoder.getParseHttpAfterConnectRequest() != null) {
s.parseHttpAfterConnectRequest(decoder.getParseHttpAfterConnectRequest());
}
if (decoder.getInitialBufferSize() != null) {
s.initialBufferSize(decoder.getInitialBufferSize());
}
if (decoder.getMaxChunkSize() != null) {
s.maxChunkSize(decoder.getMaxChunkSize());
}
if (decoder.getMaxHeaderSize() != null) {
s.maxHeaderSize(decoder.getMaxHeaderSize());
}
if (decoder.getMaxInitialLineLength() != null) {
s.maxInitialLineLength(decoder.getMaxInitialLineLength());
}
if (decoder.getFailOnMissingResponse() != null) {
s.failOnMissingResponse(decoder.getFailOnMissingResponse());
}
if (decoder.getAllowDuplicateContentLengths() != null) {
s.allowDuplicateContentLengths(decoder.getAllowDuplicateContentLengths());
}
if (decoder.getValidateHeaders() != null) {
s.validateHeaders(decoder.getValidateHeaders());
}
if (decoder.getH2cMaxContentLength() != null) {
s.h2cMaxContentLength(decoder.getH2cMaxContentLength());
}
return s;
});
}
if (CollectionHelper.isNotEmpty(option.getAttrs())) {
for (Map.Entry entry : option.getNioChannelOptions().entrySet()) {
final ConfigKey configKey = entry.getKey();
httpClient = httpClient.attr(AttributeKey.valueOf(configKey.getKey()), configKey.parseValue(entry.getValue()));
}
}
if (CollectionHelper.isNotEmpty(option.getChannelOptions())) {
for (Map.Entry entry : option.getChannelOptions().entrySet()) {
final ConfigKey configKey = entry.getKey();
httpClient = httpClient.option(ChannelOption.valueOf(configKey.getKey()), configKey.parseValue(entry.getValue()));
}
}
if (CollectionHelper.isNotEmpty(option.getEpollChannelOptions())) {
for (Map.Entry entry : option.getEpollChannelOptions().entrySet()) {
final ConfigKey configKey = entry.getKey();
httpClient = httpClient.option(EpollChannelOption.valueOf(configKey.getKey()), configKey.parseValue(entry.getValue()));
}
}
if (CollectionHelper.isNotEmpty(option.getNioChannelOptions())) {
for (Map.Entry entry : option.getNioChannelOptions().entrySet()) {
final ConfigKey configKey = entry.getKey();
httpClient = httpClient.option(NioChannelOption.valueOf(configKey.getKey()), configKey.parseValue(entry.getValue()));
}
}
if (option.getProxy() != null) {
final ClientOption.Proxy proxy = option.getProxy();
httpClient = httpClient.proxy(p -> p.type(proxy.getType())
.address(InetSocketAddress.createUnresolved(proxy.getHost(), proxy.getPort())));
}
final List interfaceUnsorted = ComponentInterfaceHelper.get(HttpInterceptorInterface.class, name);
if (CollectionHelper.isNotEmpty(interfaceUnsorted)) {
final List interfaces = interfaceUnsorted.stream()
.sorted(Prioritized.COMPARATOR).collect(Collectors.toList());
httpClient = httpClient.doOnResolve(c -> interfaces.forEach(s -> s.onResolve(c)))
.doAfterResolve((c, address) -> interfaces.forEach(s -> s.afterResolve(c, address)))
.doOnResolveError((c, throwable) -> interfaces.forEach(s -> s.OnResolveError(c, throwable)))
.doOnRequest((r, c) -> interfaces.forEach(s -> s.onRequest(r, c)))
.doAfterRequest((r, c) -> interfaces.forEach(s -> s.afterRequest(r, c)))
.doOnRequestError((r, throwable) -> interfaces.forEach(s -> s.onRequestError(r, throwable)))
.doOnResponse((r, c) -> interfaces.forEach(s -> s.onResponse(r, c)))
.doOnResponseError((r, throwable) -> interfaces.forEach(s -> s.onResponseError(r, throwable)))
.doAfterResponseSuccess((r, c) -> interfaces.forEach(s -> s.afterResponseSuccess(r, c)));
}
if (option.getWarmup() != null && option.getWarmup()) {
httpClient.warmup().block();
}
return httpClient;
}
public ConnectionProvider getConnection(String name) {
if (name == null) {
return null;
}
return connectionMap.computeIfAbsent(name, this::loadConnection);
}
private ConnectionProvider loadConnection(String name) {
final ConnectionOption connectionOption = OptionResolver.getInstance().getConnectionOption(name);
final ConnectionOption.Pool pool = connectionOption.getPool();
final ConnectionProvider.Builder builder = ConnectionProvider.builder(connectionOption.getPool().getName());
if (pool.getMaxConnections() != null) {
builder.maxConnections(pool.getMaxConnections());
}
if (pool.getPendingAcquireMaxCount() != null) {
builder.pendingAcquireMaxCount(pool.getPendingAcquireMaxCount());
}
if (pool.getPendingAcquireTimeout() != null) {
builder.pendingAcquireTimeout(pool.getPendingAcquireTimeout());
}
if (pool.getMaxIdleTime() != null) {
builder.maxIdleTime(pool.getMaxIdleTime());
}
if (pool.getMaxLifeTime() != null) {
builder.maxLifeTime(pool.getMaxLifeTime());
}
if (pool.getEvictionInterval() != null) {
builder.evictInBackground(pool.getEvictionInterval());
}
if (LEASING_STRATEGY_LIFO.equals(pool.getLeasingStrategy())) {
builder.fifo();
}
if (pool.getDisposeTimeout() != null) {
builder.disposeTimeout(pool.getDisposeTimeout());
}
if (pool.getInactivePoolDisposeInterval() != null && pool.getPoolInactivity() != null) {
builder.disposeInactivePoolsInBackground(pool.getInactivePoolDisposeInterval(), pool.getPoolInactivity());
}
return builder.build();
}
}