001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027 028package org.apache.http.impl.execchain; 029 030import java.io.IOException; 031import java.io.InterruptedIOException; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035import org.apache.http.Header; 036import org.apache.http.HttpException; 037import org.apache.http.annotation.Contract; 038import org.apache.http.annotation.ThreadingBehavior; 039import org.apache.http.client.ServiceUnavailableRetryStrategy; 040import org.apache.http.client.methods.CloseableHttpResponse; 041import org.apache.http.client.methods.HttpExecutionAware; 042import org.apache.http.client.methods.HttpRequestWrapper; 043import org.apache.http.client.protocol.HttpClientContext; 044import org.apache.http.conn.routing.HttpRoute; 045import org.apache.http.util.Args; 046 047/** 048 * Request executor in the request execution chain that is responsible 049 * for making a decision whether a request that received a non-2xx response 050 * from the target server should be re-executed. 051 * <p> 052 * Further responsibilities such as communication with the opposite 053 * endpoint is delegated to the next executor in the request execution 054 * chain. 055 * </p> 056 * 057 * @since 4.3 058 */ 059@Contract(threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL) 060public class ServiceUnavailableRetryExec implements ClientExecChain { 061 062 private final Log log = LogFactory.getLog(getClass()); 063 064 private final ClientExecChain requestExecutor; 065 private final ServiceUnavailableRetryStrategy retryStrategy; 066 067 public ServiceUnavailableRetryExec( 068 final ClientExecChain requestExecutor, 069 final ServiceUnavailableRetryStrategy retryStrategy) { 070 super(); 071 Args.notNull(requestExecutor, "HTTP request executor"); 072 Args.notNull(retryStrategy, "Retry strategy"); 073 this.requestExecutor = requestExecutor; 074 this.retryStrategy = retryStrategy; 075 } 076 077 @Override 078 public CloseableHttpResponse execute( 079 final HttpRoute route, 080 final HttpRequestWrapper request, 081 final HttpClientContext context, 082 final HttpExecutionAware execAware) throws IOException, HttpException { 083 final Header[] origheaders = request.getAllHeaders(); 084 for (int c = 1;; c++) { 085 final CloseableHttpResponse response = this.requestExecutor.execute( 086 route, request, context, execAware); 087 try { 088 if (this.retryStrategy.retryRequest(response, c, context)) { 089 response.close(); 090 final long nextInterval = this.retryStrategy.getRetryInterval(); 091 if (nextInterval > 0) { 092 try { 093 this.log.trace("Wait for " + nextInterval); 094 Thread.sleep(nextInterval); 095 } catch (final InterruptedException e) { 096 Thread.currentThread().interrupt(); 097 throw new InterruptedIOException(); 098 } 099 } 100 request.setHeaders(origheaders); 101 } else { 102 return response; 103 } 104 } catch (final RuntimeException ex) { 105 response.close(); 106 throw ex; 107 } 108 } 109 } 110 111}