org.jboss.netty.handler.codec.frame
Class FrameDecoder

java.lang.Object
  extended by org.jboss.netty.channel.SimpleChannelUpstreamHandler
      extended by org.jboss.netty.handler.codec.frame.FrameDecoder
All Implemented Interfaces:
ChannelHandler, ChannelUpstreamHandler
Direct Known Subclasses:
DelimiterBasedFrameDecoder, FixedLengthFrameDecoder, LengthFieldBasedFrameDecoder, ProtobufVarint32FrameDecoder, SslHandler

public abstract class FrameDecoder
extends SimpleChannelUpstreamHandler

Decodes the received ChannelBuffers 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 us 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 |
 +----+-------+---+---+
 

FrameDecoder helps you defrag 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 FrameDecoder implementation could defrag the received packets like the following:

 +-----+-----+-----+
 | ABC | DEF | GHI |
 +-----+-----+-----+
 

The following code shows an example handler 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 {

   @Override
   protected Object decode(ChannelHandlerContext ctx,
                           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.
     return frame;
   }
 }
 

Returning a POJO rather than a ChannelBuffer

Please note that you can return an object of a different type than ChannelBuffer in your decode() and decodeLast() implementation. For example, you could return a POJO so that the next ChannelUpstreamHandler receives a MessageEvent which contains a POJO rather than a ChannelBuffer.

Replacing a decoder with another decoder in a pipeline

If you are going to write a protocol multiplexer, you will probably want to replace a FrameDecoder (protocol detector) with another FrameDecoder or ReplayingDecoder (actual protocol decoder). It is not possible to achieve this simply by calling ChannelPipeline.replace(ChannelHandler, String, ChannelHandler), but some additional steps are required:

 public class FirstDecoder extends FrameDecoder {

     public FirstDecoder() {
         super(true); // Enable unfold
     }

     @Override
     protected Object decode(ChannelHandlerContext ctx,
                             Channel channel,
                             ChannelBuffer buf) {
         ...
         // Decode the first message
         Object firstMessage = ...;

         // Add the second decoder
         ctx.getPipeline().addLast("second", new SecondDecoder());

         // Remove the first decoder (me)
         ctx.getPipeline().remove(this);

         if (buf.readable()) {
             // Hand off the remaining data to the second decoder
             return new Object[] { firstMessage, buf.readBytes(buf.readableBytes()) };
         } else {
             // Nothing to hand off
             return firstMessage;
         }
     }
 }
 

Version:
$Rev:231 $, $Date:2008-06-12 16:44:50 +0900 (목, 12 6월 2008) $
Author:
The Netty Project, Trustin Lee

Nested Class Summary
 
Nested classes/interfaces inherited from interface org.jboss.netty.channel.ChannelHandler
ChannelHandler.Sharable
 
Constructor Summary
protected FrameDecoder()
           
protected FrameDecoder(boolean unfold)
           
 
Method Summary
 void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
          Invoked when a Channel was closed and all its related resources were released.
 void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e)
          Invoked when a Channel was disconnected from its remote peer.
protected abstract  Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)
          Decodes the received packets so far into a frame.
protected  Object decodeLast(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)
          Decodes the received data so far into a frame when the channel is disconnected.
 void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
          Invoked when an exception was raised by an I/O thread or a ChannelHandler.
 void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
          Invoked when a message object (e.g: ChannelBuffer) was received from a remote peer.
 
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

FrameDecoder

protected FrameDecoder()

FrameDecoder

protected FrameDecoder(boolean unfold)
Method Detail

messageReceived

public void messageReceived(ChannelHandlerContext ctx,
                            MessageEvent e)
                     throws Exception
Description copied from class: SimpleChannelUpstreamHandler
Invoked when a message object (e.g: ChannelBuffer) was received from a remote peer.

Overrides:
messageReceived in class SimpleChannelUpstreamHandler
Throws:
Exception

channelDisconnected

public void channelDisconnected(ChannelHandlerContext ctx,
                                ChannelStateEvent e)
                         throws Exception
Description copied from class: SimpleChannelUpstreamHandler
Invoked when a Channel was disconnected from its remote peer.

Overrides:
channelDisconnected in class SimpleChannelUpstreamHandler
Throws:
Exception

channelClosed

public void channelClosed(ChannelHandlerContext ctx,
                          ChannelStateEvent e)
                   throws Exception
Description copied from class: SimpleChannelUpstreamHandler
Invoked when a Channel was closed and all its related resources were released.

Overrides:
channelClosed in class SimpleChannelUpstreamHandler
Throws:
Exception

exceptionCaught

public void exceptionCaught(ChannelHandlerContext ctx,
                            ExceptionEvent e)
                     throws Exception
Description copied from class: SimpleChannelUpstreamHandler
Invoked when an exception was raised by an I/O thread or a ChannelHandler.

Overrides:
exceptionCaught in class SimpleChannelUpstreamHandler
Throws:
Exception

decode

protected abstract Object decode(ChannelHandlerContext ctx,
                                 Channel channel,
                                 ChannelBuffer buffer)
                          throws Exception
Decodes the received packets so far into a frame.

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

decodeLast

protected Object decodeLast(ChannelHandlerContext ctx,
                            Channel channel,
                            ChannelBuffer buffer)
                     throws Exception
Decodes the received data so far into a frame when the channel is disconnected.

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


Copyright © 2008-2011 JBoss, a division of Red Hat, Inc.. All Rights Reserved.