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 = new ConcurrentHashSet<AbstractIoSession>();
    43
    44      /* create a task you can execute in the transport code,
    45       * if the transport is like NIO or APR you don't need to call it,
    46       * you just need to call the needed static sessions on select()/poll()
    47       * timeout.
    48       */
    49      private final NotifyingTask notifyingTask = new NotifyingTask();
    50
    51      private final IoFutureListener<IoFuture> sessionCloseListener = new SessionCloseListener();
    52
    53      public IdleStatusChecker() {
    54          // Do nothing
    55      }
    56
    57      /**
    58       * Add the session for being checked for idle.
    59       * @param session the session to check
    60       */
    61      public void addSession(AbstractIoSession session) {
    62          sessions.add(session);
    63          CloseFuture closeFuture = session.getCloseFuture();
    64
    65          // isn't service reponsability to remove the session nicely ?
    66          closeFuture.addListener(sessionCloseListener);
    67      }
    68
    69      /**
    70       * remove a session from the list of session being checked.
    71       * @param session
    72       */
    73      private void removeSession(AbstractIoSession session) {
    74          sessions.remove(session);
    75      }
    76
    77      /**
    78       * get a runnable task able to be scheduled in the {@link IoService} executor.
    79       * @return
    80       */
    81      public NotifyingTask getNotifyingTask() {
    82          return notifyingTask;
    83      }
    84
    85      /**
    86       * The class to place in the transport executor for checking the sessions idle
    87       */
    88      public class NotifyingTask implements Runnable {
    89          private volatile boolean cancelled;
    90
    91          private volatile Thread thread;
    92
    93          // we forbid instantiation of this class outside
    94          /** No qualifier */
    95          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 }