/**
*
*/
package org.frameworkset.spi.remote.http;
import org.apache.http.*;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.*;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.HttpConnectionFactory;
import org.apache.http.conn.ManagedHttpClientConnection;
import org.apache.http.conn.routing.HttpRoute;
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.entity.ContentType;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.*;
import org.apache.http.impl.io.DefaultHttpRequestWriterFactory;
import org.apache.http.io.HttpMessageParser;
import org.apache.http.io.HttpMessageParserFactory;
import org.apache.http.io.HttpMessageWriterFactory;
import org.apache.http.io.SessionInputBuffer;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicLineParser;
import org.apache.http.message.LineParser;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.CharArrayBuffer;
import org.frameworkset.spi.BaseApplicationContext;
import org.frameworkset.spi.BeanNameAware;
import org.frameworkset.spi.DefaultApplicationContext;
import org.frameworkset.spi.InitializingBean;
import javax.net.ssl.SSLContext;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.CodingErrorAction;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* This example demonstrates how to customize and configure the most common aspects
* of HTTP request execution and connection management.
*/
/**
* @author yinbp
*
* @Date:2016-11-20 11:50:36
*/
public class ClientConfiguration implements InitializingBean,BeanNameAware{
private final static int TIMEOUT_CONNECTION = 20000;
private final static int TIMEOUT_SOCKET = 20000;
private final static int RETRY_TIME = 3;
private CloseableHttpClient httpclient;
private static RequestConfig defaultRequestConfig ;
private RequestConfig requestConfig;
private static HttpClient defaultHttpclient;
private int timeoutConnection = TIMEOUT_CONNECTION;
private int timeoutSocket = TIMEOUT_SOCKET;
private int retryTime = RETRY_TIME;
private int maxLineLength = 2000;
private int maxHeaderCount = 200;
private int maxTotal = 200;
private int defaultMaxPerRoute = 10;
private String beanName;
private static Map<String,ClientConfiguration> clientConfigs = new HashMap<String,ClientConfiguration>();
private static BaseApplicationContext context;
private static void loadClientConfiguration(){
if(context == null)
context = DefaultApplicationContext.getApplicationContext("conf/httpclient.xml");
}
public static final ContentType TEXT_PLAIN_UTF_8 = ContentType.create(
"text/plain", Consts.UTF_8);
/**
*
*/
public ClientConfiguration() {
// TODO Auto-generated constructor stub
}
public static RequestConfig getDefaultRequestConfig() {
return defaultRequestConfig;
}
public int getTimeoutConnection() {
return timeoutConnection;
}
public void setTimeoutConnection(int timeoutConnection) {
this.timeoutConnection = timeoutConnection;
}
public int getTimeoutSocket() {
return timeoutSocket;
}
public void setTimeoutSocket(int timeoutSocket) {
this.timeoutSocket = timeoutSocket;
}
public int getRetryTime() {
return retryTime;
}
public void setRetryTime(int retryTime) {
this.retryTime = retryTime;
}
public final CloseableHttpClient getHttpClient() throws Exception {
if(httpclient != null)
return httpclient;
// synchronized(ClientConfiguration.class)
{
// if(httpclient != null)
// return httpclient;
// Use custom message parser / writer to customize the way HTTP
// messages are parsed from and written out to the data stream.
HttpMessageParserFactory<HttpResponse> responseParserFactory = new DefaultHttpResponseParserFactory() {
@Override
public HttpMessageParser<HttpResponse> create(
SessionInputBuffer buffer, MessageConstraints constraints) {
LineParser lineParser = new BasicLineParser() {
@Override
public Header parseHeader(final CharArrayBuffer buffer) {
try {
return super.parseHeader(buffer);
} catch (ParseException ex) {
return new BasicHeader(buffer.toString(), null);
}
}
};
return new DefaultHttpResponseParser(
buffer, lineParser, DefaultHttpResponseFactory.INSTANCE, constraints) {
@Override
protected boolean reject(final CharArrayBuffer line, int count) {
// try to ignore all garbage preceding a status line infinitely
return false;
}
};
}
};
HttpMessageWriterFactory<HttpRequest> requestWriterFactory = new DefaultHttpRequestWriterFactory();
// Use a custom connection factory to customize the process of
// initialization of outgoing HTTP connections. Beside standard connection
// configuration parameters HTTP connection factory can define message
// parser / writer routines to be employed by individual connections.
HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory = new ManagedHttpClientConnectionFactory(
requestWriterFactory, responseParserFactory);
// Client HTTP connection objects when fully initialized can be bound to
// an arbitrary network socket. The process of network socket initialization,
// its connection to a remote address and binding to a local one is controlled
// by a connection socket factory.
// SSL context for secure connections can be created either based on
// system or application specific properties.
SSLContext sslcontext = SSLContexts.createSystemDefault();
// Create a registry of custom connection socket factories for supported
// protocol schemes.
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslcontext))
.build();
// Use custom DNS resolver to override the system DNS resolution.
DnsResolver dnsResolver = new SystemDefaultDnsResolver() {
@Override
public InetAddress[] resolve(final String host) throws UnknownHostException {
if (host.equalsIgnoreCase("localhost")) {
return new InetAddress[] { InetAddress.getByAddress(new byte[] {127, 0, 0, 1}) };
} else {
return super.resolve(host);
}
}
};
// Create a connection manager with custom configuration.
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(
socketFactoryRegistry, connFactory, dnsResolver);
// Create socket configuration
SocketConfig socketConfig = SocketConfig.custom()
.setTcpNoDelay(true)
.setSoTimeout(timeoutSocket)
.build();
// Configure the connection manager to use socket configuration either
// by default or for a specific host.
connManager.setDefaultSocketConfig(socketConfig);
// connManager.setSocketConfig(new HttpHost("localhost", 80), socketConfig);
// Validate connections after 1 sec of inactivity
connManager.setValidateAfterInactivity(1000);
// Create message constraints
MessageConstraints messageConstraints = MessageConstraints.custom()
.setMaxHeaderCount(this.maxHeaderCount)
.setMaxLineLength(this.maxLineLength)
.build();
// Create connection configuration
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setMalformedInputAction(CodingErrorAction.IGNORE)
.setUnmappableInputAction(CodingErrorAction.IGNORE)
.setCharset(Consts.UTF_8)
.setMessageConstraints(messageConstraints)
.build();
// Configure the connection manager to use connection configuration either
// by default or for a specific host.
connManager.setDefaultConnectionConfig(connectionConfig);
// connManager.setConnectionConfig(new HttpHost("localhost", 80), ConnectionConfig.DEFAULT);
// Configure total max or per route limits for persistent connections
// that can be kept in the pool or leased by the connection manager.
connManager.setMaxTotal(maxTotal);
connManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
// connManager.setMaxPerRoute(new HttpRoute(new HttpHost("localhost", 80)), 20);
// Use custom cookie store if necessary.
CookieStore cookieStore = new BasicCookieStore();
// Use custom credentials provider if necessary.
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
// Create global request configuration
RequestConfig requestConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.DEFAULT)
.setExpectContinueEnabled(true)
.setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
.setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
.setConnectTimeout(this.timeoutConnection).setConnectionRequestTimeout(TIMEOUT_CONNECTION)
.build();
// Create an HttpClient with the given custom dependencies and configuration.
httpclient = HttpClients.custom()
.setConnectionManager(connManager)
.setDefaultCookieStore(cookieStore)
.setDefaultCredentialsProvider(credentialsProvider)
//.setProxy(new HttpHost("myproxy", 8080))
.setDefaultRequestConfig(requestConfig)
.build();
if(this.beanName.equals("default")){
defaultRequestConfig = requestConfig;
defaultHttpclient = httpclient;
}
clientConfigs.put(beanName, this);
}
return httpclient;
// try {
// HttpGet httpget = new HttpGet("http://www.baidu.com");
// // Request configuration can be overridden at the request level.
// // They will take precedence over the one set at the client level.
// RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
// .setSocketTimeout(5000)
// .setConnectTimeout(5000)
// .setConnectionRequestTimeout(5000)
// // .setProxy(new HttpHost("myotherproxy", 8080))
// .build();
// httpget.setConfig(requestConfig);
//
// // Execution context can be customized locally.
// HttpClientContext context = HttpClientContext.create();
// // Contextual attributes set the local context level will take
// // precedence over those set at the client level.
// context.setCookieStore(cookieStore);
// context.setCredentialsProvider(credentialsProvider);
//
// System.out.println("executing request " + httpget.getURI());
// CloseableHttpResponse response = httpclient.execute(httpget, context);
// try {
// System.out.println("----------------------------------------");
// System.out.println(response.getStatusLine());
// System.out.println(EntityUtils.toString(response.getEntity()));
// System.out.println("----------------------------------------");
//
// // Once the request has been executed the local context can
// // be used to examine updated state and various objects affected
// // by the request execution.
//
// // Last executed request
// context.getRequest();
// // Execution route
// context.getHttpRoute();
// // Target auth state
// context.getTargetAuthState();
// // Proxy auth state
// context.getTargetAuthState();
// // Cookie origin
// context.getCookieOrigin();
// // Cookie spec used
// context.getCookieSpec();
// // User security token
// context.getUserToken();
//
// } finally {
// response.close();
// }
// } finally {
// httpclient.close();
// }
}
public HttpClient getHttpclient() {
return httpclient;
}
public int getMaxTotal() {
return maxTotal;
}
public void setMaxTotal(int maxTotal) {
this.maxTotal = maxTotal;
}
public int getDefaultMaxPerRoute() {
return defaultMaxPerRoute;
}
public void setDefaultMaxPerRoute(int defaultMaxPerRoute) {
this.defaultMaxPerRoute = defaultMaxPerRoute;
}
/** (non-Javadoc)
* @see org.frameworkset.spi.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
this.getHttpClient();
}
/** (non-Javadoc)
* @see org.frameworkset.spi.BeanNameAware#setBeanName(java.lang.String)
*/
@Override
public void setBeanName(String name) {
this.beanName = name;
}
public static HttpClient getDefaultHttpclient() {
loadClientConfiguration();
return getDefaultClientConfiguration().getHttpclient();
}
private static ClientConfiguration defaultClientConfiguration;
public static ClientConfiguration getDefaultClientConfiguration(){
loadClientConfiguration();
if(defaultClientConfiguration != null)
return defaultClientConfiguration;
defaultClientConfiguration = context.getTBeanObject("default", ClientConfiguration.class);
return defaultClientConfiguration;
}
public static ClientConfiguration getClientConfiguration(String poolname){
loadClientConfiguration();
ClientConfiguration config = clientConfigs.get(poolname);
if(config != null)
return config;
config = context.getTBeanObject(poolname, ClientConfiguration.class);
return config;
}
public RequestConfig getRequestConfig() {
return requestConfig;
}
}