/* * Copyright (c) 2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.vplex.api; import java.io.IOException; import java.net.URI; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; 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.client.apache.ApacheHttpClient; import com.sun.jersey.client.apache.ApacheHttpClientHandler; /** * VPlex API client factory */ public class VPlexApiFactory { // Default maximum number of outstanding connections. private static final int DEFAULT_MAX_CONN = 300; // Default maximum number of outstanding connections per host. private static final int DEFAULT_MAX_CONN_PER_HOST = 100; // Default connection timeout in milliseconds. private static final int DEFAULT_CONN_TIMEOUT = 1000 * 30; // The default socket time in milliseconds. private static final int DEFAULT_SOCKET_TIMEOUT = 1000 * 60 * 60; // The default connection mgr timeout. private static final int DEFAULT_CONN_MGR_TIMEOUT = 1000 * 60 * 60; // The maximum number of outstanding connections. private int _maxConn = DEFAULT_MAX_CONN; // The maximum number of outstanding connections per host. private int _maxConnPerHost = DEFAULT_MAX_CONN_PER_HOST; // The connection timeout in milliseconds. private int _connTimeoutMs = DEFAULT_CONN_TIMEOUT; // The connection timeout in milliseconds. private int _socketTimeoutMs = DEFAULT_SOCKET_TIMEOUT; // Timeout to retrieve the connection from ConnectionManager. private int connManagerTimeout = DEFAULT_CONN_MGR_TIMEOUT; // Socket connection timeout in milliseconds. private int socketConnectionTimeoutMs = DEFAULT_CONN_TIMEOUT; // A map of client connections to VPlex Management Stations keyed // by the URI of the Management Station. private ConcurrentMap<String, VPlexApiClient> _clientMap; // The root HTTP client handler. private ApacheHttpClientHandler _clientHandler; // The singleton VPLEX client factory. private static VPlexApiFactory _instance = null; // Logger reference. private static Logger s_logger = LoggerFactory.getLogger(VPlexApiFactory.class); /** * Default constructor is private. */ private VPlexApiFactory() { } /** * Public static member to create or get a reference to the * singleton client factory. * * @return The VPLEX client factory. */ public static synchronized VPlexApiFactory getInstance() { if (_instance == null) { s_logger.info("Creating VPLEX client factory."); _instance = new VPlexApiFactory(); _instance.init(); } return _instance; } /** * Setter for the maximum number of outstanding connections. * * @param maxConn The maximum number of outstanding connections. */ public void setMaxConnections(int maxConn) { _maxConn = maxConn; } /** * Setter for the maximum number of outstanding connections per host. * * @param maxConnPerHost */ public void setMaxConnectionsPerHost(int maxConnPerHost) { _maxConnPerHost = maxConnPerHost; } /** * Setter for the connection timeout. * * @param connTimeoutMs The connection timeout in ms. */ public void setConnectionTimeoutMs(int connTimeoutMs) { _connTimeoutMs = connTimeoutMs; } /** * @param connManagerTimeout the connManagerTimeout to set */ public void setConnManagerTimeout(int connManagerTimeout) { this.connManagerTimeout = connManagerTimeout; } /** * @param socketConnectionTimeoutMs the socket connection timeout ms to set */ public void setSocketConnectionTimeoutMs(int socketConnectionTimeoutMs) { this.socketConnectionTimeoutMs = socketConnectionTimeoutMs; } /** * Initialize HTTP client */ private void init() { // Create the VPlex API client map. _clientMap = new ConcurrentHashMap<String, VPlexApiClient>(); // Setup the connection parameters. HttpConnectionManagerParams params = new HttpConnectionManagerParams(); params.setMaxTotalConnections(_maxConn); params.setDefaultMaxConnectionsPerHost(_maxConnPerHost); params.setConnectionTimeout(_connTimeoutMs); params.setSoTimeout(_socketTimeoutMs); params.setTcpNoDelay(true); // Create the HTTP connection manager for managing the set of HTTP // connections and set the configuration parameters. Also, make sure // idle connections are closed immediately to prevent a buildup of // connections in the CLOSE_WAIT state. MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager(); mgr.setParams(params); mgr.closeIdleConnections(0); // Create the HTTP client and set the handler for determining if an // HttpMethod should be retried after a recoverable exception during // execution. HttpClient client = new HttpClient(mgr); client.getParams().setConnectionManagerTimeout(connManagerTimeout); client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new HttpMethodRetryHandler() { @Override public boolean retryMethod(HttpMethod httpMethod, IOException e, int i) { return false; } }); // Create the client handler. _clientHandler = new ApacheHttpClientHandler(client); // Register the specific for the HTTPS protocol. Protocol.registerProtocol("https", new Protocol("https", new NonValidatingSocketFactory(), 443)); } /** * Get the VPlex API client for the VPlex Management Station identified * by the passed endpoint suing the passed username and password. * * @param endpoint VPlex Management Station endpoint URI. * @param username The user name to authenticate. * @param password The password to authenticate. * * @return Reference to a VPlexApiClient. */ public synchronized VPlexApiClient getClient(URI endpoint, String username, String password) { // Make the key dependent on user and password in case they // change for a client endpoint. StringBuilder clientKeyBuilder = new StringBuilder(); clientKeyBuilder.append(endpoint.toString()); clientKeyBuilder.append("_"); clientKeyBuilder.append(username); clientKeyBuilder.append("_"); clientKeyBuilder.append(password); String clientKey = clientKeyBuilder.toString(); VPlexApiClient vplexApiClient = _clientMap.get(clientKey); if (vplexApiClient == null) { s_logger.info("Creating new VPLEX client for the management server {}", endpoint); Client jerseyClient = new ApacheHttpClient(_clientHandler); RESTClient restClient = new RESTClient(jerseyClient, username, password); vplexApiClient = new VPlexApiClient(endpoint, restClient); _clientMap.putIfAbsent(clientKey, vplexApiClient); } return vplexApiClient; } }