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.lang.reflect.UndeclaredThrowableException;
032
033import org.apache.http.HttpException;
034import org.apache.http.annotation.Contract;
035import org.apache.http.annotation.ThreadingBehavior;
036import org.apache.http.client.BackoffManager;
037import org.apache.http.client.ConnectionBackoffStrategy;
038import org.apache.http.client.methods.CloseableHttpResponse;
039import org.apache.http.client.methods.HttpExecutionAware;
040import org.apache.http.client.methods.HttpRequestWrapper;
041import org.apache.http.client.protocol.HttpClientContext;
042import org.apache.http.conn.routing.HttpRoute;
043import org.apache.http.util.Args;
044
045/**
046 * @since 4.3
047 */
048@Contract(threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL)
049public class BackoffStrategyExec implements ClientExecChain {
050
051    private final ClientExecChain requestExecutor;
052    private final ConnectionBackoffStrategy connectionBackoffStrategy;
053    private final BackoffManager backoffManager;
054
055    public BackoffStrategyExec(
056            final ClientExecChain requestExecutor,
057            final ConnectionBackoffStrategy connectionBackoffStrategy,
058            final BackoffManager backoffManager) {
059        super();
060        Args.notNull(requestExecutor, "HTTP client request executor");
061        Args.notNull(connectionBackoffStrategy, "Connection backoff strategy");
062        Args.notNull(backoffManager, "Backoff manager");
063        this.requestExecutor = requestExecutor;
064        this.connectionBackoffStrategy = connectionBackoffStrategy;
065        this.backoffManager = backoffManager;
066    }
067
068    @Override
069    public CloseableHttpResponse execute(
070            final HttpRoute route,
071            final HttpRequestWrapper request,
072            final HttpClientContext context,
073            final HttpExecutionAware execAware) throws IOException, HttpException {
074        Args.notNull(route, "HTTP route");
075        Args.notNull(request, "HTTP request");
076        Args.notNull(context, "HTTP context");
077        CloseableHttpResponse out = null;
078        try {
079            out = this.requestExecutor.execute(route, request, context, execAware);
080        } catch (final Exception ex) {
081            if (out != null) {
082                out.close();
083            }
084            if (this.connectionBackoffStrategy.shouldBackoff(ex)) {
085                this.backoffManager.backOff(route);
086            }
087            if (ex instanceof RuntimeException) {
088                throw (RuntimeException) ex;
089            }
090            if (ex instanceof HttpException) {
091                throw (HttpException) ex;
092            }
093            if (ex instanceof IOException) {
094                throw (IOException) ex;
095            }
096            throw new UndeclaredThrowableException(ex);
097        }
098        if (this.connectionBackoffStrategy.shouldBackoff(out)) {
099            this.backoffManager.backOff(route);
100        } else {
101            this.backoffManager.probe(route);
102        }
103        return out;
104    }
105
106}