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