io.netty.handler.codec.ByteToMessageDecoder Maven / Gradle / Ivy
/*
* 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 io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelInboundByteHandlerAdapter;
/**
* {@link ChannelInboundByteHandler} which decodes bytes in a stream-like fashion from one {@link ByteBuf} to an other
* Message type.
*
* For example here is an implementation which reads all readable bytes from
* the input {@link ByteBuf} and create a new {@link ByteBuf}.
*
*
* public class SquareDecoder extends {@link ByteToMessageDecoder} {
* {@code @Override}
* public {@link Object} decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in)
* throws {@link Exception} {
* return in.readBytes(in.readableBytes());
* }
* }
*
*/
public abstract class ByteToMessageDecoder
extends ChannelInboundByteHandlerAdapter {
private volatile boolean singleDecode;
private boolean decodeWasNull;
/**
* If set then only one message is decoded on each {@link #inboundBufferUpdated(ChannelHandlerContext)} call.
* This may be useful if you need to do some protocol upgrade and want to make sure nothing is mixed up.
*
* Default is {@code false} as this has performance impacts.
*/
public void setSingleDecode(boolean singleDecode) {
this.singleDecode = singleDecode;
}
/**
* If {@code true} then only one message is decoded on each
* {@link #inboundBufferUpdated(ChannelHandlerContext)} call.
*
* Default is {@code false} as this has performance impacts.
*/
public boolean isSingleDecode() {
return singleDecode;
}
@Override
public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
callDecode(ctx, in);
}
@Override
public void channelReadSuspended(ChannelHandlerContext ctx) throws Exception {
if (decodeWasNull) {
decodeWasNull = false;
if (!ctx.channel().config().isAutoRead()) {
ctx.read();
}
}
super.channelReadSuspended(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
try {
ByteBuf in = ctx.inboundByteBuffer();
if (in.isReadable()) {
callDecode(ctx, in);
}
if (ctx.nextInboundMessageBuffer().unfoldAndAdd(decodeLast(ctx, in))) {
ctx.fireInboundBufferUpdated();
}
} catch (Throwable t) {
if (t instanceof CodecException) {
ctx.fireExceptionCaught(t);
} else {
ctx.fireExceptionCaught(new DecoderException(t));
}
} finally {
ctx.fireChannelInactive();
}
}
protected void callDecode(ChannelHandlerContext ctx, ByteBuf in) {
boolean wasNull = false;
boolean decoded = false;
MessageBuf