Class FrameDecoder
- java.lang.Object
-
- org.jboss.netty.channel.SimpleChannelUpstreamHandler
-
- org.jboss.netty.handler.codec.frame.FrameDecoder
-
- All Implemented Interfaces:
ChannelHandler,ChannelUpstreamHandler,LifeCycleAwareChannelHandler
- Direct Known Subclasses:
BigIntegerDecoder,DelimiterBasedFrameDecoder,FixedLengthFrameDecoder,LengthFieldBasedFrameDecoder,LineBasedFrameDecoder,PortUnificationServerHandler,ProtobufVarint32FrameDecoder,ReplayingDecoder,SpdyFrameCodec,SslHandler
public abstract class FrameDecoder extends SimpleChannelUpstreamHandler implements LifeCycleAwareChannelHandler
Decodes the receivedChannelBuffers 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 | +----+-------+---+---+
FrameDecoderhelps 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, yourFrameDecoderimplementation 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 extendsFrameDecoder{@Overrideprotected Object decode(ChannelHandlerContextctx,channel,ChannelBufferbuf) 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.ChannelBufferframe = buf.readBytes(length); // Successfully decoded a frame. Return the decoded frame. return frame; } }Returning a POJO rather than a
ChannelBufferPlease note that you can return an object of a different type than
ChannelBufferin yourdecode()anddecodeLast()implementation. For example, you could return a POJO so that the nextChannelUpstreamHandlerreceives aMessageEventwhich contains a POJO rather than aChannelBuffer.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 anotherFrameDecoderorReplayingDecoder(actual protocol decoder). It is not possible to achieve this simply by callingChannelPipeline.replace(ChannelHandler, String, ChannelHandler), but some additional steps are required:public class FirstDecoder extends
FrameDecoder{ public FirstDecoder() { super(true); // Enable unfold }@Overrideprotected Object decode(ChannelHandlerContextctx,Channelchannel,ChannelBufferbuf) { ... // 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; } } }
-
-
Nested Class Summary
-
Nested classes/interfaces inherited from interface org.jboss.netty.channel.ChannelHandler
ChannelHandler.Sharable
-
-
Field Summary
Fields Modifier and Type Field Description private intcopyThresholdprivate ChannelHandlerContextctxprotected ChannelBuffercumulationstatic intDEFAULT_MAX_COMPOSITEBUFFER_COMPONENTSprivate intmaxCumulationBufferComponentsprivate booleanunfold
-
Constructor Summary
Constructors Modifier Constructor Description protectedFrameDecoder()protectedFrameDecoder(boolean unfold)
-
Method Summary
All Methods Instance Methods Abstract Methods Concrete Methods Modifier and Type Method Description protected intactualReadableBytes()Returns the actual number of readable bytes in the internal cumulative buffer of this decoder.voidafterAdd(ChannelHandlerContext ctx)voidafterRemove(ChannelHandlerContext ctx)protected ChannelBufferappendToCumulation(ChannelBuffer input)voidbeforeAdd(ChannelHandlerContext ctx)voidbeforeRemove(ChannelHandlerContext ctx)private voidcallDecode(ChannelHandlerContext context, Channel channel, ChannelBuffer cumulation, java.net.SocketAddress remoteAddress)voidchannelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)Invoked when aChannelwas closed and all its related resources were released.voidchannelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e)Invoked when aChannelwas disconnected from its remote peer.protected voidcleanup(ChannelHandlerContext ctx, ChannelStateEvent e)protected abstract java.lang.Objectdecode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)Decodes the received packets so far into a frame.protected java.lang.ObjectdecodeLast(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)Decodes the received data so far into a frame when the channel is disconnected.voidexceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)Invoked when an exception was raised by an I/O thread or aChannelHandler.protected ChannelBufferextractFrame(ChannelBuffer buffer, int index, int length)Extract a Frame of the specified buffer.intgetMaxCumulationBufferCapacity()SeesetMaxCumulationBufferCapacity(int)for explaintation of this settingintgetMaxCumulationBufferComponents()Returns the maximum number of components in the cumulation buffer.protected ChannelBufferinternalBuffer()Returns the internal cumulative buffer of this decoder.booleanisUnfold()voidmessageReceived(ChannelHandlerContext ctx, MessageEvent e)Invoked when a message object (e.g:ChannelBuffer) was received from a remote peer.protected ChannelBuffernewCumulationBuffer(ChannelHandlerContext ctx, int minimumCapacity)Create a newChannelBufferwhich is used for the cumulation.voidreplace(java.lang.String handlerName, ChannelHandler handler)voidsetMaxCumulationBufferCapacity(int copyThreshold)Set the maximal capacity of the internal cumulation ChannelBuffer to use before theFrameDecodertries to minimize the memory usage by "byte copy".voidsetMaxCumulationBufferComponents(int maxCumulationBufferComponents)Sets the maximum number of components in the cumulation buffer.voidsetUnfold(boolean unfold)protected voidunfoldAndFireMessageReceived(ChannelHandlerContext context, java.net.SocketAddress remoteAddress, java.lang.Object result)protected ChannelBufferupdateCumulation(ChannelHandlerContext ctx, ChannelBuffer input)-
Methods inherited from class org.jboss.netty.channel.SimpleChannelUpstreamHandler
channelBound, channelConnected, channelInterestChanged, channelOpen, channelUnbound, childChannelClosed, childChannelOpen, handleUpstream, writeComplete
-
-
-
-
Field Detail
-
DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS
public static final int DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS
- See Also:
- Constant Field Values
-
unfold
private boolean unfold
-
cumulation
protected ChannelBuffer cumulation
-
ctx
private volatile ChannelHandlerContext ctx
-
copyThreshold
private int copyThreshold
-
maxCumulationBufferComponents
private int maxCumulationBufferComponents
-
-
Method Detail
-
isUnfold
public final boolean isUnfold()
-
setUnfold
public final void setUnfold(boolean unfold)
-
getMaxCumulationBufferCapacity
public final int getMaxCumulationBufferCapacity()
SeesetMaxCumulationBufferCapacity(int)for explaintation of this setting
-
setMaxCumulationBufferCapacity
public final void setMaxCumulationBufferCapacity(int copyThreshold)
Set the maximal capacity of the internal cumulation ChannelBuffer to use before theFrameDecodertries to minimize the memory usage by "byte copy". What you use here really depends on your application and need. UsingInteger.MAX_VALUEwill disable all byte copies but give you the cost of a higher memory usage if bigChannelBuffer's will be received. By default a threshold of0is used, which means it will always copy to try to reduce memory usage- Parameters:
copyThreshold- the threshold (in bytes) orInteger.MAX_VALUEto disable it. The value must be at least 0- Throws:
java.lang.IllegalStateException- get thrown if someone tries to change this setting after the Decoder was added to theChannelPipeline
-
getMaxCumulationBufferComponents
public final int getMaxCumulationBufferComponents()
Returns the maximum number of components in the cumulation buffer. If the number of the components in the cumulation buffer exceeds this value, the components of the cumulation buffer are consolidated into a single component, involving memory copies. The default value of this propertyDEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS.
-
setMaxCumulationBufferComponents
public final void setMaxCumulationBufferComponents(int maxCumulationBufferComponents)
Sets the maximum number of components in the cumulation buffer. If the number of the components in the cumulation buffer exceeds this value, the components of the cumulation buffer are consolidated into a single component, involving memory copies. The default value of this property isDEFAULT_MAX_COMPOSITEBUFFER_COMPONENTSand its minimum allowed value is2.
-
messageReceived
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws java.lang.Exception
Description copied from class:SimpleChannelUpstreamHandlerInvoked when a message object (e.g:ChannelBuffer) was received from a remote peer.- Overrides:
messageReceivedin classSimpleChannelUpstreamHandler- Throws:
java.lang.Exception
-
appendToCumulation
protected ChannelBuffer appendToCumulation(ChannelBuffer input)
-
updateCumulation
protected ChannelBuffer updateCumulation(ChannelHandlerContext ctx, ChannelBuffer input)
-
channelDisconnected
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws java.lang.Exception
Description copied from class:SimpleChannelUpstreamHandlerInvoked when aChannelwas disconnected from its remote peer.- Overrides:
channelDisconnectedin classSimpleChannelUpstreamHandler- Throws:
java.lang.Exception
-
channelClosed
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws java.lang.Exception
Description copied from class:SimpleChannelUpstreamHandlerInvoked when aChannelwas closed and all its related resources were released.- Overrides:
channelClosedin classSimpleChannelUpstreamHandler- Throws:
java.lang.Exception
-
exceptionCaught
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws java.lang.Exception
Description copied from class:SimpleChannelUpstreamHandlerInvoked when an exception was raised by an I/O thread or aChannelHandler.- Overrides:
exceptionCaughtin classSimpleChannelUpstreamHandler- Throws:
java.lang.Exception
-
decode
protected abstract java.lang.Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws java.lang.Exception
Decodes the received packets so far into a frame. If an sub-class wants to extract a frame out of the buffer it should use theextractFrame(ChannelBuffer, int, int)method, to make optimizations easier later.- Parameters:
ctx- the context of this handlerchannel- the current channelbuffer- 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.
nullif there's not enough data in the buffer to decode a frame. - Throws:
java.lang.Exception
-
decodeLast
protected java.lang.Object decodeLast(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws java.lang.Exception
Decodes the received data so far into a frame when the channel is disconnected.- Parameters:
ctx- the context of this handlerchannel- the current channelbuffer- 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.
nullif there's not enough data in the buffer to decode a frame. - Throws:
java.lang.Exception
-
callDecode
private void callDecode(ChannelHandlerContext context, Channel channel, ChannelBuffer cumulation, java.net.SocketAddress remoteAddress) throws java.lang.Exception
- Throws:
java.lang.Exception
-
unfoldAndFireMessageReceived
protected final void unfoldAndFireMessageReceived(ChannelHandlerContext context, java.net.SocketAddress remoteAddress, java.lang.Object result)
-
cleanup
protected void cleanup(ChannelHandlerContext ctx, ChannelStateEvent e) throws java.lang.Exception
Gets called onchannelDisconnected(ChannelHandlerContext, ChannelStateEvent)andchannelClosed(ChannelHandlerContext, ChannelStateEvent)- Throws:
java.lang.Exception
-
newCumulationBuffer
protected ChannelBuffer newCumulationBuffer(ChannelHandlerContext ctx, int minimumCapacity)
Create a newChannelBufferwhich is used for the cumulation. Sub-classes may override this.- Parameters:
ctx-ChannelHandlerContextfor this handler- Returns:
- buffer the
ChannelBufferwhich is used for cumulation
-
replace
public void replace(java.lang.String handlerName, ChannelHandler handler)Replace thisFrameDecoderin theChannelPipelinewith the givenChannelHandler. All remaining bytes in theChannelBufferwill get send to the newChannelHandlerthat was used as replacement
-
actualReadableBytes
protected int actualReadableBytes()
Returns the actual number of readable bytes in the internal cumulative buffer of this decoder. You usually do not need to rely on this value to write a decoder. Use it only when you muse use it at your own risk. This method is a shortcut tointernalBuffer().readableBytes().
-
internalBuffer
protected ChannelBuffer internalBuffer()
Returns the internal cumulative buffer of this decoder. You usually do not need to access the internal buffer directly to write a decoder. Use it only when you must use it at your own risk.
-
extractFrame
protected ChannelBuffer extractFrame(ChannelBuffer buffer, int index, int length)
Extract a Frame of the specified buffer. By default this implementation will return a extract the sub-region of the buffer and create a new one. If an sub-class want to extract a frame from the buffer it should use this method by default. Be sure that this method MUST not modify the readerIndex of the given buffer
-
beforeAdd
public void beforeAdd(ChannelHandlerContext ctx) throws java.lang.Exception
- Specified by:
beforeAddin interfaceLifeCycleAwareChannelHandler- Throws:
java.lang.Exception
-
afterAdd
public void afterAdd(ChannelHandlerContext ctx) throws java.lang.Exception
- Specified by:
afterAddin interfaceLifeCycleAwareChannelHandler- Throws:
java.lang.Exception
-
beforeRemove
public void beforeRemove(ChannelHandlerContext ctx) throws java.lang.Exception
- Specified by:
beforeRemovein interfaceLifeCycleAwareChannelHandler- Throws:
java.lang.Exception
-
afterRemove
public void afterRemove(ChannelHandlerContext ctx) throws java.lang.Exception
- Specified by:
afterRemovein interfaceLifeCycleAwareChannelHandler- Throws:
java.lang.Exception
-
-