001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.oozie.client.retry;
020
021import java.io.IOException;
022import java.net.ConnectException;
023import java.net.SocketException;
024import java.net.URL;
025
026/**
027 * HTTP connection retryable class. It retries =oozie.connection.retry.count= times for ConnectException. For
028 * SocketException all create connection are retried except =PUT= and =POST=.
029 */
030public abstract class ConnectionRetriableClient {
031    private final int retryCount;
032
033    public ConnectionRetriableClient(int retryCount) {
034        this.retryCount = retryCount;
035    }
036
037    public Object execute(URL url, String method) throws IOException {
038        int numTries = 0;
039        boolean stopRetry = false;
040        Exception cliException = null;
041
042        while (numTries < retryCount && !stopRetry) {
043            try {
044                return doExecute(url, method);
045            }
046            catch (ConnectException e) {
047                sleep(e, numTries++);
048                cliException = e;
049            }
050            catch (SocketException e) {
051                if (method.equals("POST") || method.equals("PUT")) {
052                    stopRetry = true;
053                }
054                else {
055                    sleep(e, numTries++);
056                }
057                cliException = e;
058            }
059            catch (Exception e) {
060                stopRetry = true;
061                cliException = e;
062                numTries++;
063                // No retry for other exceptions
064            }
065        }
066        throw new IOException("Error while connecting Oozie server. No of retries = " + numTries + ". Exception = "
067                + cliException.getMessage(), cliException);
068    }
069
070    private void sleep(Exception e, int numTries) {
071        try {
072            long wait = getWaitTimeExp(numTries);
073            System.err.println("Connection exception has occurred [ " + e.getClass().getName() + " " + e.getMessage()
074                    + " ]. Trying after " + wait / 1000 + " sec." + " Retry count = " + (numTries + 1));
075            Thread.sleep(wait);
076        }
077        catch (InterruptedException e1) {
078            // Ignore InterruptedException
079        }
080    }
081
082    /*
083     * Returns the next wait interval, in milliseconds, using an exponential backoff algorithm.
084     */
085    private long getWaitTimeExp(int retryCount) {
086        long waitTime = ((long) Math.pow(2, retryCount) * 1000L);
087        return waitTime;
088    }
089
090    public abstract Object doExecute(URL url, String method) throws Exception;
091
092}