1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.mina.util;
20
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.concurrent.CancellationException;
24 import java.util.concurrent.CountDownLatch;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.TimeUnit;
27 import java.util.concurrent.TimeoutException;
28 import java.util.concurrent.atomic.AtomicReference;
29
30 import org.apache.mina.api.IoFuture;
31 import org.apache.mina.api.IoFutureListener;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public abstract class AbstractIoFuture<V> implements IoFuture<V> {
48
49 static final Logger LOG = LoggerFactory.getLogger(AbstractIoFuture.class);
50
51 private final CountDownLatch latch = new CountDownLatch(1);
52
53 private final List<IoFutureListener<V>> listeners = new ArrayList<IoFutureListener<V>>();
54
55 private final AtomicReference<Object> result = new AtomicReference<Object>();
56
57
58
59
60 @Override
61 @SuppressWarnings({ "unchecked" })
62 public IoFuture<V> register(IoFutureListener<V> listener) {
63
64 LOG.debug("registering listener {}", listener);
65
66 synchronized (latch) {
67 if (!isDone()) {
68 LOG.debug("future is not done, adding listener to listener set");
69 listeners.add(listener);
70 listener = null;
71 }
72 }
73
74 if (listener != null) {
75 LOG.debug("future is done calling listener");
76 Object object = result.get();
77
78 if (object instanceof Throwable) {
79 scheduleException(listener, (Throwable) object);
80 } else {
81 scheduleResult(listener, (V) object);
82 }
83 }
84
85 return this;
86 }
87
88
89
90
91 @Override
92 public boolean cancel(boolean mayInterruptIfRunning) {
93
94 LOG.debug("Attempting to cancel");
95
96 CancellationException ce = null;
97 synchronized (latch) {
98 if (!isCancelled() && !isDone() && cancelOwner(mayInterruptIfRunning)) {
99
100 LOG.debug("Successfully cancelled");
101
102 ce = new CancellationException();
103 result.set(ce);
104 } else {
105 LOG.debug("Unable to cancel");
106 }
107
108 latch.countDown();
109 }
110
111 if (ce != null) {
112 LOG.debug("Calling listeners");
113
114 for (IoFutureListener<V> listener : listeners) {
115 scheduleException(listener, ce);
116 }
117 }
118
119 return ce != null;
120 }
121
122
123
124
125 @Override
126 public boolean isCancelled() {
127 return result.get() instanceof CancellationException;
128 }
129
130
131
132
133 @Override
134 public boolean isDone() {
135 return latch.getCount() == 0;
136 }
137
138
139
140
141 @Override
142 @SuppressWarnings({ "unchecked" })
143 public V get() throws InterruptedException, ExecutionException {
144
145 LOG.trace("Entering wait");
146 latch.await();
147 LOG.trace("Wait completed");
148
149 if (isCancelled()) {
150 throw new CancellationException();
151 }
152
153 Object object = result.get();
154
155 if (object instanceof ExecutionException) {
156 throw (ExecutionException) object;
157 } else {
158 return (V) object;
159 }
160 }
161
162
163
164
165 @Override
166 @SuppressWarnings({ "unchecked" })
167 public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
168
169 LOG.trace("Entering wait");
170
171 if (!latch.await(timeout, unit)) {
172 throw new TimeoutException();
173 }
174
175 LOG.trace("Wait completed");
176
177 if (isCancelled()) {
178 throw new CancellationException();
179 }
180
181 Object object = result.get();
182
183 if (object instanceof ExecutionException) {
184 throw (ExecutionException) object;
185 } else {
186 return (V) object;
187 }
188 }
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208 protected abstract boolean cancelOwner(boolean mayInterruptIfRunning);
209
210
211
212
213
214
215
216
217 protected void scheduleResult(IoFutureListener<V> listener, V result) {
218 LOG.debug("Calling the default result scheduler");
219
220 try {
221 listener.completed(result);
222 } catch (Exception e) {
223 LOG.warn("Listener threw an exception", e);
224 }
225 }
226
227
228
229
230
231
232
233
234 protected void scheduleException(IoFutureListener<V> listener, Throwable throwable) {
235 LOG.debug("Calling the default exception scheduler");
236
237 try {
238 listener.exception(throwable);
239 } catch (Exception e) {
240 LOG.warn("Listener threw an exception", e);
241 }
242 }
243
244
245
246
247
248
249 protected final void setResult(V value) {
250 assert !isDone();
251
252 synchronized (latch) {
253 result.set(value);
254 latch.countDown();
255 }
256
257 for (IoFutureListener<V> listener : listeners) {
258 scheduleResult(listener, value);
259 }
260
261 listeners.clear();
262 }
263
264
265
266
267
268
269
270
271
272 protected final void setException(Throwable t) {
273 assert !isDone();
274
275 ExecutionException ee = new ExecutionException(t);
276
277 synchronized (latch) {
278 result.set(ee);
279 latch.countDown();
280 }
281
282 for (IoFutureListener<V> listener : listeners) {
283 scheduleException(listener, ee);
284 }
285
286 listeners.clear();
287 }
288 }