Java tutorial
/** * ***************************************************************************** * Copyright (c) 2014 yama. * This is not a free software,all rights reserved by yama(guooscar@gmail.com). * ANY use of this software MUST be subject to the consent of yama. * * ***************************************************************************** */ /* * Copyright 2012 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 jazmin.server.msg.codec.json; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.TooLongFrameException; import java.nio.charset.Charset; import java.util.List; import jazmin.log.Logger; import jazmin.log.LoggerFactory; import jazmin.misc.io.NetworkTrafficStat; import jazmin.server.msg.codec.JSONRequestParser; import jazmin.server.msg.codec.RequestMessage; import jazmin.util.DumpUtil; /** * */ public class JSONDecoder extends ByteToMessageDecoder { private static Logger logger = LoggerFactory.get(JSONDecoder.class); /** Maximum length of a frame we're willing to decode. */ private final int maxLength; /** Whether or not to throw an exception as soon as we exceed maxLength. */ private final boolean failFast; private final boolean stripDelimiter; /** True if we're discarding input because we're already over maxLength. */ private boolean discarding; private int discardedBytes; private final Charset charset; // private static final int DEFAULT_MAX_LENGTH = 3000; // NetworkTrafficStat networkTrafficStat; public JSONDecoder(NetworkTrafficStat networkTrafficStat) { this(DEFAULT_MAX_LENGTH, true, false); this.networkTrafficStat = networkTrafficStat; } /** * Creates a new decoder. * @param maxLength the maximum length of the decoded frame. * A {@link TooLongFrameException} is thrown if * the length of the frame exceeds this value. */ public JSONDecoder(final int maxLength) { this(maxLength, true, false); } /** * Creates a new decoder. * @param maxLength the maximum length of the decoded frame. * A {@link TooLongFrameException} is thrown if * the length of the frame exceeds this value. * @param stripDelimiter whether the decoded frame should strip out the * delimiter or not * @param failFast If <tt>true</tt>, a {@link TooLongFrameException} is * thrown as soon as the decoder notices the length of the * frame will exceed <tt>maxFrameLength</tt> regardless of * whether the entire frame has been read. * If <tt>false</tt>, a {@link TooLongFrameException} is * thrown after the entire frame that exceeds * <tt>maxFrameLength</tt> has been read. */ public JSONDecoder(final int maxLength, final boolean stripDelimiter, final boolean failFast) { this.maxLength = maxLength; this.failFast = failFast; this.stripDelimiter = stripDelimiter; charset = Charset.forName("UTF-8"); } @Override protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { ByteBuf decoded = decode(ctx, in); if (decoded == null) { return; } String s = decoded.toString(charset); RequestMessage reqMessage = JSONRequestParser.createRequestMessage(s); if (logger.isDebugEnabled()) { logger.debug("\ndecode message--------------------------------------\n" + DumpUtil.formatJSON(s)); } networkTrafficStat.inBound(s.getBytes().length); out.add(reqMessage); } /** * Create a frame out of the {@link ByteBuf} and return it. * * @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to * @param buffer the {@link ByteBuf} from which to read data * @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could * be created. */ protected ByteBuf decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception { final int eol = findEndOfLine(buffer); if (!discarding) { if (eol >= 0) { final ByteBuf frame; final int length = eol - buffer.readerIndex(); final int delimLength = buffer.getByte(eol) == '\r' ? 2 : 1; if (length > maxLength) { buffer.readerIndex(eol + delimLength); fail(ctx, length); return null; } if (stripDelimiter) { frame = buffer.readBytes(length); buffer.skipBytes(delimLength); } else { frame = buffer.readBytes(length + delimLength); } return frame; } else { final int length = buffer.readableBytes(); if (length > maxLength) { discardedBytes = length; buffer.readerIndex(buffer.writerIndex()); discarding = true; if (failFast) { fail(ctx, "over " + discardedBytes); } } return null; } } else { if (eol >= 0) { final int length = discardedBytes + eol - buffer.readerIndex(); final int delimLength = buffer.getByte(eol) == '\r' ? 2 : 1; buffer.readerIndex(eol + delimLength); discardedBytes = 0; discarding = false; if (!failFast) { fail(ctx, length); } } else { discardedBytes = buffer.readableBytes(); buffer.readerIndex(buffer.writerIndex()); } return null; } } private void fail(final ChannelHandlerContext ctx, int length) { fail(ctx, String.valueOf(length)); } private void fail(final ChannelHandlerContext ctx, String length) { ctx.fireExceptionCaught(new TooLongFrameException( "frame length (" + length + ") exceeds the allowed maximum (" + maxLength + ')')); } /** * Returns the index in the buffer of the end of line found. * Returns -1 if no end of line was found in the buffer. */ private static int findEndOfLine(final ByteBuf buffer) { final int n = buffer.writerIndex(); for (int i = buffer.readerIndex(); i < n; i++) { final byte b = buffer.getByte(i); if (b == '\n') { return i; } else if (b == '\r' && i < n - 1 && buffer.getByte(i + 1) == '\n') { return i; // \r\n } } return -1; // Not found. } }