/*
* Copyright (c) 2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.services.restutil;
import java.io.IOException;
import java.net.URI;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpMethodRetryHandler;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.client.apache.ApacheHttpClient;
import com.sun.jersey.client.apache.ApacheHttpClientHandler;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
abstract public class RestClientFactory {
private final Logger _log = LoggerFactory.getLogger(RestClientFactory.class);
private int _maxConn;
private int _maxConnPerHost;
private int _connTimeout;
private int connManagerTimeout;
private int _socketConnTimeout;
private boolean _needCertificateManager;
protected ApacheHttpClientHandler _clientHandler;
protected ConcurrentMap<String, RestClientItf> _clientMap;
private MultiThreadedHttpConnectionManager _connectionManager;
/**
* Maximum number of outstanding connections
*
* @param maxConn
*/
public void setMaxConnections(int maxConn) {
_maxConn = maxConn;
}
public int getMaxConnections() {
return _maxConn;
}
/**
* Maximum number of outstanding connections per host
*
* @param maxConnPerHost
*/
public void setMaxConnectionsPerHost(int maxConnPerHost) {
_maxConnPerHost = maxConnPerHost;
}
public int getMaxConnectionsPerHost() {
return _maxConnPerHost;
}
/**
* Connection timeout
*
* @param connectionTimeoutMs
*/
public void setConnectionTimeoutMs(int connectionTimeoutMs) {
_connTimeout = connectionTimeoutMs;
}
public int getConnectionTimeoutMs() {
return _connTimeout;
}
/**
* @return the connManagerTimeout
*/
public int getConnManagerTimeout() {
return connManagerTimeout;
}
/**
* @param connManagerTimeout the connManagerTimeout to set
*/
public void setConnManagerTimeout(int connManagerTimeout) {
this.connManagerTimeout = connManagerTimeout;
}
/**
* Socket connection timeout
*
* @param connectionTimeoutMs
*/
public void setSocketConnectionTimeoutMs(int connectionTimeoutMs) {
_socketConnTimeout = connectionTimeoutMs;
}
public int getSocketConnectionTimeoutMs() {
return _socketConnTimeout;
}
/**
* If Factory should create a ApacheHTTPClient client with Cetificate Manager
*
* @param need
*/
public void setNeedCertificateManager(boolean need) {
_needCertificateManager = need;
}
public boolean getNeedCertificateManager() {
return _needCertificateManager;
}
/**
* Initialize HTTP client
*/
public void init() {
_clientMap = new ConcurrentHashMap<String, RestClientItf>();
_log.info("Init");
HttpConnectionManagerParams params = new HttpConnectionManagerParams();
params.setDefaultMaxConnectionsPerHost(_maxConnPerHost);
params.setMaxTotalConnections(_maxConn);
params.setTcpNoDelay(true);
params.setConnectionTimeout(_connTimeout);
params.setSoTimeout(_socketConnTimeout);
_connectionManager = new MultiThreadedHttpConnectionManager();
_connectionManager.setParams(params);
_connectionManager.closeIdleConnections(0); // close idle connections immediately
HttpClient client = new HttpClient(_connectionManager);
client.getParams().setConnectionManagerTimeout(connManagerTimeout);
client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new HttpMethodRetryHandler() {
@Override
public boolean retryMethod(HttpMethod httpMethod, IOException e, int i) {
return false;
}
});
// client.
if (_needCertificateManager) {
// TMP CODE to create dummy security certificate manager
ClientConfig clientConfig = null;
try {
final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted(final X509Certificate[] chain, final String authType) {
}
@Override
public void checkServerTrusted(final X509Certificate[] chain, final String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
} };
// Install the all-trusting trust manager
SSLContext sslContext;
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
javax.net.ssl.HostnameVerifier hostVerifier = new javax.net.ssl.HostnameVerifier() {
@Override
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
return true;
}
};
clientConfig = new com.sun.jersey.client.apache.config.DefaultApacheHttpClientConfig();
clientConfig.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
new HTTPSProperties(hostVerifier, sslContext));
} catch (GeneralSecurityException ex) {
throw new RuntimeException("Failed to obtain ApacheHTTPClient Config");
}
_clientHandler = new ApacheHttpClientHandler(client, clientConfig);
} else {
_clientHandler = new ApacheHttpClientHandler(client);
}
Protocol.registerProtocol("https", new Protocol("https", new NonValidatingSocketFactory(), 443));
}
/**
* shutdown http connection manager.
*/
protected void shutdown() {
_connectionManager.shutdown();
}
public RestClientItf getRESTClient(URI endpoint, String username, String password, boolean authFilter) {
RestClientItf clientApi = _clientMap.get(endpoint.toString() + ":" + username + ":" + password);
if (clientApi == null) {
Client jerseyClient = new ApacheHttpClient(_clientHandler);
if (authFilter) {
jerseyClient.addFilter(new HTTPBasicAuthFilter(username, password));
}
clientApi = createNewRestClient(endpoint, username, password, jerseyClient);
_clientMap.putIfAbsent(endpoint.toString() + ":" + username + ":" + password, clientApi);
}
return clientApi;
}
/**
* Remove the connection from the cache.
*
* @param endpoint
* @param username
* @param password
*/
public void removeRESTClient(URI endpoint, String username, String password) {
String clientKey = endpoint.toString() + ":" + username + ":" + password;
RestClientItf clientApi = _clientMap.get(clientKey);
if (null != clientApi) {
_clientMap.remove(clientKey);
}
}
public RestClientItf getRESTClient(URI endpoint, String username, String password) {
RestClientItf clientApi = _clientMap.get(endpoint.toString() + ":" + username + ":" + password);
if (clientApi == null) {
Client jerseyClient = new ApacheHttpClient(_clientHandler);
clientApi = createNewRestClient(endpoint, username, password, jerseyClient);
_clientMap.putIfAbsent(endpoint.toString() + ":" + username + ":" + password, clientApi);
}
return clientApi;
}
abstract protected RestClientItf createNewRestClient(URI endpoint, String username, String password,
com.sun.jersey.api.client.Client client);
protected Client getBaseClient(URI endpoint, String username, String password, boolean authFilter) {
Client jerseyClient = new ApacheHttpClient(_clientHandler);
if (authFilter) {
jerseyClient.addFilter(new HTTPBasicAuthFilter(username, password));
}
return jerseyClient;
}
}