package com.sequenceiq.cloudbreak.client;
import static org.terracotta.modules.ehcache.store.TerracottaClusteredInstanceFactory.LOGGER;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.net.ssl.SSLContext;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.glassfish.jersey.apache.connector.ApacheClientProperties;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.JerseyClientBuilder;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
public class RestClientUtil {
// apache http connection pool defaults are constraining
// https://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html
private static final int MAX_TOTAL_CONNECTION = 100;
private static final int MAX_PER_ROUTE_CONNECTION = 20;
private static ConcurrentMap<ConfigKey, Client> clients = new ConcurrentHashMap<>();
private RestClientUtil() {
}
public static synchronized Client get() {
return get(new ConfigKey(false, false));
}
public static synchronized Client get(ConfigKey configKey) {
Client client = clients.get(configKey);
if (client == null) {
client = createClient(configKey);
clients.put(configKey, client);
}
LOGGER.info("RestClient cache size: {}, key: {}, fetched client: {}", clients.size(), configKey, client);
return client;
}
public static Client createClient(String serverCert, String clientCert, String clientKey) throws Exception {
return createClient(serverCert, clientCert, clientKey, false, null);
}
public static Client createClient(String serverCert, String clientCert, String clientKey, boolean debug, Class debugClass) throws Exception {
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(KeyStoreUtil.createTrustStore(serverCert), null)
.loadKeyMaterial(KeyStoreUtil.createKeyStore(clientCert, clientKey), "consul".toCharArray())
.build();
LOGGER.debug("Constructing jax rs client for config: server cert: {}, client cert: {}, debug: {}", serverCert, clientCert, debug);
ClientConfig config = new ClientConfig();
config.property(ClientProperties.FOLLOW_REDIRECTS, "false");
RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.create();
registryBuilder.register("http", PlainConnectionSocketFactory.getSocketFactory());
registryBuilder.register("https", new SSLConnectionSocketFactory(sslContext));
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager(registryBuilder.build());
connectionManager.setMaxTotal(MAX_TOTAL_CONNECTION);
connectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE_CONNECTION);
// tell the jersey config about the connection manager
config.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
config.connectorProvider(new ApacheConnectorProvider());
config.register(MultiPartFeature.class);
ClientBuilder builder = JerseyClientBuilder.newBuilder().withConfig(config);
if (debug) {
builder = builder.register(new LoggingFilter(java.util.logging.Logger.getLogger(debugClass.getName()),
true));
}
Client client = builder.build();
LOGGER.debug("Jax rs client has been constructed: {}, sslContext: {}", client, sslContext);
return client;
}
private static Client createClient(ConfigKey configKey) {
LOGGER.debug("Constructing jax rs client: {}", configKey);
ClientConfig config = new ClientConfig();
config.property(ClientProperties.FOLLOW_REDIRECTS, "false");
PoolingHttpClientConnectionManager connectionManager;
if (configKey.isSecure()) {
connectionManager = new PoolingHttpClientConnectionManager();
} else {
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", new SSLConnectionSocketFactory(CertificateTrustManager.sslContext(), CertificateTrustManager.hostnameVerifier()))
.build();
connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
}
connectionManager.setMaxTotal(MAX_TOTAL_CONNECTION);
connectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE_CONNECTION);
// tell the jersey config about the connection manager
config.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
config.connectorProvider(new ApacheConnectorProvider());
config.register(MultiPartFeature.class);
ClientBuilder builder = JerseyClientBuilder.newBuilder().withConfig(config);
if (configKey.isDebug()) {
builder = builder.register(new LoggingFilter(java.util.logging.Logger.getLogger(RestClientUtil.class.getName()), true));
}
Client client = builder.build();
SSLContext sslContext = client.getSslContext();
LOGGER.warn("RestClient has been constructed: {}, client: {}, sslContext: {}", configKey, client, sslContext);
return client;
}
}