com.whizzosoftware.wzwave.channel.outbound.FrameQueueHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.whizzosoftware.wzwave.channel.outbound.FrameQueueHandler.java

Source

/*
 *******************************************************************************
 * Copyright (c) 2013 Whizzo Software, LLC.
 * 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 com.whizzosoftware.wzwave.channel.outbound;

import com.whizzosoftware.wzwave.channel.event.*;
import com.whizzosoftware.wzwave.frame.ACK;
import com.whizzosoftware.wzwave.frame.DataFrame;
import com.whizzosoftware.wzwave.frame.OutboundDataFrame;
import io.netty.channel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.SocketAddress;
import java.util.Deque;
import java.util.LinkedList;

/**
 * Handler responsible for queueing data frames and writing them to the Z-Wave network when appropriate.
 *
 * @author Dan Noguerol
 */
public class FrameQueueHandler extends ChannelHandlerAdapter
        implements ChannelOutboundHandler, ChannelInboundHandler {
    private static final Logger logger = LoggerFactory.getLogger(FrameQueueHandler.class);

    private Deque<FrameWrite> pendingQueue = new LinkedList<>();
    private String currentTransactionId;

    @Override
    public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
            throws Exception {
        ctx.bind(localAddress, promise);
    }

    @Override
    public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
            ChannelPromise promise) throws Exception {
        ctx.connect(remoteAddress, localAddress, promise);
    }

    @Override
    public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
        ctx.disconnect(promise);
    }

    @Override
    public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
        ctx.close(promise);
    }

    @Override
    public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
        ctx.deregister(promise);
    }

    @Override
    public void read(ChannelHandlerContext ctx) throws Exception {
        ctx.read();
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        logger.trace("write: " + msg);
        if (msg instanceof OutboundDataFrame) {
            OutboundDataFrame odf = (OutboundDataFrame) msg;
            if (currentTransactionId == null || odf.matchesTransaction(currentTransactionId)) {
                ctx.writeAndFlush(odf.getDataFrame(), promise);
                odf.getDataFrame().incremenentSendCount();
                ctx.fireUserEventTriggered(new DataFrameSentEvent(odf.getDataFrame(), odf.isListeningNode()));
            } else {
                logger.trace("Queueing data frame: {}", msg);
                pendingQueue.add(new FrameWrite(odf.getDataFrame(), odf.isListeningNode(), promise));
            }
        } else if (msg instanceof TransactionStartedEvent) {
            currentTransactionId = ((TransactionStartedEvent) msg).getId();
            logger.trace("Detected data frame transaction start: {}", currentTransactionId);
        } else if (msg instanceof TransactionCompletedEvent) {
            logger.trace("Detected data frame transaction completion: {}", currentTransactionId);
            currentTransactionId = null;
            sendNextFrame(ctx);
        } else if (msg instanceof TransactionFailedEvent) {
            logger.trace("Detected data frame transaction failure: {}", currentTransactionId);
            currentTransactionId = null;
            sendNextFrame(ctx);
        } else if (msg instanceof ACK) {
            ctx.writeAndFlush(msg, promise);
        } else {
            logger.error("Direct DataFrame write attempt detected");
        }
    }

    private void sendNextFrame(ChannelHandlerContext ctx) {
        if (pendingQueue.size() > 0) {
            FrameWrite fw = pendingQueue.pop();
            logger.trace("Sending next queued data frame: {}", fw.frame);
            ctx.writeAndFlush(fw.frame, fw.promise);
            fw.frame.incremenentSendCount();
            ctx.fireUserEventTriggered(new DataFrameSentEvent(fw.frame, fw.isListeningNode));
        } else {
            logger.trace("No pending data frames to send");
        }
    }

    @Override
    public void flush(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelRegistered();
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelUnregistered();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelActive();
    }

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

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.fireChannelRead(msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelReadComplete();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        ctx.fireUserEventTriggered(evt);
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelWritabilityChanged();
    }

    private class FrameWrite {
        DataFrame frame;
        ChannelPromise promise;
        boolean isListeningNode;

        FrameWrite(DataFrame frame, boolean isListeningNode, ChannelPromise promise) {
            this.frame = frame;
            this.promise = promise;
            this.isListeningNode = isListeningNode;
        }
    }
}