View Javadoc

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 }