/*
* Copyright 2015 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.apiman.gateway.engine.es;
import io.apiman.common.util.ssl.KeyStoreUtil;
import io.apiman.common.util.ssl.KeyStoreUtil.Info;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.config.HttpClientConfig;
import io.searchbox.client.config.HttpClientConfig.Builder;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
/**
* Factory for creating elasticsearch clients.
*
* @author eric.wittmann@redhat.com
*/
public class DefaultESClientFactory extends AbstractClientFactory implements IESClientFactory {
/**
* Clears all the clients from the cache. Useful for unit testing.
*/
public static void clearClientCache() {
clients.clear();
}
/**
* Constructor.
*/
public DefaultESClientFactory() {
}
/**
* Creates a client from information in the config map.
* @param config the configuration
* @param defaultIndexName the default index to use if not specified in the config
* @return the ES client
*/
public JestClient createClient(Map<String, String> config, String defaultIndexName) {
JestClient client;
String indexName = config.get("client.index"); //$NON-NLS-1$
if (indexName == null) {
indexName = defaultIndexName;
}
client = createJestClient(config, indexName, defaultIndexName);
return client;
}
/**
* Creates a transport client from a configuration map.
* @param config the configuration
* @param indexName the name of the index
* @param defaultIndexName the default index name
* @return the ES client
*/
protected JestClient createJestClient(Map<String, String> config, String indexName, String defaultIndexName) {
String host = config.get("client.host"); //$NON-NLS-1$
String port = config.get("client.port"); //$NON-NLS-1$
String protocol = config.get("client.protocol"); //$NON-NLS-1$
String initialize = config.get("client.initialize"); //$NON-NLS-1$
if (initialize == null) {
initialize = "true"; //$NON-NLS-1$
}
if (StringUtils.isBlank(host)) {
throw new RuntimeException("Missing client.host configuration for ESRegistry."); //$NON-NLS-1$
}
if (StringUtils.isBlank(port)) {
throw new RuntimeException("Missing client.port configuration for ESRegistry."); //$NON-NLS-1$
}
if (StringUtils.isBlank(protocol)) {
protocol = "http"; //$NON-NLS-1$
}
String clientKey = "jest:" + host + ':' + port + '/' + indexName; //$NON-NLS-1$
synchronized (clients) {
if (clients.containsKey(clientKey)) {
return clients.get(clientKey);
} else {
StringBuilder builder = new StringBuilder();
builder.append(protocol);
builder.append("://"); //$NON-NLS-1$
builder.append(host);
builder.append(":"); //$NON-NLS-1$
builder.append(String.valueOf(port));
String connectionUrl = builder.toString();
JestClientFactory factory = new JestClientFactory();
Builder httpClientConfig = new HttpClientConfig.Builder(connectionUrl);
updateHttpConfig(httpClientConfig, config);
factory.setHttpClientConfig(httpClientConfig.build());
updateJestClientFactory(factory, config);
JestClient client = factory.getObject();
clients.put(clientKey, client);
if ("true".equals(initialize)) { //$NON-NLS-1$
initializeClient(client, indexName, defaultIndexName);
}
return client;
}
}
}
/**
* Update the http client config.
* @param httpClientConfig
* @param config
*/
protected void updateHttpConfig(Builder httpClientConfig, Map<String, String> config) {
String username = config.get("client.username"); //$NON-NLS-1$
String password = config.get("client.password"); //$NON-NLS-1$
String timeout = config.get("client.timeout"); //$NON-NLS-1$
if (StringUtils.isBlank(timeout)) {
timeout = "10000"; //$NON-NLS-1$
}
httpClientConfig
.connTimeout(new Integer(timeout))
.readTimeout(new Integer(timeout))
.maxTotalConnection(75)
.defaultMaxTotalConnectionPerRoute(75)
.multiThreaded(true);
if (!StringUtils.isBlank(username)) {
httpClientConfig.defaultCredentials(username, password);
}
if ("https".equals(config.get("protocol"))) { //$NON-NLS-1$ //$NON-NLS-2$
updateSslConfig(httpClientConfig, config);
}
}
/**
* @param httpConfig
* @param config
*/
@SuppressWarnings("nls")
private void updateSslConfig(Builder httpConfig, Map<String, String> config) {
try {
String clientKeystorePath = config.get("client-keystore");
String clientKeystorePassword = config.get("client-keystore.password");
String trustStorePath = config.get("trust-store");
String trustStorePassword = config.get("trust-store.password");
SSLContext sslContext = SSLContext.getInstance("TLS");
Info kPathInfo = new Info(clientKeystorePath, clientKeystorePassword);
Info tPathInfo = new Info(trustStorePath, trustStorePassword);
sslContext.init(KeyStoreUtil.getKeyManagers(kPathInfo), KeyStoreUtil.getTrustManagers(tPathInfo), null);
HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier();
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
SchemeIOSessionStrategy httpsIOSessionStrategy = new SSLIOSessionStrategy(sslContext, hostnameVerifier);
httpConfig.defaultSchemeForDiscoveredNodes("https");
httpConfig.sslSocketFactory(sslSocketFactory); // for sync calls
httpConfig.httpsIOSessionStrategy(httpsIOSessionStrategy); // for async calls
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Update the jest client factory with any settings.
* @param factory
* @param config
*/
protected void updateJestClientFactory(JestClientFactory factory, Map<String, String> config) {
}
}