| /* |
| * ==================================================================== |
| * 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.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 LoggingAsyncRequestExecutor handler = new LoggingAsyncRequestExecutor(); |
| 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; |
| } |
| |
| } |