1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.util;
20
21 import java.io.IOException;
22 import java.util.concurrent.CancellationException;
23 import java.util.concurrent.CountDownLatch;
24 import java.util.concurrent.ExecutionException;
25 import java.util.concurrent.Future;
26 import java.util.concurrent.TimeUnit;
27 import java.util.concurrent.TimeoutException;
28 import java.util.concurrent.atomic.AtomicReference;
29
30
31 public class FutureCallback<C> implements Future<C>,Callback<C>
32 {
33 private enum State {NOT_DONE,DOING,DONE};
34 private final AtomicReference<State> _state=new AtomicReference<>(State.NOT_DONE);
35 private CountDownLatch _done= new CountDownLatch(1);
36 private Throwable _cause;
37 private C _context;
38 private boolean _completed;
39
40 public FutureCallback()
41 {}
42
43 public FutureCallback(C ctx)
44 {
45 _state.set(State.DONE);
46 _context=ctx;
47 _completed=true;
48 _done.countDown();
49 }
50
51 public FutureCallback(C ctx, Throwable failed)
52 {
53 _state.set(State.DONE);
54 _context=ctx;
55 _cause=failed;
56 _done.countDown();
57 }
58
59 @Override
60 public void completed(C context)
61 {
62 if (_state.compareAndSet(State.NOT_DONE,State.DOING))
63 {
64 _context=context;
65 _completed=true;
66 if (_state.compareAndSet(State.DOING,State.DONE))
67 {
68 _done.countDown();
69 return;
70 }
71 }
72 else if (!isCancelled())
73 throw new IllegalStateException();
74 }
75
76 @Override
77 public void failed(C context, Throwable cause)
78 {
79 if (_state.compareAndSet(State.NOT_DONE,State.DOING))
80 {
81 _context=context;
82 _cause=cause;
83 if (_state.compareAndSet(State.DOING,State.DONE))
84 {
85 _done.countDown();
86 return;
87 }
88 }
89 else if (!isCancelled())
90 throw new IllegalStateException();
91 }
92
93 @Override
94 public boolean cancel(boolean mayInterruptIfRunning)
95 {
96 failed(null,new CancellationException());
97 return false;
98 }
99
100 @Override
101 public boolean isCancelled()
102 {
103 return State.DONE.equals(_state.get())&&_cause instanceof CancellationException;
104 }
105
106 @Override
107 public boolean isDone()
108 {
109 return State.DONE.equals(_state.get());
110 }
111
112 @Override
113 public C get() throws InterruptedException, ExecutionException
114 {
115 _done.await();
116 if (_completed)
117 return _context;
118 if (_cause instanceof CancellationException)
119 throw (CancellationException) new CancellationException().initCause(_cause);
120 throw new ExecutionException(_cause);
121 }
122
123 @Override
124 public C get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
125 {
126 if (!_done.await(timeout,unit))
127 throw new TimeoutException();
128 if (_completed)
129 return _context;
130 if (_cause instanceof TimeoutException)
131 throw (TimeoutException)_cause;
132 if (_cause instanceof CancellationException)
133 throw (CancellationException) new CancellationException().initCause(_cause);
134 throw new ExecutionException(_cause);
135 }
136
137 public static void rethrow(ExecutionException e) throws IOException
138 {
139 Throwable cause=e.getCause();
140 if (cause instanceof IOException)
141 throw (IOException)cause;
142 if (cause instanceof Error)
143 throw (Error)cause;
144 if (cause instanceof RuntimeException)
145 throw (RuntimeException)cause;
146 throw new RuntimeException(cause);
147 }
148
149
150 @Override
151 public String toString()
152 {
153 return String.format("FutureCallback@%x{%s,%b,%s}",hashCode(),_state,_completed,_context);
154 }
155
156 }