Package org.jboss.aerogear.io.netty.handler.codec.sockjs.handler

Source Code of org.jboss.aerogear.io.netty.handler.codec.sockjs.handler.SessionHandler$DefaultSockJsSessionContext

/*
* Copyright 2013 The Netty Project
*
* The Netty Project 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.jboss.aerogear.io.netty.handler.codec.sockjs.handler;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.jboss.aerogear.io.netty.handler.codec.sockjs.SockJsSessionContext;
import org.jboss.aerogear.io.netty.handler.codec.sockjs.handler.SessionState.State;
import org.jboss.aerogear.io.netty.handler.codec.sockjs.protocol.CloseFrame;
import org.jboss.aerogear.io.netty.handler.codec.sockjs.protocol.MessageFrame;
import org.jboss.aerogear.io.netty.handler.codec.sockjs.protocol.OpenFrame;
import org.jboss.aerogear.io.netty.handler.codec.sockjs.util.ArgumentUtil;


/**
* A ChannelHandler that manages SockJS sessions.
*
* For every connection received a new SessionHandler will be created and added to
* the pipeline.
*
* Depending on the type of connection (polling, streaming, send, or websocket)
* the type of {@link SessionState} that this session handles will differ.
*
*/
public class SessionHandler extends ChannelHandlerAdapter {

    public enum Event { CLOSE_SESSION, HANDLE_SESSION }

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(SessionHandler.class);

    private final SessionState sessionState;

    public SessionHandler(final SessionState sessionState) {
        ArgumentUtil.checkNotNull(sessionState, "sessionState");
        this.sessionState = sessionState;
    }

    @Override
    public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
        if (msg instanceof HttpRequest) {
            if (logger.isDebugEnabled()) {
                logger.debug("Handle session : {}", sessionState);
            }
            ReferenceCountUtil.release(msg);
            handleSession(ctx);
        } else if (msg instanceof String) {
            handleMessage((String) msg);
        } else {
            ctx.fireChannelRead(ReferenceCountUtil.retain(msg));
        }
    }

    private void handleSession(final ChannelHandlerContext ctx) throws Exception {
        switch (sessionState.getState()) {
        case CONNECTING:
            sessionConnecting(ctx);
            break;
        case OPEN:
            sessionOpen(ctx);
            break;
        case INTERRUPTED:
            sessionInterrupted(ctx);
            break;
        case CLOSED:
            sessionClosed(ctx);
            break;
        }
    }

    private void sessionConnecting(final ChannelHandlerContext ctx) {
        logger.debug("State.CONNECTING sending open frame");
        writeOpenFrame(ctx);
        sessionState.onConnect(ctx, new DefaultSockJsSessionContext());
    }

    private void sessionOpen(ChannelHandlerContext ctx) {
        if (sessionState.isInUse()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Another connection still in open for {}", sessionState);
            }
            writeCloseFrame(ctx, 2010, "Another connection still open");
            sessionState.setState(State.INTERRUPTED);
        } else {
            sessionState.onOpen(ctx);
        }
    }

    private void sessionInterrupted(ChannelHandlerContext ctx) {
        writeCloseFrame(ctx, 1002, "Connection interrupted");
    }

    private void sessionClosed(ChannelHandlerContext ctx) {
        writeCloseFrame(ctx, 3000, "Go away!");
        sessionState.onClose();
    }

    private void handleMessage(final String message) throws Exception {
        sessionState.onMessage(message);
    }

    @Override
    public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
        sessionState.resetInuse();
        ctx.fireChannelInactive();
    }

    private static boolean isWritable(final Channel channel) {
        return channel.isActive() && channel.isRegistered();
    }

    @Override
    public void userEventTriggered(final ChannelHandlerContext ctx, final Object event) throws Exception {
        if (event == Event.CLOSE_SESSION) {
            sessionState.onClose();
            sessionState.onSockJSServerInitiatedClose();
        } else if (event == Event.HANDLE_SESSION) {
            handleSession(ctx);
        }
    }

    private static void writeCloseFrame(final ChannelHandlerContext ctx, final int code, final String message) {
        ctx.channel().writeAndFlush(new CloseFrame(code, message));
    }

    private static void writeOpenFrame(final ChannelHandlerContext ctx) {
        ctx.channel().writeAndFlush(new OpenFrame());
    }

    public class DefaultSockJsSessionContext implements SockJsSessionContext {

        @Override
        public void send(String message) {
            final Channel channel = sessionState.getSendingContext().channel();
            if (isWritable(channel)) {
                channel.writeAndFlush(new MessageFrame(message));
            } else {
                sessionState.storeMessage(message);
            }
        }

        @Override
        public void close() {
            sessionState.onClose();
            final Channel channel = sessionState.getSendingContext().channel();
            if (isWritable(channel)) {
                final CloseFrame closeFrame = new CloseFrame(3000, "Go away!");
                if (logger.isDebugEnabled()) {
                    logger.debug("Writing {}", closeFrame);
                }
                channel.writeAndFlush(closeFrame).addListener(ChannelFutureListener.CLOSE);
            }
        }

        @Override
        public ChannelHandlerContext getContext() {
            return sessionState.getSendingContext();
        }
    }

}
TOP

Related Classes of org.jboss.aerogear.io.netty.handler.codec.sockjs.handler.SessionHandler$DefaultSockJsSessionContext

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.