1 package org.mortbay.jetty;
2
3 import java.io.IOException;
4 import org.mortbay.io.AsyncEndPoint;
5 import org.mortbay.io.EndPoint;
6 import org.mortbay.log.Log;
7 import org.mortbay.thread.Timeout;
8
9 public class Suspendable
10 {
11
12 private static final int __IDLE=0;
13 private static final int __HANDLING=1;
14 private static final int __SUSPENDING=2;
15 private static final int __RESUMING=3;
16 private static final int __COMPLETING=4;
17 private static final int __SUSPENDED=5;
18 private static final int __UNSUSPENDING=6;
19
20
21
22
23
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 protected HttpConnection _connection;
51
52 protected int _state;
53 protected boolean _initial;
54 protected boolean _resumed;
55 protected boolean _timeout;
56
57 protected long _timeoutMs;
58 protected final Timeout.Task _timeoutTask;
59
60
61
62 public Suspendable(HttpConnection connection)
63 {
64 _connection=connection;
65 _state=__IDLE;
66 _initial=true;
67 _resumed=false;
68
69 _timeoutTask= new Timeout.Task()
70 {
71 public void expired()
72 {
73 Suspendable.this.expire();
74 }
75 };
76 }
77
78
79
80
81 public long getTimeout()
82 {
83 return _timeoutMs;
84 }
85
86
87
88
89
90
91
92 public boolean isInitial()
93 {
94 synchronized(this)
95 {
96 return _initial;
97 }
98 }
99
100
101
102
103
104 public boolean isResumed()
105 {
106 synchronized(this)
107 {
108 return _resumed;
109 }
110 }
111
112
113
114
115
116 public boolean isSuspended()
117 {
118 synchronized(this)
119 {
120 return _state==__SUSPENDING || _state==__SUSPENDED;
121 }
122 }
123
124
125
126
127
128
129 public boolean isTimeout()
130 {
131 synchronized(this)
132 {
133 return _timeout;
134 }
135 }
136
137
138
139
140
141
142 public void suspend()
143 {
144 long timeout = 30000L;
145 suspend(timeout);
146 }
147
148
149 public String toString()
150 {
151 return getStatusString();
152 }
153
154
155 public String getStatusString()
156 {
157 synchronized (this)
158 {
159 return
160 ((_state==__IDLE)?"IDLE":
161 (_state==__HANDLING)?"HANDLING":
162 (_state==__SUSPENDING)?"SUSPENDING":
163 (_state==__SUSPENDED)?"SUSPENDED":
164 (_state==__RESUMING)?"RESUMING":
165 (_state==__UNSUSPENDING)?"UNSUSPENDING":
166 (_state==__COMPLETING)?"COMPLETING":
167 ("???"+_state))+
168 (_initial?",initial":"")+
169 (_resumed?",resumed":"")+
170 (_timeout?",timeout":"");
171 }
172 }
173
174
175
176
177
178 public void handling()
179 {
180 synchronized (this)
181 {
182 switch(_state)
183 {
184 case __HANDLING:
185 throw new IllegalStateException(this.getStatusString());
186
187 case __IDLE:
188 _initial=true;
189 _state=__HANDLING;
190 return;
191
192 case __SUSPENDING:
193 case __RESUMING:
194 throw new IllegalStateException(this.getStatusString());
195
196 case __COMPLETING:
197 return;
198
199 case __SUSPENDED:
200 cancelTimeout();
201 case __UNSUSPENDING:
202 _state=__HANDLING;
203 return;
204
205 default:
206 throw new IllegalStateException(""+_state);
207 }
208
209 }
210 }
211
212
213
214
215
216 public void suspend(long timeoutMs)
217 {
218 synchronized (this)
219 {
220 switch(_state)
221 {
222 case __HANDLING:
223 _timeout=false;
224 _resumed=false;
225 _state=__SUSPENDING;
226 _timeoutMs = timeoutMs;
227 return;
228
229 case __IDLE:
230 throw new IllegalStateException(this.getStatusString());
231
232 case __SUSPENDING:
233 case __RESUMING:
234 if (timeoutMs<_timeoutMs)
235 _timeoutMs = timeoutMs;
236 return;
237
238 case __COMPLETING:
239 case __SUSPENDED:
240 case __UNSUSPENDING:
241 throw new IllegalStateException(this.getStatusString());
242
243 default:
244 throw new IllegalStateException(""+_state);
245 }
246
247 }
248 }
249
250
251 public boolean unhandling()
252 {
253 synchronized (this)
254 {
255 switch(_state)
256 {
257 case __HANDLING:
258 _state=__IDLE;
259 return true;
260
261 case __IDLE:
262 throw new IllegalStateException(this.getStatusString());
263
264 case __SUSPENDING:
265 _initial=false;
266 _state=__SUSPENDED;
267 scheduleTimeout();
268 if (_state==__SUSPENDED)
269 return true;
270
271
272 case __RESUMING:
273 _initial=false;
274 _state=__HANDLING;
275 return false;
276
277 case __COMPLETING:
278 _initial=false;
279 _state=__IDLE;
280 return true;
281
282 case __SUSPENDED:
283 throw new IllegalStateException(this.getStatusString());
284
285 case __UNSUSPENDING:
286 throw new IllegalStateException(this.getStatusString());
287
288 default:
289 throw new IllegalStateException(""+_state);
290 }
291
292 }
293 }
294
295
296 public void resume()
297 {
298 synchronized (this)
299 {
300 switch(_state)
301 {
302 case __HANDLING:
303 _resumed=true;
304 return;
305
306 case __IDLE:
307 return;
308
309 case __SUSPENDING:
310 _resumed=true;
311 _state=__RESUMING;
312 return;
313
314 case __RESUMING:
315 _resumed=true;
316 _state=__RESUMING;
317 return;
318
319 case __COMPLETING:
320 return;
321
322 case __SUSPENDED:
323 _resumed=true;
324 _state=__UNSUSPENDING;
325 cancelTimeout();
326 scheduleDispatch();
327 return;
328
329 case __UNSUSPENDING:
330 _resumed=true;
331 return;
332
333 default:
334 throw new IllegalStateException(""+_state);
335 }
336 }
337 }
338
339
340
341 protected void expire()
342 {
343
344 synchronized (this)
345 {
346 switch(_state)
347 {
348 case __HANDLING:
349 return;
350
351 case __IDLE:
352 throw new IllegalStateException(this.getStatusString());
353
354 case __SUSPENDING:
355 _timeout=true;
356 _state=__RESUMING;
357 return;
358
359 case __RESUMING:
360 _timeout=true;
361 _state=__RESUMING;
362 return;
363
364 case __COMPLETING:
365 throw new IllegalStateException(this.getStatusString());
366
367 case __SUSPENDED:
368 _timeout=true;
369 _state=__UNSUSPENDING;
370 cancelTimeout();
371 scheduleDispatch();
372 return;
373
374 case __UNSUSPENDING:
375 _timeout=true;
376 return;
377
378 default:
379 throw new IllegalStateException(""+_state);
380 }
381 }
382 }
383
384
385
386
387
388 public void complete() throws IOException
389 {
390
391 synchronized (this)
392 {
393 switch(_state)
394 {
395 case __HANDLING:
396 _state=__COMPLETING;
397 break;
398
399 case __IDLE:
400 return;
401
402 case __SUSPENDING:
403 case __RESUMING:
404 _state=__COMPLETING;
405 break;
406
407 case __COMPLETING:
408 return;
409
410 case __SUSPENDED:
411 _state=__COMPLETING;
412 cancelTimeout();
413 scheduleDispatch();
414 return;
415
416 case __UNSUSPENDING:
417 _state=__COMPLETING;
418 return;
419
420 default:
421 throw new IllegalStateException(""+_state);
422 }
423 }
424 }
425
426
427
428 public void reset()
429 {
430 synchronized (this)
431 {
432 _state=(_state==__SUSPENDED||_state==__IDLE)?__IDLE:__HANDLING;
433 _resumed = false;
434 _initial = true;
435 cancelTimeout();
436 }
437 }
438
439
440 protected void scheduleDispatch()
441 {
442 EndPoint endp=_connection.getEndPoint();
443 if (!endp.isBlocking())
444 {
445 ((AsyncEndPoint)endp).dispatch();
446 }
447 }
448
449
450 protected void scheduleTimeout()
451 {
452 EndPoint endp=_connection.getEndPoint();
453 if (endp.isBlocking())
454 {
455 synchronized(this)
456 {
457 long expire_at = System.currentTimeMillis()+_timeoutMs;
458 long wait=_timeoutMs;
459 while (_timeoutMs>0 && wait>0)
460 {
461 try
462 {
463 this.wait(wait);
464 }
465 catch (InterruptedException e)
466 {
467 Log.ignore(e);
468 }
469 wait=expire_at-System.currentTimeMillis();
470 }
471
472 if (_timeoutMs>0 && wait<=0)
473 expire();
474 }
475
476 }
477 else
478 _connection.scheduleTimeout(_timeoutTask,_timeoutMs);
479 }
480
481
482 protected void cancelTimeout()
483 {
484 EndPoint endp=_connection.getEndPoint();
485 if (endp.isBlocking())
486 {
487 synchronized(this)
488 {
489 _timeoutMs=0;
490 this.notifyAll();
491 }
492 }
493 else
494 _connection.cancelTimeout(_timeoutTask);
495 }
496
497
498 public boolean isCompleting()
499 {
500 return _state==__COMPLETING;
501 }
502
503
504 public boolean shouldHandleRequest()
505 {
506 switch(_state)
507 {
508 case __COMPLETING:
509 return false;
510
511 default:
512 return true;
513 }
514 }
515
516
517 public boolean shouldComplete()
518 {
519 switch(_state)
520 {
521 case __RESUMING:
522 case __SUSPENDED:
523 case __SUSPENDING:
524 return false;
525
526 default:
527 return true;
528 }
529 }
530
531 }