/** * AnalyzerBeans * Copyright (C) 2014 Neopost - Customer Information Management * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.eobjects.analyzer.util.ws; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A {@link ServiceSession} that automatically retries a service request in case * it fails. */ public class RetryServiceSession<R> extends SimpleServiceSession<R> implements ServiceSession<R> { public static final int DEFAULT_RETRY_SLEEP_TIME = 1000; private static final Logger logger = LoggerFactory.getLogger(SimpleServiceSession.class); private final int _maxRetries; private final AtomicInteger _successCount; private final AtomicInteger _retryCount; private final AtomicInteger _failureCount; private final int[] _sleepTimeBetweenRetries; /** * Constructs a {@link RetryServiceSession}. * * @param maxRetries * maximum number of retries */ public RetryServiceSession(int maxRetries) { this(maxRetries, null); } /** * Constructs a {@link RetryServiceSession}. * * @param maxRetries * maximum number of retries * @param sleepTimeBetweenRetries * the amount of time to sleep between retries. When this array * is null, empty or not of appropriate size, a sleep time of * {@link #DEFAULT_RETRY_SLEEP_TIME} will be used. */ public RetryServiceSession(int maxRetries, int[] sleepTimeBetweenRetries) { if (maxRetries < 0) { throw new IllegalArgumentException("Max retries cannot be a negative number"); } _maxRetries = maxRetries; _sleepTimeBetweenRetries = sleepTimeBetweenRetries; _successCount = new AtomicInteger(); _retryCount = new AtomicInteger(); _failureCount = new AtomicInteger(); } @Override public ServiceResult<R> invokeService(Callable<R> callable) { // note attemptNo is 1-based int attemptNo = 1; while (true) { final ServiceResult<R> result = super.invokeService(callable); if (result.isSuccesfull()) { _successCount.incrementAndGet(); return result; } else { if (logger.isDebugEnabled()) { logger.debug("Attempt no. " + attemptNo + " to invoke service failed", result.getError()); } } if (attemptNo > _maxRetries) { _failureCount.incrementAndGet(); return result; } long sleepTime = getSleepTime(attemptNo); attemptNo++; _retryCount.incrementAndGet(); if (sleepTime > 0) { try { Thread.sleep(sleepTime); } catch (InterruptedException e) { // do nothing } } } } private long getSleepTime(int attemptNo) { int index = attemptNo - 1; if (_sleepTimeBetweenRetries != null && _sleepTimeBetweenRetries.length > index) { return _sleepTimeBetweenRetries[index]; } return DEFAULT_RETRY_SLEEP_TIME; } /** * Gets the maximum number of retries tolerated before the service * invocation is considered a failure. * * @return */ public int getMaxRetries() { return _maxRetries; } /** * Gets the actual number of service invocation retries performed * * @return */ public int getRetryCount() { return _retryCount.get(); } /** * Gets the number of failed service invocations. A failure in this sense * mean that all retries failed. * * @return */ public int getFailureCount() { return _failureCount.get(); } /** * Gets the number of successful service invocations. * * @return */ public int getSuccessCount() { return _successCount.get(); } }