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