org.jboss.netty.handler.codec.frame

## Class LengthFieldBasedFrameDecoder

- java.lang.Object
- - org.jboss.netty.channel.SimpleChannelUpstreamHandler
  - - org.jboss.netty.handler.codec.frame.FrameDecoder
    - - org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder

- All Implemented Interfaces:
    ChannelHandler, ChannelUpstreamHandler, LifeCycleAwareChannelHandler
  Direct Known Subclasses:
    MarshallingDecoder, ObjectDecoder

      public class LengthFieldBasedFrameDecoder
      extends FrameDecoder

  A decoder that splits the received `ChannelBuffer`s dynamically by the value of the length field in the message. It is particularly useful when you decode a binary message which has an integer header field that represents the length of the message body or the whole message.

  `LengthFieldBasedFrameDecoder` has many configuration parameters so that it can decode any message with a length field, which is often seen in proprietary client-server protocols. Here are some example that will give you the basic idea on which option does what.

  ### 2 bytes length field at offset 0, do not strip header

  The value of the length field in this example is `12 (0x0C)` which represents the length of "HELLO, WORLD". By default, the decoder assumes that the length field represents the number of the bytes that follows the length field. Therefore, it can be decoded with the simplistic parameter combination.

       lengthFieldOffset   = 0
       lengthFieldLength   = 2
       lengthAdjustment    = 0
       initialBytesToStrip = 0 (= do not strip header)

       BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
       +--------+----------------+      +--------+----------------+
       | Length | Actual Content |----->| Length | Actual Content |
       | 0x000C | "HELLO, WORLD" |      | 0x000C | "HELLO, WORLD" |
       +--------+----------------+      +--------+----------------+

  ### 2 bytes length field at offset 0, strip header

  Because we can get the length of the content by calling `ChannelBuffer.readableBytes()`, you might want to strip the length field by specifying `initialBytesToStrip`. In this example, we specified `2`, that is same with the length of the length field, to strip the first two bytes.

       lengthFieldOffset   = 0
       lengthFieldLength   = 2
       lengthAdjustment    = 0
       initialBytesToStrip = 2 (= the length of the Length field)

       BEFORE DECODE (14 bytes)         AFTER DECODE (12 bytes)
       +--------+----------------+      +----------------+
       | Length | Actual Content |----->| Actual Content |
       | 0x000C | "HELLO, WORLD" |      | "HELLO, WORLD" |
       +--------+----------------+      +----------------+

  ### 2 bytes length field at offset 0, do not strip header, the length field represents the length of the whole message

  In most cases, the length field represents the length of the message body only, as shown in the previous examples. However, in some protocols, the length field represents the length of the whole message, including the message header. In such a case, we specify a non-zero `lengthAdjustment`. Because the length value in this example message is always greater than the body length by `2`, we specify `-2` as `lengthAdjustment` for compensation.

       lengthFieldOffset   =  0
       lengthFieldLength   =  2
       lengthAdjustment    = -2 (= the length of the Length field)
       initialBytesToStrip =  0

       BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
       +--------+----------------+      +--------+----------------+
       | Length | Actual Content |----->| Length | Actual Content |
       | 0x000E | "HELLO, WORLD" |      | 0x000E | "HELLO, WORLD" |
       +--------+----------------+      +--------+----------------+

  ### 3 bytes length field at the end of 5 bytes header, do not strip header

  The following message is a simple variation of the first example. An extra header value is prepended to the message. `lengthAdjustment` is zero again because the decoder always takes the length of the prepended data into account during frame length calculation.

       lengthFieldOffset   = 2 (= the length of Header 1)
       lengthFieldLength   = 3
       lengthAdjustment    = 0
       initialBytesToStrip = 0

       BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
       +----------+----------+----------------+      +----------+----------+----------------+
       | Header 1 |  Length  | Actual Content |----->| Header 1 |  Length  | Actual Content |
       |  0xCAFE  | 0x00000C | "HELLO, WORLD" |      |  0xCAFE  | 0x00000C | "HELLO, WORLD" |
       +----------+----------+----------------+      +----------+----------+----------------+

  ### 3 bytes length field at the beginning of 5 bytes header, do not strip header

  This is an advanced example that shows the case where there is an extra header between the length field and the message body. You have to specify a positive `lengthAdjustment` so that the decoder counts the extra header into the frame length calculation.

       lengthFieldOffset   = 0
       lengthFieldLength   = 3
       lengthAdjustment    = 2 (= the length of Header 1)
       initialBytesToStrip = 0

       BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
       +----------+----------+----------------+      +----------+----------+----------------+
       |  Length  | Header 1 | Actual Content |----->|  Length  | Header 1 | Actual Content |
       | 0x00000C |  0xCAFE  | "HELLO, WORLD" |      | 0x00000C |  0xCAFE  | "HELLO, WORLD" |
       +----------+----------+----------------+      +----------+----------+----------------+

  ### 2 bytes length field at offset 1 in the middle of 4 bytes header, strip the first header field and the length field

  This is a combination of all the examples above. There are the prepended header before the length field and the extra header after the length field. The prepended header affects the `lengthFieldOffset` and the extra header affects the `lengthAdjustment`. We also specified a non-zero `initialBytesToStrip` to strip the length field and the prepended header from the frame. If you don't want to strip the prepended header, you could specify `0` for `initialBytesToSkip`.

       lengthFieldOffset   = 1 (= the length of HDR1)
       lengthFieldLength   = 2
       lengthAdjustment    = 1 (= the length of HDR2)
       initialBytesToStrip = 3 (= the length of HDR1 + LEN)

       BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
       +------+--------+------+----------------+      +------+----------------+
       | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
       | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
       +------+--------+------+----------------+      +------+----------------+

  ### 2 bytes length field at offset 1 in the middle of 4 bytes header, strip the first header field and the length field, the length field represents the length of the whole message

  Let's give another twist to the previous example. The only difference from the previous example is that the length field represents the length of the whole message instead of the message body, just like the third example. We have to count the length of HDR1 and Length into `lengthAdjustment`. Please note that we don't need to take the length of HDR2 into account because the length field already includes the whole header length.

       lengthFieldOffset   =  1
       lengthFieldLength   =  2
       lengthAdjustment    = -3 (= the length of HDR1 + LEN, negative)
       initialBytesToStrip =  3

       BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
       +------+--------+------+----------------+      +------+----------------+
       | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
       | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
       +------+--------+------+----------------+      +------+----------------+

  See Also:
    `LengthFieldPrepender`

- - ### Nested Class Summary

    - ### Nested classes/interfaces inherited from interface org.jboss.netty.channel.ChannelHandler

      `ChannelHandler.Sharable`

  - ### Field Summary

    - ### Fields inherited from class org.jboss.netty.handler.codec.frame.FrameDecoder

      `cumulation, DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `LengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength)` Creates a new instance.
    `LengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip)` Creates a new instance.
    `LengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast)` Creates a new instance.

  - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `protected Object` | `decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)` Decodes the received packets so far into a frame.
    `protected ChannelBuffer` | `extractFrame(ChannelBuffer buffer, int index, int length)` Extract the sub-region of the specified buffer.

    - ### Methods inherited from class org.jboss.netty.handler.codec.frame.FrameDecoder

      `actualReadableBytes, afterAdd, afterRemove, appendToCumulation, beforeAdd, beforeRemove, channelClosed, channelDisconnected, cleanup, decodeLast, exceptionCaught, getMaxCumulationBufferCapacity, getMaxCumulationBufferComponents, internalBuffer, isUnfold, messageReceived, newCumulationBuffer, replace, setMaxCumulationBufferCapacity, setMaxCumulationBufferComponents, setUnfold, unfoldAndFireMessageReceived, updateCumulation`

    - ### Methods inherited from class org.jboss.netty.channel.SimpleChannelUpstreamHandler

      `channelBound, channelConnected, channelInterestChanged, channelOpen, channelUnbound, childChannelClosed, childChannelOpen, handleUpstream, writeComplete`

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Constructor Detail

    - #### LengthFieldBasedFrameDecoder

          public LengthFieldBasedFrameDecoder(int maxFrameLength,
                                      int lengthFieldOffset,
                                      int lengthFieldLength)

      Creates a new instance.
      Parameters:
        `maxFrameLength` - the maximum length of the frame. If the length of the frame is greater than this value, `TooLongFrameException` will be thrown.
        `lengthFieldOffset` - the offset of the length field
        `lengthFieldLength` - the length of the length field

    - #### LengthFieldBasedFrameDecoder

          public LengthFieldBasedFrameDecoder(int maxFrameLength,
                                      int lengthFieldOffset,
                                      int lengthFieldLength,
                                      int lengthAdjustment,
                                      int initialBytesToStrip)

      Creates a new instance.
      Parameters:
        `maxFrameLength` - the maximum length of the frame. If the length of the frame is greater than this value, `TooLongFrameException` will be thrown.
        `lengthFieldOffset` - the offset of the length field
        `lengthFieldLength` - the length of the length field
        `lengthAdjustment` - the compensation value to add to the value of the length field
        `initialBytesToStrip` - the number of first bytes to strip out from the decoded frame

    - #### LengthFieldBasedFrameDecoder

          public LengthFieldBasedFrameDecoder(int maxFrameLength,
                                      int lengthFieldOffset,
                                      int lengthFieldLength,
                                      int lengthAdjustment,
                                      int initialBytesToStrip,
                                      boolean failFast)

      Creates a new instance.
      Parameters:
        `maxFrameLength` - the maximum length of the frame. If the length of the frame is greater than this value, `TooLongFrameException` will be thrown.
        `lengthFieldOffset` - the offset of the length field
        `lengthFieldLength` - the length of the length field
        `lengthAdjustment` - the compensation value to add to the value of the length field
        `initialBytesToStrip` - the number of first bytes to strip out from the decoded frame
        `failFast` - If `true`, a `TooLongFrameException` is thrown as soon as the decoder notices the length of the frame will exceed `maxFrameLength` regardless of whether the entire frame has been read. If `false`, a `TooLongFrameException` is thrown after the entire frame that exceeds `maxFrameLength` has been read.

  - ### Method Detail

    - #### decode

          protected Object decode(ChannelHandlerContext ctx,
                      Channel channel,
                      ChannelBuffer buffer)
                           throws Exception

      Description copied from class: `FrameDecoder`
      Decodes the received packets so far into a frame.
      Specified by:
        `decode` in class `FrameDecoder`
      Parameters:
        `ctx` - the context of this handler
        `channel` - the current channel
        `buffer` - the cumulative buffer of received packets so far. Note that the buffer might be empty, which means you should not make an assumption that the buffer contains at least one byte in your decoder implementation.
      Returns:
        the decoded frame if a full frame was received and decoded. `null` if there's not enough data in the buffer to decode a frame.
      Throws:
        `Exception`

    - #### extractFrame

          protected ChannelBuffer extractFrame(ChannelBuffer buffer,
                                   int index,
                                   int length)

      Extract the sub-region of the specified buffer. This method is called by `decode(ChannelHandlerContext, Channel, ChannelBuffer)` for each frame. The default implementation returns a copy of the sub-region. For example, you could override this method to use an alternative `ChannelBufferFactory`.

      If you are sure that the frame and its content are not accessed after the current `decode(ChannelHandlerContext, Channel, ChannelBuffer)` call returns, you can even avoid memory copy by returning the sliced sub-region (i.e. `return buffer.slice(index, length)`). It's often useful when you convert the extracted frame into an object. Refer to the source code of `ObjectDecoder` to see how this method is overridden to avoid memory copy.

Copyright © 2008-2012 The Netty Project. All Rights Reserved.