1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.core5.concurrent;
28
29 import java.util.concurrent.CancellationException;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.Future;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.TimeoutException;
34 import java.util.concurrent.locks.Condition;
35 import java.util.concurrent.locks.ReentrantLock;
36
37 import org.apache.hc.core5.util.Args;
38 import org.apache.hc.core5.util.TimeoutValueException;
39
40
41
42
43
44
45
46
47
48 public class BasicFuture<T> implements Future<T>, Cancellable {
49
50 private final FutureCallback<T> callback;
51
52 private volatile boolean completed;
53 private volatile boolean cancelled;
54 private volatile T result;
55 private volatile Exception ex;
56
57 private final ReentrantLock lock;
58 private final Condition condition;
59
60 public BasicFuture(final FutureCallback<T> callback) {
61 super();
62 this.callback = callback;
63 this.lock = new ReentrantLock();
64 this.condition = lock.newCondition();
65 }
66
67 @Override
68 public boolean isCancelled() {
69 return this.cancelled;
70 }
71
72 @Override
73 public boolean isDone() {
74 return this.completed;
75 }
76
77 private T getResult() throws ExecutionException {
78 if (this.ex != null) {
79 throw new ExecutionException(this.ex);
80 }
81 if (cancelled) {
82 throw new CancellationException();
83 }
84 return this.result;
85 }
86
87 @Override
88 public T get() throws InterruptedException, ExecutionException {
89 lock.lock();
90 try {
91 while (!this.completed) {
92 condition.await();
93 }
94 return getResult();
95 } finally {
96 lock.unlock();
97 }
98 }
99
100 @Override
101 public T get(final long timeout, final TimeUnit unit)
102 throws InterruptedException, ExecutionException, TimeoutException {
103 Args.notNull(unit, "Time unit");
104 final long msecs = unit.toMillis(timeout);
105 final long startTime = (msecs <= 0) ? 0 : System.currentTimeMillis();
106 long waitTime = msecs;
107 try {
108 lock.lock();
109 if (this.completed) {
110 return getResult();
111 } else if (waitTime <= 0) {
112 throw TimeoutValueException.fromMilliseconds(msecs, msecs + Math.abs(waitTime));
113 } else {
114 for (; ; ) {
115 condition.await(waitTime, TimeUnit.MILLISECONDS);
116 if (this.completed) {
117 return getResult();
118 }
119 waitTime = msecs - (System.currentTimeMillis() - startTime);
120 if (waitTime <= 0) {
121 throw TimeoutValueException.fromMilliseconds(msecs, msecs + Math.abs(waitTime));
122 }
123 }
124 }
125 } finally {
126 lock.unlock();
127 }
128 }
129
130 public boolean completed(final T result) {
131 lock.lock();
132 try {
133 if (this.completed) {
134 return false;
135 }
136 this.completed = true;
137 this.result = result;
138 condition.signalAll();
139 } finally {
140 lock.unlock();
141 }
142 if (this.callback != null) {
143 this.callback.completed(result);
144 }
145 return true;
146 }
147
148 public boolean failed(final Exception exception) {
149 lock.lock();
150 try {
151 if (this.completed) {
152 return false;
153 }
154 this.completed = true;
155 this.ex = exception;
156 condition.signalAll();
157 } finally {
158 lock.unlock();
159 }
160 if (this.callback != null) {
161 this.callback.failed(exception);
162 }
163 return true;
164 }
165
166 @Override
167 public boolean cancel(final boolean mayInterruptIfRunning) {
168 lock.lock();
169 try {
170 if (this.completed) {
171 return false;
172 }
173 this.completed = true;
174 this.cancelled = true;
175 condition.signalAll();
176 } finally {
177 lock.unlock();
178 }
179 if (this.callback != null) {
180 this.callback.cancelled();
181 }
182 return true;
183 }
184
185 @Override
186 public boolean cancel() {
187 return cancel(true);
188 }
189
190 }