1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.filter.keepalive;
21
22 import org.apache.mina.common.AttributeKey;
23 import org.apache.mina.common.DefaultWriteRequest;
24 import org.apache.mina.common.IdleStatus;
25 import org.apache.mina.common.IoFilter;
26 import org.apache.mina.common.IoFilterAdapter;
27 import org.apache.mina.common.IoFilterChain;
28 import org.apache.mina.common.IoSession;
29 import org.apache.mina.common.IoSessionConfig;
30 import org.apache.mina.common.WriteRequest;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34
35
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 public class KeepAliveFilter extends IoFilterAdapter {
123
124 private final AttributeKey WAITING_FOR_RESPONSE = new AttributeKey(
125 getClass(), "waitingForResponse");
126
127 private final KeepAliveMessageFactory messageFactory;
128 private volatile KeepAlivePolicy policy;
129 private volatile int keepAliveRequestInterval;
130 private volatile int keepAliveRequestTimeout;
131
132 private final Logger logger = LoggerFactory.getLogger(getClass());
133
134
135
136
137
138
139
140 public KeepAliveFilter(KeepAliveMessageFactory messageFactory) {
141 this(messageFactory, KeepAlivePolicy.CLOSE);
142 }
143
144
145
146
147
148
149 public KeepAliveFilter(
150 KeepAliveMessageFactory messageFactory, KeepAlivePolicy policy) {
151 this(messageFactory, policy, 60, 30);
152 }
153
154
155
156
157 public KeepAliveFilter(
158 KeepAliveMessageFactory messageFactory, KeepAlivePolicy policy,
159 int keepAliveRequestInterval, int keepAliveRequestTimeout) {
160 if (messageFactory == null) {
161 throw new NullPointerException("messageFactory");
162 }
163 if (policy == null) {
164 throw new NullPointerException("policy");
165 }
166
167 this.messageFactory = messageFactory;
168 this.policy = policy;
169
170 setKeepAliveRequestInterval(keepAliveRequestInterval);
171 setKeepAliveRequestTimeout(keepAliveRequestTimeout);
172 }
173
174 public KeepAlivePolicy getPolicy() {
175 return policy;
176 }
177
178 public void setPolicy(KeepAlivePolicy policy) {
179 if (policy == null) {
180 throw new NullPointerException("policy");
181 }
182 this.policy = policy;
183 }
184
185 public int getKeepAliveRequestInterval() {
186 return keepAliveRequestInterval;
187 }
188
189 public void setKeepAliveRequestInterval(int keepAliveRequestInterval) {
190 if (keepAliveRequestInterval <= 0) {
191 throw new IllegalArgumentException(
192 "keepAliveRequestInterval must be a positive integer: " +
193 keepAliveRequestInterval);
194 }
195 this.keepAliveRequestInterval = keepAliveRequestInterval;
196 }
197
198 public int getKeepAliveRequestTimeout() {
199 return keepAliveRequestTimeout;
200 }
201
202 public void setKeepAliveRequestTimeout(int keepAliveRequestTimeout) {
203 if (keepAliveRequestTimeout <= 0) {
204 throw new IllegalArgumentException(
205 "keepAliveRequestTimeout must be a positive integer: " +
206 keepAliveRequestTimeout);
207 }
208 this.keepAliveRequestTimeout = keepAliveRequestTimeout;
209 }
210
211 public KeepAliveMessageFactory getMessageFactory() {
212 return messageFactory;
213 }
214
215 @Override
216 public void onPreAdd(IoFilterChain parent, String name,
217 NextFilter nextFilter) throws Exception {
218 if (parent.contains(this)) {
219 throw new IllegalArgumentException(
220 "You can't add the same filter instance more than once. " +
221 "Create another instance and add it.");
222 }
223 }
224
225 @Override
226 public void onPostAdd(
227 IoFilterChain parent, String name, NextFilter nextFilter) throws Exception {
228 resetStatus(parent.getSession());
229 }
230
231 @Override
232 public void onPostRemove(
233 IoFilterChain parent, String name, NextFilter nextFilter) throws Exception {
234 resetStatus(parent.getSession());
235 }
236
237 @Override
238 public void messageReceived(
239 NextFilter nextFilter, IoSession session, Object message) throws Exception {
240 try {
241 if (messageFactory.isRequest(session, message)) {
242 Object pongMessage =
243 messageFactory.getResponse(session, message);
244
245 if (pongMessage != null) {
246 nextFilter.filterWrite(
247 session, new DefaultWriteRequest(pongMessage));
248 }
249 }
250
251 if (messageFactory.isResponse(session, message)) {
252 resetStatus(session);
253 }
254 } finally {
255 if (!isKeepAliveMessage(session, message)) {
256 nextFilter.messageReceived(session, message);
257 }
258 }
259 }
260
261 @Override
262 public void messageSent(
263 NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
264 Object message = writeRequest.getMessage();
265 if (!isKeepAliveMessage(session, message)) {
266 nextFilter.messageSent(session, writeRequest);
267 }
268 }
269
270 @Override
271 public void sessionIdle(
272 NextFilter nextFilter, IoSession session, IdleStatus status) throws Exception {
273 try {
274 if (status == IdleStatus.READER_IDLE) {
275 if (!session.containsAttribute(WAITING_FOR_RESPONSE)) {
276 Object pingMessage = messageFactory.getRequest(session);
277 if (pingMessage != null) {
278 nextFilter.filterWrite(
279 session,
280 new DefaultWriteRequest(pingMessage));
281
282
283
284 if (getPolicy() != KeepAlivePolicy.OFF) {
285 markStatus(session);
286 } else {
287 resetStatus(session);
288 }
289 }
290 } else {
291 resetStatus(session);
292 switch (getPolicy()) {
293 case OFF:
294 break;
295 case LOG:
296 logTimeout(session);
297 break;
298 case EXCEPTION:
299 throw new KeepAliveTimeoutException(
300 getTimeoutMessage());
301 case CLOSE:
302 logTimeout(session);
303 session.close();
304 break;
305 default:
306 throw new InternalError();
307 }
308 }
309 }
310 } finally {
311 nextFilter.sessionIdle(session, status);
312 }
313 }
314
315 private void logTimeout(IoSession session) {
316 if (logger.isWarnEnabled()) {
317 logger.warn(getTimeoutMessage());
318 }
319 }
320
321 private String getTimeoutMessage() {
322 return "Keep-alive response message was not received within " +
323 getKeepAliveRequestTimeout() + " second(s).";
324 }
325
326 private void markStatus(IoSession session) {
327 session.getConfig().setIdleTime(
328 IdleStatus.READER_IDLE, getKeepAliveRequestTimeout());
329 session.setAttribute(WAITING_FOR_RESPONSE);
330 }
331
332 private void resetStatus(IoSession session) {
333 session.getConfig().setIdleTime(
334 IdleStatus.READER_IDLE, getKeepAliveRequestInterval());
335 session.removeAttribute(WAITING_FOR_RESPONSE);
336 }
337
338 private boolean isKeepAliveMessage(IoSession session, Object message) {
339 return messageFactory.isRequest(session, message) ||
340 messageFactory.isResponse(session, message);
341 }
342 }