You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by el...@apache.org on 2008/09/11 16:36:17 UTC
svn commit: r694277 - in /mina/trunk:
core/src/main/java/org/apache/mina/filter/codec/
example/src/main/java/org/apache/mina/example/chat/client/
Author: elecharny
Date: Thu Sep 11 07:36:17 2008
New Revision: 694277
URL: http://svn.apache.org/viewvc?rev=694277&view=rev
Log:
o Added Javadoc and comments
o The encoder/decoder are now stored into the session, instead of being created on the fly.
o Added a sessionCreated() handler to create the encoder/decoder when the session is created
o Removed the useless getEncoder0() and getDecoder0() methods.
o Added defensive tests to avoid a NPE if the encoders/decoders are not present in the session
o The messageReceive() should loop until there are no more bytes to decode, instead of just getting out. Aded a TODO: check this part
o Modified the chat example to inject the codec filter before creating the session.
Modified:
mina/trunk/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
mina/trunk/example/src/main/java/org/apache/mina/example/chat/client/ChatClientSupport.java
mina/trunk/example/src/main/java/org/apache/mina/example/chat/client/SwingChatClientHandler.java
Modified: mina/trunk/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java?rev=694277&r1=694276&r2=694277&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java (original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java Thu Sep 11 07:36:17 2008
@@ -55,10 +55,19 @@
private final AttributeKey ENCODER = new AttributeKey(getClass(), "encoder");
private final AttributeKey DECODER = new AttributeKey(getClass(), "decoder");
private final AttributeKey DECODER_OUT = new AttributeKey(getClass(), "decoderOut");
+
+ /** The factory responsible for creating the encoder and decoder */
private final ProtocolCodecFactory factory;
private final Logger logger = LoggerFactory.getLogger(getClass());
+ /**
+ *
+ * Creates a new instance of ProtocolCodecFilter, associating a factory
+ * for the creation of the encoder and decoder.
+ *
+ * @param factory The associated factory
+ */
public ProtocolCodecFilter(ProtocolCodecFactory factory) {
if (factory == null) {
throw new NullPointerException("factory");
@@ -66,6 +75,15 @@
this.factory = factory;
}
+
+ /**
+ * Creates a new instance of ProtocolCodecFilter, without any factory.
+ * The encoder/decoder factory will be created as an inner class, using
+ * the two parameters (encoder and decoder).
+ *
+ * @param encoder The class responsible for encoding the message
+ * @param decoder The class responsible for decoding the message
+ */
public ProtocolCodecFilter(final ProtocolEncoder encoder,
final ProtocolDecoder decoder) {
if (encoder == null) {
@@ -75,6 +93,7 @@
throw new NullPointerException("decoder");
}
+ // Create the inner Factory based on the two parameters
this.factory = new ProtocolCodecFactory() {
public ProtocolEncoder getEncoder(IoSession session) {
return encoder;
@@ -86,6 +105,15 @@
};
}
+ /**
+ * Creates a new instance of ProtocolCodecFilter, without any factory.
+ * The encoder/decoder factory will be created as an inner class, using
+ * the two parameters (encoder and decoder), which are class names. Instances
+ * for those classes will be created in this constructor.
+ *
+ * @param encoder The class responsible for encoding the message
+ * @param decoder The class responsible for decoding the message
+ */
public ProtocolCodecFilter(
final Class<? extends ProtocolEncoder> encoderClass,
final Class<? extends ProtocolDecoder> decoderClass) {
@@ -116,6 +144,8 @@
"decoderClass doesn't have a public default constructor.");
}
+ // Create the inner Factory based on the two parameters. We instanciate
+ // the encoder and decoder locally.
this.factory = new ProtocolCodecFactory() {
public ProtocolEncoder getEncoder(IoSession session) throws Exception {
return encoderClass.newInstance();
@@ -127,10 +157,23 @@
};
}
+
+ /**
+ * Get the encoder instance from a given session.
+ *
+ * @param session The associated session we will get the encoder from
+ * @return The encoder instance, if any
+ */
public ProtocolEncoder getEncoder(IoSession session) {
return (ProtocolEncoder) session.getAttribute(ENCODER);
}
+ /**
+ * Get the decoder instance from a given session.
+ *
+ * @param session The associated session we will get the decoder from
+ * @return The decoder instance
+ */
public ProtocolDecoder getDecoder(IoSession session) {
return (ProtocolDecoder) session.getAttribute(DECODER);
}
@@ -147,11 +190,27 @@
@Override
public void onPostRemove(IoFilterChain parent, String name,
NextFilter nextFilter) throws Exception {
+ // We just remove the two instances of encoder/decoder to release resources
+ // from the session
disposeEncoder(parent.getSession());
disposeDecoder(parent.getSession());
+
+ // We also remove the callback
disposeDecoderOut(parent.getSession());
}
+ /**
+ * Process the incoming message, calling the session decoder. As the incoming
+ * buffer might contains more than one messages, we have to loop until the decoder
+ * throws an exception.
+ *
+ * while ( buffer not empty )
+ * try
+ * decode ( buffer )
+ * catch
+ * break;
+ *
+ */
@Override
public void messageReceived(NextFilter nextFilter, IoSession session,
Object message) throws Exception {
@@ -161,17 +220,52 @@
}
IoBuffer in = (IoBuffer) message;
- ProtocolDecoder decoder = getDecoder0(session);
+ ProtocolDecoder decoder = getDecoder(session);
+
+ if ( decoder == null) {
+ // The decoder must not be null. It's null if
+ // the sessionCreated message has not be called, for
+ // instance if the filter has been added after the
+ // first session is created.
+ ProtocolDecoderException pde = new ProtocolDecoderException(
+ "Cannot decode if the decoder is null. Add the filter in the chain" +
+ "before the first session is created" );
+ nextFilter.exceptionCaught(session, pde);
+ return;
+ }
+
ProtocolDecoderOutput decoderOut = getDecoderOut(session, nextFilter);
+
+ if ( decoderOut == null) {
+ // The decoderOut must not be null. It's null if
+ // the sessionCreated message has not be called, for
+ // instance if the filter has been added after the
+ // first session is created.
+ ProtocolDecoderException pde = new ProtocolDecoderException(
+ "Cannot decode if the decoder is null. Add the filter in the chain" +
+ "before the first session is created" );
+ nextFilter.exceptionCaught(session, pde);
+ return;
+ }
+
+ // Loop until we don't have anymore byte in the buffer,
+ // or until the decoder throws an unrecoverable exception or
+ // can't decoder a message, because there are not enough
+ // data in the buffer
while (in.hasRemaining()) {
int oldPos = in.position();
try {
synchronized (decoderOut) {
+ // Call the decoder with the read bytes
decoder.decode(session, in, decoderOut);
}
// Finish decoding if no exception was thrown.
decoderOut.flush();
+
+ // TODO :
+ // here, we shouldn't break,
+ // we should loop to decode the next portion of the buffer.
break;
} catch (Throwable t) {
ProtocolDecoderException pde;
@@ -182,6 +276,7 @@
}
if (pde.getHexdump() == null) {
+ // Generate a message hex dump
int curPos = in.position();
in.position(oldPos);
pde.setHexdump(in.getHexDump());
@@ -197,7 +292,7 @@
// We check buffer position additionally to prevent an
// infinite loop.
if (!(t instanceof RecoverableProtocolDecoderException) ||
- in.position() == oldPos) {
+ (in.position() == oldPos)) {
break;
}
}
@@ -224,37 +319,125 @@
public void filterWrite(NextFilter nextFilter, IoSession session,
WriteRequest writeRequest) throws Exception {
Object message = writeRequest.getMessage();
+
+ // Bypass the encoding if the message is contained in a ByteBuffer,
+ // as it has already been encoded before
if (message instanceof IoBuffer || message instanceof FileRegion) {
nextFilter.filterWrite(session, writeRequest);
return;
}
- ProtocolEncoder encoder = getEncoder0(session);
+ // Get the encoder in the session
+ ProtocolEncoder encoder = getEncoder(session);
+
+ if ( encoder == null) {
+ // The encoder must not be null. It's null if
+ // the sessionCreated message has not be called, for
+ // instance if the filter has been added after the
+ // first session is created.
+ ProtocolDecoderException pde = new ProtocolDecoderException(
+ "Cannot encode if the encoder is null. Add the filter in the chain" +
+ "before the first session is created" );
+ nextFilter.exceptionCaught(session, pde);
+ return;
+ }
+
ProtocolEncoderOutputImpl encoderOut = getEncoderOut(session,
nextFilter, writeRequest);
+ if ( encoderOut == null) {
+ // The encoder must not be null. It's null if
+ // the sessionCreated message has not be called, for
+ // instance if the filter has been added after the
+ // first session is created.
+ ProtocolDecoderException pde = new ProtocolDecoderException(
+ "Cannot encode if the encoder is null. Add the filter in the chain" +
+ "before the first session is created" );
+ nextFilter.exceptionCaught(session, pde);
+ return;
+ }
+
try {
+ // Now we can try to encode the response
encoder.encode(session, message, encoderOut);
+
+ // Send it directly
encoderOut.flushWithoutFuture();
+
+ // Call the next filter
nextFilter.filterWrite(session, new MessageWriteRequest(
writeRequest));
} catch (Throwable t) {
ProtocolEncoderException pee;
+
+ // Generate the correct exception
if (t instanceof ProtocolEncoderException) {
pee = (ProtocolEncoderException) t;
} else {
pee = new ProtocolEncoderException(t);
}
+
throw pee;
}
}
+
+ /**
+ * Associate a decoder and encoder instances to the newly created session.
+ * <br>
+ * <br>
+ * In order to get the encoder and decoder crea
+ *
+ * @param nextFilter The next filter to invoke when having processed the current
+ * method
+ * @param session The newly created session
+ * @throws Exception if we can't create instances of the decoder or encoder
+ */
+ @Override
+ public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
+ // Creates the decoder and stores it into the newly created session
+ ProtocolDecoder decoder = factory.getDecoder(session);
+ session.setAttribute(DECODER, decoder);
+
+ // Creates the encoder and stores it into the newly created session
+ ProtocolEncoder encoder = factory.getEncoder(session);
+ session.setAttribute(ENCODER, encoder);
+
+ // Call the next filter
+ nextFilter.sessionCreated(session);
+ }
@Override
public void sessionClosed(NextFilter nextFilter, IoSession session)
throws Exception {
// Call finishDecode() first when a connection is closed.
- ProtocolDecoder decoder = getDecoder0(session);
+ ProtocolDecoder decoder = getDecoder(session);
+
+ if ( decoder == null) {
+ // The decoder must not be null. It's null if
+ // the sessionCreated message has not be called, for
+ // instance if the filter has been added after the
+ // first session is created.
+ ProtocolDecoderException pde = new ProtocolDecoderException(
+ "Cannot decode if the decoder is null. Add the filter in the chain" +
+ "before the first session is created" );
+ nextFilter.exceptionCaught(session, pde);
+ return;
+ }
+
ProtocolDecoderOutput decoderOut = getDecoderOut(session, nextFilter);
+
+ if ( decoderOut == null) {
+ // The decoder must not be null. It's null if
+ // the sessionCreated message has not be called, for
+ // instance if the filter has been added after the
+ // first session is created.
+ ProtocolDecoderException pde = new ProtocolDecoderException(
+ "Cannot decode if the decoder is null. Add the filter in the chain" +
+ "before the first session is created" );
+ nextFilter.exceptionCaught(session, pde);
+ return;
+ }
+
try {
decoder.finishDecode(session, decoderOut);
} catch (Throwable t) {
@@ -276,31 +459,11 @@
nextFilter.sessionClosed(session);
}
- private ProtocolEncoder getEncoder0(IoSession session) throws Exception {
- ProtocolEncoder encoder = (ProtocolEncoder) session
- .getAttribute(ENCODER);
- if (encoder == null) {
- encoder = factory.getEncoder(session);
- session.setAttribute(ENCODER, encoder);
- }
- return encoder;
- }
-
private ProtocolEncoderOutputImpl getEncoderOut(IoSession session,
NextFilter nextFilter, WriteRequest writeRequest) {
return new ProtocolEncoderOutputImpl(session, nextFilter, writeRequest);
}
- private ProtocolDecoder getDecoder0(IoSession session) throws Exception {
- ProtocolDecoder decoder = (ProtocolDecoder) session
- .getAttribute(DECODER);
- if (decoder == null) {
- decoder = factory.getDecoder(session);
- session.setAttribute(DECODER, decoder);
- }
- return decoder;
- }
-
private ProtocolDecoderOutput getDecoderOut(IoSession session,
NextFilter nextFilter) {
ProtocolDecoderOutput out = (ProtocolDecoderOutput) session.getAttribute(DECODER_OUT);
Modified: mina/trunk/example/src/main/java/org/apache/mina/example/chat/client/ChatClientSupport.java
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/java/org/apache/mina/example/chat/client/ChatClientSupport.java?rev=694277&r1=694276&r2=694277&view=diff
==============================================================================
--- mina/trunk/example/src/main/java/org/apache/mina/example/chat/client/ChatClientSupport.java (original)
+++ mina/trunk/example/src/main/java/org/apache/mina/example/chat/client/ChatClientSupport.java Thu Sep 11 07:36:17 2008
@@ -23,11 +23,15 @@
import javax.net.ssl.SSLContext;
+import org.apache.mina.core.filterchain.IoFilter;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory;
import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
+import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
+import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.filter.logging.MdcInjectionFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
@@ -60,7 +64,14 @@
}
try {
+ IoFilter LOGGING_FILTER = new LoggingFilter();
+
+ IoFilter CODEC_FILTER = new ProtocolCodecFilter(
+ new TextLineCodecFactory());
+
connector.getFilterChain().addLast("mdc", new MdcInjectionFilter());
+ connector.getFilterChain().addLast("codec", CODEC_FILTER);
+ connector.getFilterChain().addLast("logger", LOGGING_FILTER);
if (useSsl) {
SSLContext sslContext = BogusSslContextFactory
Modified: mina/trunk/example/src/main/java/org/apache/mina/example/chat/client/SwingChatClientHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/example/src/main/java/org/apache/mina/example/chat/client/SwingChatClientHandler.java?rev=694277&r1=694276&r2=694277&view=diff
==============================================================================
--- mina/trunk/example/src/main/java/org/apache/mina/example/chat/client/SwingChatClientHandler.java (original)
+++ mina/trunk/example/src/main/java/org/apache/mina/example/chat/client/SwingChatClientHandler.java Thu Sep 11 07:36:17 2008
@@ -19,14 +19,10 @@
*/
package org.apache.mina.example.chat.client;
-import org.apache.mina.core.filterchain.IoFilter;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.example.chat.ChatCommand;
-import org.apache.mina.filter.codec.ProtocolCodecFilter;
-import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
-import org.apache.mina.filter.logging.LoggingFilter;
/**
* {@link IoHandler} implementation of the client side of the simple chat protocol.
@@ -50,11 +46,6 @@
void error(String message);
}
- private static final IoFilter LOGGING_FILTER = new LoggingFilter();
-
- private static final IoFilter CODEC_FILTER = new ProtocolCodecFilter(
- new TextLineCodecFactory());
-
private final Callback callback;
public SwingChatClientHandler(Callback callback) {
@@ -62,12 +53,6 @@
}
@Override
- public void sessionCreated(IoSession session) throws Exception {
- session.getFilterChain().addLast("codec", CODEC_FILTER);
- session.getFilterChain().addLast("logger", LOGGING_FILTER);
- }
-
- @Override
public void sessionOpened(IoSession session) throws Exception {
callback.connected();
}