diff --git a/src/main/java/org/jboss/netty/handler/codec/frame/FrameDecoder.java b/src/main/java/org/jboss/netty/handler/codec/frame/FrameDecoder.java index e1e5dd3724..55d2998cdf 100644 --- a/src/main/java/org/jboss/netty/handler/codec/frame/FrameDecoder.java +++ b/src/main/java/org/jboss/netty/handler/codec/frame/FrameDecoder.java @@ -32,11 +32,108 @@ import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipelineCoverage; import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; /** + * Assembles and splits incoming {@link ChannelBuffer}s into a meaningful + * frame object. + *
+ * In a stream-based transport such as TCP/IP, packets can be fragmented and + * reassembled during transmission even in a LAN environment. For example, + * let's assume you have received three packets: + *
+ * +-----+-----+-----+ + * | ABC | DEF | GHI | + * +-----+-----+-----+ + *+ * because of the packet fragmentation, a server can receive them like the + * following: + *
+ * +----+-------+---+---+ + * | AB | CDEFG | H | I | + * +----+-------+---+---+ + *+ *
+ * {@link FrameDecoder} helps you defrag and split the received packets into + * one or more meaningful frames that could be easily + * understood by the application logic. In case of the example above, your + * {@link FrameDecoder} implementation could defrag the received packets like + * the following: + *
+ * +-----+-----+-----+ + * | ABC | DEF | GHI | + * +-----+-----+-----+ + *+ *
+ * The following code shows an example decoder which decodes a frame whose + * first 4 bytes header represents the length of the frame, excluding the + * header. + *
+ * MESSAGE FORMAT + * ============== + * + * Offset: 0 4 (Length + 4) + * +--------+------------------------+ + * Fields: | Length | Actual message content | + * +--------+------------------------+ + * + * DECODER IMPLEMENTATION + * ====================== + * + * public class IntegerHeaderFrameDecoder extends FrameDecoder { + * protected Object decode(ChannelHandlerContext ctx, + * Channel channel, + * ChannelBuffer buf) throws Exception { + * + * // Make sure if the length field was received. + * if (buf.readableBytes() < 4) { + * // The length field was not received yet - return null. + * // This method will be invoked again when more packets are + * // received and appended to the buffer. + * return null; + * } + * + * // The length field is in the buffer. + * + * // Mark the current buffer position before reading the length field + * // because the whole frame might not be in the buffer yet. + * // We will reset the buffer position to the marked position if + * // there's not enough bytes in the buffer. + * buf.markReaderIndex(); + * + * // Read the length field. + * int length = buf.readInt(); + * + * // Make sure if there's enough bytes in the buffer. + * if (buf.readableBytes() < length) { + * // The whole bytes were not received yet - return null. + * // This method will be invoked again when more packets are + * // received and appended to the buffer. + * + * // Reset to the marked position to read the length field again + * // next time. + * buf.resetReaderIndex(); + * + * return null; + * } + * + * // There's enough bytes in the buffer. Read it. + * ChannelBuffer frame = buf.readBytes(length); + * + * // Successfully decoded a frame. Return the decoded frame. + * // Please note that you can return a different type than + * // {@link ChannelBuffer} although this example returns a {@link ChannelBuffer}. + * // For example, you could return a POJO here so that the next + * // {@link ChannelUpstreamHandler} receives a {@link MessageEvent} which contains + * // a POJO rather than a {@link ChannelBuffer}. + * return frame; + * } + * } + *+ * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * @@ -93,9 +190,30 @@ public abstract class FrameDecoder extends SimpleChannelHandler { ctx.sendUpstream(e); } + /** + * Decodes the received packets so far into a frame. + * + * @param ctx the context of this handler + * @param channel the current channel + * @param buffer the cumulative buffer of received packets so far + * + * @return the decoded frame if a full frame was received and decoded. + * {@code null} if there's not enough data in the buffer to decode a frame. + */ protected abstract Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception; + /** + * Decodes the received data so far into a frame when the channel is + * disconnected. + * + * @param ctx the context of this handler + * @param channel the current channel + * @param buffer the cumulative buffer of received packets so far + * + * @return the decoded frame if a full frame was received and decoded. + * {@code null} if there's not enough data in the buffer to decode a frame. + */ protected Object decodeLast( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { return decode(ctx, channel, buffer);