package jdrivesync.gdrive; import jdrivesync.cli.Options; import jdrivesync.exception.JDriveSyncException; import jdrivesync.logging.LoggerFactory; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; public class RetryOperation { private static final Logger LOGGER = LoggerFactory.getLogger(); public interface RetryCallback<T> { T execute() throws IOException; } public static <T> T executeWithRetry(Options options, RetryCallback<T> retryCallback) throws IOException { boolean successful = false; int numberOfAttempts = 0; T returnValue = null; while (!successful && numberOfAttempts < options.getNetworkNumberOfRetries()) { try { numberOfAttempts++; if (numberOfAttempts > 1) { LOGGER.log(Level.FINE, "Retrying network operation for the " + numberOfAttempts + ". time."); } returnValue = retryCallback.execute(); successful = true; } catch (IOException e) { LOGGER.log(Level.FINE, "Network operation failed for the " + numberOfAttempts + ". time.", e); } if (!successful) { try { long sleepMillis = (numberOfAttempts * numberOfAttempts) * options.getNetworkSleepBetweenAttempts(); LOGGER.log(Level.FINE, "Sleeping for " + sleepMillis + "."); Thread.sleep(sleepMillis); } catch (InterruptedException ignored) { } } } if (!successful) { throw new JDriveSyncException(JDriveSyncException.Reason.IOException, "Failed to execute network operation for " + numberOfAttempts + ". time(s)."); } else { if (numberOfAttempts > 1) { LOGGER.log(Level.FINE, "Successfully completed network operation after " + numberOfAttempts + " attempt(s)."); } } return returnValue; } }