/** * */ package jframe.httpclient.service.impl; import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.Charset; import java.util.Map; import java.util.concurrent.TimeUnit; import org.apache.http.Consts; import org.apache.http.HeaderElement; import org.apache.http.HeaderElementIterator; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.conn.ConnectionKeepAliveStrategy; import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicHeaderElementIterator; import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import jframe.core.plugin.annotation.InjectPlugin; import jframe.core.plugin.annotation.Injector; import jframe.core.plugin.annotation.Start; import jframe.core.plugin.annotation.Stop; import jframe.httpclient.HttpClientConfig; import jframe.httpclient.HttpClientPlugin; import jframe.httpclient.service.HttpClientService; /** * * @author dzh * @date Dec 2, 2014 12:11:23 PM * @since 1.0 */ @Injector public class HttpClientServiceImpl implements HttpClientService { HttpClientServiceImpl() { } static Logger LOG = LoggerFactory.getLogger(HttpClientServiceImpl.class); static String FILE_CONF = "file.httpclient"; private CloseableHttpClient httpClient; private IdleConnectionMonitorThread IdleConnectionMonitorThread; @InjectPlugin static HttpClientPlugin plugin; static RequestConfig requestConfig; @Start public void start() { try { HttpClientConfig.init(plugin.getConfig(FILE_CONF)); requestConfig = RequestConfig.custom() .setSocketTimeout( Integer.parseInt(HttpClientConfig.getConf(null, HttpClientConfig.HTTP_SO_TIMEOUT, "6000"))) .setConnectTimeout(Integer .parseInt(HttpClientConfig.getConf(null, HttpClientConfig.HTTP_CONN_TIMEOUT, "3000"))) .build(); // SSLContext sslContext = SSLContexts.createSystemDefault(); // SSLConnectionSocketFactory sslsf = new // SSLConnectionSocketFactory( // sslContext, // SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER); // KeyStore myTrustStore = <...> // SSLContext sslContext = SSLContexts.custom() // .useTLS() // .loadTrustMaterial(myTrustStore) // .build(); // SSLConnectionSocketFactory sslsf = new // SSLConnectionSocketFactory(sslContext); // ConnectionSocketFactory plainsf = <...> // LayeredConnectionSocketFactory sslsf = <...> // Registry<ConnectionSocketFactory> r = // RegistryBuilder.<ConnectionSocketFactory>create() // .register("http", plainsf) // .register("https", sslsf) // .build(); // HttpClientConnectionManager cm = new // PoolingHttpClientConnectionManager(r); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); cm.setMaxTotal(Integer.parseInt(HttpClientConfig.getConf(null, HttpClientConfig.HTTP_MAX_CONN, "200"))); cm.setDefaultMaxPerRoute( Integer.parseInt(HttpClientConfig.getConf(null, HttpClientConfig.HTTP_MAX_CONN_ROUTE, "60"))); for (String host : HttpClientConfig.getHosts()) { String maxConn = HttpClientConfig.getConf(host, HttpClientConfig.HTTP_MAX_CONN, null); if (null == maxConn) { continue; } HttpHost localhost = new HttpHost(HttpClientConfig.getConf(host, HttpClientConfig.IP), Integer.parseInt(HttpClientConfig.getConf(host, HttpClientConfig.PORT, "80"))); cm.setMaxPerRoute(new HttpRoute(localhost), Integer.parseInt(maxConn)); } // _httpClient.getParams().setIntParameter("http.socket.timeout", // 5000); ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() { public long getKeepAliveDuration(HttpResponse response, HttpContext context) { // Honor 'keep-alive' header HeaderElementIterator it = new BasicHeaderElementIterator( response.headerIterator(HTTP.CONN_KEEP_ALIVE)); while (it.hasNext()) { HeaderElement he = it.nextElement(); String param = he.getName(); String value = he.getValue(); if (value != null && param.equalsIgnoreCase("timeout")) { try { return Long.parseLong(value) * 1000; } catch (NumberFormatException ignore) { } } } String keepAlive = null; HttpHost target = (HttpHost) context.getAttribute(HttpClientContext.HTTP_TARGET_HOST); for (String host : HttpClientConfig.getHosts()) { String ip = HttpClientConfig.getConf(host, HttpClientConfig.IP, "0"); if (target.getHostName().equals(ip)) { keepAlive = HttpClientConfig.getConf(host, HttpClientConfig.HTTP_KEEP_ALIVE, null); break; } } if (keepAlive == null) { keepAlive = HttpClientConfig.getConf(null, HttpClientConfig.HTTP_KEEP_ALIVE, "10"); } return Integer.parseInt(keepAlive) * 1000; } }; httpClient = HttpClients.custom().setConnectionManager(cm).setKeepAliveStrategy(myStrategy).build(); IdleConnectionMonitorThread = new IdleConnectionMonitorThread(cm); IdleConnectionMonitorThread.start(); } catch (Exception e) { LOG.error("HttpClientServiceImpl init error {}!", e.getMessage()); } } @Stop public void stop() { if (IdleConnectionMonitorThread != null) { IdleConnectionMonitorThread.shutdown(); } if (httpClient != null) try { httpClient.close(); } catch (Exception e) { LOG.error(e.getMessage()); } LOG.info("HttpClientServiceImpl closed!"); } public static class IdleConnectionMonitorThread extends Thread { private final HttpClientConnectionManager connMgr; private volatile boolean shutdown; public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) { super(); this.connMgr = connMgr; } @Override public void run() { try { while (!shutdown) { synchronized (this) { wait(5000); // TODO // Close expired connections connMgr.closeExpiredConnections(); // Optionally, close connections // that have been idle longer than 30 sec connMgr.closeIdleConnections( Integer.parseInt( HttpClientConfig.getConf(null, HttpClientConfig.HTTP_IDLE_CONN_CLOSE, "30")), TimeUnit.SECONDS); } } } catch (InterruptedException ex) { LOG.error(ex.getMessage()); } } public void shutdown() { shutdown = true; synchronized (this) { notifyAll(); } } } @Override public <T> T send(String id, String path, String data, Map<String, String> headers, Map<String, String> paras) throws Exception { LOG.debug("HttpClientServiceImpl.send {} {} {}", id, path, data); // String ip = paras != null && paras.containsKey("ip") ? paras.get("ip") : HttpClientConfig.getConf(id, HttpClientConfig.IP); String port = paras != null && paras.containsKey("port") ? paras.get("port") : HttpClientConfig.getConf(id, HttpClientConfig.PORT, "80"); HttpHost target = new HttpHost(ip, Integer.parseInt(port), HttpHost.DEFAULT_SCHEME_NAME); HttpRequestBase request; String mehtod = HttpClientConfig.getConf(id, HttpClientConfig.HTTP_METHOD, HttpClientConfig.M_POST); if (HttpClientConfig.M_GET.equals(mehtod)) { request = new HttpGet(target.toURI() + path + "?" + data); } else { request = new HttpPost(target.toURI() + path); String mimeType = paras == null ? "text/plain" : paras.get(P_MIMETYPE); ((HttpPost) request).setEntity(new StringEntity(data, ContentType.create(mimeType, HttpClientConfig.getConf(id, HttpClientConfig.HTTP_CHARSET)))); } request.setConfig(requestConfig); if (headers != null) { for (String key : headers.keySet()) { request.addHeader(key, headers.get(key)); } } CloseableHttpResponse rsp = null; try { rsp = httpClient.execute(request); // ResponseHandler<String> responseHandler = new // ResponseHandler<String>() { // // @Override // public String handleResponse( // final HttpResponse response) throws ClientProtocolException, // IOException { // int status = response.getStatusLine().getStatusCode(); // if (status >= 200 && status < 300) { // HttpEntity entity = response.getEntity(); // return entity != null ? EntityUtils.toString(entity) : null; // } else { // throw new ClientProtocolException("Unexpected response status: " // + status); // } // } // // }; HttpEntity entity = rsp.getEntity(); ContentType contentType = ContentType.get(entity); if (contentType == null) { contentType = ContentType.APPLICATION_JSON; } Charset charset = paras.containsKey("rsp.charset") ? Charset.forName(paras.get("rsp.charset")) : contentType.getCharset(); // TODO decode by mime-type if ("application/json".equalsIgnoreCase(contentType.getMimeType())) { Reader reader = new InputStreamReader(entity.getContent(), charset == null ? Consts.UTF_8 : charset); return GSON.fromJson(reader, new TypeToken<T>() { }.getType()); // } else { return (T) EntityUtils.toString(entity, charset); } } finally { if (rsp != null) { EntityUtils.consume(rsp.getEntity()); rsp.close(); } } } static final Gson GSON = new GsonBuilder().create(); // // public static final String toJson(Object obj) { // return gson.toJson(obj); // } // // public static final <T> T fromJson(String json, Class<T> clazz) { // return gson.fromJson(json, clazz); // } @Override public <T> T sendGroup(String gid, String path, String data, Map<String, String> headers, Map<String, String> paras) throws Exception { throw new Exception(""); } @Override public <T> T sendRandom(String path, String data, Map<String, String> headers, Map<String, String> paras) throws Exception { throw new Exception(""); } @Override public <T> T sendAll(String path, String data, Map<String, String> headers, Map<String, String> paras) throws Exception { throw new Exception(""); } public static HttpClientService testHttpClient(String httpclient) { try { HttpClientConfig.init(httpclient); // SSLContext sslContext = SSLContexts.createSystemDefault(); // SSLConnectionSocketFactory sslsf = new // SSLConnectionSocketFactory( // sslContext, // SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER); // KeyStore myTrustStore = <...> // SSLContext sslContext = SSLContexts.custom() // .useTLS() // .loadTrustMaterial(myTrustStore) // .build(); // SSLConnectionSocketFactory sslsf = new // SSLConnectionSocketFactory(sslContext); // ConnectionSocketFactory plainsf = <...> // LayeredConnectionSocketFactory sslsf = <...> // Registry<ConnectionSocketFactory> r = // RegistryBuilder.<ConnectionSocketFactory>create() // .register("http", plainsf) // .register("https", sslsf) // .build(); // HttpClientConnectionManager cm = new // PoolingHttpClientConnectionManager(r); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); cm.setMaxTotal(Integer.parseInt(HttpClientConfig.getConf(null, HttpClientConfig.HTTP_MAX_CONN, "200"))); cm.setDefaultMaxPerRoute( Integer.parseInt(HttpClientConfig.getConf(null, HttpClientConfig.HTTP_MAX_CONN_ROUTE, "60"))); for (String host : HttpClientConfig.getHosts()) { String maxConn = HttpClientConfig.getConf(host, HttpClientConfig.HTTP_MAX_CONN, null); if (null == maxConn) { continue; } HttpHost localhost = new HttpHost(HttpClientConfig.getConf(host, HttpClientConfig.IP), Integer.parseInt(HttpClientConfig.getConf(host, HttpClientConfig.PORT, "80"))); cm.setMaxPerRoute(new HttpRoute(localhost), Integer.parseInt(maxConn)); } // _httpClient.getParams().setIntParameter("http.socket.timeout", // 5000); ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() { public long getKeepAliveDuration(HttpResponse response, HttpContext context) { // Honor 'keep-alive' header HeaderElementIterator it = new BasicHeaderElementIterator( response.headerIterator(HTTP.CONN_KEEP_ALIVE)); while (it.hasNext()) { HeaderElement he = it.nextElement(); String param = he.getName(); String value = he.getValue(); if (value != null && param.equalsIgnoreCase("timeout")) { try { return Long.parseLong(value) * 1000; } catch (NumberFormatException ignore) { } } } String keepAlive = null; HttpHost target = (HttpHost) context.getAttribute(HttpClientContext.HTTP_TARGET_HOST); for (String host : HttpClientConfig.getHosts()) { String ip = HttpClientConfig.getConf(host, HttpClientConfig.IP, "0"); if (target.getHostName().equals(ip)) { keepAlive = HttpClientConfig.getConf(host, HttpClientConfig.HTTP_KEEP_ALIVE, null); break; } } if (keepAlive == null) { keepAlive = HttpClientConfig.getConf(null, HttpClientConfig.HTTP_KEEP_ALIVE, "10"); } return Integer.parseInt(keepAlive) * 1000; } }; // httpClient = HttpClients.custom().setConnectionManager(cm) // .setKeepAliveStrategy(myStrategy).build(); // // IdleConnectionMonitorThread = new IdleConnectionMonitorThread( // cm); // IdleConnectionMonitorThread.start(); } catch (Exception e) { LOG.error("HttpClientServiceImpl init error {}!", e.getMessage()); } // return this; return null; } }