org.jactr.tools.async.controller.RemoteIOHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.jactr.tools.async.controller.RemoteIOHandler.java

Source

/*
 * Created on Feb 20, 2007 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu
 * (jactr.org) This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of the License,
 * or (at your option) any later version. This library is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the GNU Lesser General Public License for more details. You should have
 * received a copy of the GNU Lesser General Public License along with this
 * library; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */
package org.jactr.tools.async.controller;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.handler.demux.ExceptionHandler;
import org.jactr.core.runtime.controller.IController;
import org.jactr.core.runtime.controller.debug.IDebugController;
import org.jactr.tools.async.common.BaseIOHandler;
import org.jactr.tools.async.controller.handlers.BreakpointHandler;
import org.jactr.tools.async.controller.handlers.LoginHandler;
import org.jactr.tools.async.controller.handlers.LogoutHandler;
import org.jactr.tools.async.controller.handlers.ModelStateHandler;
import org.jactr.tools.async.controller.handlers.ProductionHandler;
import org.jactr.tools.async.controller.handlers.RuntimeStateHandler;
import org.jactr.tools.async.message.command.breakpoint.IBreakpointCommand;
import org.jactr.tools.async.message.command.breakpoint.IProductionCommand;
import org.jactr.tools.async.message.command.login.LoginCommand;
import org.jactr.tools.async.message.command.login.LogoutCommand;
import org.jactr.tools.async.message.command.state.IModelStateCommand;
import org.jactr.tools.async.message.command.state.IRuntimeStateCommand;
import org.jactr.tools.async.message.event.login.LoginAcknowledgedMessage;

/**
 * @author developer
 */
public class RemoteIOHandler extends BaseIOHandler {
    /**
     * logger definition
     */
    static private final Log LOGGER = LogFactory.getLog(RemoteIOHandler.class);

    static public final String CREDENTIALS = "jactr.credentials";

    private IoSession _ownerSession;

    private boolean _allowListeners = false;

    private IController _controller;

    /**
     * 
     */
    public RemoteIOHandler(IController controller) {
        _controller = controller;

        /*
         * handle start up credential
         */
        addReceivedMessageHandler(LoginCommand.class, new LoginHandler(this));
        /*
         * state control
         */
        addReceivedMessageHandler(IRuntimeStateCommand.class, new RuntimeStateHandler(this));

        addReceivedMessageHandler(IModelStateCommand.class, new ModelStateHandler(this));

        addReceivedMessageHandler(LogoutCommand.class, new LogoutHandler());

        /*
         * breakpoints
         */
        if (_controller instanceof IDebugController) {
            addReceivedMessageHandler(IBreakpointCommand.class, new BreakpointHandler(this));
            addReceivedMessageHandler(IProductionCommand.class, new ProductionHandler(this));
        }

        addExceptionHandler(Throwable.class, new ExceptionHandler<Throwable>() {

            public void exceptionCaught(IoSession session, Throwable exception) throws Exception {
                /**
                 * Error : error
                 */
                LOGGER.error("Exception caught from session " + session + ", closing. ", exception);
                /*
                 * waiting for all the pending writes would result in a serious backlog
                 * of queued messages if we couldn't actually wait for the pending
                 * writes.
                 */
                // waitForPendingWrites();
                session.close();
            }

        });
    }

    /**
     * return the controller, we require the session so we can ensure no errant
     * handlers access the controller
     */
    public IController getController(IoSession session) {
        allowsCommands(session);
        return _controller;
    }

    final synchronized public boolean isOwner(IoSession session) {
        boolean couldBeOwner = getCredentials().equals(session.getAttribute(CREDENTIALS));
        if (couldBeOwner) {
            if (_ownerSession == null) {
                _ownerSession = session;
                if (LOGGER.isDebugEnabled())
                    LOGGER.debug("Acknowledging login");
                session.write(new LoginAcknowledgedMessage(true, "You are the owner of this runtime"));
            }

            if (session != _ownerSession) {
                String msg = "Another session with the same credentials owns this runtime";
                if (LOGGER.isDebugEnabled())
                    LOGGER.debug("Rejecting login : " + msg);
                session.write(new LoginAcknowledgedMessage(false, msg));
                throw new SecurityException(msg);
            }
        } else if (LOGGER.isDebugEnabled())
            LOGGER.debug(getCredentials() + " do not match those of session " + session.getAttribute(CREDENTIALS));

        return couldBeOwner;
    }

    final public void allowsCommands(IoSession session) {
        if (!isOwner(session)) {
            String message = session + " is not allowed to send commands, disconnecting ";
            SecurityException e = new SecurityException(message);
            if (LOGGER.isWarnEnabled())
                LOGGER.warn(message, e);
            throw e;
        }
    }

    final public void allowsListeners(IoSession session) {
        if (!isOwner(session) && !_allowListeners) {
            String message = "Listening is not permitted by anyone other than owner, closing " + session;
            session.write(new LoginAcknowledgedMessage(false, message));
            if (LOGGER.isWarnEnabled())
                LOGGER.warn(message);
            throw new SecurityException(message);
        }
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Accepted connection from " + session);
        _ownerSession = session;
        super.sessionOpened(session);
    }

    public IoSession getOwner() {
        return _ownerSession;
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        super.sessionClosed(session);
        if (isOwner(session)) {
            _ownerSession = null;
            if (_controller.isRunning()) {
                if (LOGGER.isDebugEnabled())
                    LOGGER.debug("No master is connected, must permit uninterrupted run");
                /*
                 * clear all the break points and resume
                 */
                if (_controller instanceof IDebugController)
                    ((IDebugController) _controller).clearBreakpoints();

                if (_controller.isSuspended())
                    _controller.resume();
            }
        }
    }
}