1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.core.session;
21
22 import java.util.Iterator;
23 import java.util.Set;
24
25 import org.apache.mina.core.future.CloseFuture;
26 import org.apache.mina.core.future.IoFuture;
27 import org.apache.mina.core.future.IoFutureListener;
28 import org.apache.mina.core.service.IoService;
29 import org.apache.mina.util.ConcurrentHashSet;
30
31 /**
32 * Detects idle sessions and fires <tt>sessionIdle</tt> events to them.
33 * To be used for service unable to trigger idle events alone, like VmPipe
34 * or SerialTransport. Polling base transport are advised to trigger idle
35 * events alone, using the poll/select timeout.
36 *
37 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
38 */
39 public class IdleStatusChecker {
40
41 // the list of session to check
42 private final Set<AbstractIoSession> sessions =
43 new ConcurrentHashSet<AbstractIoSession>();
44
45 /* create a task you can execute in the transport code,
46 * if the transport is like NIO or APR you don't need to call it,
47 * you just need to call the needed static sessions on select()/poll()
48 * timeout.
49 */
50 private final NotifyingTask notifyingTask = new NotifyingTask();
51
52 private final IoFutureListener<IoFuture> sessionCloseListener =
53 new SessionCloseListener();
54
55 public IdleStatusChecker() {
56 // Do nothing
57 }
58
59 /**
60 * Add the session for being checked for idle.
61 * @param session the session to check
62 */
63 public void addSession(AbstractIoSession session) {
64 sessions.add(session);
65 CloseFuture closeFuture = session.getCloseFuture();
66
67 // isn't service reponsability to remove the session nicely ?
68 closeFuture.addListener(sessionCloseListener);
69 }
70
71 /**
72 * remove a session from the list of session being checked.
73 * @param session
74 */
75 private void removeSession(AbstractIoSession session) {
76 sessions.remove(session);
77 }
78
79 /**
80 * get a runnable task able to be scheduled in the {@link IoService} executor.
81 * @return
82 */
83 public NotifyingTask getNotifyingTask() {
84 return notifyingTask;
85 }
86
87 /**
88 * The class to place in the transport executor for checking the sessions idle
89 */
90 public class NotifyingTask implements Runnable {
91 private volatile boolean cancelled;
92 private volatile Thread thread;
93
94 // we forbid instantiation of this class outside
95 /** No qualifier */ NotifyingTask() {
96 // Do nothing
97 }
98
99 public void run() {
100 thread = Thread.currentThread();
101 try {
102 while (!cancelled) {
103 // Check idleness with fixed delay (1 second).
104 long currentTime = System.currentTimeMillis();
105
106 notifySessions(currentTime);
107
108 try {
109 Thread.sleep(1000);
110 } catch (InterruptedException e) {
111 // will exit the loop if interrupted from interrupt()
112 }
113 }
114 } finally {
115 thread = null;
116 }
117 }
118
119 /**
120 * stop execution of the task
121 */
122 public void cancel() {
123 cancelled = true;
124 Thread thread = this.thread;
125 if (thread != null) {
126 thread.interrupt();
127 }
128 }
129
130 private void notifySessions(long currentTime) {
131 Iterator<AbstractIoSession> it = sessions.iterator();
132 while (it.hasNext()) {
133 AbstractIoSession session = it.next();
134 if (session.isConnected()) {
135 AbstractIoSession.notifyIdleSession(session, currentTime);
136 }
137 }
138 }
139 }
140
141 private class SessionCloseListener implements IoFutureListener<IoFuture> {
142 /**
143 * Default constructor
144 */
145 public SessionCloseListener() {
146 super();
147 }
148
149 public void operationComplete(IoFuture future) {
150 removeSession((AbstractIoSession) future.getSession());
151 }
152 }
153 }