RATIS-2057. Add back JavaUtils.attemptUntilTrue(..). (#1066)

diff --git a/ratis-common/src/main/java/org/apache/ratis/util/JavaUtils.java b/ratis-common/src/main/java/org/apache/ratis/util/JavaUtils.java
index f689006..7d1d753 100644
--- a/ratis-common/src/main/java/org/apache/ratis/util/JavaUtils.java
+++ b/ratis-common/src/main/java/org/apache/ratis/util/JavaUtils.java
@@ -41,6 +41,7 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
+import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Supplier;
@@ -244,6 +245,18 @@
     attemptRepeatedly(CheckedRunnable.asCheckedSupplier(runnable), numAttempts, sleepTime, name, log);
   }
 
+  /** Attempt to wait the given condition to return true multiple times. */
+  static void attemptUntilTrue(
+      BooleanSupplier condition, int numAttempts, TimeDuration sleepTime, String name, Logger log)
+      throws InterruptedException {
+    Objects.requireNonNull(condition, "condition == null");
+    attempt(() -> {
+      if (!condition.getAsBoolean()) {
+        throw new IllegalStateException("Condition " + name + " is false.");
+      }
+    }, numAttempts, sleepTime, name, log);
+  }
+
   static Timer runRepeatedly(Runnable runnable, long delay, long period, TimeUnit unit) {
     final Timer timer = new Timer(true);
     timer.schedule(new TimerTask() {