View Javadoc

1   /**
2    * Copyright 2008 Atlassian Pty Ltd 
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0 
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
15   */
16  
17  package com.atlassian.util.concurrent;
18  
19  import java.util.concurrent.TimeUnit;
20  import java.util.concurrent.TimeoutException;
21  import java.util.concurrent.locks.Condition;
22  
23  import net.jcip.annotations.Immutable;
24  
25  /**
26   * Automatically calculates elapsed time from when it is created. Useful when
27   * successively calling blocking methods and a time since call time needs to be
28   * worked out.
29   * <p>
30   * Usage:
31   * 
32   * <pre>
33   * Timeout timeout = Timeout.getNanosTimeout(1, TimeUnit.SECONDS);
34   * String str = futureString.get(timeout.getTime(), timeout.getUnit());
35   * Integer num = futureInt.get(timeout.getTime(), timeout.getUnit());
36   * </pre>
37   * 
38   * where if the first call takes quarter of a second, the second call is passed
39   * the equivalent of three-quarters of a second.
40   */
41  @Immutable
42  public final class Timeout {
43  
44      private static final TimeSupplier NANO_SUPPLIER = new TimeSupplier() {
45          public long currentTime() {
46              return System.nanoTime();
47          };
48  
49          public TimeUnit precision() {
50              return TimeUnit.NANOSECONDS;
51          };
52      };
53  
54      private static final TimeSupplier MILLIS_SUPPLIER = new TimeSupplier() {
55          public long currentTime() {
56              return System.currentTimeMillis();
57          };
58  
59          public TimeUnit precision() {
60              return TimeUnit.MILLISECONDS;
61          };
62      };
63  
64      /**
65       * Get a {@link Timeout} that uses nanosecond precision. The accuracy will
66       * depend on the accuracy of {@link System#nanoTime()}.
67       * 
68       * @param time the maximum time to wait for the lock
69       * @param unit the time unit of the <tt>time</tt> argument.
70       * @return timeout with {@link TimeUnit#NANOSECONDS} precision.
71       */
72      public static Timeout getNanosTimeout(final long time, final TimeUnit unit) {
73          return new Timeout(time, unit, NANO_SUPPLIER);
74      }
75  
76      /**
77       * Get a {@link Timeout} that uses nanosecond precision. The accuracy will
78       * depend on the accuracy of {@link System#nanoTime()}.
79       * 
80       * @param time the maximum time to wait for the lock
81       * @param unit the time unit of the <tt>time</tt> argument.
82       * @return timeout with {@link TimeUnit#NANOSECONDS} precision.
83       */
84      public static Timeout getMillisTimeout(final long time, final TimeUnit unit) {
85          return new Timeout(time, unit, MILLIS_SUPPLIER);
86      }
87  
88      private final long created;
89      private final long time;
90      private final TimeSupplier supplier;
91  
92      Timeout(final long time, final TimeUnit unit, final TimeSupplier supplier) {
93          created = supplier.currentTime();
94          this.supplier = supplier;
95          this.time = this.supplier.precision().convert(time, unit);
96      }
97  
98      public long getTime() {
99          return (created + time) - supplier.currentTime();
100     }
101 
102     public TimeUnit getUnit() {
103         return supplier.precision();
104     }
105 
106     /**
107      * Has this timeout expired
108      * 
109      * @return true if expired
110      */
111     public boolean isExpired() {
112         return getTime() <= 0;
113     }
114 
115     //
116     // util
117     //
118 
119     void await(final Awaitable waitable) throws TimeoutException, InterruptedException {
120         if (!waitable.await(getTime(), getUnit())) {
121             throwTimeoutException();
122         }
123     }
124 
125     // TODO unused, retire?
126     // /CLOVER:OFF
127     void await(final Condition condition) throws TimeoutException, InterruptedException {
128         if (!condition.await(getTime(), getUnit())) {
129             throwTimeoutException();
130         }
131     }
132 
133     /**
134      * Always throws a {@link TimeoutException}.
135      * 
136      * @throws TimedOutException, always.
137      */
138     public void throwTimeoutException() throws TimedOutException {
139         throw new TimedOutException(getTime(), getUnit());
140     }
141 
142     // /CLOVER:ON
143 
144     /**
145      * Supply time and precision to a {@link Timeout}.
146      */
147     interface TimeSupplier {
148         long currentTime();
149 
150         TimeUnit precision();
151     }
152 }