1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.io;
20
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.TimeoutException;
23 import java.util.concurrent.atomic.AtomicReference;
24
25 import org.eclipse.jetty.util.log.Log;
26 import org.eclipse.jetty.util.log.Logger;
27 import org.eclipse.jetty.util.thread.Scheduler;
28
29
30
31
32
33
34
35
36
37
38
39
40 public abstract class IdleTimeout
41 {
42 private static final Logger LOG = Log.getLogger(IdleTimeout.class);
43 private final Scheduler _scheduler;
44 private final AtomicReference<Scheduler.Task> _timeout = new AtomicReference<>();
45 private volatile long _idleTimeout;
46 private volatile long _idleTimestamp=System.currentTimeMillis();
47
48 private final Runnable _idleTask = new Runnable()
49 {
50 @Override
51 public void run()
52 {
53 long idleLeft=checkIdleTimeout();
54 if (idleLeft>=0)
55 scheduleIdleTimeout(idleLeft > 0 ? idleLeft : getIdleTimeout());
56 }
57 };
58
59
60
61
62 public IdleTimeout(Scheduler scheduler)
63 {
64 _scheduler=scheduler;
65 }
66
67 public long getIdleTimestamp()
68 {
69 return _idleTimestamp;
70 }
71
72 public long getIdleTimeout()
73 {
74 return _idleTimeout;
75 }
76
77 public void setIdleTimeout(long idleTimeout)
78 {
79 long old=_idleTimeout;
80 _idleTimeout = idleTimeout;
81
82
83 if (old>0)
84 {
85
86 if (old<=idleTimeout)
87 return;
88
89
90 Scheduler.Task oldTimeout = _timeout.getAndSet(null);
91 if (oldTimeout != null)
92 oldTimeout.cancel();
93 }
94
95
96 if (idleTimeout>0 && isOpen())
97 _idleTask.run();
98 }
99
100
101
102 public void notIdle()
103 {
104 _idleTimestamp=System.currentTimeMillis();
105 }
106
107 private void scheduleIdleTimeout(long delay)
108 {
109 Scheduler.Task newTimeout = null;
110 if (isOpen() && delay > 0 && _scheduler!=null)
111 newTimeout = _scheduler.schedule(_idleTask, delay, TimeUnit.MILLISECONDS);
112 Scheduler.Task oldTimeout = _timeout.getAndSet(newTimeout);
113 if (oldTimeout != null)
114 oldTimeout.cancel();
115 }
116
117 public void onOpen()
118 {
119 if (_idleTimeout>0)
120 _idleTask.run();
121 }
122
123 protected void close()
124 {
125 Scheduler.Task oldTimeout = _timeout.getAndSet(null);
126 if (oldTimeout != null)
127 oldTimeout.cancel();
128 }
129
130 protected long checkIdleTimeout()
131 {
132 if (isOpen())
133 {
134 long idleTimestamp = getIdleTimestamp();
135 long idleTimeout = getIdleTimeout();
136 long idleElapsed = System.currentTimeMillis() - idleTimestamp;
137 long idleLeft = idleTimeout - idleElapsed;
138
139 LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
140
141 if (idleTimestamp != 0 && idleTimeout > 0)
142 {
143 if (idleLeft <= 0)
144 {
145 LOG.debug("{} idle timeout expired", this);
146 try
147 {
148 onIdleExpired(new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms"));
149 }
150 finally
151 {
152 notIdle();
153 }
154 }
155 }
156
157 return idleLeft>=0?idleLeft:0;
158 }
159 return -1;
160 }
161
162
163
164
165
166 abstract protected void onIdleExpired(TimeoutException timeout);
167
168
169
170
171
172
173
174 abstract protected boolean isOpen();
175 }