1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.timeout;
17
18 import static org.jboss.netty.channel.Channels.*;
19
20 import java.util.concurrent.TimeUnit;
21
22 import org.jboss.netty.bootstrap.ServerBootstrap;
23 import org.jboss.netty.channel.ChannelHandlerContext;
24 import org.jboss.netty.channel.ChannelPipeline;
25 import org.jboss.netty.channel.ChannelPipelineFactory;
26 import org.jboss.netty.channel.ChannelStateEvent;
27 import org.jboss.netty.channel.Channels;
28 import org.jboss.netty.channel.LifeCycleAwareChannelHandler;
29 import org.jboss.netty.channel.MessageEvent;
30 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
31 import org.jboss.netty.util.ExternalResourceReleasable;
32 import org.jboss.netty.util.HashedWheelTimer;
33 import org.jboss.netty.util.Timeout;
34 import org.jboss.netty.util.Timer;
35 import org.jboss.netty.util.TimerTask;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public class ReadTimeoutHandler extends SimpleChannelUpstreamHandler
81 implements LifeCycleAwareChannelHandler,
82 ExternalResourceReleasable {
83
84 static final ReadTimeoutException EXCEPTION = new ReadTimeoutException();
85
86 final Timer timer;
87 final long timeoutMillis;
88 volatile Timeout timeout;
89 private volatile ReadTimeoutTask task;
90 volatile long lastReadTime;
91
92
93
94
95
96
97
98
99
100
101 public ReadTimeoutHandler(Timer timer, int timeoutSeconds) {
102 this(timer, timeoutSeconds, TimeUnit.SECONDS);
103 }
104
105
106
107
108
109
110
111
112
113
114
115
116 public ReadTimeoutHandler(Timer timer, long timeout, TimeUnit unit) {
117 if (timer == null) {
118 throw new NullPointerException("timer");
119 }
120 if (unit == null) {
121 throw new NullPointerException("unit");
122 }
123
124 this.timer = timer;
125 if (timeout <= 0) {
126 timeoutMillis = 0;
127 } else {
128 timeoutMillis = Math.max(unit.toMillis(timeout), 1);
129 }
130 }
131
132
133
134
135
136
137 public void releaseExternalResources() {
138 timer.stop();
139 }
140
141 public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
142 if (ctx.getPipeline().isAttached()) {
143
144
145
146 initialize(ctx);
147 } else {
148
149
150 }
151 }
152
153 public void afterAdd(ChannelHandlerContext ctx) throws Exception {
154
155 }
156
157 public void beforeRemove(ChannelHandlerContext ctx) throws Exception {
158 destroy();
159 }
160
161 public void afterRemove(ChannelHandlerContext ctx) throws Exception {
162
163 }
164
165 @Override
166 public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
167 throws Exception {
168
169
170
171 initialize(ctx);
172 ctx.sendUpstream(e);
173 }
174
175 @Override
176 public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
177 throws Exception {
178 destroy();
179 ctx.sendUpstream(e);
180 }
181
182 @Override
183 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
184 throws Exception {
185 updateLastReadTime();
186 ctx.sendUpstream(e);
187 }
188
189 private void initialize(ChannelHandlerContext ctx) {
190 updateLastReadTime();
191 task = new ReadTimeoutTask(ctx);
192 if (timeoutMillis > 0) {
193 timeout = timer.newTimeout(task, timeoutMillis, TimeUnit.MILLISECONDS);
194 }
195 }
196
197 private void updateLastReadTime() {
198 lastReadTime = System.currentTimeMillis();
199 }
200
201 private void destroy() {
202 if (timeout != null) {
203 timeout.cancel();
204 }
205 timeout = null;
206 task = null;
207 }
208
209 protected void readTimedOut(ChannelHandlerContext ctx) throws Exception {
210 Channels.fireExceptionCaught(ctx, EXCEPTION);
211 }
212
213 private final class ReadTimeoutTask implements TimerTask {
214
215 private final ChannelHandlerContext ctx;
216
217 ReadTimeoutTask(ChannelHandlerContext ctx) {
218 this.ctx = ctx;
219 }
220
221 public void run(Timeout timeout) throws Exception {
222 if (timeout.isCancelled()) {
223 return;
224 }
225
226 if (!ctx.getChannel().isOpen()) {
227 return;
228 }
229
230 long currentTime = System.currentTimeMillis();
231 long nextDelay = timeoutMillis - (currentTime - lastReadTime);
232 if (nextDelay <= 0) {
233
234 ReadTimeoutHandler.this.timeout =
235 timer.newTimeout(this, timeoutMillis, TimeUnit.MILLISECONDS);
236 try {
237 readTimedOut(ctx);
238 } catch (Throwable t) {
239 fireExceptionCaught(ctx, t);
240 }
241 } else {
242
243 ReadTimeoutHandler.this.timeout =
244 timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS);
245 }
246 }
247 }
248 }