blob: 78aee8b337b72cb742a4e4cad33ab6e8092dc0d6 [file] [log] [blame]
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.nio.client;
import java.io.IOException;
import java.net.URI;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Future;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.auth.AuthSchemeRegistry;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.RedirectStrategy;
import org.apache.http.client.UserTokenHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.AuthPolicy;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.concurrent.BasicFuture;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.routing.HttpRoutePlanner;
import org.apache.http.cookie.CookieSpecRegistry;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.auth.DigestSchemeFactory;
import org.apache.http.impl.auth.KerberosSchemeFactory;
import org.apache.http.impl.auth.NTLMSchemeFactory;
import org.apache.http.impl.auth.SPNegoSchemeFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.DefaultUserTokenHandler;
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
import org.apache.http.impl.client.TargetAuthenticationStrategy;
import org.apache.http.impl.cookie.BestMatchSpecFactory;
import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
import org.apache.http.impl.cookie.IgnoreSpecFactory;
import org.apache.http.impl.cookie.NetscapeDraftSpecFactory;
import org.apache.http.impl.cookie.RFC2109SpecFactory;
import org.apache.http.impl.cookie.RFC2965SpecFactory;
import org.apache.http.impl.nio.DefaultHttpClientIODispatch;
import org.apache.http.impl.nio.conn.DefaultHttpAsyncRoutePlanner;
import org.apache.http.impl.nio.conn.PoolingClientAsyncConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.nio.client.methods.HttpAsyncMethods;
import org.apache.http.nio.conn.ClientAsyncConnectionManager;
import org.apache.http.nio.protocol.HttpAsyncRequestExecutionHandler;
import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.nio.reactor.IOReactorStatus;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.DefaultedHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.ImmutableHttpProcessor;
@Deprecated
public abstract class AbstractHttpAsyncClient implements HttpAsyncClient {
private final Log log = LogFactory.getLog(getClass());
private final ClientAsyncConnectionManager connmgr;
private final Queue<HttpAsyncRequestExecutionHandler<?>> queue;
private Thread reactorThread;
private BasicHttpProcessor mutableProcessor;
private ImmutableHttpProcessor protocolProcessor;
private ConnectionReuseStrategy reuseStrategy;
private ConnectionKeepAliveStrategy keepAliveStrategy;
private RedirectStrategy redirectStrategy;
private CookieSpecRegistry supportedCookieSpecs;
private CookieStore cookieStore;
private AuthSchemeRegistry supportedAuthSchemes;
private AuthenticationStrategy targetAuthStrategy;
private AuthenticationStrategy proxyAuthStrategy;
private CredentialsProvider credsProvider;
private HttpRoutePlanner routePlanner;
private UserTokenHandler userTokenHandler;
private HttpParams params;
private volatile boolean terminated;
protected AbstractHttpAsyncClient(final ClientAsyncConnectionManager connmgr) {
super();
this.connmgr = connmgr;
this.queue = new ConcurrentLinkedQueue<HttpAsyncRequestExecutionHandler<?>>();
}
protected AbstractHttpAsyncClient(final IOReactorConfig config) throws IOReactorException {
super();
final DefaultConnectingIOReactor defaultioreactor = new DefaultConnectingIOReactor(config);
defaultioreactor.setExceptionHandler(new InternalIOReactorExceptionHandler(this.log));
this.connmgr = new PoolingClientAsyncConnectionManager(defaultioreactor);
this.queue = new ConcurrentLinkedQueue<HttpAsyncRequestExecutionHandler<?>>();
}
protected abstract HttpParams createHttpParams();
protected abstract BasicHttpProcessor createHttpProcessor();
protected HttpContext createHttpContext() {
final HttpContext context = new BasicHttpContext();
context.setAttribute(
ClientContext.SCHEME_REGISTRY,
getConnectionManager().getSchemeRegistry());
context.setAttribute(
ClientContext.AUTHSCHEME_REGISTRY,
getAuthSchemes());
context.setAttribute(
ClientContext.COOKIESPEC_REGISTRY,
getCookieSpecs());
context.setAttribute(
ClientContext.COOKIE_STORE,
getCookieStore());
context.setAttribute(
ClientContext.CREDS_PROVIDER,
getCredentialsProvider());
return context;
}
protected ConnectionReuseStrategy createConnectionReuseStrategy() {
return new DefaultConnectionReuseStrategy();
}
protected ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy() {
return new DefaultConnectionKeepAliveStrategy();
}
protected AuthSchemeRegistry createAuthSchemeRegistry() {
final AuthSchemeRegistry registry = new AuthSchemeRegistry();
registry.register(
AuthPolicy.BASIC,
new BasicSchemeFactory());
registry.register(
AuthPolicy.DIGEST,
new DigestSchemeFactory());
registry.register(
AuthPolicy.NTLM,
new NTLMSchemeFactory());
registry.register(
AuthPolicy.SPNEGO,
new SPNegoSchemeFactory());
registry.register(
AuthPolicy.KERBEROS,
new KerberosSchemeFactory());
return registry;
}
protected CookieSpecRegistry createCookieSpecRegistry() {
final CookieSpecRegistry registry = new CookieSpecRegistry();
registry.register(
CookiePolicy.BEST_MATCH,
new BestMatchSpecFactory());
registry.register(
CookiePolicy.BROWSER_COMPATIBILITY,
new BrowserCompatSpecFactory());
registry.register(
CookiePolicy.NETSCAPE,
new NetscapeDraftSpecFactory());
registry.register(
CookiePolicy.RFC_2109,
new RFC2109SpecFactory());
registry.register(
CookiePolicy.RFC_2965,
new RFC2965SpecFactory());
registry.register(
CookiePolicy.IGNORE_COOKIES,
new IgnoreSpecFactory());
return registry;
}
protected AuthenticationStrategy createTargetAuthenticationStrategy() {
return new TargetAuthenticationStrategy();
}
protected AuthenticationStrategy createProxyAuthenticationStrategy() {
return new ProxyAuthenticationStrategy();
}
protected CookieStore createCookieStore() {
return new BasicCookieStore();
}
protected CredentialsProvider createCredentialsProvider() {
return new BasicCredentialsProvider();
}
protected HttpRoutePlanner createHttpRoutePlanner() {
return new DefaultHttpAsyncRoutePlanner(getConnectionManager().getSchemeRegistry());
}
protected UserTokenHandler createUserTokenHandler() {
return new DefaultUserTokenHandler();
}
public synchronized final HttpParams getParams() {
if (this.params == null) {
this.params = createHttpParams();
}
return this.params;
}
public synchronized void setParams(final HttpParams params) {
this.params = params;
}
public synchronized ClientAsyncConnectionManager getConnectionManager() {
return this.connmgr;
}
public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
if (this.reuseStrategy == null) {
this.reuseStrategy = createConnectionReuseStrategy();
}
return this.reuseStrategy;
}
public synchronized void setReuseStrategy(final ConnectionReuseStrategy reuseStrategy) {
this.reuseStrategy = reuseStrategy;
}
public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
if (this.keepAliveStrategy == null) {
this.keepAliveStrategy = createConnectionKeepAliveStrategy();
}
return this.keepAliveStrategy;
}
public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy keepAliveStrategy) {
this.keepAliveStrategy = keepAliveStrategy;
}
public synchronized final RedirectStrategy getRedirectStrategy() {
if (this.redirectStrategy == null) {
this.redirectStrategy = new DefaultRedirectStrategy();
}
return this.redirectStrategy;
}
public synchronized void setRedirectStrategy(final RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
public synchronized final AuthSchemeRegistry getAuthSchemes() {
if (this.supportedAuthSchemes == null) {
this.supportedAuthSchemes = createAuthSchemeRegistry();
}
return this.supportedAuthSchemes;
}
public synchronized void setAuthSchemes(final AuthSchemeRegistry authSchemeRegistry) {
this.supportedAuthSchemes = authSchemeRegistry;
}
public synchronized final CookieSpecRegistry getCookieSpecs() {
if (this.supportedCookieSpecs == null) {
this.supportedCookieSpecs = createCookieSpecRegistry();
}
return this.supportedCookieSpecs;
}
public synchronized void setCookieSpecs(final CookieSpecRegistry cookieSpecRegistry) {
this.supportedCookieSpecs = cookieSpecRegistry;
}
public synchronized final AuthenticationStrategy getTargetAuthenticationStrategy() {
if (this.targetAuthStrategy == null) {
this.targetAuthStrategy = createTargetAuthenticationStrategy();
}
return this.targetAuthStrategy;
}
public synchronized void setTargetAuthenticationStrategy(
final AuthenticationStrategy targetAuthStrategy) {
this.targetAuthStrategy = targetAuthStrategy;
}
public synchronized final AuthenticationStrategy getProxyAuthenticationStrategy() {
if (this.proxyAuthStrategy == null) {
this.proxyAuthStrategy = createProxyAuthenticationStrategy();
}
return this.proxyAuthStrategy;
}
public synchronized void setProxyAuthenticationStrategy(
final AuthenticationStrategy proxyAuthStrategy) {
this.proxyAuthStrategy = proxyAuthStrategy;
}
public synchronized final CookieStore getCookieStore() {
if (this.cookieStore == null) {
this.cookieStore = createCookieStore();
}
return this.cookieStore;
}
public synchronized void setCookieStore(final CookieStore cookieStore) {
this.cookieStore = cookieStore;
}
public synchronized final CredentialsProvider getCredentialsProvider() {
if (this.credsProvider == null) {
this.credsProvider = createCredentialsProvider();
}
return this.credsProvider;
}
public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) {
this.credsProvider = credsProvider;
}
public synchronized final HttpRoutePlanner getRoutePlanner() {
if (this.routePlanner == null) {
this.routePlanner = createHttpRoutePlanner();
}
return this.routePlanner;
}
public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
this.routePlanner = routePlanner;
}
public synchronized final UserTokenHandler getUserTokenHandler() {
if (this.userTokenHandler == null) {
this.userTokenHandler = createUserTokenHandler();
}
return this.userTokenHandler;
}
public synchronized void setUserTokenHandler(final UserTokenHandler userTokenHandler) {
this.userTokenHandler = userTokenHandler;
}
protected synchronized final BasicHttpProcessor getHttpProcessor() {
if (this.mutableProcessor == null) {
this.mutableProcessor = createHttpProcessor();
}
return this.mutableProcessor;
}
private synchronized final HttpProcessor getProtocolProcessor() {
if (this.protocolProcessor == null) {
// Get mutable HTTP processor
final BasicHttpProcessor proc = getHttpProcessor();
// and upgrade an immutable copy of it
final int reqc = proc.getRequestInterceptorCount();
final HttpRequestInterceptor[] reqinterceptors = new HttpRequestInterceptor[reqc];
for (int i = 0; i < reqc; i++) {
reqinterceptors[i] = proc.getRequestInterceptor(i);
}
final int resc = proc.getResponseInterceptorCount();
final HttpResponseInterceptor[] resinterceptors = new HttpResponseInterceptor[resc];
for (int i = 0; i < resc; i++) {
resinterceptors[i] = proc.getResponseInterceptor(i);
}
this.protocolProcessor = new ImmutableHttpProcessor(reqinterceptors, resinterceptors);
}
return this.protocolProcessor;
}
public synchronized int getResponseInterceptorCount() {
return getHttpProcessor().getResponseInterceptorCount();
}
public synchronized HttpResponseInterceptor getResponseInterceptor(final int index) {
return getHttpProcessor().getResponseInterceptor(index);
}
public synchronized HttpRequestInterceptor getRequestInterceptor(final int index) {
return getHttpProcessor().getRequestInterceptor(index);
}
public synchronized int getRequestInterceptorCount() {
return getHttpProcessor().getRequestInterceptorCount();
}
public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
getHttpProcessor().addInterceptor(itcp);
this.protocolProcessor = null;
}
public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, final int index) {
getHttpProcessor().addInterceptor(itcp, index);
this.protocolProcessor = null;
}
public synchronized void clearResponseInterceptors() {
getHttpProcessor().clearResponseInterceptors();
this.protocolProcessor = null;
}
public synchronized void removeResponseInterceptorByClass(final Class<? extends HttpResponseInterceptor> clazz) {
getHttpProcessor().removeResponseInterceptorByClass(clazz);
this.protocolProcessor = null;
}
public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
getHttpProcessor().addInterceptor(itcp);
this.protocolProcessor = null;
}
public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, final int index) {
getHttpProcessor().addInterceptor(itcp, index);
this.protocolProcessor = null;
}
public synchronized void clearRequestInterceptors() {
getHttpProcessor().clearRequestInterceptors();
this.protocolProcessor = null;
}
public synchronized void removeRequestInterceptorByClass(final Class<? extends HttpRequestInterceptor> clazz) {
getHttpProcessor().removeRequestInterceptorByClass(clazz);
this.protocolProcessor = null;
}
private void doExecute() {
final InternalRequestExecutor handler = new InternalRequestExecutor(this.log, new HttpAsyncRequestExecutor());
try {
final IOEventDispatch ioEventDispatch = new DefaultHttpClientIODispatch(handler, getParams());
this.connmgr.execute(ioEventDispatch);
} catch (final Exception ex) {
this.log.error("I/O reactor terminated abnormally", ex);
} finally {
this.terminated = true;
while (!this.queue.isEmpty()) {
final HttpAsyncRequestExecutionHandler<?> exchangeHandler = this.queue.remove();
exchangeHandler.cancel();
}
}
}
public IOReactorStatus getStatus() {
return this.connmgr.getStatus();
}
public synchronized void start() {
this.reactorThread = new Thread() {
@Override
public void run() {
doExecute();
}
};
this.reactorThread.start();
}
public void shutdown() throws InterruptedException {
try {
this.connmgr.shutdown(5000);
} catch (final IOException ex) {
this.log.error("I/O error shutting down", ex);
}
if (this.reactorThread != null) {
this.reactorThread.join();
}
}
@Override
public <T> Future<T> execute(
final HttpAsyncRequestProducer requestProducer,
final HttpAsyncResponseConsumer<T> responseConsumer,
final HttpContext context,
final FutureCallback<T> callback) {
if (this.terminated) {
throw new IllegalStateException("Client has been shut down");
}
final BasicFuture<T> future = new BasicFuture<T>(callback);
final ResultCallback<T> resultCallback = new DefaultResultCallback<T>(future, this.queue);
DefaultAsyncRequestDirector<T> httpexchange;
synchronized (this) {
final HttpContext defaultContext = createHttpContext();
HttpContext execContext;
if (context == null) {
execContext = defaultContext;
} else {
execContext = new DefaultedHttpContext(context, defaultContext);
}
httpexchange = new DefaultAsyncRequestDirector<T>(
this.log,
requestProducer,
responseConsumer,
execContext,
resultCallback,
this.connmgr,
getProtocolProcessor(),
getRoutePlanner(),
getConnectionReuseStrategy(),
getConnectionKeepAliveStrategy(),
getRedirectStrategy(),
getTargetAuthenticationStrategy(),
getProxyAuthenticationStrategy(),
getUserTokenHandler(),
getParams());
}
this.queue.add(httpexchange);
httpexchange.start();
return future;
}
@Override
public <T> Future<T> execute(
final HttpAsyncRequestProducer requestProducer,
final HttpAsyncResponseConsumer<T> responseConsumer,
final FutureCallback<T> callback) {
return execute(requestProducer, responseConsumer, new BasicHttpContext(), callback);
}
@Override
public Future<HttpResponse> execute(
final HttpHost target, final HttpRequest request, final HttpContext context,
final FutureCallback<HttpResponse> callback) {
return execute(
HttpAsyncMethods.create(target, request),
HttpAsyncMethods.createConsumer(),
context, callback);
}
@Override
public Future<HttpResponse> execute(
final HttpHost target, final HttpRequest request,
final FutureCallback<HttpResponse> callback) {
return execute(target, request, new BasicHttpContext(), callback);
}
@Override
public Future<HttpResponse> execute(
final HttpUriRequest request,
final FutureCallback<HttpResponse> callback) {
return execute(request, new BasicHttpContext(), callback);
}
@Override
public Future<HttpResponse> execute(
final HttpUriRequest request,
final HttpContext context,
final FutureCallback<HttpResponse> callback) {
HttpHost target;
try {
target = determineTarget(request);
} catch (final ClientProtocolException ex) {
final BasicFuture<HttpResponse> future = new BasicFuture<HttpResponse>(callback);
future.failed(ex);
return future;
}
return execute(target, request, context, callback);
}
private HttpHost determineTarget(final HttpUriRequest request) throws ClientProtocolException {
// A null target may be acceptable if there is a default target.
// Otherwise, the null target is detected in the director.
HttpHost target = null;
final URI requestURI = request.getURI();
if (requestURI.isAbsolute()) {
target = URIUtils.extractHost(requestURI);
if (target == null) {
throw new ClientProtocolException(
"URI does not specify a valid host name: " + requestURI);
}
}
return target;
}
}