You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by mi...@apache.org on 2019/12/12 07:49:25 UTC
[httpcomponents-client] branch master updated: HTTPCLIENT-2035:
Remove HttpRequestRetryHandler in favor of HttpRequestRetryStrategy
This is an automated email from the ASF dual-hosted git repository.
michaelo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git
The following commit(s) were added to refs/heads/master by this push:
new 52c6cf7 HTTPCLIENT-2035: Remove HttpRequestRetryHandler in favor of HttpRequestRetryStrategy
52c6cf7 is described below
commit 52c6cf70370205b55e6eaef1b03c341366d59916
Author: Michael Osipov <mi...@apache.org>
AuthorDate: Tue Dec 10 22:24:17 2019 +0100
HTTPCLIENT-2035: Remove HttpRequestRetryHandler in favor of HttpRequestRetryStrategy
This closes #183
---
.../hc/client5/http/HttpRequestRetryHandler.java | 65 -------
.../apache/hc/client5/http/impl/ChainElement.java | 3 +-
.../http/impl/DefaultHttpRequestRetryHandler.java | 169 -------------------
.../hc/client5/http/impl/async/AsyncRetryExec.java | 151 -----------------
.../http/impl/async/H2AsyncClientBuilder.java | 32 +---
.../http/impl/async/HttpAsyncClientBuilder.java | 32 +---
.../http/impl/classic/HttpClientBuilder.java | 33 +---
.../hc/client5/http/impl/classic/RetryExec.java | 122 --------------
.../impl/TestDefaultHttpRequestRetryHandler.java | 88 ----------
.../client5/http/impl/classic/TestRetryExec.java | 186 ---------------------
10 files changed, 19 insertions(+), 862 deletions(-)
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/HttpRequestRetryHandler.java b/httpclient5/src/main/java/org/apache/hc/client5/http/HttpRequestRetryHandler.java
deleted file mode 100644
index e1573b4..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/HttpRequestRetryHandler.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * ====================================================================
- * 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.hc.client5.http;
-
-import java.io.IOException;
-
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.http.HttpRequest;
-import org.apache.hc.core5.http.protocol.HttpContext;
-
-/**
- * A handler for determining if an HttpRequest should be retried after a
- * recoverable exception during execution.
- * <p>
- * Implementations of this interface must be thread-safe. Access to shared
- * data must be synchronized as methods of this interface may be executed
- * from multiple threads.
- *
- * @since 4.0
- */
-@Contract(threading = ThreadingBehavior.STATELESS)
-public interface HttpRequestRetryHandler {
-
- /**
- * Determines if a method should be retried after an IOException
- * occurs during execution.
- *
- * @param request request failed die to an I/O exception.
- * @param exception the exception that occurred
- * @param executionCount the number of times this method has been
- * unsuccessfully executed
- * @param context the context for the request execution
- *
- * @return {@code true} if the method should be retried, {@code false}
- * otherwise
- */
- boolean retryRequest(HttpRequest request, IOException exception, int executionCount, HttpContext context);
-
-}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ChainElement.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ChainElement.java
index 43c8dfb..0c34f83 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ChainElement.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ChainElement.java
@@ -34,7 +34,6 @@ package org.apache.hc.client5.http.impl;
*/
public enum ChainElement {
- REDIRECT, BACK_OFF, RETRY, RETRY_IO_ERROR, CACHING, PROTOCOL,
- CONNECT, MAIN_TRANSPORT
+ REDIRECT, BACK_OFF, RETRY, CACHING, PROTOCOL, CONNECT, MAIN_TRANSPORT
}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultHttpRequestRetryHandler.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultHttpRequestRetryHandler.java
deleted file mode 100644
index 2591aa9..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultHttpRequestRetryHandler.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * ====================================================================
- * 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.hc.client5.http.impl;
-
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.ConnectException;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.net.ssl.SSLException;
-
-import org.apache.hc.client5.http.HttpRequestRetryHandler;
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.concurrent.CancellableDependency;
-import org.apache.hc.core5.http.ConnectionClosedException;
-import org.apache.hc.core5.http.HttpRequest;
-import org.apache.hc.core5.http.Methods;
-import org.apache.hc.core5.http.protocol.HttpContext;
-import org.apache.hc.core5.util.Args;
-
-/**
- * The default {@link HttpRequestRetryHandler} used by request executors.
- *
- * @since 4.0
- */
-@Contract(threading = ThreadingBehavior.STATELESS)
-public class DefaultHttpRequestRetryHandler implements HttpRequestRetryHandler {
-
- public static final DefaultHttpRequestRetryHandler INSTANCE = new DefaultHttpRequestRetryHandler();
-
- /**
- * the number of times a method will be retried
- */
- private final int retryCount;
-
- private final Set<Class<? extends IOException>> nonRetriableClasses;
-
- /**
- * Create the request retry handler using the specified IOException classes
- *
- * @param retryCount how many times to retry; 0 means no retries
- * @param clazzes the IOException types that should not be retried
- * @since 5.0
- */
- @SafeVarargs
- protected DefaultHttpRequestRetryHandler(
- final int retryCount,
- final Class<? extends IOException>... clazzes) {
- super();
- this.retryCount = retryCount;
- this.nonRetriableClasses = new HashSet<>();
- this.nonRetriableClasses.addAll(Arrays.asList(clazzes));
- }
-
- /**
- * Create the request retry handler using the following list of
- * non-retriable IOException classes: <br>
- * <ul>
- * <li>InterruptedIOException</li>
- * <li>UnknownHostException</li>
- * <li>ConnectException</li>
- * <li>ConnectionClosedException</li>
- * <li>SSLException</li>
- * </ul>
- *
- * @param retryCount how many times to retry; 0 means no retries
- * @since 5.0
- */
- public DefaultHttpRequestRetryHandler(final int retryCount) {
- this(retryCount,
- InterruptedIOException.class,
- UnknownHostException.class,
- ConnectException.class,
- ConnectionClosedException.class,
- SSLException.class);
- }
-
- /**
- * Create the request retry handler with a retry count of 3, requestSentRetryEnabled false
- * and using the following list of non-retriable IOException classes: <br>
- * <ul>
- * <li>InterruptedIOException</li>
- * <li>UnknownHostException</li>
- * <li>ConnectException</li>
- * <li>SSLException</li>
- * </ul>
- */
- public DefaultHttpRequestRetryHandler() {
- this(3);
- }
-
- /**
- * Used {@code retryCount} and {@code requestSentRetryEnabled} to determine
- * if the given method should be retried.
- */
- @Override
- public boolean retryRequest(
- final HttpRequest request,
- final IOException exception,
- final int executionCount,
- final HttpContext context) {
- Args.notNull(request, "HTTP request");
- Args.notNull(exception, "I/O exception");
-
- if (executionCount > this.retryCount) {
- // Do not retry if over max retry count
- return false;
- }
- if (this.nonRetriableClasses.contains(exception.getClass())) {
- return false;
- } else {
- for (final Class<? extends IOException> rejectException : this.nonRetriableClasses) {
- if (rejectException.isInstance(exception)) {
- return false;
- }
- }
- }
- if (request instanceof CancellableDependency && ((CancellableDependency) request).isCancelled()) {
- return false;
- }
-
- // Retry if the request is considered idempotent
- return handleAsIdempotent(request);
- }
-
- /**
- * @return the maximum number of times a method will be retried
- */
- public int getRetryCount() {
- return retryCount;
- }
-
- /**
- * @since 4.2
- */
- protected boolean handleAsIdempotent(final HttpRequest request) {
- return Methods.isIdempotent(request.getMethod());
- }
-
-}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRetryExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRetryExec.java
deleted file mode 100644
index d301cf0..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRetryExec.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * ====================================================================
- * 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.hc.client5.http.impl.async;
-
-import java.io.IOException;
-
-import org.apache.hc.client5.http.HttpRequestRetryHandler;
-import org.apache.hc.client5.http.HttpRoute;
-import org.apache.hc.client5.http.async.AsyncExecCallback;
-import org.apache.hc.client5.http.async.AsyncExecChain;
-import org.apache.hc.client5.http.async.AsyncExecChainHandler;
-import org.apache.hc.client5.http.impl.RequestCopier;
-import org.apache.hc.client5.http.protocol.HttpClientContext;
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.Internal;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.http.EntityDetails;
-import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpRequest;
-import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.nio.AsyncDataConsumer;
-import org.apache.hc.core5.http.nio.AsyncEntityProducer;
-import org.apache.hc.core5.util.Args;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Request execution handler in the asynchronous request execution chain
- * responsbile for making a decision whether a request failed due to
- * an I/O error should be re-executed.
- * <p>
- * Further responsibilities such as communication with the opposite
- * endpoint is delegated to the next executor in the request execution
- * chain.
- * </p>
- *
- * @since 5.0
- */
-@Contract(threading = ThreadingBehavior.STATELESS)
-@Internal
-public final class AsyncRetryExec implements AsyncExecChainHandler {
-
- private final Logger log = LoggerFactory.getLogger(getClass());
-
- private final HttpRequestRetryHandler retryHandler;
-
- public AsyncRetryExec(final HttpRequestRetryHandler retryHandler) {
- Args.notNull(retryHandler, "HTTP request retry handler");
- this.retryHandler = retryHandler;
- }
-
- private void internalExecute(
- final int execCount,
- final HttpRequest request,
- final AsyncEntityProducer entityProducer,
- final AsyncExecChain.Scope scope,
- final AsyncExecChain chain,
- final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
-
- final String exchangeId = scope.exchangeId;
-
- chain.proceed(RequestCopier.INSTANCE.copy(request), entityProducer, scope, new AsyncExecCallback() {
-
- @Override
- public AsyncDataConsumer handleResponse(
- final HttpResponse response,
- final EntityDetails entityDetails) throws HttpException, IOException {
- return asyncExecCallback.handleResponse(response, entityDetails);
- }
-
- @Override
- public void handleInformationResponse(final HttpResponse response) throws HttpException, IOException {
- asyncExecCallback.handleInformationResponse(response);
- }
-
- @Override
- public void completed() {
- asyncExecCallback.completed();
- }
-
- @Override
- public void failed(final Exception cause) {
- if (cause instanceof IOException) {
- final HttpRoute route = scope.route;
- final HttpClientContext clientContext = scope.clientContext;
- if (entityProducer != null && !entityProducer.isRepeatable()) {
- if (log.isDebugEnabled()) {
- log.debug(exchangeId + ": cannot retry non-repeatable request");
- }
- } else if (retryHandler.retryRequest(request, (IOException) cause, execCount, clientContext)) {
- if (log.isDebugEnabled()) {
- log.debug(exchangeId + ": " + cause.getMessage(), cause);
- }
- if (log.isInfoEnabled()) {
- log.info("Recoverable I/O exception ("+ cause.getClass().getName() + ") " +
- "caught when processing request to " + route);
- }
- scope.execRuntime.discardEndpoint();
- if (entityProducer != null) {
- entityProducer.releaseResources();
- }
- try {
- internalExecute(execCount + 1, request, entityProducer, scope, chain, asyncExecCallback);
- } catch (final IOException | HttpException ex) {
- asyncExecCallback.failed(ex);
- }
- return;
- }
- }
- asyncExecCallback.failed(cause);
- }
-
- });
-
- }
-
- @Override
- public void execute(
- final HttpRequest request,
- final AsyncEntityProducer entityProducer,
- final AsyncExecChain.Scope scope,
- final AsyncExecChain chain,
- final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
- internalExecute(1, request, entityProducer, scope, chain, asyncExecCallback);
- }
-
-}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
index 501ece7..13ddb63 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
@@ -40,7 +40,6 @@ import java.util.concurrent.ThreadFactory;
import org.apache.hc.client5.http.AuthenticationStrategy;
import org.apache.hc.client5.http.DnsResolver;
-import org.apache.hc.client5.http.HttpRequestRetryHandler;
import org.apache.hc.client5.http.HttpRequestRetryStrategy;
import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
@@ -192,7 +191,6 @@ public class H2AsyncClientBuilder {
private HttpRoutePlanner routePlanner;
private RedirectStrategy redirectStrategy;
- private HttpRequestRetryHandler retryHandler;
private HttpRequestRetryStrategy retryStrategy;
private Lookup<AuthSchemeProvider> authSchemeRegistry;
@@ -381,17 +379,6 @@ public class H2AsyncClientBuilder {
}
/**
- * Assigns {@link HttpRequestRetryHandler} instance.
- * <p>
- * Please note this value can be overridden by the {@link #disableAutomaticRetries()}
- * method.
- */
- public final H2AsyncClientBuilder setRetryHandler(final HttpRequestRetryHandler retryHandler) {
- this.retryHandler = retryHandler;
- return this;
- }
-
- /**
* Assigns {@link HttpRequestRetryStrategy} instance.
* <p>
* Please note this value can be overridden by the {@link #disableAutomaticRetries()}
@@ -687,20 +674,13 @@ public class H2AsyncClientBuilder {
// Add request retry executor, if not disabled
if (!automaticRetriesDisabled) {
- final HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
- if (retryHandlerCopy != null) {
- execChainDefinition.addFirst(
- new AsyncRetryExec(retryHandlerCopy),
- ChainElement.RETRY_IO_ERROR.name());
- } else {
- HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
- if (retryStrategyCopy == null) {
- retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
- }
- execChainDefinition.addFirst(
- new AsyncHttpRequestRetryExec(retryStrategyCopy),
- ChainElement.RETRY.name());
+ HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
+ if (retryStrategyCopy == null) {
+ retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
}
+ execChainDefinition.addFirst(
+ new AsyncHttpRequestRetryExec(retryStrategyCopy),
+ ChainElement.RETRY.name());
}
HttpRoutePlanner routePlannerCopy = this.routePlanner;
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
index 97784b8..3a724f9 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
@@ -40,7 +40,6 @@ import java.util.concurrent.ThreadFactory;
import org.apache.hc.client5.http.AuthenticationStrategy;
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
-import org.apache.hc.client5.http.HttpRequestRetryHandler;
import org.apache.hc.client5.http.HttpRequestRetryStrategy;
import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
@@ -227,7 +226,6 @@ public class HttpAsyncClientBuilder {
private HttpRoutePlanner routePlanner;
private RedirectStrategy redirectStrategy;
- private HttpRequestRetryHandler retryHandler;
private HttpRequestRetryStrategy retryStrategy;
private ConnectionReuseStrategy reuseStrategy;
@@ -488,17 +486,6 @@ public class HttpAsyncClientBuilder {
}
/**
- * Assigns {@link HttpRequestRetryHandler} instance.
- * <p>
- * Please note this value can be overridden by the {@link #disableAutomaticRetries()}
- * method.
- */
- public final HttpAsyncClientBuilder setRetryHandler(final HttpRequestRetryHandler retryHandler) {
- this.retryHandler = retryHandler;
- return this;
- }
-
- /**
* Assigns {@link HttpRequestRetryStrategy} instance.
* <p>
* Please note this value can be overridden by the {@link #disableAutomaticRetries()}
@@ -837,20 +824,13 @@ public class HttpAsyncClientBuilder {
// Add request retry executor, if not disabled
if (!automaticRetriesDisabled) {
- final HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
- if (retryHandlerCopy != null) {
- execChainDefinition.addFirst(
- new AsyncRetryExec(retryHandlerCopy),
- ChainElement.RETRY_IO_ERROR.name());
- } else {
- HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
- if (retryStrategyCopy == null) {
- retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
- }
- execChainDefinition.addFirst(
- new AsyncHttpRequestRetryExec(retryStrategyCopy),
- ChainElement.RETRY.name());
+ HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
+ if (retryStrategyCopy == null) {
+ retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
}
+ execChainDefinition.addFirst(
+ new AsyncHttpRequestRetryExec(retryStrategyCopy),
+ ChainElement.RETRY.name());
}
HttpRoutePlanner routePlannerCopy = this.routePlanner;
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
index c0c4a9c..b1d8a6b 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
@@ -39,7 +39,6 @@ import java.util.Map;
import org.apache.hc.client5.http.AuthenticationStrategy;
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
-import org.apache.hc.client5.http.HttpRequestRetryHandler;
import org.apache.hc.client5.http.HttpRequestRetryStrategy;
import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
@@ -203,7 +202,6 @@ public class HttpClientBuilder {
private LinkedList<ResponseInterceptorEntry> responseInterceptors;
private LinkedList<ExecInterceptorEntry> execInterceptors;
- private HttpRequestRetryHandler retryHandler;
private HttpRequestRetryStrategy retryStrategy;
private HttpRoutePlanner routePlanner;
private RedirectStrategy redirectStrategy;
@@ -495,17 +493,6 @@ public class HttpClientBuilder {
}
/**
- * Assigns {@link HttpRequestRetryHandler} instance.
- * <p>
- * Please note this value can be overridden by the {@link #disableAutomaticRetries()}
- * method.
- */
- public final HttpClientBuilder setRetryHandler(final HttpRequestRetryHandler retryHandler) {
- this.retryHandler = retryHandler;
- return this;
- }
-
- /**
* Assigns {@link HttpRequestRetryStrategy} instance.
* <p>
* Please note this value can be overridden by the {@link #disableAutomaticRetries()}
@@ -861,21 +848,13 @@ public class HttpClientBuilder {
// Add request retry executor, if not disabled
if (!automaticRetriesDisabled) {
- // This needs to be cleaned up as soon as HttpRequestRetryHandler will be removed
- final HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
- if (retryHandlerCopy != null) {
- execChainDefinition.addFirst(
- new RetryExec(retryHandlerCopy),
- ChainElement.RETRY_IO_ERROR.name());
- } else {
- HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
- if (retryStrategyCopy == null) {
- retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
- }
- execChainDefinition.addFirst(
- new HttpRequestRetryExec(retryStrategyCopy),
- ChainElement.RETRY.name());
+ HttpRequestRetryStrategy retryStrategyCopy = this.retryStrategy;
+ if (retryStrategyCopy == null) {
+ retryStrategyCopy = DefaultHttpRequestRetryStrategy.INSTANCE;
}
+ execChainDefinition.addFirst(
+ new HttpRequestRetryExec(retryStrategyCopy),
+ ChainElement.RETRY.name());
}
HttpRoutePlanner routePlannerCopy = this.routePlanner;
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/RetryExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/RetryExec.java
deleted file mode 100644
index 2e89f4a..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/RetryExec.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * ====================================================================
- * 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.hc.client5.http.impl.classic;
-
-import java.io.IOException;
-
-import org.apache.hc.client5.http.HttpRequestRetryHandler;
-import org.apache.hc.client5.http.HttpRoute;
-import org.apache.hc.client5.http.classic.ExecChain;
-import org.apache.hc.client5.http.classic.ExecChainHandler;
-import org.apache.hc.client5.http.protocol.HttpClientContext;
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.Internal;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.ClassicHttpResponse;
-import org.apache.hc.core5.http.HttpEntity;
-import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.NoHttpResponseException;
-import org.apache.hc.core5.util.Args;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Request execution handler in the classic request execution chain
- * responsible for making a decision whether a request failed due to
- * an I/O error should be re-executed.
- * <p>
- * Further responsibilities such as communication with the opposite
- * endpoint is delegated to the next executor in the request execution
- * chain.
- * </p>
- *
- * @since 4.3
- */
-@Contract(threading = ThreadingBehavior.STATELESS)
-@Internal
-public final class RetryExec implements ExecChainHandler {
-
- private final Logger log = LoggerFactory.getLogger(getClass());
-
- private final HttpRequestRetryHandler retryHandler;
-
- public RetryExec(
- final HttpRequestRetryHandler retryHandler) {
- Args.notNull(retryHandler, "HTTP request retry handler");
- this.retryHandler = retryHandler;
- }
-
- @Override
- public ClassicHttpResponse execute(
- final ClassicHttpRequest request,
- final ExecChain.Scope scope,
- final ExecChain chain) throws IOException, HttpException {
- Args.notNull(request, "HTTP request");
- Args.notNull(scope, "Scope");
- final String exchangeId = scope.exchangeId;
- final HttpRoute route = scope.route;
- final HttpClientContext context = scope.clientContext;
- ClassicHttpRequest currentRequest = request;
- for (int execCount = 1;; execCount++) {
- try {
- return chain.proceed(currentRequest, scope);
- } catch (final IOException ex) {
- if (scope.execRuntime.isExecutionAborted()) {
- throw new RequestFailedException("Request aborted");
- }
- final HttpEntity requestEntity = request.getEntity();
- if (requestEntity != null && !requestEntity.isRepeatable()) {
- if (log.isDebugEnabled()) {
- log.debug(exchangeId + ": cannot retry non-repeatable request");
- }
- throw ex;
- }
- if (retryHandler.retryRequest(request, ex, execCount, context)) {
- if (log.isDebugEnabled()) {
- log.debug(exchangeId + ": " + ex.getMessage(), ex);
- }
- if (log.isInfoEnabled()) {
- log.info("Recoverable I/O exception ("+ ex.getClass().getName() + ") " +
- "caught when processing request to " + route);
- }
- currentRequest = ClassicRequestCopier.INSTANCE.copy(scope.originalRequest);
- } else {
- if (ex instanceof NoHttpResponseException) {
- final NoHttpResponseException updatedex = new NoHttpResponseException(
- route.getTargetHost().toHostString() + " failed to respond");
- updatedex.setStackTrace(ex.getStackTrace());
- throw updatedex;
- }
- throw ex;
- }
- }
- }
- }
-
-}
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultHttpRequestRetryHandler.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultHttpRequestRetryHandler.java
deleted file mode 100644
index faf13af..0000000
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultHttpRequestRetryHandler.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * ====================================================================
- * 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.hc.client5.http.impl;
-
-import java.io.IOException;
-import java.net.SocketTimeoutException;
-import java.net.UnknownHostException;
-
-import org.apache.hc.client5.http.classic.methods.HttpGet;
-import org.junit.Assert;
-import org.junit.Test;
-
-
-@SuppressWarnings("boxing") // test class
-public class TestDefaultHttpRequestRetryHandler {
-
- @Test
- public void noRetryOnConnectTimeout() throws Exception {
- final HttpGet request = new HttpGet("/");
-
- final DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler();
- Assert.assertEquals(3, retryHandler.getRetryCount());
-
- Assert.assertFalse(retryHandler.retryRequest(request, new SocketTimeoutException(), 1, null));
- }
-
- @Test
- public void noRetryOnUnknownHost() throws Exception {
- final HttpGet request = new HttpGet("/");
-
- final DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler();
-
- Assert.assertFalse(retryHandler.retryRequest(request, new UnknownHostException(), 1, null));
- }
-
- @Test
- public void noRetryOnAbortedRequests() throws Exception{
- final HttpGet request = new HttpGet("/");
- request.cancel();
-
- final DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler();
-
- Assert.assertFalse(retryHandler.retryRequest(request, new IOException(), 3, null));
- }
-
- @Test
- public void retryOnNonAbortedRequests() throws Exception{
- final HttpGet request = new HttpGet("/");
-
- final DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler();
-
- Assert.assertTrue(retryHandler.retryRequest(request, new IOException(), 3, null));
- }
-
- @Test
- public void noRetryOnConnectionTimeout() throws Exception{
- final HttpGet request = new HttpGet("/");
-
- final DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler();
-
- Assert.assertFalse(retryHandler.retryRequest(request, new SocketTimeoutException(), 3, null));
- }
-
-}
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestRetryExec.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestRetryExec.java
deleted file mode 100644
index 955753b..0000000
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestRetryExec.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * ====================================================================
- * 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.hc.client5.http.impl.classic;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import org.apache.hc.client5.http.HttpRequestRetryHandler;
-import org.apache.hc.client5.http.HttpRoute;
-import org.apache.hc.client5.http.classic.ExecChain;
-import org.apache.hc.client5.http.classic.ExecRuntime;
-import org.apache.hc.client5.http.classic.methods.HttpGet;
-import org.apache.hc.client5.http.classic.methods.HttpPost;
-import org.apache.hc.client5.http.entity.EntityBuilder;
-import org.apache.hc.client5.http.protocol.HttpClientContext;
-import org.apache.hc.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.HttpRequest;
-import org.apache.hc.core5.http.protocol.HttpContext;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-@SuppressWarnings({"boxing","static-access"}) // test code
-public class TestRetryExec {
-
- @Mock
- private HttpRequestRetryHandler retryHandler;
- @Mock
- private ExecRuntime endpoint;
- @Mock
- private ExecChain chain;
-
- private RetryExec retryExec;
- private HttpHost target;
-
- @Before
- public void setup() throws Exception {
- MockitoAnnotations.initMocks(this);
- retryExec = new RetryExec(retryHandler);
- target = new HttpHost("localhost", 80);
- }
-
- @Test(expected = IOException.class)
- public void testFundamentals() throws Exception {
- final HttpRoute route = new HttpRoute(target);
- final HttpGet originalRequest = new HttpGet("/test");
- originalRequest.addHeader("header", "this");
- originalRequest.addHeader("header", "that");
- final HttpClientContext context = HttpClientContext.create();
-
- Mockito.when(chain.proceed(
- Mockito.<ClassicHttpRequest>any(),
- Mockito.<ExecChain.Scope>any())).thenAnswer(new Answer<Object>() {
-
- @Override
- public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
- final Object[] args = invocationOnMock.getArguments();
- final ClassicHttpRequest wrapper = (ClassicHttpRequest) args[0];
- final Header[] headers = wrapper.getHeaders();
- Assert.assertEquals(2, headers.length);
- Assert.assertEquals("this", headers[0].getValue());
- Assert.assertEquals("that", headers[1].getValue());
- wrapper.addHeader("Cookie", "monster");
- throw new IOException("Ka-boom");
- }
-
- });
- Mockito.when(retryHandler.retryRequest(
- Mockito.<HttpRequest>any(),
- Mockito.<IOException>any(),
- Mockito.eq(1),
- Mockito.<HttpContext>any())).thenReturn(Boolean.TRUE);
- final ExecChain.Scope scope = new ExecChain.Scope("test", route, originalRequest, endpoint, context);
- final ClassicHttpRequest request = ClassicRequestCopier.INSTANCE.copy(originalRequest);
- try {
- retryExec.execute(request, scope, chain);
- } catch (final IOException ex) {
- Mockito.verify(chain, Mockito.times(2)).proceed(
- Mockito.<ClassicHttpRequest>any(),
- Mockito.same(scope));
- throw ex;
- }
- }
-
- @Test(expected = IOException.class)
- public void testAbortedRequest() throws Exception {
- final HttpRoute route = new HttpRoute(target);
- final HttpGet originalRequest = new HttpGet("/test");
- final HttpClientContext context = HttpClientContext.create();
-
- Mockito.when(chain.proceed(
- Mockito.<ClassicHttpRequest>any(),
- Mockito.<ExecChain.Scope>any())).thenThrow(new IOException("Ka-boom"));
- Mockito.when(endpoint.isExecutionAborted()).thenReturn(true);
-
- final ExecChain.Scope scope = new ExecChain.Scope("test", route, originalRequest, endpoint, context);
- final ClassicHttpRequest request = ClassicRequestCopier.INSTANCE.copy(originalRequest);
- try {
- retryExec.execute(request, scope, chain);
- } catch (final IOException ex) {
- Mockito.verify(chain, Mockito.times(1)).proceed(
- Mockito.same(request),
- Mockito.same(scope));
- Mockito.verify(retryHandler, Mockito.never()).retryRequest(
- Mockito.<HttpRequest>any(),
- Mockito.<IOException>any(),
- Mockito.anyInt(),
- Mockito.<HttpContext>any());
-
- throw ex;
- }
- }
-
- @Test(expected = IOException.class)
- public void testNonRepeatableRequest() throws Exception {
- final HttpRoute route = new HttpRoute(target);
- final HttpPost originalRequest = new HttpPost("/test");
- originalRequest.setEntity(EntityBuilder.create()
- .setStream(new ByteArrayInputStream(new byte[]{}))
- .build());
- final HttpClientContext context = HttpClientContext.create();
-
- Mockito.when(chain.proceed(
- Mockito.<ClassicHttpRequest>any(),
- Mockito.<ExecChain.Scope>any())).thenAnswer(new Answer<Object>() {
-
- @Override
- public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
- final Object[] args = invocationOnMock.getArguments();
- final ClassicHttpRequest req = (ClassicHttpRequest) args[0];
- req.getEntity().writeTo(new ByteArrayOutputStream());
- throw new IOException("Ka-boom");
- }
-
- });
- Mockito.when(retryHandler.retryRequest(
- Mockito.<HttpRequest>any(),
- Mockito.<IOException>any(),
- Mockito.eq(1),
- Mockito.<HttpContext>any())).thenReturn(Boolean.TRUE);
- final ExecChain.Scope scope = new ExecChain.Scope("test", route, originalRequest, endpoint, context);
- final ClassicHttpRequest request = ClassicRequestCopier.INSTANCE.copy(originalRequest);
- try {
- retryExec.execute(request, scope, chain);
- } catch (final IOException ex) {
- Mockito.verify(chain, Mockito.times(1)).proceed(
- Mockito.same(request),
- Mockito.same(scope));
-
- throw ex;
- }
- }
-
-}