|
Page Edited :
MINA :
ProtocolCodec discussion
ProtocolCodec discussion has been edited by Emmanuel Lécharny (Nov 11, 2008). Change summary: Added comments on messageReceived event IntroductionThis filter is one of the most important one. In many case, writing a MINA based application without having such a filter added is not really meaningful. Events handledHere is a list of all the handled events in this filter :
DescriptionConstructorIn order to be able to encode or decode a message, we need to pass the filter a factory, which will be used to create those two parts of the codec :
The factory is pretty simple. It offers two methods : public interface ProtocolCodecFactory { /** * Returns a new (or reusable) instance of [EMAIL PROTECTED] ProtocolEncoder} which * encodes message objects into binary or protocol-specific data. */ ProtocolEncoder getEncoder(IoSession session) throws Exception;
/**
* Returns a new (or reusable) instance of [EMAIL PROTECTED] ProtocolDecoder} which
* decodes binary or protocol-specific data into message objects.
*/
ProtocolDecoder getDecoder(IoSession session) throws Exception;
}
It's also possible to pass the encoder and decoder directly, as a factory will be created internally to encapsulate those two methods. SessionCreated eventThe current handling for this event is pretty simple : it stores the Encoder and Decoder instances in the session attributes. public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception { // Creates the decoder and stores it into the newly created session session.setAttribute(DECODER, factory.getDecoder(session)); // Creates the encoder and stores it into the newly created session session.setAttribute(ENCODER, factory.getEncoder(session)); // Call the next filter nextFilter.sessionCreated(session); }
SessionClosed eventThis event is received when the session is closed. We have to remove the Encoder and Decoder instances from the session's attributes, and to dispose those elements. As we may have remaining messages to decode, we have to process them first. We have different cases, as of MINA 2.0.0-M3 :
OnPreAddThis event is received when we try to insert this filter during a session. What it does is very simple : - Checks that the filter is not already present in the chain. If so, generates an exception Nothing much to tell about this simple handler OnPostRemoveThis event is received when this filter is removed from the chain. We simply :
Nothing much to tell about this simple handler MessageReceived eventThis is the heart of the decoding part. We receive some bytes, and we must produce some messages out of it. Again, we have many cases to consider :
We also have a special case : we received an object which is not a byte buffer.
Generally speaking, the way the decoder works is exposed in the following pseudo-code : process messageReceived :
while we have bytes in the incoming buffer
do
call the decoder(callback)
flush the accumulated decoded messages the decoder has stored in a queue
done
decode(callback) :
while we have more bytes
do
decode a message from the bytes
push it into the callback queue
done
flush :
while we have messages in the queue
do
get the first message from the queue
call next filter.messageReceived( message )
done
Let's now analyze those 6 cases. 1) The incoming buffer is emptyWe just do nothing in this case. We don't even have to call the next filter.
2) We received a byte buffer which is not enough to generate a messageIn this case - as in the other case when we have remaining bytes - everything will depend on the capacity the decoder has to keep a transitioanl state until we can decode the message with some more bytes. The decoder has to be stateful, which all the decoder aren't. In many cases, we must rely on a cumulative decoder, which will gather bytes up to a boundary (like a \n, for instance). The decoding process will be done in two steps :
This is not that easy, considering that many protocol do not define a clear boundary, or make it complicated to find it. For instance :
We may need to have a stateful decoder to avoid such problems, but we won't discuss this aspect here. So what we do is to call the decoder, and if we didn't got an exception, we just call the callback which will do nothing. 3) We received a byte buffer containing exactly one messageThis is an easy case : we simply have to decode the message, and send it to the next filter, before returning. 4) We received a byte buffer containing one message plus some remaining bytesWe have to loop after having processed the first message. We will generate an exception if the decoder can't handle partial messages, or isntead stores the remaining bytes in a context associated with the session, waiting for more bytes to come. 5) We received a byte buffer containing more than one message exactlyThis is the exact same case as (3), but we will loop for each message, sending them one by one to the next filter. 6) We received a byte buffer containing more than one message plus some extra bytesWe loop on each messages, as in (5), and fallback to case (2) |
Unsubscribe or edit your notifications preferences
