1/* 2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java $ 3 * $Revision: 677250 $ 4 * $Date: 2008-07-16 04:45:47 -0700 (Wed, 16 Jul 2008) $ 5 * 6 * ==================================================================== 7 * Licensed to the Apache Software Foundation (ASF) under one 8 * or more contributor license agreements. See the NOTICE file 9 * distributed with this work for additional information 10 * regarding copyright ownership. The ASF licenses this file 11 * to you under the Apache License, Version 2.0 (the 12 * "License"); you may not use this file except in compliance 13 * with the License. You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, 18 * software distributed under the License is distributed on an 19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 20 * KIND, either express or implied. See the License for the 21 * specific language governing permissions and limitations 22 * under the License. 23 * ==================================================================== 24 * 25 * This software consists of voluntary contributions made by many 26 * individuals on behalf of the Apache Software Foundation. For more 27 * information on the Apache Software Foundation, please see 28 * <http://www.apache.org/>. 29 * 30 */ 31 32package org.apache.http.impl.client; 33 34import java.io.IOException; 35import java.net.URI; 36import java.lang.reflect.UndeclaredThrowableException; 37 38import org.apache.commons.logging.Log; 39import org.apache.commons.logging.LogFactory; 40import org.apache.http.ConnectionReuseStrategy; 41import org.apache.http.HttpException; 42import org.apache.http.HttpHost; 43import org.apache.http.HttpRequest; 44import org.apache.http.HttpRequestInterceptor; 45import org.apache.http.HttpResponse; 46import org.apache.http.HttpResponseInterceptor; 47import org.apache.http.HttpEntity; 48import org.apache.http.auth.AuthSchemeRegistry; 49import org.apache.http.client.AuthenticationHandler; 50import org.apache.http.client.ClientProtocolException; 51import org.apache.http.client.RequestDirector; 52import org.apache.http.client.ResponseHandler; 53import org.apache.http.client.CookieStore; 54import org.apache.http.client.CredentialsProvider; 55import org.apache.http.client.HttpClient; 56import org.apache.http.client.HttpRequestRetryHandler; 57import org.apache.http.client.RedirectHandler; 58import org.apache.http.client.UserTokenHandler; 59import org.apache.http.client.methods.HttpUriRequest; 60import org.apache.http.conn.ClientConnectionManager; 61import org.apache.http.conn.ConnectionKeepAliveStrategy; 62import org.apache.http.conn.routing.HttpRoutePlanner; 63import org.apache.http.cookie.CookieSpecRegistry; 64import org.apache.http.params.HttpParams; 65import org.apache.http.protocol.BasicHttpProcessor; 66import org.apache.http.protocol.DefaultedHttpContext; 67import org.apache.http.protocol.HttpContext; 68import org.apache.http.protocol.HttpProcessor; 69import org.apache.http.protocol.HttpRequestExecutor; 70 71/** 72 * Convenience base class for HTTP client implementations. 73 * 74 * @author <a href="mailto:rolandw at apache.org">Roland Weber</a> 75 * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> 76 * 77 * <!-- empty lines to avoid svn diff problems --> 78 * @version $Revision: 677250 $ 79 * 80 * @since 4.0 81 */ 82public abstract class AbstractHttpClient implements HttpClient { 83 84 private final Log log = LogFactory.getLog(getClass()); 85 86 /** The parameters. */ 87 private HttpParams defaultParams; 88 89 /** The request executor. */ 90 private HttpRequestExecutor requestExec; 91 92 /** The connection manager. */ 93 private ClientConnectionManager connManager; 94 95 /** The connection re-use strategy. */ 96 private ConnectionReuseStrategy reuseStrategy; 97 98 /** The connection keep-alive strategy. */ 99 private ConnectionKeepAliveStrategy keepAliveStrategy; 100 101 /** The cookie spec registry. */ 102 private CookieSpecRegistry supportedCookieSpecs; 103 104 /** The authentication scheme registry. */ 105 private AuthSchemeRegistry supportedAuthSchemes; 106 107 /** The HTTP processor. */ 108 private BasicHttpProcessor httpProcessor; 109 110 /** The request retry handler. */ 111 private HttpRequestRetryHandler retryHandler; 112 113 /** The redirect handler. */ 114 private RedirectHandler redirectHandler; 115 116 /** The target authentication handler. */ 117 private AuthenticationHandler targetAuthHandler; 118 119 /** The proxy authentication handler. */ 120 private AuthenticationHandler proxyAuthHandler; 121 122 /** The cookie store. */ 123 private CookieStore cookieStore; 124 125 /** The credentials provider. */ 126 private CredentialsProvider credsProvider; 127 128 /** The route planner. */ 129 private HttpRoutePlanner routePlanner; 130 131 /** The user token handler. */ 132 private UserTokenHandler userTokenHandler; 133 134 135 /** 136 * Creates a new HTTP client. 137 * 138 * @param conman the connection manager 139 * @param params the parameters 140 */ 141 protected AbstractHttpClient( 142 final ClientConnectionManager conman, 143 final HttpParams params) { 144 defaultParams = params; 145 connManager = conman; 146 } // constructor 147 148 protected abstract HttpParams createHttpParams(); 149 150 151 protected abstract HttpContext createHttpContext(); 152 153 154 protected abstract HttpRequestExecutor createRequestExecutor(); 155 156 157 protected abstract ClientConnectionManager createClientConnectionManager(); 158 159 160 protected abstract AuthSchemeRegistry createAuthSchemeRegistry(); 161 162 163 protected abstract CookieSpecRegistry createCookieSpecRegistry(); 164 165 166 protected abstract ConnectionReuseStrategy createConnectionReuseStrategy(); 167 168 169 protected abstract ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy(); 170 171 172 protected abstract BasicHttpProcessor createHttpProcessor(); 173 174 175 protected abstract HttpRequestRetryHandler createHttpRequestRetryHandler(); 176 177 178 protected abstract RedirectHandler createRedirectHandler(); 179 180 181 protected abstract AuthenticationHandler createTargetAuthenticationHandler(); 182 183 184 protected abstract AuthenticationHandler createProxyAuthenticationHandler(); 185 186 187 protected abstract CookieStore createCookieStore(); 188 189 190 protected abstract CredentialsProvider createCredentialsProvider(); 191 192 193 protected abstract HttpRoutePlanner createHttpRoutePlanner(); 194 195 196 protected abstract UserTokenHandler createUserTokenHandler(); 197 198 199 // non-javadoc, see interface HttpClient 200 public synchronized final HttpParams getParams() { 201 if (defaultParams == null) { 202 defaultParams = createHttpParams(); 203 } 204 return defaultParams; 205 } 206 207 208 /** 209 * Replaces the parameters. 210 * The implementation here does not update parameters of dependent objects. 211 * 212 * @param params the new default parameters 213 */ 214 public synchronized void setParams(HttpParams params) { 215 defaultParams = params; 216 } 217 218 219 public synchronized final ClientConnectionManager getConnectionManager() { 220 if (connManager == null) { 221 connManager = createClientConnectionManager(); 222 } 223 return connManager; 224 } 225 226 227 public synchronized final HttpRequestExecutor getRequestExecutor() { 228 if (requestExec == null) { 229 requestExec = createRequestExecutor(); 230 } 231 return requestExec; 232 } 233 234 235 public synchronized final AuthSchemeRegistry getAuthSchemes() { 236 if (supportedAuthSchemes == null) { 237 supportedAuthSchemes = createAuthSchemeRegistry(); 238 } 239 return supportedAuthSchemes; 240 } 241 242 243 public synchronized void setAuthSchemes(final AuthSchemeRegistry authSchemeRegistry) { 244 supportedAuthSchemes = authSchemeRegistry; 245 } 246 247 248 public synchronized final CookieSpecRegistry getCookieSpecs() { 249 if (supportedCookieSpecs == null) { 250 supportedCookieSpecs = createCookieSpecRegistry(); 251 } 252 return supportedCookieSpecs; 253 } 254 255 256 public synchronized void setCookieSpecs(final CookieSpecRegistry cookieSpecRegistry) { 257 supportedCookieSpecs = cookieSpecRegistry; 258 } 259 260 261 public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() { 262 if (reuseStrategy == null) { 263 reuseStrategy = createConnectionReuseStrategy(); 264 } 265 return reuseStrategy; 266 } 267 268 269 public synchronized void setReuseStrategy(final ConnectionReuseStrategy reuseStrategy) { 270 this.reuseStrategy = reuseStrategy; 271 } 272 273 274 public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() { 275 if (keepAliveStrategy == null) { 276 keepAliveStrategy = createConnectionKeepAliveStrategy(); 277 } 278 return keepAliveStrategy; 279 } 280 281 282 public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy keepAliveStrategy) { 283 this.keepAliveStrategy = keepAliveStrategy; 284 } 285 286 287 public synchronized final HttpRequestRetryHandler getHttpRequestRetryHandler() { 288 if (retryHandler == null) { 289 retryHandler = createHttpRequestRetryHandler(); 290 } 291 return retryHandler; 292 } 293 294 295 public synchronized void setHttpRequestRetryHandler(final HttpRequestRetryHandler retryHandler) { 296 this.retryHandler = retryHandler; 297 } 298 299 300 public synchronized final RedirectHandler getRedirectHandler() { 301 if (redirectHandler == null) { 302 redirectHandler = createRedirectHandler(); 303 } 304 return redirectHandler; 305 } 306 307 308 public synchronized void setRedirectHandler(final RedirectHandler redirectHandler) { 309 this.redirectHandler = redirectHandler; 310 } 311 312 313 public synchronized final AuthenticationHandler getTargetAuthenticationHandler() { 314 if (targetAuthHandler == null) { 315 targetAuthHandler = createTargetAuthenticationHandler(); 316 } 317 return targetAuthHandler; 318 } 319 320 321 public synchronized void setTargetAuthenticationHandler( 322 final AuthenticationHandler targetAuthHandler) { 323 this.targetAuthHandler = targetAuthHandler; 324 } 325 326 327 public synchronized final AuthenticationHandler getProxyAuthenticationHandler() { 328 if (proxyAuthHandler == null) { 329 proxyAuthHandler = createProxyAuthenticationHandler(); 330 } 331 return proxyAuthHandler; 332 } 333 334 335 public synchronized void setProxyAuthenticationHandler( 336 final AuthenticationHandler proxyAuthHandler) { 337 this.proxyAuthHandler = proxyAuthHandler; 338 } 339 340 341 public synchronized final CookieStore getCookieStore() { 342 if (cookieStore == null) { 343 cookieStore = createCookieStore(); 344 } 345 return cookieStore; 346 } 347 348 349 public synchronized void setCookieStore(final CookieStore cookieStore) { 350 this.cookieStore = cookieStore; 351 } 352 353 354 public synchronized final CredentialsProvider getCredentialsProvider() { 355 if (credsProvider == null) { 356 credsProvider = createCredentialsProvider(); 357 } 358 return credsProvider; 359 } 360 361 362 public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) { 363 this.credsProvider = credsProvider; 364 } 365 366 367 public synchronized final HttpRoutePlanner getRoutePlanner() { 368 if (this.routePlanner == null) { 369 this.routePlanner = createHttpRoutePlanner(); 370 } 371 return this.routePlanner; 372 } 373 374 375 public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) { 376 this.routePlanner = routePlanner; 377 } 378 379 380 public synchronized final UserTokenHandler getUserTokenHandler() { 381 if (this.userTokenHandler == null) { 382 this.userTokenHandler = createUserTokenHandler(); 383 } 384 return this.userTokenHandler; 385 } 386 387 388 public synchronized void setUserTokenHandler(final UserTokenHandler userTokenHandler) { 389 this.userTokenHandler = userTokenHandler; 390 } 391 392 393 protected synchronized final BasicHttpProcessor getHttpProcessor() { 394 if (httpProcessor == null) { 395 httpProcessor = createHttpProcessor(); 396 } 397 return httpProcessor; 398 } 399 400 401 public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) { 402 getHttpProcessor().addInterceptor(itcp); 403 } 404 405 406 public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, int index) { 407 getHttpProcessor().addInterceptor(itcp, index); 408 } 409 410 411 public synchronized HttpResponseInterceptor getResponseInterceptor(int index) { 412 return getHttpProcessor().getResponseInterceptor(index); 413 } 414 415 416 public synchronized int getResponseInterceptorCount() { 417 return getHttpProcessor().getResponseInterceptorCount(); 418 } 419 420 421 public synchronized void clearResponseInterceptors() { 422 getHttpProcessor().clearResponseInterceptors(); 423 } 424 425 426 public void removeResponseInterceptorByClass(Class<? extends HttpResponseInterceptor> clazz) { 427 getHttpProcessor().removeResponseInterceptorByClass(clazz); 428 } 429 430 431 public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) { 432 getHttpProcessor().addInterceptor(itcp); 433 } 434 435 436 public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, int index) { 437 getHttpProcessor().addInterceptor(itcp, index); 438 } 439 440 441 public synchronized HttpRequestInterceptor getRequestInterceptor(int index) { 442 return getHttpProcessor().getRequestInterceptor(index); 443 } 444 445 446 public synchronized int getRequestInterceptorCount() { 447 return getHttpProcessor().getRequestInterceptorCount(); 448 } 449 450 451 public synchronized void clearRequestInterceptors() { 452 getHttpProcessor().clearRequestInterceptors(); 453 } 454 455 456 public void removeRequestInterceptorByClass(Class<? extends HttpRequestInterceptor> clazz) { 457 getHttpProcessor().removeRequestInterceptorByClass(clazz); 458 } 459 460 461 // non-javadoc, see interface HttpClient 462 public final HttpResponse execute(HttpUriRequest request) 463 throws IOException, ClientProtocolException { 464 465 return execute(request, (HttpContext) null); 466 } 467 468 469 /** 470 * Maps to {@link HttpClient#execute(HttpHost,HttpRequest,HttpContext) 471 * execute(target, request, context)}. 472 * The target is determined from the URI of the request. 473 * 474 * @param request the request to execute 475 * @param context the request-specific execution context, 476 * or <code>null</code> to use a default context 477 */ 478 public final HttpResponse execute(HttpUriRequest request, 479 HttpContext context) 480 throws IOException, ClientProtocolException { 481 482 if (request == null) { 483 throw new IllegalArgumentException 484 ("Request must not be null."); 485 } 486 487 return execute(determineTarget(request), request, context); 488 } 489 490 private HttpHost determineTarget(HttpUriRequest request) { 491 // A null target may be acceptable if there is a default target. 492 // Otherwise, the null target is detected in the director. 493 HttpHost target = null; 494 495 URI requestURI = request.getURI(); 496 if (requestURI.isAbsolute()) { 497 target = new HttpHost( 498 requestURI.getHost(), 499 requestURI.getPort(), 500 requestURI.getScheme()); 501 } 502 return target; 503 } 504 505 // non-javadoc, see interface HttpClient 506 public final HttpResponse execute(HttpHost target, HttpRequest request) 507 throws IOException, ClientProtocolException { 508 509 return execute(target, request, (HttpContext) null); 510 } 511 512 513 // non-javadoc, see interface HttpClient 514 public final HttpResponse execute(HttpHost target, HttpRequest request, 515 HttpContext context) 516 throws IOException, ClientProtocolException { 517 518 if (request == null) { 519 throw new IllegalArgumentException 520 ("Request must not be null."); 521 } 522 // a null target may be acceptable, this depends on the route planner 523 // a null context is acceptable, default context created below 524 525 HttpContext execContext = null; 526 RequestDirector director = null; 527 528 // Initialize the request execution context making copies of 529 // all shared objects that are potentially threading unsafe. 530 synchronized (this) { 531 532 HttpContext defaultContext = createHttpContext(); 533 if (context == null) { 534 execContext = defaultContext; 535 } else { 536 execContext = new DefaultedHttpContext(context, defaultContext); 537 } 538 // Create a director for this request 539 director = createClientRequestDirector( 540 getRequestExecutor(), 541 getConnectionManager(), 542 getConnectionReuseStrategy(), 543 getConnectionKeepAliveStrategy(), 544 getRoutePlanner(), 545 getHttpProcessor().copy(), 546 getHttpRequestRetryHandler(), 547 getRedirectHandler(), 548 getTargetAuthenticationHandler(), 549 getProxyAuthenticationHandler(), 550 getUserTokenHandler(), 551 determineParams(request)); 552 } 553 554 try { 555 return director.execute(target, request, execContext); 556 } catch(HttpException httpException) { 557 throw new ClientProtocolException(httpException); 558 } 559 } // execute 560 561 562 protected RequestDirector createClientRequestDirector( 563 final HttpRequestExecutor requestExec, 564 final ClientConnectionManager conman, 565 final ConnectionReuseStrategy reustrat, 566 final ConnectionKeepAliveStrategy kastrat, 567 final HttpRoutePlanner rouplan, 568 final HttpProcessor httpProcessor, 569 final HttpRequestRetryHandler retryHandler, 570 final RedirectHandler redirectHandler, 571 final AuthenticationHandler targetAuthHandler, 572 final AuthenticationHandler proxyAuthHandler, 573 final UserTokenHandler stateHandler, 574 final HttpParams params) { 575 return new DefaultRequestDirector( 576 requestExec, 577 conman, 578 reustrat, 579 kastrat, 580 rouplan, 581 httpProcessor, 582 retryHandler, 583 redirectHandler, 584 targetAuthHandler, 585 proxyAuthHandler, 586 stateHandler, 587 params); 588 } 589 590 /** 591 * Obtains parameters for executing a request. 592 * The default implementation in this class creates a new 593 * {@link ClientParamsStack} from the request parameters 594 * and the client parameters. 595 * <br/> 596 * This method is called by the default implementation of 597 * {@link #execute(HttpHost,HttpRequest,HttpContext)} 598 * to obtain the parameters for the 599 * {@link DefaultRequestDirector}. 600 * 601 * @param req the request that will be executed 602 * 603 * @return the parameters to use 604 */ 605 protected HttpParams determineParams(HttpRequest req) { 606 return new ClientParamsStack 607 (null, getParams(), req.getParams(), null); 608 } 609 610 611 // non-javadoc, see interface HttpClient 612 public <T> T execute( 613 final HttpUriRequest request, 614 final ResponseHandler<? extends T> responseHandler) 615 throws IOException, ClientProtocolException { 616 return execute(request, responseHandler, null); 617 } 618 619 620 // non-javadoc, see interface HttpClient 621 public <T> T execute( 622 final HttpUriRequest request, 623 final ResponseHandler<? extends T> responseHandler, 624 final HttpContext context) 625 throws IOException, ClientProtocolException { 626 HttpHost target = determineTarget(request); 627 return execute(target, request, responseHandler, context); 628 } 629 630 631 // non-javadoc, see interface HttpClient 632 public <T> T execute( 633 final HttpHost target, 634 final HttpRequest request, 635 final ResponseHandler<? extends T> responseHandler) 636 throws IOException, ClientProtocolException { 637 return execute(target, request, responseHandler, null); 638 } 639 640 641 // non-javadoc, see interface HttpClient 642 public <T> T execute( 643 final HttpHost target, 644 final HttpRequest request, 645 final ResponseHandler<? extends T> responseHandler, 646 final HttpContext context) 647 throws IOException, ClientProtocolException { 648 if (responseHandler == null) { 649 throw new IllegalArgumentException 650 ("Response handler must not be null."); 651 } 652 653 HttpResponse response = execute(target, request, context); 654 655 T result; 656 try { 657 result = responseHandler.handleResponse(response); 658 } catch (Throwable t) { 659 HttpEntity entity = response.getEntity(); 660 if (entity != null) { 661 try { 662 entity.consumeContent(); 663 } catch (Throwable t2) { 664 // Log this exception. The original exception is more 665 // important and will be thrown to the caller. 666 this.log.warn("Error consuming content after an exception.", t2); 667 } 668 } 669 670 if (t instanceof Error) { 671 throw (Error) t; 672 } 673 674 if (t instanceof RuntimeException) { 675 throw (RuntimeException) t; 676 } 677 678 if (t instanceof IOException) { 679 throw (IOException) t; 680 } 681 682 throw new UndeclaredThrowableException(t); 683 } 684 685 // Handling the response was successful. Ensure that the content has 686 // been fully consumed. 687 HttpEntity entity = response.getEntity(); 688 if (entity != null) { 689 // Let this exception go to the caller. 690 entity.consumeContent(); 691 } 692 693 return result; 694 } 695 696 697} // class AbstractHttpClient 698