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 public abstract class IdleTimeout
38 {
39 private static final Logger LOG = Log.getLogger(IdleTimeout.class);
40 private final Scheduler _scheduler;
41 private final AtomicReference<Scheduler.Task> _timeout = new AtomicReference<>();
42 private volatile long _idleTimeout;
43 private volatile long _idleTimestamp = System.currentTimeMillis();
44
45 private final Runnable _idleTask = new Runnable()
46 {
47 @Override
48 public void run()
49 {
50 long idleLeft = checkIdleTimeout();
51 if (idleLeft >= 0)
52 scheduleIdleTimeout(idleLeft > 0 ? idleLeft : getIdleTimeout());
53 }
54 };
55
56
57
58
59 public IdleTimeout(Scheduler scheduler)
60 {
61 _scheduler = scheduler;
62 }
63
64 public long getIdleTimestamp()
65 {
66 return _idleTimestamp;
67 }
68
69 public long getIdleFor()
70 {
71 return System.currentTimeMillis() - getIdleTimestamp();
72 }
73
74 public long getIdleTimeout()
75 {
76 return _idleTimeout;
77 }
78
79 public void setIdleTimeout(long idleTimeout)
80 {
81 long old = _idleTimeout;
82 _idleTimeout = idleTimeout;
83
84
85 if (old > 0)
86 {
87
88 if (old <= idleTimeout)
89 return;
90
91
92 deactivate();
93 }
94
95
96 if (isOpen())
97 activate();
98 }
99
100
101
102
103 public void notIdle()
104 {
105 _idleTimestamp = System.currentTimeMillis();
106 }
107
108 private void scheduleIdleTimeout(long delay)
109 {
110 Scheduler.Task newTimeout = null;
111 if (isOpen() && delay > 0 && _scheduler != null)
112 newTimeout = _scheduler.schedule(_idleTask, delay, TimeUnit.MILLISECONDS);
113 Scheduler.Task oldTimeout = _timeout.getAndSet(newTimeout);
114 if (oldTimeout != null)
115 oldTimeout.cancel();
116 }
117
118 public void onOpen()
119 {
120 activate();
121 }
122
123 private void activate()
124 {
125 if (_idleTimeout > 0)
126 _idleTask.run();
127 }
128
129 public void onClose()
130 {
131 deactivate();
132 }
133
134 private void deactivate()
135 {
136 Scheduler.Task oldTimeout = _timeout.getAndSet(null);
137 if (oldTimeout != null)
138 oldTimeout.cancel();
139 }
140
141 protected long checkIdleTimeout()
142 {
143 if (isOpen())
144 {
145 long idleTimestamp = getIdleTimestamp();
146 long idleTimeout = getIdleTimeout();
147 long idleElapsed = System.currentTimeMillis() - idleTimestamp;
148 long idleLeft = idleTimeout - idleElapsed;
149
150 if (LOG.isDebugEnabled())
151 LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
152
153 if (idleTimestamp != 0 && idleTimeout > 0)
154 {
155 if (idleLeft <= 0)
156 {
157 if (LOG.isDebugEnabled())
158 LOG.debug("{} idle timeout expired", this);
159 try
160 {
161 onIdleExpired(new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms"));
162 }
163 finally
164 {
165 notIdle();
166 }
167 }
168 }
169
170 return idleLeft >= 0 ? idleLeft : 0;
171 }
172 return -1;
173 }
174
175
176
177
178
179
180 protected abstract void onIdleExpired(TimeoutException timeout);
181
182
183
184
185
186
187
188 public abstract boolean isOpen();
189 }