com.mnt.base.stream.netty.NStreamLightweightParser.java Source code

Java tutorial

Introduction

Here is the source code for com.mnt.base.stream.netty.NStreamLightweightParser.java

Source

/**
 * $Revision: 1.0
 * $Date: 2013-5-21
 *
 * Copyright (C) 2013-2020 MNT. All rights reserved.
 *
 * Licensed 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 com.mnt.base.stream.netty;

import io.netty.buffer.ByteBuf;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.mnt.base.stream.comm.BytesUtil;
import com.mnt.base.stream.dtd.StreamPacketDef;

/**
 * This is a Light-Weight stream Parser.
 * It read data from a channel and collect data until data are available in
 * the channel.
 * When a message is complete you can retrieve messages invoking the method
 * getMsgs() and you can invoke the method areThereMsgs() to know if at least
 * an message is presents.
 *
 * @author Peng Peng
 */
public class NStreamLightweightParser {

    //private static final Log Log = LogFactory.getLog(XMLLightweightParser.class);

    private static int maxBufferSize;

    // Buffer with all data retrieved
    protected ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    private List<byte[]> cachedPackets = new ArrayList<byte[]>();

    private int curIndex;
    private int curSize;

    private byte[] packetLenBytes = new byte[StreamPacketDef.PACKET_LEN_BYTE_SIZE];
    private byte[] vcBytes = new byte[StreamPacketDef.PACKET_VC_BYTE_SIZE];

    private int status = 0;

    private static final int STATUS_WAIT = 0;
    private static final int STATU_READ_LEN = 1;
    private static final int STATUS_READ_DATA = 2;
    private static final int STATUS_READ_VD = 3;

    static {
        // Set default max buffer size to 100MB. If limit is reached then close connection
        maxBufferSize = 104857600;
        // Listen for changes to this property
    }

    public NStreamLightweightParser() {
        // empty
    }

    /*
    * true if the parser has found some complete xml message.
    */
    public boolean areTherePackets() {
        return (cachedPackets.size() > 0);
    }

    /*
    * @return an array with all messages found
    */
    public List<byte[]> getPacketBytes() {
        return cachedPackets;
    }

    /*
    * Method use to re-initialize the buffer
    */
    protected void invalidateBufferAndClear() {
        cachedPackets.clear();
    }

    /*
    * Method that add a message to the list and reinit parser.
    */
    protected void foundMsgEnd() {
        // Add message to the complete message list
        buffer.reset();
        curIndex = -1;
        curSize = 0;
        status = STATUS_WAIT;
    }

    /*
    * Main reading method
    */
    public void read(ByteBuf byteBuffer) throws Exception {

        // Check that the buffer is not bigger than 100 Megabyte. For security reasons
        // we will abort parsing when 100 MB of queued byte was found.
        if (buffer.size() > maxBufferSize) {
            throw new Exception("Stopped parsing never ending stream");
        }

        int len = byteBuffer.readableBytes();

        if (len > 0) {
            byte[] bytes = new byte[len];
            byteBuffer.readBytes(bytes, 0, len);
            readBytes(bytes, 0);
        }
    }

    private void readBytes(byte[] bytes, int position) throws Exception {

        if (status == STATUS_READ_DATA) {
            int delta = curSize - curIndex;

            int remaining = bytes.length - position;

            if (remaining < delta) {
                buffer.write(bytes, position, remaining);
                curIndex += remaining;
            } else {
                buffer.write(bytes, position, delta);
                curIndex = curSize;

                position += delta;
                status = STATUS_READ_VD;
                curIndex = 0;
                curSize = StreamPacketDef.PACKET_VC_BYTE_SIZE;

                if (position < bytes.length) {
                    readBytes(bytes, position);
                }
            }
        } else {
            switch (status) {
            case STATUS_WAIT: {
                for (; position < bytes.length; position++) {
                    if (bytes[position] == StreamPacketDef.BYTE_STREAM_PACKET_START) {
                        status = STATU_READ_LEN;
                        curIndex = 0;
                        curSize = StreamPacketDef.PACKET_LEN_BYTE_SIZE;
                        position++;
                        break;
                    }
                }

                if (position == bytes.length) {
                    break;
                }
            }
            case STATU_READ_LEN: {

                while (position < bytes.length) {
                    if (curIndex == curSize) {
                        break;
                    }

                    packetLenBytes[curIndex++] = bytes[position++];
                }

                if (curIndex == curSize) {
                    curIndex = 0;
                    curSize = BytesUtil.bytesToInt(packetLenBytes);
                    status = STATUS_READ_DATA;
                }

                if (position < bytes.length) {
                    readBytes(bytes, position);
                }
                break;
            }
            case STATUS_READ_VD: {
                while (position < bytes.length) {
                    if (curIndex == curSize) {
                        break;
                    }

                    vcBytes[curIndex++] = bytes[position++];
                }

                if (curIndex == curSize) {
                    curIndex = 0;
                    byte[] source = buffer.toByteArray();
                    if (BytesUtil.equals(BytesUtil.genSign(source), vcBytes)) {
                        cachedPackets.add(source);
                        foundMsgEnd();
                    } else {
                        throw new Exception("error while check the vc:" + Arrays.toString(vcBytes)
                                + ", get sign value: " + BytesUtil.genSign(source));
                    }

                    status = STATUS_WAIT;
                }

                if (position < bytes.length) {
                    readBytes(bytes, position);
                }
            }
            }
        }
    }
}