1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.impl.execchain;
29
30 import java.io.IOException;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.http.Header;
35 import org.apache.http.HttpException;
36 import org.apache.http.NoHttpResponseException;
37 import org.apache.http.annotation.Contract;
38 import org.apache.http.annotation.ThreadingBehavior;
39 import org.apache.http.client.HttpRequestRetryHandler;
40 import org.apache.http.client.NonRepeatableRequestException;
41 import org.apache.http.client.methods.CloseableHttpResponse;
42 import org.apache.http.client.methods.HttpExecutionAware;
43 import org.apache.http.client.methods.HttpRequestWrapper;
44 import org.apache.http.client.protocol.HttpClientContext;
45 import org.apache.http.conn.routing.HttpRoute;
46 import org.apache.http.util.Args;
47
48
49
50
51
52
53
54
55
56
57
58
59
60 @Contract(threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL)
61 public class RetryExec implements ClientExecChain {
62
63 private final Log log = LogFactory.getLog(getClass());
64
65 private final ClientExecChain requestExecutor;
66 private final HttpRequestRetryHandler retryHandler;
67
68 public RetryExec(
69 final ClientExecChain requestExecutor,
70 final HttpRequestRetryHandler retryHandler) {
71 Args.notNull(requestExecutor, "HTTP request executor");
72 Args.notNull(retryHandler, "HTTP request retry handler");
73 this.requestExecutor = requestExecutor;
74 this.retryHandler = retryHandler;
75 }
76
77 @Override
78 public CloseableHttpResponse execute(
79 final HttpRoute route,
80 final HttpRequestWrapper request,
81 final HttpClientContext context,
82 final HttpExecutionAware execAware) throws IOException, HttpException {
83 Args.notNull(route, "HTTP route");
84 Args.notNull(request, "HTTP request");
85 Args.notNull(context, "HTTP context");
86 final Header[] origheaders = request.getAllHeaders();
87 for (int execCount = 1;; execCount++) {
88 try {
89 return this.requestExecutor.execute(route, request, context, execAware);
90 } catch (final IOException ex) {
91 if (execAware != null && execAware.isAborted()) {
92 this.log.debug("Request has been aborted");
93 throw ex;
94 }
95 if (retryHandler.retryRequest(ex, execCount, context)) {
96 if (this.log.isInfoEnabled()) {
97 this.log.info("I/O exception ("+ ex.getClass().getName() +
98 ") caught when processing request to "
99 + route +
100 ": "
101 + ex.getMessage());
102 }
103 if (this.log.isDebugEnabled()) {
104 this.log.debug(ex.getMessage(), ex);
105 }
106 if (!RequestEntityProxy.isRepeatable(request)) {
107 this.log.debug("Cannot retry non-repeatable request");
108 throw new NonRepeatableRequestException("Cannot retry request " +
109 "with a non-repeatable request entity", ex);
110 }
111 request.setHeaders(origheaders);
112 if (this.log.isInfoEnabled()) {
113 this.log.info("Retrying request to " + route);
114 }
115 } else {
116 if (ex instanceof NoHttpResponseException) {
117 final NoHttpResponseException updatedex = new NoHttpResponseException(
118 route.getTargetHost().toHostString() + " failed to respond");
119 updatedex.setStackTrace(ex.getStackTrace());
120 throw updatedex;
121 }
122 throw ex;
123 }
124 }
125 }
126 }
127
128 }