1 package com.atlassian.plugin.util;
2
3 import io.atlassian.util.concurrent.Timeout;
4 import org.slf4j.Logger;
5 import org.slf4j.LoggerFactory;
6
7 import java.util.concurrent.TimeUnit;
8
9 import static java.lang.Thread.sleep;
10
11 /**
12 * Utility methods for synchronising on asynchronous processes
13 */
14 public class WaitUntil {
15 private static final Logger log = LoggerFactory.getLogger(WaitUntil.class);
16
17 /**
18 * Default {@link #STARTUP_WAIT}
19 */
20 private static final int DEFAULT_STARTUP_WAIT = 60;
21
22 /**
23 * Number of seconds to wait before a plugin starts up. Configurable through
24 * system property "com.atlassian.plugin.startup.wait". Defaults to
25 * {@link #DEFAULT_STARTUP_WAIT}
26 */
27 private static final int STARTUP_WAIT = Integer.getInteger("com.atlassian.plugin.startup.wait", DEFAULT_STARTUP_WAIT);
28
29 private WaitUntil() {
30 }
31
32 /**
33 * Invokes the wait condition, trying every second for 10 seconds
34 *
35 * @param waitCondition The condition that determines when to stop waiting
36 * @return True if the condition returned true
37 */
38 public static boolean invoke(final WaitCondition waitCondition) {
39 return invoke(waitCondition, STARTUP_WAIT);
40 }
41
42 /**
43 * Invokes the wait condition, trying every second for the configured
44 * seconds
45 *
46 * @param waitCondition The condition that determines when to stop waiting
47 * @param tries The number of tries to attempt
48 * @return True if the condition returned true
49 */
50 public static boolean invoke(final WaitCondition waitCondition, final int tries) {
51 final int secondMillis = 1000;
52 return invoke(waitCondition, tries * secondMillis, TimeUnit.MILLISECONDS, secondMillis);
53 }
54
55 /**
56 * Invokes the wait condition, trying every second for the configured
57 * seconds
58 *
59 * @param waitCondition The condition that determines when to stop waiting
60 * @param time the amount of time to wait
61 * @param unit the time unit time is specified in
62 * @param retryInterval how often to re-check the condition (specified in
63 * the supplied TimeUnit)
64 * @return True if the condition returned true
65 */
66 public static boolean invoke(final WaitCondition waitCondition, final int time, final TimeUnit unit, final int retryInterval) {
67 final Timeout timeout = Timeout.getMillisTimeout(time, unit);
68 boolean successful = false;
69 while (!timeout.isExpired()) {
70 if (waitCondition.isFinished()) {
71 successful = true;
72 break;
73 }
74
75 if (log.isInfoEnabled()) {
76 log.info(waitCondition.getWaitMessage() + ", " + TimeUnit.SECONDS.convert(timeout.getTime(), timeout.getUnit()) + " seconds remaining");
77 }
78 try {
79 sleep(unit.toMillis(retryInterval));
80 } catch (final InterruptedException e) {
81 break;
82 }
83 }
84 return successful;
85 }
86
87 /**
88 * The condition to determine when to stop waiting
89 */
90 public interface WaitCondition {
91 /**
92 * If the condition has been finished
93 *
94 * @return True if finished and should stop waiting
95 */
96 boolean isFinished();
97
98 /**
99 * Gets the wait message to log for each try
100 *
101 * @return The string to print describing why the code is waiting
102 */
103 String getWaitMessage();
104 }
105 }