View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.http.impl.nio.client;
28  
29  import java.io.IOException;
30  import java.net.URI;
31  import java.util.Queue;
32  import java.util.concurrent.ConcurrentLinkedQueue;
33  import java.util.concurrent.Future;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.http.ConnectionReuseStrategy;
38  import org.apache.http.HttpHost;
39  import org.apache.http.HttpRequest;
40  import org.apache.http.HttpRequestInterceptor;
41  import org.apache.http.HttpResponse;
42  import org.apache.http.HttpResponseInterceptor;
43  import org.apache.http.auth.AuthSchemeRegistry;
44  import org.apache.http.client.AuthenticationStrategy;
45  import org.apache.http.client.ClientProtocolException;
46  import org.apache.http.client.CookieStore;
47  import org.apache.http.client.CredentialsProvider;
48  import org.apache.http.client.RedirectStrategy;
49  import org.apache.http.client.UserTokenHandler;
50  import org.apache.http.client.methods.HttpUriRequest;
51  import org.apache.http.client.params.AuthPolicy;
52  import org.apache.http.client.params.CookiePolicy;
53  import org.apache.http.client.protocol.ClientContext;
54  import org.apache.http.client.utils.URIUtils;
55  import org.apache.http.concurrent.BasicFuture;
56  import org.apache.http.concurrent.FutureCallback;
57  import org.apache.http.conn.ConnectionKeepAliveStrategy;
58  import org.apache.http.conn.routing.HttpRoutePlanner;
59  import org.apache.http.cookie.CookieSpecRegistry;
60  import org.apache.http.impl.DefaultConnectionReuseStrategy;
61  import org.apache.http.impl.auth.BasicSchemeFactory;
62  import org.apache.http.impl.auth.DigestSchemeFactory;
63  import org.apache.http.impl.auth.KerberosSchemeFactory;
64  import org.apache.http.impl.auth.NTLMSchemeFactory;
65  import org.apache.http.impl.auth.SPNegoSchemeFactory;
66  import org.apache.http.impl.client.BasicCookieStore;
67  import org.apache.http.impl.client.BasicCredentialsProvider;
68  import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
69  import org.apache.http.impl.client.DefaultRedirectStrategy;
70  import org.apache.http.impl.client.DefaultUserTokenHandler;
71  import org.apache.http.impl.client.ProxyAuthenticationStrategy;
72  import org.apache.http.impl.client.TargetAuthenticationStrategy;
73  import org.apache.http.impl.cookie.BestMatchSpecFactory;
74  import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
75  import org.apache.http.impl.cookie.IgnoreSpecFactory;
76  import org.apache.http.impl.cookie.NetscapeDraftSpecFactory;
77  import org.apache.http.impl.cookie.RFC2109SpecFactory;
78  import org.apache.http.impl.cookie.RFC2965SpecFactory;
79  import org.apache.http.impl.nio.DefaultHttpClientIODispatch;
80  import org.apache.http.impl.nio.conn.DefaultHttpAsyncRoutePlanner;
81  import org.apache.http.impl.nio.conn.PoolingClientAsyncConnectionManager;
82  import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
83  import org.apache.http.impl.nio.reactor.IOReactorConfig;
84  import org.apache.http.nio.client.HttpAsyncClient;
85  import org.apache.http.nio.client.methods.HttpAsyncMethods;
86  import org.apache.http.nio.conn.ClientAsyncConnectionManager;
87  import org.apache.http.nio.protocol.HttpAsyncRequestExecutionHandler;
88  import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
89  import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
90  import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
91  import org.apache.http.nio.reactor.IOEventDispatch;
92  import org.apache.http.nio.reactor.IOReactorException;
93  import org.apache.http.nio.reactor.IOReactorStatus;
94  import org.apache.http.params.HttpParams;
95  import org.apache.http.protocol.BasicHttpContext;
96  import org.apache.http.protocol.BasicHttpProcessor;
97  import org.apache.http.protocol.DefaultedHttpContext;
98  import org.apache.http.protocol.HttpContext;
99  import org.apache.http.protocol.HttpProcessor;
100 import org.apache.http.protocol.ImmutableHttpProcessor;
101 
102 @Deprecated
103 public abstract class AbstractHttpAsyncClient implements HttpAsyncClient {
104 
105     private final Log log = LogFactory.getLog(getClass());
106     private final ClientAsyncConnectionManager connmgr;
107     private final Queue<HttpAsyncRequestExecutionHandler<?>> queue;
108 
109     private Thread reactorThread;
110     private BasicHttpProcessor mutableProcessor;
111     private ImmutableHttpProcessor protocolProcessor;
112     private ConnectionReuseStrategy reuseStrategy;
113     private ConnectionKeepAliveStrategy keepAliveStrategy;
114     private RedirectStrategy redirectStrategy;
115     private CookieSpecRegistry supportedCookieSpecs;
116     private CookieStore cookieStore;
117     private AuthSchemeRegistry supportedAuthSchemes;
118     private AuthenticationStrategy targetAuthStrategy;
119     private AuthenticationStrategy proxyAuthStrategy;
120     private CredentialsProvider credsProvider;
121     private HttpRoutePlanner routePlanner;
122     private UserTokenHandler userTokenHandler;
123     private HttpParams params;
124 
125     private volatile boolean terminated;
126 
127     protected AbstractHttpAsyncClient(final ClientAsyncConnectionManager connmgr) {
128         super();
129         this.connmgr = connmgr;
130         this.queue = new ConcurrentLinkedQueue<HttpAsyncRequestExecutionHandler<?>>();
131     }
132 
133     protected AbstractHttpAsyncClient(final IOReactorConfig config) throws IOReactorException {
134         super();
135         final DefaultConnectingIOReactor defaultioreactor = new DefaultConnectingIOReactor(config);
136         defaultioreactor.setExceptionHandler(new InternalIOReactorExceptionHandler(this.log));
137         this.connmgr = new PoolingClientAsyncConnectionManager(defaultioreactor);
138         this.queue = new ConcurrentLinkedQueue<HttpAsyncRequestExecutionHandler<?>>();
139     }
140 
141     protected abstract HttpParams createHttpParams();
142 
143     protected abstract BasicHttpProcessor createHttpProcessor();
144 
145     protected HttpContext createHttpContext() {
146         final HttpContext context = new BasicHttpContext();
147         context.setAttribute(
148                 ClientContext.SCHEME_REGISTRY,
149                 getConnectionManager().getSchemeRegistry());
150         context.setAttribute(
151                 ClientContext.AUTHSCHEME_REGISTRY,
152                 getAuthSchemes());
153         context.setAttribute(
154                 ClientContext.COOKIESPEC_REGISTRY,
155                 getCookieSpecs());
156         context.setAttribute(
157                 ClientContext.COOKIE_STORE,
158                 getCookieStore());
159         context.setAttribute(
160                 ClientContext.CREDS_PROVIDER,
161                 getCredentialsProvider());
162         return context;
163     }
164 
165     protected ConnectionReuseStrategy createConnectionReuseStrategy() {
166         return new DefaultConnectionReuseStrategy();
167     }
168 
169     protected ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy() {
170         return new DefaultConnectionKeepAliveStrategy();
171     }
172 
173     protected AuthSchemeRegistry createAuthSchemeRegistry() {
174         final AuthSchemeRegistry registry = new AuthSchemeRegistry();
175         registry.register(
176                 AuthPolicy.BASIC,
177                 new BasicSchemeFactory());
178         registry.register(
179                 AuthPolicy.DIGEST,
180                 new DigestSchemeFactory());
181         registry.register(
182                 AuthPolicy.NTLM,
183                 new NTLMSchemeFactory());
184         registry.register(
185                 AuthPolicy.SPNEGO,
186                 new SPNegoSchemeFactory());
187         registry.register(
188                 AuthPolicy.KERBEROS,
189                 new KerberosSchemeFactory());
190         return registry;
191     }
192 
193     protected CookieSpecRegistry createCookieSpecRegistry() {
194         final CookieSpecRegistry registry = new CookieSpecRegistry();
195         registry.register(
196                 CookiePolicy.BEST_MATCH,
197                 new BestMatchSpecFactory());
198         registry.register(
199                 CookiePolicy.BROWSER_COMPATIBILITY,
200                 new BrowserCompatSpecFactory());
201         registry.register(
202                 CookiePolicy.NETSCAPE,
203                 new NetscapeDraftSpecFactory());
204         registry.register(
205                 CookiePolicy.RFC_2109,
206                 new RFC2109SpecFactory());
207         registry.register(
208                 CookiePolicy.RFC_2965,
209                 new RFC2965SpecFactory());
210         registry.register(
211                 CookiePolicy.IGNORE_COOKIES,
212                 new IgnoreSpecFactory());
213         return registry;
214     }
215 
216     protected AuthenticationStrategy createTargetAuthenticationStrategy() {
217         return new TargetAuthenticationStrategy();
218     }
219 
220     protected AuthenticationStrategy createProxyAuthenticationStrategy() {
221         return new ProxyAuthenticationStrategy();
222     }
223 
224     protected CookieStore createCookieStore() {
225         return new BasicCookieStore();
226     }
227 
228     protected CredentialsProvider createCredentialsProvider() {
229         return new BasicCredentialsProvider();
230     }
231 
232     protected HttpRoutePlanner createHttpRoutePlanner() {
233         return new DefaultHttpAsyncRoutePlanner(getConnectionManager().getSchemeRegistry());
234     }
235 
236     protected UserTokenHandler createUserTokenHandler() {
237         return new DefaultUserTokenHandler();
238     }
239 
240     public synchronized final HttpParams getParams() {
241         if (this.params == null) {
242             this.params = createHttpParams();
243         }
244         return this.params;
245     }
246 
247     public synchronized void setParams(final HttpParams params) {
248         this.params = params;
249     }
250 
251     public synchronized ClientAsyncConnectionManager getConnectionManager() {
252         return this.connmgr;
253     }
254 
255     public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
256         if (this.reuseStrategy == null) {
257             this.reuseStrategy = createConnectionReuseStrategy();
258         }
259         return this.reuseStrategy;
260     }
261 
262     public synchronized void setReuseStrategy(final ConnectionReuseStrategy reuseStrategy) {
263         this.reuseStrategy = reuseStrategy;
264     }
265 
266     public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
267         if (this.keepAliveStrategy == null) {
268             this.keepAliveStrategy = createConnectionKeepAliveStrategy();
269         }
270         return this.keepAliveStrategy;
271     }
272 
273     public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy keepAliveStrategy) {
274         this.keepAliveStrategy = keepAliveStrategy;
275     }
276 
277     public synchronized final RedirectStrategy getRedirectStrategy() {
278         if (this.redirectStrategy == null) {
279             this.redirectStrategy = new DefaultRedirectStrategy();
280         }
281         return this.redirectStrategy;
282     }
283 
284     public synchronized void setRedirectStrategy(final RedirectStrategy redirectStrategy) {
285         this.redirectStrategy = redirectStrategy;
286     }
287 
288     public synchronized final AuthSchemeRegistry getAuthSchemes() {
289         if (this.supportedAuthSchemes == null) {
290             this.supportedAuthSchemes = createAuthSchemeRegistry();
291         }
292         return this.supportedAuthSchemes;
293     }
294 
295     public synchronized void setAuthSchemes(final AuthSchemeRegistry authSchemeRegistry) {
296         this.supportedAuthSchemes = authSchemeRegistry;
297     }
298 
299     public synchronized final CookieSpecRegistry getCookieSpecs() {
300         if (this.supportedCookieSpecs == null) {
301             this.supportedCookieSpecs = createCookieSpecRegistry();
302         }
303         return this.supportedCookieSpecs;
304     }
305 
306     public synchronized void setCookieSpecs(final CookieSpecRegistry cookieSpecRegistry) {
307         this.supportedCookieSpecs = cookieSpecRegistry;
308     }
309 
310     public synchronized final AuthenticationStrategy getTargetAuthenticationStrategy() {
311         if (this.targetAuthStrategy == null) {
312             this.targetAuthStrategy = createTargetAuthenticationStrategy();
313         }
314         return this.targetAuthStrategy;
315     }
316 
317     public synchronized void setTargetAuthenticationStrategy(
318             final AuthenticationStrategy targetAuthStrategy) {
319         this.targetAuthStrategy = targetAuthStrategy;
320     }
321 
322     public synchronized final AuthenticationStrategy getProxyAuthenticationStrategy() {
323         if (this.proxyAuthStrategy == null) {
324             this.proxyAuthStrategy = createProxyAuthenticationStrategy();
325         }
326         return this.proxyAuthStrategy;
327     }
328 
329     public synchronized void setProxyAuthenticationStrategy(
330             final AuthenticationStrategy proxyAuthStrategy) {
331         this.proxyAuthStrategy = proxyAuthStrategy;
332     }
333 
334     public synchronized final CookieStore getCookieStore() {
335         if (this.cookieStore == null) {
336             this.cookieStore = createCookieStore();
337         }
338         return this.cookieStore;
339     }
340 
341     public synchronized void setCookieStore(final CookieStore cookieStore) {
342         this.cookieStore = cookieStore;
343     }
344 
345     public synchronized final CredentialsProvider getCredentialsProvider() {
346         if (this.credsProvider == null) {
347             this.credsProvider = createCredentialsProvider();
348         }
349         return this.credsProvider;
350     }
351 
352     public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) {
353         this.credsProvider = credsProvider;
354     }
355 
356     public synchronized final HttpRoutePlanner getRoutePlanner() {
357         if (this.routePlanner == null) {
358             this.routePlanner = createHttpRoutePlanner();
359         }
360         return this.routePlanner;
361     }
362 
363     public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
364         this.routePlanner = routePlanner;
365     }
366 
367     public synchronized final UserTokenHandler getUserTokenHandler() {
368         if (this.userTokenHandler == null) {
369             this.userTokenHandler = createUserTokenHandler();
370         }
371         return this.userTokenHandler;
372     }
373 
374 
375     public synchronized void setUserTokenHandler(final UserTokenHandler userTokenHandler) {
376         this.userTokenHandler = userTokenHandler;
377     }
378 
379     protected synchronized final BasicHttpProcessor getHttpProcessor() {
380         if (this.mutableProcessor == null) {
381             this.mutableProcessor = createHttpProcessor();
382         }
383         return this.mutableProcessor;
384     }
385 
386     private synchronized final HttpProcessor getProtocolProcessor() {
387         if (this.protocolProcessor == null) {
388             // Get mutable HTTP processor
389             final BasicHttpProcessor proc = getHttpProcessor();
390             // and upgrade an immutable copy of it
391             final int reqc = proc.getRequestInterceptorCount();
392             final HttpRequestInterceptor[] reqinterceptors = new HttpRequestInterceptor[reqc];
393             for (int i = 0; i < reqc; i++) {
394                 reqinterceptors[i] = proc.getRequestInterceptor(i);
395             }
396             final int resc = proc.getResponseInterceptorCount();
397             final HttpResponseInterceptor[] resinterceptors = new HttpResponseInterceptor[resc];
398             for (int i = 0; i < resc; i++) {
399                 resinterceptors[i] = proc.getResponseInterceptor(i);
400             }
401             this.protocolProcessor = new ImmutableHttpProcessor(reqinterceptors, resinterceptors);
402         }
403         return this.protocolProcessor;
404     }
405 
406     public synchronized int getResponseInterceptorCount() {
407         return getHttpProcessor().getResponseInterceptorCount();
408     }
409 
410     public synchronized HttpResponseInterceptor getResponseInterceptor(final int index) {
411         return getHttpProcessor().getResponseInterceptor(index);
412     }
413 
414     public synchronized HttpRequestInterceptor getRequestInterceptor(final int index) {
415         return getHttpProcessor().getRequestInterceptor(index);
416     }
417 
418     public synchronized int getRequestInterceptorCount() {
419         return getHttpProcessor().getRequestInterceptorCount();
420     }
421 
422     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
423         getHttpProcessor().addInterceptor(itcp);
424         this.protocolProcessor = null;
425     }
426 
427     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, final int index) {
428         getHttpProcessor().addInterceptor(itcp, index);
429         this.protocolProcessor = null;
430     }
431 
432     public synchronized void clearResponseInterceptors() {
433         getHttpProcessor().clearResponseInterceptors();
434         this.protocolProcessor = null;
435     }
436 
437     public synchronized void removeResponseInterceptorByClass(final Class<? extends HttpResponseInterceptor> clazz) {
438         getHttpProcessor().removeResponseInterceptorByClass(clazz);
439         this.protocolProcessor = null;
440     }
441 
442     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
443         getHttpProcessor().addInterceptor(itcp);
444         this.protocolProcessor = null;
445     }
446 
447     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, final int index) {
448         getHttpProcessor().addInterceptor(itcp, index);
449         this.protocolProcessor = null;
450     }
451 
452     public synchronized void clearRequestInterceptors() {
453         getHttpProcessor().clearRequestInterceptors();
454         this.protocolProcessor = null;
455     }
456 
457     public synchronized void removeRequestInterceptorByClass(final Class<? extends HttpRequestInterceptor> clazz) {
458         getHttpProcessor().removeRequestInterceptorByClass(clazz);
459         this.protocolProcessor = null;
460     }
461 
462     private void doExecute() {
463         final InternalRequestExecutor handler = new InternalRequestExecutor(this.log, new HttpAsyncRequestExecutor());
464         try {
465             final IOEventDispatch ioEventDispatch = new DefaultHttpClientIODispatch(handler, getParams());
466             this.connmgr.execute(ioEventDispatch);
467         } catch (final Exception ex) {
468             this.log.error("I/O reactor terminated abnormally", ex);
469         } finally {
470             this.terminated = true;
471             while (!this.queue.isEmpty()) {
472                 final HttpAsyncRequestExecutionHandler<?> exchangeHandler = this.queue.remove();
473                 exchangeHandler.cancel();
474             }
475         }
476     }
477 
478     public IOReactorStatus getStatus() {
479         return this.connmgr.getStatus();
480     }
481 
482     public synchronized void start() {
483         this.reactorThread = new Thread() {
484 
485             @Override
486             public void run() {
487                 doExecute();
488             }
489 
490         };
491         this.reactorThread.start();
492     }
493 
494     public void shutdown() throws InterruptedException {
495         try {
496             this.connmgr.shutdown(5000);
497         } catch (final IOException ex) {
498             this.log.error("I/O error shutting down", ex);
499         }
500         if (this.reactorThread != null) {
501             this.reactorThread.join();
502         }
503     }
504 
505     @Override
506     public <T> Future<T> execute(
507             final HttpAsyncRequestProducer requestProducer,
508             final HttpAsyncResponseConsumer<T> responseConsumer,
509             final HttpContext context,
510             final FutureCallback<T> callback) {
511         if (this.terminated) {
512             throw new IllegalStateException("Client has been shut down");
513         }
514         final BasicFuture<T> future = new BasicFuture<T>(callback);
515         final ResultCallback<T> resultCallback = new DefaultResultCallback<T>(future, this.queue);
516         final DefaultAsyncRequestDirector<T> httpexchange;
517         synchronized (this) {
518             final HttpContext defaultContext = createHttpContext();
519             final HttpContext execContext;
520             if (context == null) {
521                 execContext = defaultContext;
522             } else {
523                 execContext = new DefaultedHttpContext(context, defaultContext);
524             }
525             httpexchange = new DefaultAsyncRequestDirector<T>(
526                     this.log,
527                     requestProducer,
528                     responseConsumer,
529                     execContext,
530                     resultCallback,
531                     this.connmgr,
532                     getProtocolProcessor(),
533                     getRoutePlanner(),
534                     getConnectionReuseStrategy(),
535                     getConnectionKeepAliveStrategy(),
536                     getRedirectStrategy(),
537                     getTargetAuthenticationStrategy(),
538                     getProxyAuthenticationStrategy(),
539                     getUserTokenHandler(),
540                     getParams());
541         }
542         this.queue.add(httpexchange);
543         httpexchange.start();
544         return future;
545     }
546 
547     @Override
548     public <T> Future<T> execute(
549             final HttpAsyncRequestProducer requestProducer,
550             final HttpAsyncResponseConsumer<T> responseConsumer,
551             final FutureCallback<T> callback) {
552         return execute(requestProducer, responseConsumer, new BasicHttpContext(), callback);
553     }
554 
555     @Override
556     public Future<HttpResponse> execute(
557             final HttpHost target, final HttpRequest request, final HttpContext context,
558             final FutureCallback<HttpResponse> callback) {
559         return execute(
560                 HttpAsyncMethods.create(target, request),
561                 HttpAsyncMethods.createConsumer(),
562                 context, callback);
563     }
564 
565     @Override
566     public Future<HttpResponse> execute(
567             final HttpHost target, final HttpRequest request,
568             final FutureCallback<HttpResponse> callback) {
569         return execute(target, request, new BasicHttpContext(), callback);
570     }
571 
572     @Override
573     public Future<HttpResponse> execute(
574             final HttpUriRequest request,
575             final FutureCallback<HttpResponse> callback) {
576         return execute(request, new BasicHttpContext(), callback);
577     }
578 
579     @Override
580     public Future<HttpResponse> execute(
581             final HttpUriRequest request,
582             final HttpContext context,
583             final FutureCallback<HttpResponse> callback) {
584         final HttpHost target;
585         try {
586             target = determineTarget(request);
587         } catch (final ClientProtocolException ex) {
588             final BasicFuture<HttpResponse> future = new BasicFuture<HttpResponse>(callback);
589             future.failed(ex);
590             return future;
591         }
592         return execute(target, request, context, callback);
593     }
594 
595     private HttpHost determineTarget(final HttpUriRequest request) throws ClientProtocolException {
596         // A null target may be acceptable if there is a default target.
597         // Otherwise, the null target is detected in the director.
598         HttpHost target = null;
599 
600         final URI requestURI = request.getURI();
601         if (requestURI.isAbsolute()) {
602             target = URIUtils.extractHost(requestURI);
603             if (target == null) {
604                 throw new ClientProtocolException(
605                         "URI does not specify a valid host name: " + requestURI);
606             }
607         }
608         return target;
609     }
610 
611 }