1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.common;
21
22 import java.util.Iterator;
23 import java.util.Set;
24 import java.util.concurrent.Executors;
25 import java.util.concurrent.ScheduledExecutorService;
26 import java.util.concurrent.TimeUnit;
27
28 import org.apache.mina.util.ConcurrentHashSet;
29 import org.apache.mina.util.NamePreservingRunnable;
30
31
32
33
34
35
36
37 public class IdleStatusChecker {
38 private static final IdleStatusChecker INSTANCE = new IdleStatusChecker();
39
40 public static IdleStatusChecker getInstance() {
41 return INSTANCE;
42 }
43
44 private final Set<AbstractIoSession> sessions =
45 new ConcurrentHashSet<AbstractIoSession>();
46 private final Set<AbstractIoService> services =
47 new ConcurrentHashSet<AbstractIoService>();
48
49 private final Object lock = new Object();
50 private final Runnable notifyingTask = new NamePreservingRunnable(
51 new NotifyingTask(), "IdleStatusChecker");
52 private final IoFutureListener<IoFuture> sessionCloseListener =
53 new SessionCloseListener();
54 private volatile ScheduledExecutorService executor;
55
56 private IdleStatusChecker() {}
57
58 public void addSession(AbstractIoSession session) {
59 synchronized (lock) {
60 boolean start = false;
61 if (sessions.isEmpty() && services.isEmpty()) {
62 start = true;
63 }
64 if (!sessions.add(session)) {
65 return;
66 }
67 if (start) {
68 start();
69 }
70 }
71
72 session.getCloseFuture().addListener(sessionCloseListener);
73 }
74
75 public void addService(AbstractIoService service) {
76 synchronized (lock) {
77 boolean start = false;
78 if (sessions.isEmpty() && services.isEmpty()) {
79 start = true;
80 }
81 if (!services.add(service)) {
82 return;
83 }
84 if (start) {
85 start();
86 }
87 }
88 }
89
90 public void removeSession(AbstractIoSession session) {
91 synchronized (lock) {
92 sessions.remove(session);
93 if (sessions.isEmpty() && services.isEmpty()) {
94 stop();
95 }
96 }
97 }
98
99 public void removeService(AbstractIoService service) {
100 synchronized (lock) {
101 services.remove(service);
102 if (sessions.isEmpty() && services.isEmpty()) {
103 stop();
104 }
105 }
106 }
107
108 private void start() {
109 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
110 this.executor = executor;
111 executor.scheduleWithFixedDelay(
112 notifyingTask, 1000, 1000, TimeUnit.MILLISECONDS);
113 }
114
115 private void stop() {
116 ScheduledExecutorService executor = this.executor;
117 if (executor == null) {
118 return;
119 }
120 executor.shutdownNow();
121 this.executor = null;
122 }
123
124 private class NotifyingTask implements Runnable {
125 public void run() {
126 long currentTime = System.currentTimeMillis();
127 notifyServices(currentTime);
128 notifySessions(currentTime);
129 }
130
131 private void notifyServices(long currentTime) {
132 Iterator<AbstractIoService> it = services.iterator();
133 while (it.hasNext()) {
134 AbstractIoService service = it.next();
135 if (service.isActive()) {
136 notifyIdleness(service, currentTime, false);
137 }
138 }
139 }
140
141 private void notifySessions(long currentTime) {
142 Iterator<AbstractIoSession> it = sessions.iterator();
143 while (it.hasNext()) {
144 AbstractIoSession session = it.next();
145 if (session.isConnected()) {
146 notifyIdleSession(session, currentTime);
147 }
148 }
149 }
150 }
151
152 private class SessionCloseListener implements IoFutureListener<IoFuture> {
153 public void operationComplete(IoFuture future) {
154 removeSession((AbstractIoSession) future.getSession());
155 }
156 }
157
158
159
160
161
162
163
164 public static void notifyIdleness(Iterator<? extends IoSession> sessions, long currentTime) {
165 IoSession s = null;
166 while (sessions.hasNext()) {
167 s = sessions.next();
168 notifyIdleSession(s, currentTime);
169 }
170 }
171
172 public static void notifyIdleness(IoService service, long currentTime) {
173 notifyIdleness(service, currentTime, true);
174 }
175
176 private static void notifyIdleness(IoService service, long currentTime, boolean includeSessions) {
177 if (!(service instanceof AbstractIoService)) {
178 return;
179 }
180
181 ((AbstractIoService) service).notifyIdleness(currentTime);
182
183 if (includeSessions) {
184 notifyIdleness(service.getManagedSessions().iterator(), currentTime);
185 }
186 }
187
188
189
190
191
192
193
194 public static void notifyIdleSession(IoSession session, long currentTime) {
195 if (session instanceof AbstractIoSession) {
196 AbstractIoSession s = (AbstractIoSession) session;
197 notifyIdleSession1(
198 s, currentTime,
199 s.getConfig().getIdleTimeInMillis(IdleStatus.BOTH_IDLE),
200 IdleStatus.BOTH_IDLE, Math.max(
201 s.getLastIoTime(),
202 s.getLastIdleTime(IdleStatus.BOTH_IDLE)));
203
204 notifyIdleSession1(
205 s, currentTime,
206 s.getConfig().getIdleTimeInMillis(IdleStatus.READER_IDLE),
207 IdleStatus.READER_IDLE, Math.max(
208 s.getLastReadTime(),
209 s.getLastIdleTime(IdleStatus.READER_IDLE)));
210
211 notifyIdleSession1(
212 s, currentTime,
213 s.getConfig().getIdleTimeInMillis(IdleStatus.WRITER_IDLE),
214 IdleStatus.WRITER_IDLE, Math.max(
215 s.getLastWriteTime(),
216 s.getLastIdleTime(IdleStatus.WRITER_IDLE)));
217
218 notifyWriteTimeout(s, currentTime);
219 updateThroughput(s, currentTime);
220 } else {
221 notifyIdleSession0(
222 session, currentTime,
223 session.getConfig().getIdleTimeInMillis(IdleStatus.BOTH_IDLE),
224 IdleStatus.BOTH_IDLE, Math.max(
225 session.getLastIoTime(),
226 session.getLastIdleTime(IdleStatus.BOTH_IDLE)));
227
228 notifyIdleSession0(
229 session, currentTime,
230 session.getConfig().getIdleTimeInMillis(IdleStatus.READER_IDLE),
231 IdleStatus.READER_IDLE, Math.max(
232 session.getLastReadTime(),
233 session.getLastIdleTime(IdleStatus.READER_IDLE)));
234
235 notifyIdleSession0(
236 session, currentTime,
237 session.getConfig().getIdleTimeInMillis(IdleStatus.WRITER_IDLE),
238 IdleStatus.WRITER_IDLE, Math.max(
239 session.getLastWriteTime(),
240 session.getLastIdleTime(IdleStatus.WRITER_IDLE)));
241 }
242 }
243
244 private static void notifyIdleSession0(
245 IoSession session, long currentTime,
246 long idleTime, IdleStatus status, long lastIoTime) {
247 if (idleTime > 0 && lastIoTime != 0
248 && currentTime - lastIoTime >= idleTime) {
249 session.getFilterChain().fireSessionIdle(status);
250 }
251 }
252
253 private static void notifyIdleSession1(
254 AbstractIoSession session, long currentTime,
255 long idleTime, IdleStatus status, long lastIoTime) {
256 if (idleTime > 0 && lastIoTime != 0
257 && currentTime - lastIoTime >= idleTime) {
258 session.getFilterChain().fireSessionIdle(status);
259 }
260 }
261
262 private static void notifyWriteTimeout(
263 AbstractIoSession session, long currentTime) {
264
265 long writeTimeout = session.getConfig().getWriteTimeoutInMillis();
266 if (writeTimeout > 0 &&
267 currentTime - session.getLastWriteTime() >= writeTimeout &&
268 !session.getWriteRequestQueue().isEmpty(session)) {
269 WriteRequest request = session.getCurrentWriteRequest();
270 if (request != null) {
271 session.setCurrentWriteRequest(null);
272 WriteTimeoutException cause = new WriteTimeoutException(request);
273 request.getFuture().setException(cause);
274 session.getFilterChain().fireExceptionCaught(cause);
275
276 session.close();
277 }
278 }
279 }
280
281 private static void updateThroughput(
282 AbstractIoSession session, long currentTime) {
283 session.updateThroughput(currentTime, false);
284 }
285 }