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