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.Callable;
20  import java.util.concurrent.CancellationException;
21  import java.util.concurrent.CountDownLatch;
22  import java.util.concurrent.ExecutionException;
23  import java.util.concurrent.Future;
24  import java.util.concurrent.FutureTask;
25  import java.util.concurrent.TimeUnit;
26  import java.util.concurrent.TimeoutException;
27  import java.util.concurrent.atomic.AtomicReference;
28  
29  import net.jcip.annotations.ThreadSafe;
30  
31  /**
32   * {@link SettableFuture} is a {@link Future} implementation where the
33   * responsibility for producing the result is external to the future instance,
34   * unlike {@link FutureTask} where the future holds the operation (a
35   * {@link Callable} or {@link Runnable} instance) and the first thread that
36   * calls {@link FutureTask#run()} executes the operation.
37   * <p>
38   * This is useful in situations where all the inputs may not be available at
39   * construction time.
40   */
41  @ThreadSafe
42  public class SettableFuture<T> implements Future<T> {
43      private final AtomicReference<Value<T>> ref = new AtomicReference<Value<T>>();
44      private final CountDownLatch latch = new CountDownLatch(1);
45  
46      /**
47       * Set the value returned by {@link #get()} and {@link #get(long, TimeUnit)}
48       * <p>
49       * Note that this can only be done once unless the value of the second set
50       * equals the first value otherwise an exception will be thrown. It also
51       * cannot be set if this future has been cancelled or an exception has been
52       * set.
53       * 
54       * @param value the value to be set.
55       */
56      public void set(final T value) {
57          setAndCheckValue(new ReferenceValue<T>(value));
58      }
59  
60      /**
61       * Set the exception thrown as the causal exception of an ExecutionException
62       * by {@link #get()} and {@link #get(long, TimeUnit)}
63       * <p>
64       * Note that this can only be done once unless the value of the second
65       * {@link #setException(Throwable)} equals the first value otherwise an
66       * exception will be thrown (as most exceptions do not implement equals this
67       * effectively means the same reference). It also cannot be set if this
68       * future has been cancelled or a a value has been set.
69       * 
70       * @param value the value to be set.
71       */
72      public void setException(final Throwable throwable) {
73          setAndCheckValue(new ThrowableValue<T>(throwable));
74      }
75  
76      public T get() throws InterruptedException, ExecutionException {
77          latch.await();
78          return ref.get().get();
79      }
80  
81      public T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
82          if (!latch.await(timeout, unit)) {
83              throw new TimedOutException(timeout, unit);
84          }
85          return ref.get().get();
86      }
87  
88      public boolean isDone() {
89          return ref.get() != null;
90      }
91  
92      public boolean isCancelled() {
93          return isDone() && (ref.get() instanceof CancelledValue);
94      }
95  
96      public boolean cancel(final boolean mayInterruptIfRunning) {
97          return setValue(new CancelledValue<T>()) == null;
98      }
99  
100     /**
101      * Set the inner value and check that if there is an old value it equals the
102      * one we are setting.
103      * 
104      * @param value to set.
105      * @return the old value if set or null.
106      */
107     private void setAndCheckValue(final Value<T> value) {
108         final Value<T> oldValue = setValue(value);
109         if ((oldValue != null) && !value.equals(oldValue)) {
110             throw new IllegalStateException("cannot change value after it has been set");
111         }
112     }
113 
114     /**
115      * Set the inner value.
116      * 
117      * @param value to set.
118      * @return the old value if set or null.
119      */
120     private Value<T> setValue(final Value<T> value) {
121         while (true) {
122             final Value<T> oldValue = ref.get();
123             if (oldValue != null) {
124                 return oldValue;
125             }
126             // /CLOVER:OFF
127             if (!ref.compareAndSet(null, value)) {
128                 continue;
129             }
130             // /CLOVER:ON
131             latch.countDown();
132             return null;
133         }
134     }
135 
136     /** the inner value */
137     private static interface Value<T> {
138         T get() throws ExecutionException;
139     }
140 
141     /** holds a reference */
142     private static class ReferenceValue<T> implements Value<T> {
143         private final T value;
144 
145         ReferenceValue(final T value) {
146             this.value = value;
147         }
148 
149         public T get() {
150             return value;
151         }
152 
153         @Override
154         public boolean equals(final Object obj) {
155             // no need to check for reference equality, not possible
156             if (!(obj instanceof ReferenceValue)) {
157                 return false;
158             }
159             final ReferenceValue<?> other = (ReferenceValue<?>) obj;
160             return (value == null) ? (other.value == null) : value.equals(other.value);
161         }
162 
163         // /CLOVER:OFF
164         @Override
165         public int hashCode() {
166             throw new UnsupportedOperationException();
167         }
168         // /CLOVER:ON
169     }
170 
171     /** holds an exception */
172     private static class ThrowableValue<T> implements Value<T> {
173         private final Throwable throwable;
174 
175         ThrowableValue(final Throwable throwable) {
176             this.throwable = throwable;
177         }
178 
179         public T get() throws ExecutionException {
180             throw new ExecutionException(throwable);
181         }
182 
183         @Override
184         public boolean equals(final Object obj) {
185             // no need to check for reference equality, not possible
186             if (!(obj instanceof ThrowableValue)) {
187                 return false;
188             }
189             return throwable.equals(((ThrowableValue<?>) obj).throwable);
190         }
191 
192         // /CLOVER:OFF
193         @Override
194         public int hashCode() {
195             throw new UnsupportedOperationException();
196         }
197         // /CLOVER:ON
198     }
199 
200     // doesn't need to implement equals as cancel doesn't check
201     private static class CancelledValue<T> implements Value<T> {
202         public T get() throws ExecutionException {
203             throw new CancellationException();
204         }
205     }
206 }