org.opendaylight.usc.plugin.UscDemultiplexer.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.usc.plugin.UscDemultiplexer.java

Source

/*
 * Copyright (c) 2015 Huawei, Inc and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.usc.plugin;

import java.net.SocketAddress;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.local.LocalChannel;

import org.opendaylight.usc.manager.monitor.evt.UscChannelErrorEvent;
import org.opendaylight.usc.manager.monitor.evt.UscSessionErrorEvent;
import org.opendaylight.usc.manager.monitor.evt.UscSessionTransactionEvent;
import org.opendaylight.usc.plugin.exception.UscChannelException;
import org.opendaylight.usc.plugin.exception.UscConnectionException;
import org.opendaylight.usc.plugin.exception.UscSessionException;
import org.opendaylight.usc.plugin.model.UscChannelImpl;
import org.opendaylight.usc.plugin.model.UscSessionImpl;
import org.opendaylight.usc.protocol.UscControl;
import org.opendaylight.usc.protocol.UscData;
import org.opendaylight.usc.protocol.UscError;
import org.opendaylight.usc.protocol.UscFrame;
import org.opendaylight.usc.protocol.UscHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.util.concurrent.SettableFuture;

/**
 * This class handles the demultiplexing of the raw USC traffic into the
 * respective client sessions.
 */
@Sharable
public class UscDemultiplexer extends SimpleChannelInboundHandler<UscFrame> {

    private static final Logger LOG = LoggerFactory.getLogger(UscDemultiplexer.class);
    public final ConcurrentMap<SocketAddress, SettableFuture<Throwable>> promiseMap = new ConcurrentHashMap<>();
    private final UscPlugin plugin;

    /**
     * Constructs a new UscDemultiplexer
     * 
     * @param plugin
     *            The instance of UscPlugin on whose behalf this demultiplexer
     *            is managing session state.
     */
    public UscDemultiplexer(UscPlugin plugin) {
        this.plugin = plugin;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, UscFrame frame) throws Exception {
        LOG.trace("UscDemultiplexer.channelRead: " + frame);

        if (frame instanceof UscControl) {
            UscControl controlMsg = (UscControl) frame;
            if (controlMsg.getControlCode() == UscControl.ControlCode.ECHO) {
                SocketAddress remoteAddress = ctx.channel().remoteAddress();
                promiseMap.get(remoteAddress).set(new Throwable("Success"));
                LOG.trace("channelRead0: promiseMap = " + promiseMap);
                return;
            }
        }

        final UscHeader header = frame.getHeader();
        final int sessionId = header.getSessionId();
        final UscChannelImpl connection = ctx.channel().attr(UscPlugin.CHANNEL).get();

        final UscSessionImpl session = connection.getSession(sessionId);
        final LocalChannel serverChannel = session.getServerChannel();
        if (frame instanceof UscError) {
            // propagate exception to the client channel
            UscSessionException ex = new UscSessionException(((UscError) frame).getErrorCode());

            serverChannel.writeAndFlush(ex);
            plugin.sendEvent(new UscSessionErrorEvent(session, ex));
        } else if (frame instanceof UscData) {

            if (serverChannel != null) {
                LOG.trace("write session " + sessionId + " to " + serverChannel + ": " + frame.getPayload());

                ByteBuf payload = frame.getPayload();

                plugin.sendEvent(new UscSessionTransactionEvent(session, payload.readableBytes(), 0));

                serverChannel.writeAndFlush(payload);
            } else {
                UscChannelException ex = new UscChannelException(
                        "write unknown session " + sessionId + "; discard");
                plugin.sendEvent(new UscChannelErrorEvent(session.getChannel(), ex));

                throw ex;
            }
        } else if (frame instanceof UscControl) {
            UscControl controlMsg = (UscControl) frame;
            Channel clientChannel = serverChannel.attr(UscPlugin.CLIENT_CHANNEL).get();
            if (controlMsg.getControlCode() == UscControl.ControlCode.TERMINATION_REQUEST) {
                LOG.trace("UscDemultiplexer received control message TERMINATION_REQUEST");
                clientChannel.close();

                // send back TERMINATION_RESPONSE
                UscControl data = new UscControl(session.getPort(), session.getSessionId(), 2);
                ctx.channel().writeAndFlush(data);
            } else if (controlMsg.getControlCode() == UscControl.ControlCode.TERMINATION_RESPONSE) {
                LOG.trace("UscDemultiplexer received control message TERMINATION_RESPONSE");
                if (clientChannel != null) {
                    SettableFuture<Boolean> status = plugin.getCloseFuture().get(clientChannel);
                    status.set(true);
                    LOG.trace("UscDemultiplexer: termination status is " + status.get());
                }
            }
        } else {
            LOG.trace("UscDemultiplexer.channelRead: unexpected UscFrame object " + frame);
            UscChannelException ex = new UscChannelException("unexpected UscFrame object " + frame);
            plugin.sendEvent(new UscChannelErrorEvent(session.getChannel(), ex));

            throw ex;
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        LOG.trace("UscDemultiplexer channelInactive()");

        UscConnectionException ex = new UscConnectionException("The channel is closed.");

        throw ex;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        SocketAddress remoteAddress = ctx.channel().remoteAddress();
        promiseMap.get(remoteAddress).set(cause);
        LOG.trace("exceptionCaught: promiseMap = " + promiseMap);

        if (cause instanceof UscChannelException) {
            LOG.trace("UscDemultiplexer exceptionCaught()");
            final UscChannelImpl connection = ctx.channel().attr(UscPlugin.CHANNEL).get();

            for (UscSessionImpl session : connection.getAllSessions()) {
                final LocalChannel serverChannel = session.getServerChannel();

                if (serverChannel != null) {
                    LOG.trace("UscDemultiplexer exceptionCaught() and write to the server channel.");

                    serverChannel.writeAndFlush(cause);
                }
            }
        }
    }

}