View Javadoc

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 }