]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/CompletableCallback.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / util / CompletableCallback.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 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  *     &#64;Override
39  *     public void resume()
40  *     {
41  *         // continue processing
42  *     }
43  *
44  *     &#64;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                 case FAILED:
86                 {
87                     return;
88                 }
89                 default:
90                 {
91                     throw new IllegalStateException(current.toString());
92                 }
93             }
94         }
95     }
96
97     @Override
98     public void failed(Throwable x)
99     {
100         while (true)
101         {
102             State current = state.get();
103             switch (current)
104             {
105                 case IDLE:
106                 case COMPLETED:
107                 {
108                     if (state.compareAndSet(current, State.FAILED))
109                     {
110                         abort(x);
111                         return;
112                     }
113                     break;
114                 }
115                 case FAILED:
116                 {
117                     return;
118                 }
119                 default:
120                 {
121                     throw new IllegalStateException(current.toString());
122                 }
123             }
124         }
125     }
126
127     /**
128      * Callback method invoked when this callback is succeeded
129      * <em>after</em> a first call to {@link #tryComplete()}.
130      */
131     public abstract void resume();
132
133     /**
134      * Callback method invoked when this callback is failed.
135      */
136     public abstract void abort(Throwable failure);
137
138     /**
139      * Tries to complete this callback; driver code should call
140      * this method once <em>after</em> the asynchronous operation
141      * to detect whether the asynchronous operation has already
142      * completed or not.
143      *
144      * @return whether the attempt to complete was successful.
145      */
146     public boolean tryComplete()
147     {
148         while (true)
149         {
150             State current = state.get();
151             switch (current)
152             {
153                 case IDLE:
154                 {
155                     if (state.compareAndSet(current, State.COMPLETED))
156                         return true;
157                     break;
158                 }
159                 case SUCCEEDED:
160                 case FAILED:
161                 {
162                     return false;
163                 }
164                 default:
165                 {
166                     throw new IllegalStateException(current.toString());
167                 }
168             }
169         }
170     }
171
172     private enum State
173     {
174         IDLE, SUCCEEDED, FAILED, COMPLETED
175     }
176 }