1 package com.atlassian.plugin.util;
2
3 import java.util.concurrent.TimeUnit;
4
5 /**
6 * Used to calculate elapsed time for timeouts from when it is created when successively calling
7 * blocking methods. Always converts to nanoseconds.
8 * <p>
9 * Usage:
10 *
11 * <pre>
12 * Timeout timeout = Timeout.getNanosTimeout(1, TimeUnit.SECONDS);
13 * String str = futureString.get(timeout.getTime(), timeout.getUnit());
14 * Integer num = futureInt.get(timeout.getTime(), timeout.getUnit());
15 * </pre>
16 *
17 * where if the first call takes quarter of a second, the second call is passed the equivalent of
18 * three-quarters of a second.
19 *
20 * @since 2.2
21 */
22 public class Timeout
23 {
24 private static final TimeSupplier NANO_SUPPLIER = new TimeSupplier()
25 {
26 public long currentTime()
27 {
28 return System.nanoTime();
29 };
30
31 public TimeUnit precision()
32 {
33 return TimeUnit.NANOSECONDS;
34 };
35 };
36
37 private static final TimeSupplier MILLIS_SUPPLIER = new TimeSupplier()
38 {
39 public long currentTime()
40 {
41 return System.currentTimeMillis();
42 };
43
44 public TimeUnit precision()
45 {
46 return TimeUnit.MILLISECONDS;
47 };
48 };
49
50 /**
51 * Get a {@link Timeout} that uses nanosecond precision. The accuracy will depend on the
52 * accuracy of {@link System#nanoTime()}.
53 *
54 * @param time the maximum time to wait for the lock
55 * @param unit the time unit of the <tt>time</tt> argument.
56 * @return timeout with {@link TimeUnit#NANOSECONDS} precision.
57 */
58 public static Timeout getNanosTimeout(final long time, final TimeUnit unit)
59 {
60 return new Timeout(time, unit, NANO_SUPPLIER);
61 }
62
63 /**
64 * Get a {@link Timeout} that uses millisecond precision.
65 *
66 * @param time the maximum time to wait for the lock
67 * @param unit the time unit of the <tt>time</tt> argument.
68 * @return timeout with {@link TimeUnit#MILLISECONDS} precision.
69 */
70 public static Timeout getMillisTimeout(final long time, final TimeUnit unit)
71 {
72 return new Timeout(time, unit, MILLIS_SUPPLIER);
73 }
74
75 private final long created;
76 private final long time;
77 private final TimeSupplier supplier;
78
79 Timeout(final long time, final TimeUnit unit, final TimeSupplier supplier)
80 {
81 created = supplier.currentTime();
82 this.supplier = supplier;
83 this.time = this.supplier.precision().convert(time, unit);
84 }
85
86 public long getTime()
87 {
88 return (created + time) - supplier.currentTime();
89 }
90
91 public TimeUnit getUnit()
92 {
93 return supplier.precision();
94 }
95
96 public String getRemaining()
97 {
98 return TimeUnit.SECONDS.convert(getTime(), getUnit()) + " seconds remaining";
99 }
100
101 /**
102 * Has this timeout expired
103 *
104 * @return
105 */
106 public boolean isExpired()
107 {
108 return getTime() <= 0;
109 }
110
111 /**
112 * Supply time and precision to a {@link Timeout}.
113 */
114 interface TimeSupplier
115 {
116 long currentTime();
117
118 TimeUnit precision();
119 }
120 }