1 //
2 // ========================================================================
3 // Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.util;
20
21 import java.util.concurrent.atomic.AtomicReference;
22
23 /**
24 * A callback to be used by driver code that needs to know whether the callback has been
25 * succeeded or failed (that is, completed) just after the asynchronous operation or not,
26 * typically because further processing depends on the callback being completed.
27 * The driver code competes with the asynchronous operation to complete the callback.
28 * <p />
29 * If the callback is already completed, the driver code continues the processing,
30 * otherwise it suspends it. If it is suspended, the callback will be completed some time
31 * later, and {@link #resume()} or {@link #abort(Throwable)} will be called to allow the
32 * application to resume the processing.
33 * <p />
34 * Typical usage:
35 * <pre>
36 * CompletableCallback callback = new CompletableCallback()
37 * {
38 * @Override
39 * public void resume()
40 * {
41 * // continue processing
42 * }
43 *
44 * @Override
45 * public void abort(Throwable failure)
46 * {
47 * // abort processing
48 * }
49 * }
50 * asyncOperation(callback);
51 * boolean completed = callback.tryComplete();
52 * if (completed)
53 * // suspend processing, async operation not done yet
54 * else
55 * // continue processing, async operation already done
56 * </pre>
57 */
58 public abstract class CompletableCallback implements Callback
59 {
60 private final AtomicReference<State> state = new AtomicReference<>(State.IDLE);
61
62 @Override
63 public void succeeded()
64 {
65 while (true)
66 {
67 State current = state.get();
68 switch (current)
69 {
70 case IDLE:
71 {
72 if (state.compareAndSet(current, State.SUCCEEDED))
73 return;
74 break;
75 }
76 case COMPLETED:
77 {
78 if (state.compareAndSet(current, State.SUCCEEDED))
79 {
80 resume();
81 return;
82 }
83 break;
84 }
85 default:
86 {
87 throw new IllegalStateException(current.toString());
88 }
89 }
90 }
91 }
92
93 @Override
94 public void failed(Throwable x)
95 {
96 while (true)
97 {
98 State current = state.get();
99 switch (current)
100 {
101 case IDLE:
102 case COMPLETED:
103 {
104 if (state.compareAndSet(current, State.FAILED))
105 {
106 abort(x);
107 return;
108 }
109 break;
110 }
111 default:
112 {
113 throw new IllegalStateException(current.toString());
114 }
115 }
116 }
117 }
118
119 /**
120 * Callback method invoked when this callback is succeeded
121 * <em>after</em> a first call to {@link #tryComplete()}.
122 */
123 public abstract void resume();
124
125 /**
126 * Callback method invoked when this callback is failed.
127 */
128 public abstract void abort(Throwable failure);
129
130 /**
131 * Tries to complete this callback; driver code should call
132 * this method once <em>after</em> the asynchronous operation
133 * to detect whether the asynchronous operation has already
134 * completed or not.
135 *
136 * @return whether the attempt to complete was successful.
137 */
138 public boolean tryComplete()
139 {
140 while (true)
141 {
142 State current = state.get();
143 switch (current)
144 {
145 case IDLE:
146 {
147 if (state.compareAndSet(current, State.COMPLETED))
148 return true;
149 break;
150 }
151 case SUCCEEDED:
152 case FAILED:
153 {
154 return false;
155 }
156 default:
157 {
158 throw new IllegalStateException(current.toString());
159 }
160 }
161 }
162 }
163
164 private enum State
165 {
166 IDLE, SUCCEEDED, FAILED, COMPLETED
167 }
168 }