Package org.apache.mina.core.session

Source Code of org.apache.mina.core.session.IdleStatusChecker$NotifyingTask

/*
*  Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you under the Apache License, Version 2.0 (the
*  "License"); you may not use this file except in compliance
*  with the License.  You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing,
*  software distributed under the License is distributed on an
*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
*  KIND, either express or implied.  See the License for the
*  specific language governing permissions and limitations
*  under the License.
*
*/
package org.apache.mina.core.session;

import java.util.Iterator;
import java.util.Set;

import org.apache.mina.core.future.IoFuture;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.service.AbstractIoService;
import org.apache.mina.core.service.IoService;
import org.apache.mina.core.write.WriteRequest;
import org.apache.mina.core.write.WriteTimeoutException;
import org.apache.mina.util.ConcurrentHashSet;

/**
* Detects idle sessions and fires <tt>sessionIdle</tt> events to them.
*
* @author The Apache MINA Project (dev@mina.apache.org)
* @version $Rev: 525369 $, $Date: 2007-04-04 05:05:11 +0200 (mer., 04 avr. 2007) $
*/
public class IdleStatusChecker {
    private final Set<AbstractIoSession> sessions =
        new ConcurrentHashSet<AbstractIoSession>();
    private final Set<AbstractIoService> services =
        new ConcurrentHashSet<AbstractIoService>();

    private final NotifyingTask notifyingTask = new NotifyingTaskImpl();
    private final IoFutureListener<IoFuture> sessionCloseListener =
        new SessionCloseListener();

    public IdleStatusChecker() {}

    public void addSession(AbstractIoSession session) {
        sessions.add(session);
        session.getCloseFuture().addListener(sessionCloseListener);
    }

    public void addService(AbstractIoService service) {
        services.add(service);
    }

    public void removeSession(AbstractIoSession session) {
        sessions.remove(session);
    }

    public void removeService(AbstractIoService service) {
        services.remove(service);
    }

    public NotifyingTask getNotifyingTask() {
        return notifyingTask;
    }

    public interface NotifyingTask extends Runnable {
        /**
         * Cancels this task.  Once canceled, {@link #run()} method will always return immediately.
         * To start this task again after calling this method, you have to create a new instance of
         * {@link IdleStatusChecker} again.
         */
        void cancel();
    }

    private class NotifyingTaskImpl implements NotifyingTask {
        private volatile boolean cancelled;
        private volatile Thread thread;

        public void run() {
            thread = Thread.currentThread();
            try {
                while (!cancelled) {
                    // Check idleness with fixed delay (1 second).
                    long currentTime = System.currentTimeMillis();
                    notifyServices(currentTime);
                    notifySessions(currentTime);

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // will exit the loop if interrupted from interrupt()
                    }
                }
            } finally {
                thread = null;
            }
        }

        public void cancel() {
            cancelled = true;
            Thread thread = this.thread;
            if (thread != null) {
                thread.interrupt();
            }
        }

        private void notifyServices(long currentTime) {
            Iterator<AbstractIoService> it = services.iterator();
            while (it.hasNext()) {
                AbstractIoService service = it.next();
                if (service.isActive()) {
                    notifyIdleness(service, currentTime, false);
                }
            }
        }

        private void notifySessions(long currentTime) {
            Iterator<AbstractIoSession> it = sessions.iterator();
            while (it.hasNext()) {
                AbstractIoSession session = it.next();
                if (session.isConnected()) {
                    notifyIdleSession(session, currentTime);
                }
            }
        }
    }

    private class SessionCloseListener implements IoFutureListener<IoFuture> {
        public void operationComplete(IoFuture future) {
            removeSession((AbstractIoSession) future.getSession());
        }
    }

    /**
     * Fires a {@link IoEventType#SESSION_IDLE} event to any applicable
     * sessions in the specified collection.
     *
     * @param currentTime the current time (i.e. {@link System#currentTimeMillis()})
     */
    public static void notifyIdleness(Iterator<? extends IoSession> sessions, long currentTime) {
        IoSession s = null;
        while (sessions.hasNext()) {
            s = sessions.next();
            notifyIdleSession(s, currentTime);
        }
    }

    public static void notifyIdleness(IoService service, long currentTime) {
        notifyIdleness(service, currentTime, true);
    }

    private static void notifyIdleness(IoService service, long currentTime, boolean includeSessions) {
        if (!(service instanceof AbstractIoService)) {
            return;
        }

        ((AbstractIoService) service).notifyIdleness(currentTime);

        if (includeSessions) {
            notifyIdleness(service.getManagedSessions().values().iterator(), currentTime);
        }
    }

    /**
     * Fires a {@link IoEventType#SESSION_IDLE} event if applicable for the
     * specified {@code session}.
     *
     * @param currentTime the current time (i.e. {@link System#currentTimeMillis()})
     */
    public static void notifyIdleSession(IoSession session, long currentTime) {
        if (session instanceof AbstractIoSession) {
            AbstractIoSession s = (AbstractIoSession) session;
            notifyIdleSession1(
                    s, currentTime,
                    s.getConfig().getIdleTimeInMillis(IdleStatus.BOTH_IDLE),
                    IdleStatus.BOTH_IDLE, Math.max(
                            s.getLastIoTime(),
                            s.getLastIdleTime(IdleStatus.BOTH_IDLE)));

            notifyIdleSession1(
                    s, currentTime,
                    s.getConfig().getIdleTimeInMillis(IdleStatus.READER_IDLE),
                    IdleStatus.READER_IDLE, Math.max(
                            s.getLastReadTime(),
                            s.getLastIdleTime(IdleStatus.READER_IDLE)));

            notifyIdleSession1(
                    s, currentTime,
                    s.getConfig().getIdleTimeInMillis(IdleStatus.WRITER_IDLE),
                    IdleStatus.WRITER_IDLE, Math.max(
                            s.getLastWriteTime(),
                            s.getLastIdleTime(IdleStatus.WRITER_IDLE)));

            notifyWriteTimeout(s, currentTime);
            updateThroughput(s, currentTime);
        } else {
            notifyIdleSession0(
                    session, currentTime,
                    session.getConfig().getIdleTimeInMillis(IdleStatus.BOTH_IDLE),
                    IdleStatus.BOTH_IDLE, Math.max(
                            session.getLastIoTime(),
                            session.getLastIdleTime(IdleStatus.BOTH_IDLE)));

            notifyIdleSession0(
                    session, currentTime,
                    session.getConfig().getIdleTimeInMillis(IdleStatus.READER_IDLE),
                    IdleStatus.READER_IDLE, Math.max(
                            session.getLastReadTime(),
                            session.getLastIdleTime(IdleStatus.READER_IDLE)));

            notifyIdleSession0(
                    session, currentTime,
                    session.getConfig().getIdleTimeInMillis(IdleStatus.WRITER_IDLE),
                    IdleStatus.WRITER_IDLE, Math.max(
                            session.getLastWriteTime(),
                            session.getLastIdleTime(IdleStatus.WRITER_IDLE)));
        }
    }

    private static void notifyIdleSession0(
            IoSession session, long currentTime,
            long idleTime, IdleStatus status, long lastIoTime) {
        if (idleTime > 0 && lastIoTime != 0
                && currentTime - lastIoTime >= idleTime) {
            session.getFilterChain().fireSessionIdle(status);
        }
    }

    private static void notifyIdleSession1(
            AbstractIoSession session, long currentTime,
            long idleTime, IdleStatus status, long lastIoTime) {
        if (idleTime > 0 && lastIoTime != 0
                && currentTime - lastIoTime >= idleTime) {
            session.getFilterChain().fireSessionIdle(status);
        }
    }

    private static void notifyWriteTimeout(
            AbstractIoSession session, long currentTime) {

        long writeTimeout = session.getConfig().getWriteTimeoutInMillis();
        if (writeTimeout > 0 &&
                currentTime - session.getLastWriteTime() >= writeTimeout &&
                !session.getWriteRequestQueue().isEmpty(session)) {
            WriteRequest request = session.getCurrentWriteRequest();
            if (request != null) {
                session.setCurrentWriteRequest(null);
                WriteTimeoutException cause = new WriteTimeoutException(request);
                request.getFuture().setException(cause);
                session.getFilterChain().fireExceptionCaught(cause);
                // WriteException is an IOException, so we close the session.
                session.close();
            }
        }
    }

    private static void updateThroughput(
            AbstractIoSession session, long currentTime) {
        session.updateThroughput(currentTime, false);
    }
}
TOP

Related Classes of org.apache.mina.core.session.IdleStatusChecker$NotifyingTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.