You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by jv...@apache.org on 2013/03/26 13:26:45 UTC
git commit: new try for a codec API
Updated Branches:
refs/heads/trunk cb7896a19 -> 1a4ad866e
new try for a codec API
Project: http://git-wip-us.apache.org/repos/asf/mina/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina/commit/1a4ad866
Tree: http://git-wip-us.apache.org/repos/asf/mina/tree/1a4ad866
Diff: http://git-wip-us.apache.org/repos/asf/mina/diff/1a4ad866
Branch: refs/heads/trunk
Commit: 1a4ad866eb25e509a8eb4b5d52e4660152cc5ded
Parents: cb7896a
Author: jvermillard <jv...@apache.org>
Authored: Tue Mar 26 13:26:04 2013 +0100
Committer: jvermillard <jv...@apache.org>
Committed: Tue Mar 26 13:26:04 2013 +0100
----------------------------------------------------------------------
.../org/apache/mina/codec/ProtocolDecoder.java | 23 ++-
.../org/apache/mina/codec/ProtocolEncoder.java | 20 ++-
.../mina/codec/StatelessProtocolDecoder.java | 34 +++
.../mina/codec/StatelessProtocolEncoder.java | 35 +++
.../mina/filter/codec/ProtocolCodecFactory.java | 49 ----
.../mina/filter/codec/ProtocolCodecFilter.java | 170 +++------------
.../mina/filter/codec/ProtocolCodecFilterTest.java | 82 -------
.../org/apache/mina/examples/http/HttpTest.java | 6 +-
.../org/apache/mina/examples/http/HttpsTest.java | 6 +-
.../org/apache/mina/http/HttpDecoderState.java | 64 ++++++
.../org/apache/mina/http/HttpServerDecoder.java | 48 +++--
.../org/apache/mina/http/HttpServerEncoder.java | 15 +-
.../apache/mina/http/HttpServerDecoderTest.java | 30 ++-
13 files changed, 269 insertions(+), 313 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/codec/src/main/java/org/apache/mina/codec/ProtocolDecoder.java
----------------------------------------------------------------------
diff --git a/codec/src/main/java/org/apache/mina/codec/ProtocolDecoder.java b/codec/src/main/java/org/apache/mina/codec/ProtocolDecoder.java
index 8c4ffdd..c1dea93 100644
--- a/codec/src/main/java/org/apache/mina/codec/ProtocolDecoder.java
+++ b/codec/src/main/java/org/apache/mina/codec/ProtocolDecoder.java
@@ -19,29 +19,44 @@
*/
package org.apache.mina.codec;
+import java.nio.ByteBuffer;
+
/**
* Decodes binary or protocol-specific data into higher-level message objects.
*
- * Should be state-full, and have one instance per new session.
+ * Must be immutable, a CONTEXT will be provided per session.
+ *
+ * @param <INPUT> the incoming message to decode (the low level message, usually a {@link ByteBuffer})
+ * @param <OUTPUT> the decoded message (your high level protocol Pojo/DTO)
+ * @param <DECODING_STATE> the context where to save the current decoding state (e.g. accumulated bytes, encoding
+ * context switching..)
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*
*/
-public interface ProtocolDecoder<INPUT, OUTPUT> {
+public interface ProtocolDecoder<INPUT, OUTPUT, DECODING_STATE> {
+
+ /**
+ * Create a new session context for this decoder
+ *
+ * @return the newly created context
+ */
+ DECODING_STATE createDecoderState();
/**
* Decode binary or protocol-specific content of type <code>INPUT</code> into higher-level protocol message objects,
* of type OUTPUT
*
* @param input the received message to decode
+ * @param context the decoding context (will be stored in the session for the next decode call)
* @return the decoded messages or <code>null</code> if nothing was decoded
* @throws ProtocolDecoderException if something wrong happen during decoding (e.g. : a malformed input message)
*/
- OUTPUT[] decode(INPUT input) throws ProtocolDecoderException;
+ OUTPUT[] decode(INPUT input, DECODING_STATE context) throws ProtocolDecoderException;
/**
* Finish decoding, for example if the decoder accumulated some unused input, it should discard it, or throw an
* Exception
*/
- void finishDecode();
+ void finishDecode(DECODING_STATE context);
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/codec/src/main/java/org/apache/mina/codec/ProtocolEncoder.java
----------------------------------------------------------------------
diff --git a/codec/src/main/java/org/apache/mina/codec/ProtocolEncoder.java b/codec/src/main/java/org/apache/mina/codec/ProtocolEncoder.java
index f439f51..de48ed9 100644
--- a/codec/src/main/java/org/apache/mina/codec/ProtocolEncoder.java
+++ b/codec/src/main/java/org/apache/mina/codec/ProtocolEncoder.java
@@ -25,15 +25,31 @@ import java.nio.ByteBuffer;
* In charge of encoding a message of type MESSAGE into another form (could be a {@link ByteBuffer} or any other
* protocol level construction.
*
+ * Must be immutable, a CONTEXT will be provided per session.
+ *
+ * @param <INPUT> the incoming message to encode (your high level protocol Pojo/DTO)
+ * @param <OUTPUT> the encoded message (the low level message, usually a {@link ByteBuffer})
+ * @param <ENCODING_STATE> the context where to save the current encoding state (e.g. encoding context switching..)
+ *
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*
*/
-public interface ProtocolEncoder<INPUT /* message type */, OUTPUT> {
+public interface ProtocolEncoder<INPUT /* message type */, OUTPUT, ENCODING_STATE> {
+
+ /**
+ * Create a new session context for this decoder
+ *
+ * @return the newly created context
+ */
+ ENCODING_STATE createEncoderState();
/**
* Encodes higher-level message objects of type <code>INPUT</code> into binary or protocol-specific data of type
* <code>OUTPUT</code>.
+ *
+ * @param message the message to encode
+ * @param context the encoding context (will be stored in the session for the next decode call)
*/
- OUTPUT encode(INPUT message);
+ OUTPUT encode(INPUT message, ENCODING_STATE context);
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/codec/src/main/java/org/apache/mina/codec/StatelessProtocolDecoder.java
----------------------------------------------------------------------
diff --git a/codec/src/main/java/org/apache/mina/codec/StatelessProtocolDecoder.java b/codec/src/main/java/org/apache/mina/codec/StatelessProtocolDecoder.java
new file mode 100644
index 0000000..e33c2f2
--- /dev/null
+++ b/codec/src/main/java/org/apache/mina/codec/StatelessProtocolDecoder.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.codec;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A state less {@link ProtocolDecoder} : no context stored for the different sessions.
+ *
+ * @param <INPUT> the incoming message to decode (the low level message, usually a {@link ByteBuffer})
+ * @param <OUTPUT> the decoded message (your high level protocol Pojo/DTO)
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public interface StatelessProtocolDecoder<INPUT, OUTPUT> extends ProtocolDecoder<INPUT, OUTPUT, Void> {
+
+}
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/codec/src/main/java/org/apache/mina/codec/StatelessProtocolEncoder.java
----------------------------------------------------------------------
diff --git a/codec/src/main/java/org/apache/mina/codec/StatelessProtocolEncoder.java b/codec/src/main/java/org/apache/mina/codec/StatelessProtocolEncoder.java
new file mode 100644
index 0000000..840676e
--- /dev/null
+++ b/codec/src/main/java/org/apache/mina/codec/StatelessProtocolEncoder.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.mina.codec;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A state less {@link ProtocolEncoder} : no context stored for the different sessions.
+ *
+ * @param <INPUT> the incoming message to encode (your high level protocol Pojo/DTO)
+ * @param <OUTPUT> the encoded message (the low level message, usually a {@link ByteBuffer})
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public interface StatelessProtocolEncoder<INPUT, OUTPUT> extends ProtocolEncoder<INPUT, OUTPUT, Void> {
+
+}
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFactory.java b/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFactory.java
deleted file mode 100644
index 1f72812..0000000
--- a/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFactory.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.mina.filter.codec;
-
-import org.apache.mina.api.IoSession;
-import org.apache.mina.codec.ProtocolDecoder;
-import org.apache.mina.codec.ProtocolEncoder;
-
-/**
- * Provides {@link ProtocolEncoder} and {@link ProtocolDecoder} which translates
- * binary or protocol specific data into message object and vice versa.
- * <p>
- * Please refer to
- * <a href="../../../../../xref-examples/org/apache/mina/examples/reverser/ReverseProtocolProvider.html"><code>ReverserProtocolProvider</code></a>
- * example.
- *
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-public interface ProtocolCodecFactory<MESSAGE,ENCODED> {
-
- /**
- * Returns a new (or reusable) instance of {@link ProtocolEncoder} which
- * encodes message objects into binary or protocol-specific data.
- */
- ProtocolEncoder<MESSAGE,ENCODED> getEncoder(IoSession session);
-
- /**
- * Returns a new (or reusable) instance of {@link ProtocolDecoder} which
- * decodes binary or protocol-specific data into message objects.
- */
- ProtocolDecoder<ENCODED,MESSAGE> getDecoder(IoSession session);
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java b/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
index bd8ef2e..e538acb 100644
--- a/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
+++ b/core/src/main/java/org/apache/mina/filter/codec/ProtocolCodecFilter.java
@@ -39,112 +39,32 @@ import org.slf4j.LoggerFactory;
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
-public class ProtocolCodecFilter<MESSAGE, ENCODED> extends AbstractIoFilter {
+public class ProtocolCodecFilter<MESSAGE, ENCODED, ENCODING_STATE, DECODING_STATE> extends AbstractIoFilter {
/** A logger for this class */
private static final Logger LOGGER = LoggerFactory.getLogger(ProtocolCodecFilter.class);
- private static final Class<?>[] EMPTY_PARAMS = new Class[0];
+ /** the immutable encoder */
+ private final ProtocolEncoder<MESSAGE, ENCODED, ENCODING_STATE> encoder;
+
+ /** the immutable decoder */
+ private final ProtocolDecoder<ENCODED, MESSAGE, DECODING_STATE> decoder;
/** key for session attribute holding the encoder */
- @SuppressWarnings("rawtypes")
- private final AttributeKey<ProtocolEncoder> ENCODER = new AttributeKey<ProtocolEncoder>(ProtocolEncoder.class,
- "internal_encoder");
+ private final AttributeKey<Object> ENCODER = new AttributeKey<Object>(Object.class, "internal_encoder");
/** key for session attribute holding the decoder */
- @SuppressWarnings("rawtypes")
- private final AttributeKey<ProtocolDecoder> DECODER = new AttributeKey<ProtocolDecoder>(ProtocolDecoder.class,
- "internal_decoder");
-
- /** The factory responsible for creating the encoder and decoder */
- private final ProtocolCodecFactory<MESSAGE, ENCODED> factory;
-
- /**
- *
- * 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<MESSAGE, ENCODED> factory) {
- if (factory == null) {
- throw new IllegalArgumentException("factory");
- }
-
- this.factory = factory;
- }
-
- /**
- * Creates a new instance of ProtocolCodecFilter, without any factory. The encoder/decoder factory will be created
- * as an anonymous class, using the two parameters (encoder and decoder), which are class names. Instances for those
- * classes will be created in this constructor.
- *
- * @param encoderClass The class responsible for encoding the message
- * @param decoderClass The class responsible for decoding the message
- */
- public ProtocolCodecFilter(Class<? extends ProtocolEncoder<MESSAGE, ENCODED>> encoderClass,
- Class<? extends ProtocolDecoder<ENCODED, MESSAGE>> decoderClass) {
- Assert.assertNotNull(encoderClass, "Encoder Class");
- Assert.assertNotNull(decoderClass, "Decoder Class");
-
- try {
- encoderClass.getConstructor(EMPTY_PARAMS);
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException("encoderClass doesn't have a public default constructor.");
- }
-
- try {
- decoderClass.getConstructor(EMPTY_PARAMS);
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException("decoderClass doesn't have a public default constructor.");
- }
-
- final ProtocolEncoder<MESSAGE, ENCODED> encoder;
-
- try {
- encoder = encoderClass.newInstance();
- } catch (Exception e) {
- throw new IllegalArgumentException("encoderClass cannot be initialized");
- }
-
- final ProtocolDecoder<ENCODED, MESSAGE> decoder;
-
- try {
- decoder = decoderClass.newInstance();
- } catch (Exception e) {
- throw new IllegalArgumentException("decoderClass cannot be initialized");
- }
-
- // Create the inner factory based on the two parameters.
- this.factory = new ProtocolCodecFactory<MESSAGE, ENCODED>() {
- @Override
- public ProtocolEncoder<MESSAGE, ENCODED> getEncoder(IoSession session) {
- return encoder;
- }
-
- @Override
- public ProtocolDecoder<ENCODED, MESSAGE> getDecoder(IoSession session) {
- return decoder;
- }
- };
- }
-
- /**
- * 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<MESSAGE, ENCODED> getEncoder(IoSession session) {
- return factory.getEncoder(session);
- }
+ private final AttributeKey<Object> DECODER = new AttributeKey<Object>(Object.class, "internal_decoder");
/**
- * Get the decoder instance from a given session.
+ * Creates a new instance of ProtocolCodecFilter, with the specified encoder and decoder.
*
- * @param session The associated session we will get the decoder from
- * @return The decoder instance, if any
*/
- public ProtocolDecoder<ENCODED, MESSAGE> getDecoder(IoSession session) {
- return factory.getDecoder(session);
+ public ProtocolCodecFilter(ProtocolEncoder<MESSAGE, ENCODED, ENCODING_STATE> encoder,
+ ProtocolDecoder<ENCODED, MESSAGE, DECODING_STATE> decoder) {
+ Assert.assertNotNull(encoder, "encoder");
+ Assert.assertNotNull(decoder, "decoder");
+ this.encoder = encoder;
+ this.decoder = decoder;
}
/**
@@ -162,12 +82,12 @@ public class ProtocolCodecFilter<MESSAGE, ENCODED> extends AbstractIoFilter {
public void messageReceived(IoSession session, Object in, ReadFilterChainController controller) {
LOGGER.debug("Processing a MESSAGE_RECEIVED for session {}", session);
- ProtocolDecoder<ENCODED, MESSAGE> decoder = getDecoder(session);
+ DECODING_STATE state = getDecodingState(session);
- // Loop until the codec cannot decode more
+ // Loop until the decoder cannot decode more
MESSAGE[] msg;
try {
- while ((msg = decoder.decode((ENCODED) in)) != null) {
+ while ((msg = decoder.decode((ENCODED) in, state)) != null) {
for (MESSAGE m : msg) {
controller.callReadNextFilter(m);
}
@@ -185,8 +105,7 @@ public class ProtocolCodecFilter<MESSAGE, ENCODED> extends AbstractIoFilter {
public void messageWriting(IoSession session, WriteRequest message, WriteFilterChainController controller) {
LOGGER.debug("Processing a MESSAGE_WRITTING for session {}", session);
- ProtocolEncoder<MESSAGE, ENCODED> encoder = getEncoder(session);
- ENCODED encoded = encoder.encode((MESSAGE) message.getMessage());
+ ENCODED encoded = encoder.encode((MESSAGE) message.getMessage(), getEncodingState(session));
message.setMessage(encoded);
controller.callWriteNextFilter(message);
@@ -197,13 +116,13 @@ public class ProtocolCodecFilter<MESSAGE, ENCODED> extends AbstractIoFilter {
*/
@Override
public void sessionOpened(IoSession session) {
- // Initialize the encoder and decoder if we use a factory
- if (factory != null) {
- ProtocolEncoder<MESSAGE, ENCODED> encoder = factory.getEncoder(session);
- session.setAttribute(ENCODER, encoder);
- ProtocolDecoder<ENCODED, MESSAGE> decoder = factory.getDecoder(session);
- session.setAttribute(DECODER, decoder);
- }
+ // Initialize the encoder and decoder state
+
+ ENCODING_STATE encodingState = encoder.createEncoderState();
+ session.setAttribute(ENCODER, encodingState);
+
+ DECODING_STATE decodingState = decoder.createDecoderState();
+ session.setAttribute(DECODER, decodingState);
}
/**
@@ -211,39 +130,20 @@ public class ProtocolCodecFilter<MESSAGE, ENCODED> extends AbstractIoFilter {
*/
@Override
public void sessionClosed(IoSession session) {
- disposeCodec(session);
+ decoder.finishDecode(getDecodingState(session));
+
}
// ----------- Helper methods ---------------------------------------------
- /**
- * Dispose the encoder, decoder, and the callback for the decoded messages.
- */
- private void disposeCodec(IoSession session) {
- // We just remove the two instances of encoder/decoder to release resources
- // from the session
- disposeEncoder(session);
- disposeDecoder(session);
- }
- /**
- * Dispose the encoder, removing its instance from the session's attributes, and calling the associated dispose
- * method.
- */
- private void disposeEncoder(IoSession session) {
- session.removeAttribute(ENCODER);
+ @SuppressWarnings("unchecked")
+ private DECODING_STATE getDecodingState(IoSession session) {
+ return (DECODING_STATE) session.getAttribute(DECODER);
}
- /**
- * Dispose the decoder, removing its instance from the session's attributes, and calling the associated dispose
- * method.
- */
- private void disposeDecoder(IoSession session) {
- @SuppressWarnings("unchecked")
- ProtocolDecoder<ENCODED, MESSAGE> decoder = session.removeAttribute(DECODER);
- try {
- decoder.finishDecode();
- } catch (Throwable t) {
- LOGGER.warn("Failed to dispose: " + decoder.getClass().getName() + " (" + decoder + ')');
- }
+ @SuppressWarnings("unchecked")
+ private ENCODING_STATE getEncodingState(IoSession session) {
+ return (ENCODING_STATE) session.getAttribute(ENCODER);
}
+
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/core/src/test/java/org/apache/mina/filter/codec/ProtocolCodecFilterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/mina/filter/codec/ProtocolCodecFilterTest.java b/core/src/test/java/org/apache/mina/filter/codec/ProtocolCodecFilterTest.java
deleted file mode 100644
index f70415f..0000000
--- a/core/src/test/java/org/apache/mina/filter/codec/ProtocolCodecFilterTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.mina.filter.codec;
-
-import static org.junit.Assert.*;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.*;
-
-import org.apache.mina.api.IoSession;
-import org.apache.mina.codec.ProtocolDecoder;
-import org.apache.mina.codec.ProtocolEncoder;
-import org.junit.Test;
-
-/**
- * Unit test for {@link ProtocolCodecFilter}
- *
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-public class ProtocolCodecFilterTest {
- @SuppressWarnings({ "rawtypes", "unchecked" })
- @Test
- public void constructor_args() {
- try {
- new ProtocolCodecFilter(null);
- fail();
- } catch (IllegalArgumentException e) {
- // happy
- } catch (Exception e2) {
- fail();
- }
-
- try {
- new ProtocolCodecFilter(null, ProtocolDecoder.class);
- fail();
- } catch (IllegalArgumentException e) {
- // happy
- } catch (Exception e2) {
- fail();
- }
-
- try {
- new ProtocolCodecFilter(ProtocolEncoder.class, null);
- fail();
- } catch (IllegalArgumentException e) {
- // happy
- } catch (Exception e2) {
- fail();
- }
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- @Test
- public void codec_factory() {
- ProtocolEncoder encoder = mock(ProtocolEncoder.class);
- ProtocolDecoder decoder = mock(ProtocolDecoder.class);
-
- ProtocolCodecFactory factory = mock(ProtocolCodecFactory.class);
- when(factory.getEncoder(any(IoSession.class))).thenReturn(encoder);
- when(factory.getDecoder(any(IoSession.class))).thenReturn(decoder);
-
- ProtocolCodecFilter codec = new ProtocolCodecFilter(factory);
- assertEquals(encoder, codec.getEncoder(null));
- assertEquals(decoder, codec.getDecoder(null));
- }
-
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/examples/src/main/java/org/apache/mina/examples/http/HttpTest.java
----------------------------------------------------------------------
diff --git a/examples/src/main/java/org/apache/mina/examples/http/HttpTest.java b/examples/src/main/java/org/apache/mina/examples/http/HttpTest.java
index f62a712..1a34838 100644
--- a/examples/src/main/java/org/apache/mina/examples/http/HttpTest.java
+++ b/examples/src/main/java/org/apache/mina/examples/http/HttpTest.java
@@ -32,6 +32,7 @@ import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.filterchain.ReadFilterChainController;
import org.apache.mina.http.DateUtil;
+import org.apache.mina.http.HttpDecoderState;
import org.apache.mina.http.HttpServerDecoder;
import org.apache.mina.http.HttpServerEncoder;
import org.apache.mina.http.api.DefaultHttpResponse;
@@ -50,8 +51,9 @@ public class HttpTest {
NioTcpServer httpServer = new NioTcpServer();
httpServer.setReuseAddress(true);
- httpServer.setFilters(new LoggingFilter("INCOMING"), new ProtocolCodecFilter<HttpPdu, ByteBuffer>(
- HttpServerEncoder.class, HttpServerDecoder.class), new LoggingFilter("DECODED"), new DummyHttpSever());
+ httpServer.setFilters(new LoggingFilter("INCOMING"),
+ new ProtocolCodecFilter<HttpPdu, ByteBuffer, Void, HttpDecoderState>(new HttpServerEncoder(),
+ new HttpServerDecoder()), new LoggingFilter("DECODED"), new DummyHttpSever());
httpServer.getSessionConfig().setTcpNoDelay(true);
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/examples/src/main/java/org/apache/mina/examples/http/HttpsTest.java
----------------------------------------------------------------------
diff --git a/examples/src/main/java/org/apache/mina/examples/http/HttpsTest.java b/examples/src/main/java/org/apache/mina/examples/http/HttpsTest.java
index 12fedf4..a969163 100644
--- a/examples/src/main/java/org/apache/mina/examples/http/HttpsTest.java
+++ b/examples/src/main/java/org/apache/mina/examples/http/HttpsTest.java
@@ -32,6 +32,7 @@ import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.filterchain.ReadFilterChainController;
import org.apache.mina.http.DateUtil;
+import org.apache.mina.http.HttpDecoderState;
import org.apache.mina.http.HttpServerDecoder;
import org.apache.mina.http.HttpServerEncoder;
import org.apache.mina.http.api.DefaultHttpResponse;
@@ -49,8 +50,9 @@ public class HttpsTest {
NioTcpServer httpServer = new NioTcpServer();
- httpServer.setFilters(new LoggingFilter("INCOMING"), new ProtocolCodecFilter<HttpPdu, ByteBuffer>(
- HttpServerEncoder.class, HttpServerDecoder.class), new LoggingFilter("DECODED"), new DummyHttpSever());
+ httpServer.setFilters(new LoggingFilter("INCOMING"),
+ new ProtocolCodecFilter<HttpPdu, ByteBuffer, Void, HttpDecoderState>(new HttpServerEncoder(),
+ new HttpServerDecoder()), new LoggingFilter("DECODED"), new DummyHttpSever());
httpServer.getSessionConfig().setTcpNoDelay(true);
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/http/src/main/java/org/apache/mina/http/HttpDecoderState.java
----------------------------------------------------------------------
diff --git a/http/src/main/java/org/apache/mina/http/HttpDecoderState.java b/http/src/main/java/org/apache/mina/http/HttpDecoderState.java
new file mode 100644
index 0000000..73c5986
--- /dev/null
+++ b/http/src/main/java/org/apache/mina/http/HttpDecoderState.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.http;
+
+import java.nio.ByteBuffer;
+
+/**
+ * State of a HTTP decoding for a given session.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class HttpDecoderState {
+
+ /** State of the decoder */
+ private DecoderState state = DecoderState.NEW;
+
+ /** The previously received buffer, not totally decoded */
+ private ByteBuffer partial;
+
+ /** Number of bytes remaining to read for completing the body */
+ private int remainingBytes;
+
+ public DecoderState getState() {
+ return state;
+ }
+
+ public void setState(DecoderState state) {
+ this.state = state;
+ }
+
+ public ByteBuffer getPartial() {
+ return partial;
+ }
+
+ public void setPartial(ByteBuffer partial) {
+ this.partial = partial;
+ }
+
+ public int getRemainingBytes() {
+ return remainingBytes;
+ }
+
+ public void setRemainingBytes(int remainingBytes) {
+ this.remainingBytes = remainingBytes;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/http/src/main/java/org/apache/mina/http/HttpServerDecoder.java
----------------------------------------------------------------------
diff --git a/http/src/main/java/org/apache/mina/http/HttpServerDecoder.java b/http/src/main/java/org/apache/mina/http/HttpServerDecoder.java
index 94e084f..f99caef 100644
--- a/http/src/main/java/org/apache/mina/http/HttpServerDecoder.java
+++ b/http/src/main/java/org/apache/mina/http/HttpServerDecoder.java
@@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory;
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
-public class HttpServerDecoder implements ProtocolDecoder<ByteBuffer, HttpPdu> {
+public class HttpServerDecoder implements ProtocolDecoder<ByteBuffer, HttpPdu, HttpDecoderState> {
private static final Logger LOG = LoggerFactory.getLogger(HttpServerDecoder.class);
/** Regex to parse HttpRequest Request Line */
@@ -67,26 +67,29 @@ public class HttpServerDecoder implements ProtocolDecoder<ByteBuffer, HttpPdu> {
/** Regex to split cookie header following RFC6265 Section 5.4 */
public static final Pattern COOKIE_SEPARATOR_PATTERN = Pattern.compile(";");
- /** State of the decoder */
- private DecoderState state = DecoderState.NEW;
-
- /** The previously received buffer, not totally decoded */
- private ByteBuffer partial;
-
- /** Number of bytes remaining to read for completing the body */
- private int remainingBytes;
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HttpDecoderState createDecoderState() {
+ return new HttpDecoderState();
+ }
+ /**
+ * {@inheritDoc}
+ */
@Override
- public HttpPdu[] decode(ByteBuffer msg) throws ProtocolDecoderException {
+ public HttpPdu[] decode(ByteBuffer msg, HttpDecoderState context) throws ProtocolDecoderException {
LOG.debug("decode : {}", msg);
if (msg.remaining() <= 0) {
return null;
}
- switch (state) {
+ switch (context.getState()) {
case HEAD:
LOG.debug("decoding HEAD");
// concat the old buffer and the new incoming one
- msg = ByteBuffer.allocate(partial.remaining() + msg.remaining()).put(partial).put(msg);
+ msg = ByteBuffer.allocate(context.getPartial().remaining() + msg.remaining()).put(context.getPartial())
+ .put(msg);
msg.flip();
// now let's decode like it was a new message
@@ -96,9 +99,9 @@ public class HttpServerDecoder implements ProtocolDecoder<ByteBuffer, HttpPdu> {
if (rq == null) {
// we copy the incoming BB because it's going to be recycled by the inner IoProcessor for next reads
- partial = ByteBuffer.allocate(msg.remaining());
- partial.put(msg);
- partial.flip();
+ context.setPartial(ByteBuffer.allocate(msg.remaining()));
+ context.getPartial().put(msg);
+ context.getPartial().flip();
} else {
return new HttpPdu[] { rq };
}
@@ -109,18 +112,18 @@ public class HttpServerDecoder implements ProtocolDecoder<ByteBuffer, HttpPdu> {
// send the chunk of body
HttpContentChunk chunk = new HttpContentChunk(msg);
// do we have reach end of body ?
- remainingBytes -= chunkSize;
+ context.setRemainingBytes(context.getRemainingBytes() - chunkSize);
- if (remainingBytes <= 0) {
+ if (context.getRemainingBytes() <= 0) {
LOG.debug("end of HTTP body");
- state = DecoderState.NEW;
- remainingBytes = 0;
+ context.setState(DecoderState.NEW);
+ context.setRemainingBytes(0);
return new HttpPdu[] { chunk, new HttpEndOfContent() };
}
break;
default:
- throw new RuntimeException("Unknonwn decoder state : " + state);
+ throw new RuntimeException("Unknonwn decoder state : " + context.getState());
}
return null;
@@ -158,8 +161,11 @@ public class HttpServerDecoder implements ProtocolDecoder<ByteBuffer, HttpPdu> {
return new HttpRequestImpl(version, method, requestedPath, generalHeaders);
}
+ /**
+ * {@inheritDoc}
+ */
@Override
- public void finishDecode() {
+ public void finishDecode(HttpDecoderState context) {
}
}
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/http/src/main/java/org/apache/mina/http/HttpServerEncoder.java
----------------------------------------------------------------------
diff --git a/http/src/main/java/org/apache/mina/http/HttpServerEncoder.java b/http/src/main/java/org/apache/mina/http/HttpServerEncoder.java
index 8101228..1dd58d4 100644
--- a/http/src/main/java/org/apache/mina/http/HttpServerEncoder.java
+++ b/http/src/main/java/org/apache/mina/http/HttpServerEncoder.java
@@ -23,7 +23,7 @@ import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Map;
-import org.apache.mina.codec.ProtocolEncoder;
+import org.apache.mina.codec.StatelessProtocolEncoder;
import org.apache.mina.http.api.HttpContentChunk;
import org.apache.mina.http.api.HttpEndOfContent;
import org.apache.mina.http.api.HttpPdu;
@@ -36,13 +36,22 @@ import org.apache.mina.http.api.HttpResponse;
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
-public class HttpServerEncoder implements ProtocolEncoder<HttpPdu, ByteBuffer> {
+public class HttpServerEncoder implements StatelessProtocolEncoder<HttpPdu, ByteBuffer> {
/**
* {@inheritDoc}
*/
@Override
- public ByteBuffer encode(HttpPdu message) {
+ public Void createEncoderState() {
+ // steless, so it's not used
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ByteBuffer encode(HttpPdu message, Void context) {
return message.encode(visitor);
}
http://git-wip-us.apache.org/repos/asf/mina/blob/1a4ad866/http/src/test/java/org/apache/mina/http/HttpServerDecoderTest.java
----------------------------------------------------------------------
diff --git a/http/src/test/java/org/apache/mina/http/HttpServerDecoderTest.java b/http/src/test/java/org/apache/mina/http/HttpServerDecoderTest.java
index 8e18381..f811759 100644
--- a/http/src/test/java/org/apache/mina/http/HttpServerDecoderTest.java
+++ b/http/src/test/java/org/apache/mina/http/HttpServerDecoderTest.java
@@ -19,8 +19,7 @@
*/
package org.apache.mina.http;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.*;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
@@ -35,44 +34,49 @@ import org.junit.Test;
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
public class HttpServerDecoderTest {
-
+
@Test
- public void verifyThatHeaderWithoutLeadingSpaceIsSupported() throws UnsupportedEncodingException, ProtocolDecoderException {
+ public void verifyThatHeaderWithoutLeadingSpaceIsSupported() throws UnsupportedEncodingException,
+ ProtocolDecoderException {
String reqStr = "GET / HTTP/1.0\r\nHost:localhost\r\n\r\n";
ByteBuffer buffer = ByteBuffer.allocate(reqStr.length());
buffer.put(reqStr.getBytes("US-ASCII"));
buffer.rewind();
HttpServerDecoder decoder = new HttpServerDecoder();
- HttpPdu[] pdus = decoder.decode(buffer);
+ HttpDecoderState state = decoder.createDecoderState();
+ HttpPdu[] pdus = decoder.decode(buffer, state);
assertNotNull(pdus);
assertEquals(1, pdus.length);
- assertEquals("localhost", ((HttpRequestImpl)pdus[0]).getHeader("host"));
+ assertEquals("localhost", ((HttpRequestImpl) pdus[0]).getHeader("host"));
}
@Test
- public void verifyThatLeadingSpacesAreRemovedFromHeader() throws UnsupportedEncodingException, ProtocolDecoderException {
+ public void verifyThatLeadingSpacesAreRemovedFromHeader() throws UnsupportedEncodingException,
+ ProtocolDecoderException {
String reqStr = "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n";
ByteBuffer buffer = ByteBuffer.allocate(reqStr.length());
buffer.put(reqStr.getBytes("US-ASCII"));
buffer.rewind();
HttpServerDecoder decoder = new HttpServerDecoder();
- HttpPdu[] pdus = decoder.decode(buffer);
+ HttpDecoderState state = decoder.createDecoderState();
+ HttpPdu[] pdus = decoder.decode(buffer, state);
assertNotNull(pdus);
assertEquals(1, pdus.length);
- assertEquals("localhost", ((HttpRequestImpl)pdus[0]).getHeader("host"));
+ assertEquals("localhost", ((HttpRequestImpl) pdus[0]).getHeader("host"));
}
-
@Test
- public void verifyThatTrailingSpacesAreRemovedFromHeader() throws UnsupportedEncodingException, ProtocolDecoderException {
+ public void verifyThatTrailingSpacesAreRemovedFromHeader() throws UnsupportedEncodingException,
+ ProtocolDecoderException {
String reqStr = "GET / HTTP/1.0\r\nHost:localhost \r\n\r\n";
ByteBuffer buffer = ByteBuffer.allocate(reqStr.length());
buffer.put(reqStr.getBytes("US-ASCII"));
buffer.rewind();
HttpServerDecoder decoder = new HttpServerDecoder();
- HttpPdu[] pdus = decoder.decode(buffer);
+ HttpDecoderState state = decoder.createDecoderState();
+ HttpPdu[] pdus = decoder.decode(buffer, state);
assertNotNull(pdus);
assertEquals(1, pdus.length);
- assertEquals("localhost", ((HttpRequestImpl)pdus[0]).getHeader("host"));
+ assertEquals("localhost", ((HttpRequestImpl) pdus[0]).getHeader("host"));
}
}