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.nio.channels.ClosedChannelException;
22
23 import org.eclipse.jetty.util.thread.Locker;
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public abstract class IteratingCallback implements Callback
58 {
59
60
61
62 private enum State
63 {
64
65
66
67 IDLE,
68
69
70
71
72
73
74 PROCESSING,
75
76
77
78
79 PENDING,
80
81
82
83
84 CALLED,
85
86
87
88
89
90 SUCCEEDED,
91
92
93
94
95 FAILED,
96
97
98
99
100 CLOSED
101 }
102
103
104
105
106
107 protected enum Action
108 {
109
110
111
112
113
114 IDLE,
115
116
117
118
119
120 SCHEDULED,
121
122
123
124
125 SUCCEEDED
126 }
127
128 private Locker _locker = new Locker();
129 private State _state;
130 private boolean _iterate;
131
132
133 protected IteratingCallback()
134 {
135 _state = State.IDLE;
136 }
137
138 protected IteratingCallback(boolean needReset)
139 {
140 _state = needReset ? State.SUCCEEDED : State.IDLE;
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161 protected abstract Action process() throws Exception;
162
163
164
165
166
167
168 protected void onCompleteSuccess()
169 {
170 }
171
172
173
174
175
176
177
178 protected void onCompleteFailure(Throwable cause)
179 {
180 }
181
182
183
184
185
186
187
188
189 public void iterate()
190 {
191 boolean process=false;
192
193 loop: while (true)
194 {
195 try (Locker.Lock lock = _locker.lock())
196 {
197 switch (_state)
198 {
199 case PENDING:
200 case CALLED:
201
202 break loop;
203
204 case IDLE:
205 _state=State.PROCESSING;
206 process=true;
207 break loop;
208
209 case PROCESSING:
210 _iterate=true;
211 break loop;
212
213 case FAILED:
214 case SUCCEEDED:
215 break loop;
216
217 case CLOSED:
218 default:
219 throw new IllegalStateException(toString());
220 }
221 }
222 }
223 if (process)
224 processing();
225 }
226
227 private void processing()
228 {
229
230
231
232 boolean on_complete_success=false;
233
234
235 processing: while (true)
236 {
237
238 Action action;
239 try
240 {
241 action = process();
242 }
243 catch (Throwable x)
244 {
245 failed(x);
246 break processing;
247 }
248
249
250 try(Locker.Lock lock = _locker.lock())
251 {
252 switch (_state)
253 {
254 case PROCESSING:
255 {
256 switch (action)
257 {
258 case IDLE:
259 {
260
261 if (_iterate)
262 {
263
264 _iterate=false;
265 _state=State.PROCESSING;
266 continue processing;
267 }
268
269
270 _state=State.IDLE;
271 break processing;
272 }
273
274 case SCHEDULED:
275 {
276
277 _state=State.PENDING;
278 break processing;
279 }
280
281 case SUCCEEDED:
282 {
283
284 _iterate=false;
285 _state=State.SUCCEEDED;
286 on_complete_success=true;
287 break processing;
288 }
289
290 default:
291 throw new IllegalStateException(String.format("%s[action=%s]", this, action));
292 }
293 }
294
295 case CALLED:
296 {
297 switch (action)
298 {
299 case SCHEDULED:
300 {
301
302 _state=State.PROCESSING;
303 continue processing;
304 }
305
306 default:
307 throw new IllegalStateException(String.format("%s[action=%s]", this, action));
308 }
309 }
310
311 case SUCCEEDED:
312 case FAILED:
313 case CLOSED:
314 break processing;
315
316 case IDLE:
317 case PENDING:
318 default:
319 throw new IllegalStateException(String.format("%s[action=%s]", this, action));
320 }
321 }
322 }
323
324 if (on_complete_success)
325 onCompleteSuccess();
326 }
327
328
329
330
331
332
333 @Override
334 public void succeeded()
335 {
336 boolean process=false;
337 try(Locker.Lock lock = _locker.lock())
338 {
339 switch (_state)
340 {
341 case PROCESSING:
342 {
343 _state=State.CALLED;
344 break;
345 }
346 case PENDING:
347 {
348 _state=State.PROCESSING;
349 process=true;
350 break;
351 }
352 case CLOSED:
353 case FAILED:
354 {
355
356 break;
357 }
358 default:
359 {
360 throw new IllegalStateException(toString());
361 }
362 }
363 }
364 if (process)
365 processing();
366 }
367
368
369
370
371
372
373 @Override
374 public void failed(Throwable x)
375 {
376 boolean failure=false;
377 try(Locker.Lock lock = _locker.lock())
378 {
379 switch (_state)
380 {
381 case SUCCEEDED:
382 case FAILED:
383 case IDLE:
384 case CLOSED:
385 case CALLED:
386
387 break;
388
389 case PENDING:
390 case PROCESSING:
391 {
392 _state=State.FAILED;
393 failure=true;
394 break;
395 }
396 default:
397 throw new IllegalStateException(toString());
398 }
399 }
400 if (failure)
401 onCompleteFailure(x);
402 }
403
404 public void close()
405 {
406 boolean failure=false;
407 try(Locker.Lock lock = _locker.lock())
408 {
409 switch (_state)
410 {
411 case IDLE:
412 case SUCCEEDED:
413 case FAILED:
414 _state=State.CLOSED;
415 break;
416
417 case CLOSED:
418 break;
419
420 default:
421 _state=State.CLOSED;
422 failure=true;
423 }
424 }
425
426 if(failure)
427 onCompleteFailure(new ClosedChannelException());
428 }
429
430
431
432
433
434 boolean isIdle()
435 {
436 try(Locker.Lock lock = _locker.lock())
437 {
438 return _state == State.IDLE;
439 }
440 }
441
442 public boolean isClosed()
443 {
444 try(Locker.Lock lock = _locker.lock())
445 {
446 return _state == State.CLOSED;
447 }
448 }
449
450
451
452
453 public boolean isFailed()
454 {
455 try(Locker.Lock lock = _locker.lock())
456 {
457 return _state == State.FAILED;
458 }
459 }
460
461
462
463
464 public boolean isSucceeded()
465 {
466 try(Locker.Lock lock = _locker.lock())
467 {
468 return _state == State.SUCCEEDED;
469 }
470 }
471
472
473
474
475
476
477
478
479
480
481 public boolean reset()
482 {
483 try(Locker.Lock lock = _locker.lock())
484 {
485 switch(_state)
486 {
487 case IDLE:
488 return true;
489
490 case SUCCEEDED:
491 case FAILED:
492 _iterate=false;
493 _state=State.IDLE;
494 return true;
495
496 default:
497 return false;
498 }
499 }
500 }
501
502 @Override
503 public String toString()
504 {
505 return String.format("%s[%s]", super.toString(), _state);
506 }
507 }