1 package org.eclipse.aether.named.support; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import java.util.concurrent.Callable; 23 import java.util.concurrent.TimeUnit; 24 import java.util.function.Predicate; 25 26 import org.slf4j.Logger; 27 import org.slf4j.LoggerFactory; 28 29 /** 30 * Retry helper: retries given {@code Callable} as long as it returns {@code null} (interpreted 31 * as "no answer yet") or given time passes. This helper implements similar semantics regarding 32 * caller threads as {@link java.util.concurrent.locks.Lock#tryLock(long, TimeUnit)} method does: 33 * blocks the caller thread until operation return non-{@code null} value within the given waiting 34 * time and the current thread has not been {@linkplain Thread#interrupt interrupted}. 35 * 36 * @since 1.7.3 37 */ 38 public final class Retry 39 { 40 private static final Logger LOGGER = LoggerFactory.getLogger( Retry.class ); 41 42 private Retry() 43 { 44 // no instances 45 } 46 47 /** 48 * Retries for given amount of time (time, unit) the passed in operation, sleeping given 49 * {@code sleepMills} between retries. In case operation returns {@code null}, it is assumed 50 * "is not done yet" state, so retry will happen (if time barrier allows). If time barrier 51 * passes, and still {@code null} ("is not done yet") is returned from operation, the 52 * {@code defaultResult} is returned. 53 */ 54 public static <R> R retry( final long time, 55 final TimeUnit unit, 56 final long sleepMillis, 57 final Callable<R> operation, 58 final Predicate<Exception> retryPredicate, 59 final R defaultResult ) throws InterruptedException 60 { 61 long now = System.nanoTime(); 62 final long barrier = now + unit.toNanos( time ); 63 int attempt = 1; 64 R result = null; 65 while ( now < barrier && result == null ) 66 { 67 try 68 { 69 result = operation.call(); 70 if ( result == null ) 71 { 72 LOGGER.trace( "Retry attempt {}: no result", attempt ); 73 Thread.sleep( sleepMillis ); 74 } 75 } 76 catch ( InterruptedException e ) 77 { 78 throw e; 79 } 80 catch ( Exception e ) 81 { 82 LOGGER.trace( "Retry attempt {}: operation failure", attempt, e ); 83 if ( retryPredicate != null && !retryPredicate.test( e ) ) 84 { 85 throw new IllegalStateException( e ); 86 } 87 } 88 now = System.nanoTime(); 89 attempt++; 90 } 91 return result == null ? defaultResult : result; 92 } 93 }