You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by je...@apache.org on 2013/04/07 18:22:31 UTC
git commit: Added text line coded and related unit tests
Updated Branches:
refs/heads/trunk 2d51d12db -> 653d1a5ff
Added text line coded and related unit tests
Project: http://git-wip-us.apache.org/repos/asf/mina/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina/commit/653d1a5f
Tree: http://git-wip-us.apache.org/repos/asf/mina/tree/653d1a5f
Diff: http://git-wip-us.apache.org/repos/asf/mina/diff/653d1a5f
Branch: refs/heads/trunk
Commit: 653d1a5ff37904e4515bc375d24dcb301862dad4
Parents: 2d51d12
Author: Jeff MAURY <je...@apache.org>
Authored: Sun Apr 7 18:21:47 2013 +0200
Committer: Jeff MAURY <je...@apache.org>
Committed: Sun Apr 7 18:21:47 2013 +0200
----------------------------------------------------------------------
.../apache/mina/codec/textline/LineDelimiter.java | 149 ++++++
.../mina/codec/textline/TextLineDecoder.java | 407 +++++++++++++++
.../mina/codec/textline/TextLineEncoder.java | 147 ++++++
.../codec/textline/AutoTextLineDecoderTest.java | 123 +++++
.../codec/textline/UnixTextLineDecoderTest.java | 123 +++++
.../codec/textline/WindowsTextLineDecoderTest.java | 121 +++++
6 files changed, 1070 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/main/java/org/apache/mina/codec/textline/LineDelimiter.java
----------------------------------------------------------------------
diff --git a/codec/src/main/java/org/apache/mina/codec/textline/LineDelimiter.java b/codec/src/main/java/org/apache/mina/codec/textline/LineDelimiter.java
new file mode 100644
index 0000000..c6f858a
--- /dev/null
+++ b/codec/src/main/java/org/apache/mina/codec/textline/LineDelimiter.java
@@ -0,0 +1,149 @@
+/*
+ * 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.textline;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+
+/**
+ * A delimiter which is appended to the end of a text line, such as
+ * <tt>CR/LF</tt>. This class defines default delimiters for various
+ * OS :
+ * <ul>
+ * <li><b>Unix/Linux</b> : LineDelimiter.UNIX ("\n")</li>
+ * <li><b>Windows</b> : LineDelimiter.WINDOWS ("\r\n")</li>
+ * <li><b>MAC</b> : LineDelimiter.MAC ("\r")</li>
+ * </ul>
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class LineDelimiter {
+ /** the line delimiter constant of the current O/S. */
+ public static final LineDelimiter DEFAULT;
+
+ /** Compute the default delimiter on he current OS */
+ static {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ PrintWriter out = new PrintWriter(bout, true);
+ out.println();
+ DEFAULT = new LineDelimiter(new String(bout.toByteArray()));
+ }
+
+ /**
+ * A special line delimiter which is used for auto-detection of
+ * EOL in {@link TextLineDecoder}. If this delimiter is used,
+ * {@link TextLineDecoder} will consider both <tt>'\r'</tt> and
+ * <tt>'\n'</tt> as a delimiter.
+ */
+ public static final LineDelimiter AUTO = new LineDelimiter("");
+
+ /**
+ * The CRLF line delimiter constant (<tt>"\r\n"</tt>)
+ */
+ public static final LineDelimiter CRLF = new LineDelimiter("\r\n");
+
+ /**
+ * The line delimiter constant of UNIX (<tt>"\n"</tt>)
+ */
+ public static final LineDelimiter UNIX = new LineDelimiter("\n");
+
+ /**
+ * The line delimiter constant of MS Windows/DOS (<tt>"\r\n"</tt>)
+ */
+ public static final LineDelimiter WINDOWS = CRLF;
+
+ /**
+ * The line delimiter constant of Mac OS (<tt>"\r"</tt>)
+ */
+ public static final LineDelimiter MAC = new LineDelimiter("\r");
+
+ /**
+ * The line delimiter constant for NUL-terminated text protocols
+ * such as Flash XML socket (<tt>"\0"</tt>)
+ */
+ public static final LineDelimiter NUL = new LineDelimiter("\0");
+
+ /** Stores the selected Line delimiter */
+ private final String value;
+
+ /**
+ * Creates a new line delimiter with the specified <tt>value</tt>.
+ */
+ public LineDelimiter(String value) {
+ if (value == null) {
+ throw new IllegalArgumentException("delimiter");
+ }
+
+ this.value = value;
+ }
+
+ /**
+ * Return the delimiter string.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof LineDelimiter)) {
+ return false;
+ }
+
+ LineDelimiter that = (LineDelimiter) o;
+
+ return this.value.equals(that.value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ if (value.length() == 0) {
+ return "delimiter: auto";
+ } else {
+ StringBuilder buf = new StringBuilder();
+ buf.append("delimiter:");
+
+ for (int i = 0; i < value.length(); i++) {
+ buf.append(" 0x");
+ buf.append(Integer.toHexString(value.charAt(i)));
+ }
+
+ return buf.toString();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/main/java/org/apache/mina/codec/textline/TextLineDecoder.java
----------------------------------------------------------------------
diff --git a/codec/src/main/java/org/apache/mina/codec/textline/TextLineDecoder.java b/codec/src/main/java/org/apache/mina/codec/textline/TextLineDecoder.java
new file mode 100644
index 0000000..845ee24
--- /dev/null
+++ b/codec/src/main/java/org/apache/mina/codec/textline/TextLineDecoder.java
@@ -0,0 +1,407 @@
+/*
+ * 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.textline;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.mina.codec.ProtocolDecoder;
+
+/**
+ * A {@link ProtocolDecoder} which decodes a text line into a string.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class TextLineDecoder implements ProtocolDecoder<ByteBuffer, String, TextLineDecoder.Context> {
+ private final Charset charset;
+
+ /** The delimiter used to determinate when a line has been fully decoded */
+ private final LineDelimiter delimiter;
+
+ /** An ByteBuffer containing the delimiter */
+ private ByteBuffer delimBuf;
+
+ /** The default maximum Line length. Default to 1024. */
+ private int maxLineLength = 1024;
+
+ /** The default maximum buffer length. Default to 128 chars. */
+ private int bufferLength = 128;
+
+ /**
+ * Creates a new instance with the current default {@link Charset}
+ * and {@link LineDelimiter#AUTO} delimiter.
+ */
+ public TextLineDecoder() {
+ this(LineDelimiter.AUTO);
+ }
+
+ /**
+ * Creates a new instance with the current default {@link Charset}
+ * and the specified <tt>delimiter</tt>.
+ */
+ public TextLineDecoder(String delimiter) {
+ this(new LineDelimiter(delimiter));
+ }
+
+ /**
+ * Creates a new instance with the current default {@link Charset}
+ * and the specified <tt>delimiter</tt>.
+ */
+ public TextLineDecoder(LineDelimiter delimiter) {
+ this(Charset.defaultCharset(), delimiter);
+ }
+
+ /**
+ * Creates a new instance with the spcified <tt>charset</tt>
+ * and {@link LineDelimiter#AUTO} delimiter.
+ */
+ public TextLineDecoder(Charset charset) {
+ this(charset, LineDelimiter.AUTO);
+ }
+
+ /**
+ * Creates a new instance with the spcified <tt>charset</tt>
+ * and the specified <tt>delimiter</tt>.
+ */
+ public TextLineDecoder(Charset charset, String delimiter) {
+ this(charset, new LineDelimiter(delimiter));
+ }
+
+ /**
+ * Creates a new instance with the specified <tt>charset</tt>
+ * and the specified <tt>delimiter</tt>.
+ */
+ public TextLineDecoder(Charset charset, LineDelimiter delimiter) {
+ if (charset == null) {
+ throw new IllegalArgumentException("charset parameter shuld not be null");
+ }
+
+ if (delimiter == null) {
+ throw new IllegalArgumentException("delimiter parameter should not be null");
+ }
+
+ this.charset = charset;
+ this.delimiter = delimiter;
+
+ // Convert delimiter to ByteBuffer if not done yet.
+ if (delimBuf == null) {
+ ByteBuffer tmp = charset.encode(CharBuffer.wrap(delimiter.getValue()));
+ tmp.rewind();
+ delimBuf = tmp;
+ }
+ }
+
+ /**
+ * Returns the allowed maximum size of the line to be decoded.
+ * If the size of the line to be decoded exceeds this value, the
+ * decoder will throw a {@link BufferDataException}. The default
+ * value is <tt>1024</tt> (1KB).
+ */
+ public int getMaxLineLength() {
+ return maxLineLength;
+ }
+
+ /**
+ * Sets the allowed maximum size of the line to be decoded.
+ * If the size of the line to be decoded exceeds this value, the
+ * decoder will throw a {@link BufferDataException}. The default
+ * value is <tt>1024</tt> (1KB).
+ */
+ public void setMaxLineLength(int maxLineLength) {
+ if (maxLineLength <= 0) {
+ throw new IllegalArgumentException("maxLineLength (" + maxLineLength + ") should be a positive value");
+ }
+
+ this.maxLineLength = maxLineLength;
+ }
+
+ /**
+ * Sets the default buffer size. This buffer is used in the Context
+ * to store the decoded line.
+ *
+ * @param bufferLength The default bufer size
+ */
+ public void setBufferLength(int bufferLength) {
+ if (bufferLength <= 0) {
+ throw new IllegalArgumentException("bufferLength (" + maxLineLength + ") should be a positive value");
+
+ }
+
+ this.bufferLength = bufferLength;
+ }
+
+ /**
+ * Returns the allowed buffer size used to store the decoded line
+ * in the Context instance.
+ */
+ public int getBufferLength() {
+ return bufferLength;
+ }
+
+ @Override
+ public Context createDecoderState() {
+ return new Context(bufferLength);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] decode(ByteBuffer in, Context ctx) {
+ if (LineDelimiter.AUTO.equals(delimiter)) {
+ return decodeAuto(ctx, in);
+ } else {
+ return decodeNormal(ctx, in);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void finishDecode(Context ctx) {
+ }
+
+ /**
+ * Decode a line using the default delimiter on the current system
+ */
+ private String[] decodeAuto(Context ctx, ByteBuffer in) {
+ List<String> decoded = new ArrayList<String>();
+ int matchCount = ctx.getMatchCount();
+
+ // Try to find a match
+ int oldPos = in.position();
+ int oldLimit = in.limit();
+
+ while (in.hasRemaining()) {
+ byte b = in.get();
+ boolean matched = false;
+
+ switch (b) {
+ case '\r':
+ // Might be Mac, but we don't auto-detect Mac EOL
+ // to avoid confusion.
+ matchCount++;
+ break;
+
+ case '\n':
+ // UNIX
+ matchCount++;
+ matched = true;
+ break;
+
+ default:
+ matchCount = 0;
+ }
+
+ if (matched) {
+ // Found a match.
+ int pos = in.position();
+ in.limit(pos);
+ in.position(oldPos);
+
+ ctx.append(in);
+
+ in.limit(oldLimit);
+ in.position(pos);
+
+ try {
+ if (ctx.getOverflowLength() == 0) {
+ ByteBuffer buf = ctx.getBuffer();
+ buf.flip();
+ buf.limit(buf.limit() - matchCount);
+
+ CharsetDecoder decoder = ctx.getDecoder();
+ CharBuffer buffer = decoder.decode(buf);
+ String str = new String(buffer.array());
+ decoded.add(str);
+ } else {
+ int overflowPosition = ctx.getOverflowLength();
+ throw new IllegalStateException("Line is too long: " + overflowPosition);
+ }
+ } catch (CharacterCodingException cce) {
+ throw new RuntimeException(cce);
+ } finally {
+ ctx.reset();
+ }
+ oldPos = pos;
+ matchCount = 0;
+ }
+ }
+
+ // Put remainder to buf.
+ in.position(oldPos);
+ ctx.append(in);
+
+ ctx.setMatchCount(matchCount);
+ return decoded.toArray(new String[decoded.size()]);
+ }
+
+ /**
+ * Decode a line using the delimiter defined by the caller
+ * @return
+ */
+ private String[] decodeNormal(Context ctx, ByteBuffer in) {
+ List<String> decoded = new ArrayList<String>();
+ int matchCount = ctx.getMatchCount();
+
+ // Try to find a match
+ int oldPos = in.position();
+ int oldLimit = in.limit();
+
+ while (in.hasRemaining()) {
+ byte b = in.get();
+
+ if (delimBuf.get(matchCount) == b) {
+ matchCount++;
+
+ if (matchCount == delimBuf.limit()) {
+ // Found a match.
+ int pos = in.position();
+ in.limit(pos);
+ in.position(oldPos);
+
+ ctx.append(in);
+
+ in.limit(oldLimit);
+ in.position(pos);
+
+ try {
+ if (ctx.getOverflowLength() == 0) {
+ ByteBuffer buf = ctx.getBuffer();
+ buf.flip();
+ buf.limit(buf.limit() - matchCount);
+
+ CharsetDecoder decoder = ctx.getDecoder();
+ CharBuffer buffer = decoder.decode(buf);
+ String str = new String(buffer.array());
+ decoded.add(str);
+ } else {
+ int overflowLength = ctx.getOverflowLength();
+ throw new IllegalStateException("Line is too long: " + overflowLength);
+ }
+ } catch (CharacterCodingException cce) {
+ throw new RuntimeException(cce);
+ } finally {
+ ctx.reset();
+ }
+
+
+ oldPos = pos;
+ matchCount = 0;
+ }
+ } else {
+ // fix for DIRMINA-506 & DIRMINA-536
+ in.position(Math.max(0, in.position() - matchCount));
+ matchCount = 0;
+ }
+ }
+
+ // Put remainder to buf.
+ in.position(oldPos);
+ ctx.append(in);
+
+ ctx.setMatchCount(matchCount);
+ return decoded.toArray(new String[decoded.size()]);
+ }
+
+ /**
+ * A Context used during the decoding of a lin. It stores the decoder,
+ * the temporary buffer containing the decoded line, and other status flags.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+ public class Context {
+ /** The decoder */
+ private final CharsetDecoder decoder;
+
+ /** The temporary buffer containing the decoded line */
+ private ByteBuffer buf;
+
+ /** The number of lines found so far */
+ private int matchCount = 0;
+
+ /**
+ * Overflow length
+ */
+ private int overflowLength = 0;
+
+ /** Create a new Context object with a default buffer */
+ private Context(int bufferLength) {
+ decoder = charset.newDecoder();
+ buf = ByteBuffer.allocate(bufferLength);
+ }
+
+ public CharsetDecoder getDecoder() {
+ return decoder;
+ }
+
+ public ByteBuffer getBuffer() {
+ return buf;
+ }
+
+ public int getMatchCount() {
+ return matchCount;
+ }
+
+ public void setMatchCount(int matchCount) {
+ this.matchCount = matchCount;
+ }
+
+ public int getOverflowLength() {
+ return overflowLength;
+ }
+
+ public void reset() {
+ overflowLength = 0;
+ matchCount = 0;
+ decoder.reset();
+ buf.clear();
+ }
+
+ private void ensureSpace(int size) {
+ if (buf.position() + size > buf.capacity()) {
+ ByteBuffer b = ByteBuffer.allocate(buf.position() + size + bufferLength);
+ buf.flip();
+ b.put(buf);
+ buf = b;
+ }
+ }
+ public void append(ByteBuffer in) {
+ if (buf.position() > maxLineLength - in.remaining()) {
+ overflowLength = buf.position() + in.remaining();
+ buf.clear();
+ discard(in);
+ } else {
+ ensureSpace(in.remaining());
+ getBuffer().put(in);
+ }
+ }
+
+ private void discard(ByteBuffer in) {
+ in.position(in.limit());
+ }
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/main/java/org/apache/mina/codec/textline/TextLineEncoder.java
----------------------------------------------------------------------
diff --git a/codec/src/main/java/org/apache/mina/codec/textline/TextLineEncoder.java b/codec/src/main/java/org/apache/mina/codec/textline/TextLineEncoder.java
new file mode 100644
index 0000000..6ce02c3
--- /dev/null
+++ b/codec/src/main/java/org/apache/mina/codec/textline/TextLineEncoder.java
@@ -0,0 +1,147 @@
+/*
+ * 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.textline;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+
+import org.apache.mina.codec.ProtocolEncoder;
+import org.apache.mina.codec.StatelessProtocolEncoder;
+
+
+/**
+ * A {@link ProtocolEncoder} which encodes a string into a text line
+ * which ends with the delimiter.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class TextLineEncoder implements StatelessProtocolEncoder<String, ByteBuffer> {
+ private final CharsetEncoder charsetEncoder;
+
+ private final LineDelimiter delimiter;
+
+ private int maxLineLength = Integer.MAX_VALUE;
+
+ /**
+ * Creates a new instance with the current default {@link Charset}
+ * and {@link LineDelimiter#UNIX} delimiter.
+ */
+ public TextLineEncoder() {
+ this(Charset.defaultCharset(), LineDelimiter.UNIX);
+ }
+
+ /**
+ * Creates a new instance with the current default {@link Charset}
+ * and the specified <tt>delimiter</tt>.
+ */
+ public TextLineEncoder(String delimiter) {
+ this(new LineDelimiter(delimiter));
+ }
+
+ /**
+ * Creates a new instance with the current default {@link Charset}
+ * and the specified <tt>delimiter</tt>.
+ */
+ public TextLineEncoder(LineDelimiter delimiter) {
+ this(Charset.defaultCharset(), delimiter);
+ }
+
+ /**
+ * Creates a new instance with the spcified <tt>charset</tt>
+ * and {@link LineDelimiter#UNIX} delimiter.
+ */
+ public TextLineEncoder(Charset charset) {
+ this(charset, LineDelimiter.UNIX);
+ }
+
+ /**
+ * Creates a new instance with the spcified <tt>charset</tt>
+ * and the specified <tt>delimiter</tt>.
+ */
+ public TextLineEncoder(Charset charset, String delimiter) {
+ this(charset, new LineDelimiter(delimiter));
+ }
+
+ /**
+ * Creates a new instance with the spcified <tt>charset</tt>
+ * and the specified <tt>delimiter</tt>.
+ */
+ public TextLineEncoder(Charset charset, LineDelimiter delimiter) {
+ if (charset == null) {
+ throw new IllegalArgumentException("charset");
+ }
+ if (delimiter == null) {
+ throw new IllegalArgumentException("delimiter");
+ }
+ if (LineDelimiter.AUTO.equals(delimiter)) {
+ throw new IllegalArgumentException("AUTO delimiter is not allowed for encoder.");
+ }
+
+ this.charsetEncoder = charset.newEncoder();
+ this.delimiter = delimiter;
+ }
+
+ /**
+ * Returns the allowed maximum size of the encoded line.
+ * If the size of the encoded line exceeds this value, the encoder
+ * will throw a {@link IllegalArgumentException}. The default value
+ * is {@link Integer#MAX_VALUE}.
+ */
+ public int getMaxLineLength() {
+ return maxLineLength;
+ }
+
+ /**
+ * Sets the allowed maximum size of the encoded line.
+ * If the size of the encoded line exceeds this value, the encoder
+ * will throw a {@link IllegalArgumentException}. The default value
+ * is {@link Integer#MAX_VALUE}.
+ */
+ public void setMaxLineLength(int maxLineLength) {
+ if (maxLineLength <= 0) {
+ throw new IllegalArgumentException("maxLineLength: " + maxLineLength);
+ }
+
+ this.maxLineLength = maxLineLength;
+ }
+
+ @Override
+ public Void createEncoderState() {
+ return null;
+ }
+
+ @Override
+ public ByteBuffer encode(String message, Void context) {
+ try {
+ String value = (message == null ? "" : message);
+
+ if (value.length() > maxLineLength) {
+ throw new IllegalArgumentException("Line length: " + message.length());
+ }
+ return charsetEncoder.encode(CharBuffer.wrap(value).append(CharBuffer.wrap(delimiter.getValue())));
+ } catch (CharacterCodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/test/java/org/apache/mina/codec/textline/AutoTextLineDecoderTest.java
----------------------------------------------------------------------
diff --git a/codec/src/test/java/org/apache/mina/codec/textline/AutoTextLineDecoderTest.java b/codec/src/test/java/org/apache/mina/codec/textline/AutoTextLineDecoderTest.java
new file mode 100644
index 0000000..ca087c4
--- /dev/null
+++ b/codec/src/test/java/org/apache/mina/codec/textline/AutoTextLineDecoderTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.textline;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.codec.textline.TextLineDecoder.Context;
+import org.junit.Test;
+
+/**
+ * A {@link TextLineDecoder} test.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class AutoTextLineDecoderTest {
+
+ @Test
+ public void testThatEmptyBufferReturnsEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder();
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.allocate(0), context);
+ assertNotNull(results);
+ assertEquals(0, results.length);
+ }
+
+ @Test
+ public void testThatNonLineTerminatedStringReturnsEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder();
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(0, results.length);
+ assertEquals(8, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatUnixLineTerminatedStringReturnsNonEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder();
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string\n".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string", results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatWindowsLineTerminatedStringReturnsNonEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder();
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string\r\n".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string", results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatContextIsMaintainedBetweenMessages() {
+ TextLineDecoder decoder = new TextLineDecoder();
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string\na".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string", results[0]);
+ assertEquals(1, context.getBuffer().position());
+ results = decoder.decode(ByteBuffer.wrap(" string\n".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string", results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatUnixLineTerminatedLongStringReturnsNonEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder();
+ Context context = decoder.createDecoderState();
+ StringBuffer sb = new StringBuffer();
+ for(int i=0; i < 100;++i) {
+ sb.append("a string");
+ }
+ String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\n").getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals(sb.toString(), results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatWindowsLineTerminatedLongStringReturnsNonEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder();
+ Context context = decoder.createDecoderState();
+ StringBuffer sb = new StringBuffer();
+ for(int i=0; i < 100;++i) {
+ sb.append("a string");
+ }
+ String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\r\n").getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals(sb.toString(), results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/test/java/org/apache/mina/codec/textline/UnixTextLineDecoderTest.java
----------------------------------------------------------------------
diff --git a/codec/src/test/java/org/apache/mina/codec/textline/UnixTextLineDecoderTest.java b/codec/src/test/java/org/apache/mina/codec/textline/UnixTextLineDecoderTest.java
new file mode 100644
index 0000000..2023187
--- /dev/null
+++ b/codec/src/test/java/org/apache/mina/codec/textline/UnixTextLineDecoderTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.textline;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.codec.textline.TextLineDecoder.Context;
+import org.junit.Test;
+
+/**
+ * A {@link TextLineDecoder} test.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class UnixTextLineDecoderTest {
+
+ @Test
+ public void testThatEmptyBufferReturnsEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.allocate(0), context);
+ assertNotNull(results);
+ assertEquals(0, results.length);
+ }
+
+ @Test
+ public void testThatNonLineTerminatedStringReturnsEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(0, results.length);
+ assertEquals(8, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatUnixLineTerminatedStringReturnsNonEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string\n".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string", results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatWindowsLineTerminatedStringReturnsNonEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string\r\n".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string\r", results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatContextIsMaintainedBetweenMessages() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string\na".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string", results[0]);
+ assertEquals(1, context.getBuffer().position());
+ results = decoder.decode(ByteBuffer.wrap(" string\n".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string", results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatUnixLineTerminatedLongStringReturnsNonEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
+ Context context = decoder.createDecoderState();
+ StringBuffer sb = new StringBuffer();
+ for(int i=0; i < 100;++i) {
+ sb.append("a string");
+ }
+ String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\n").getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals(sb.toString(), results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatWindowsLineTerminatedLongStringReturnsNonEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
+ Context context = decoder.createDecoderState();
+ StringBuffer sb = new StringBuffer();
+ for(int i=0; i < 100;++i) {
+ sb.append("a string");
+ }
+ String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\r\n").getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals(sb.toString() + "\r", results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/test/java/org/apache/mina/codec/textline/WindowsTextLineDecoderTest.java
----------------------------------------------------------------------
diff --git a/codec/src/test/java/org/apache/mina/codec/textline/WindowsTextLineDecoderTest.java b/codec/src/test/java/org/apache/mina/codec/textline/WindowsTextLineDecoderTest.java
new file mode 100644
index 0000000..727fd17
--- /dev/null
+++ b/codec/src/test/java/org/apache/mina/codec/textline/WindowsTextLineDecoderTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.textline;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.apache.mina.codec.textline.TextLineDecoder.Context;
+import org.junit.Test;
+
+/**
+ * A {@link TextLineDecoder} test.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class WindowsTextLineDecoderTest {
+
+ @Test
+ public void testThatEmptyBufferReturnsEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.allocate(0), context);
+ assertNotNull(results);
+ assertEquals(0, results.length);
+ }
+
+ @Test
+ public void testThatNonLineTerminatedStringReturnsEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(0, results.length);
+ assertEquals(8, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatUnixLineTerminatedStringReturnsEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string\n".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(0, results.length);
+ assertEquals(9, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatWindowsLineTerminatedStringReturnsNonEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string\r\n".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string", results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatContextIsMaintainedBetweenMessages() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
+ Context context = decoder.createDecoderState();
+ String[] results = decoder.decode(ByteBuffer.wrap("a string\r\na".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string", results[0]);
+ assertEquals(1, context.getBuffer().position());
+ results = decoder.decode(ByteBuffer.wrap(" string\r\n".getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals("a string", results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatUnixLineTerminatedLongStringReturnsEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
+ Context context = decoder.createDecoderState();
+ StringBuffer sb = new StringBuffer();
+ for(int i=0; i < 100;++i) {
+ sb.append("a string");
+ }
+ String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\n").getBytes()), context);
+ assertNotNull(results);
+ assertEquals(0, results.length);
+ assertEquals(801, context.getBuffer().position());
+ }
+
+ @Test
+ public void testThatWindowsLineTerminatedLongStringReturnsNonEmptyResult() {
+ TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
+ Context context = decoder.createDecoderState();
+ StringBuffer sb = new StringBuffer();
+ for(int i=0; i < 100;++i) {
+ sb.append("a string");
+ }
+ String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\r\n").getBytes()), context);
+ assertNotNull(results);
+ assertEquals(1, results.length);
+ assertEquals(sb.toString(), results[0]);
+ assertEquals(0, context.getBuffer().position());
+ }
+}
Re: git commit: Added text line coded and related unit tests
Posted by Emmanuel Lécharny <el...@gmail.com>.
A small sugestion :
the DEFAUKT value can be initialized this way :
public static final LineDelimiter DEFAULT = new LineDelimiter(
System.getProperty( "line.separator" ) );
Le 4/7/13 6:22 PM, jeffmaury@apache.org a écrit :
> Updated Branches:
> refs/heads/trunk 2d51d12db -> 653d1a5ff
>
>
> Added text line coded and related unit tests
>
>
> Project: http://git-wip-us.apache.org/repos/asf/mina/repo
> Commit: http://git-wip-us.apache.org/repos/asf/mina/commit/653d1a5f
> Tree: http://git-wip-us.apache.org/repos/asf/mina/tree/653d1a5f
> Diff: http://git-wip-us.apache.org/repos/asf/mina/diff/653d1a5f
>
> Branch: refs/heads/trunk
> Commit: 653d1a5ff37904e4515bc375d24dcb301862dad4
> Parents: 2d51d12
> Author: Jeff MAURY <je...@apache.org>
> Authored: Sun Apr 7 18:21:47 2013 +0200
> Committer: Jeff MAURY <je...@apache.org>
> Committed: Sun Apr 7 18:21:47 2013 +0200
>
> ----------------------------------------------------------------------
> .../apache/mina/codec/textline/LineDelimiter.java | 149 ++++++
> .../mina/codec/textline/TextLineDecoder.java | 407 +++++++++++++++
> .../mina/codec/textline/TextLineEncoder.java | 147 ++++++
> .../codec/textline/AutoTextLineDecoderTest.java | 123 +++++
> .../codec/textline/UnixTextLineDecoderTest.java | 123 +++++
> .../codec/textline/WindowsTextLineDecoderTest.java | 121 +++++
> 6 files changed, 1070 insertions(+), 0 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/main/java/org/apache/mina/codec/textline/LineDelimiter.java
> ----------------------------------------------------------------------
> diff --git a/codec/src/main/java/org/apache/mina/codec/textline/LineDelimiter.java b/codec/src/main/java/org/apache/mina/codec/textline/LineDelimiter.java
> new file mode 100644
> index 0000000..c6f858a
> --- /dev/null
> +++ b/codec/src/main/java/org/apache/mina/codec/textline/LineDelimiter.java
> @@ -0,0 +1,149 @@
> +/*
> + * 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.textline;
> +
> +import java.io.ByteArrayOutputStream;
> +import java.io.PrintWriter;
> +
> +/**
> + * A delimiter which is appended to the end of a text line, such as
> + * <tt>CR/LF</tt>. This class defines default delimiters for various
> + * OS :
> + * <ul>
> + * <li><b>Unix/Linux</b> : LineDelimiter.UNIX ("\n")</li>
> + * <li><b>Windows</b> : LineDelimiter.WINDOWS ("\r\n")</li>
> + * <li><b>MAC</b> : LineDelimiter.MAC ("\r")</li>
> + * </ul>
> + *
> + * @author <a href="http://mina.apache.org">Apache MINA Project</a>
> + */
> +public class LineDelimiter {
> + /** the line delimiter constant of the current O/S. */
> + public static final LineDelimiter DEFAULT;
> +
> + /** Compute the default delimiter on he current OS */
> + static {
> + ByteArrayOutputStream bout = new ByteArrayOutputStream();
> + PrintWriter out = new PrintWriter(bout, true);
> + out.println();
> + DEFAULT = new LineDelimiter(new String(bout.toByteArray()));
> + }
> +
> + /**
> + * A special line delimiter which is used for auto-detection of
> + * EOL in {@link TextLineDecoder}. If this delimiter is used,
> + * {@link TextLineDecoder} will consider both <tt>'\r'</tt> and
> + * <tt>'\n'</tt> as a delimiter.
> + */
> + public static final LineDelimiter AUTO = new LineDelimiter("");
> +
> + /**
> + * The CRLF line delimiter constant (<tt>"\r\n"</tt>)
> + */
> + public static final LineDelimiter CRLF = new LineDelimiter("\r\n");
> +
> + /**
> + * The line delimiter constant of UNIX (<tt>"\n"</tt>)
> + */
> + public static final LineDelimiter UNIX = new LineDelimiter("\n");
> +
> + /**
> + * The line delimiter constant of MS Windows/DOS (<tt>"\r\n"</tt>)
> + */
> + public static final LineDelimiter WINDOWS = CRLF;
> +
> + /**
> + * The line delimiter constant of Mac OS (<tt>"\r"</tt>)
> + */
> + public static final LineDelimiter MAC = new LineDelimiter("\r");
> +
> + /**
> + * The line delimiter constant for NUL-terminated text protocols
> + * such as Flash XML socket (<tt>"\0"</tt>)
> + */
> + public static final LineDelimiter NUL = new LineDelimiter("\0");
> +
> + /** Stores the selected Line delimiter */
> + private final String value;
> +
> + /**
> + * Creates a new line delimiter with the specified <tt>value</tt>.
> + */
> + public LineDelimiter(String value) {
> + if (value == null) {
> + throw new IllegalArgumentException("delimiter");
> + }
> +
> + this.value = value;
> + }
> +
> + /**
> + * Return the delimiter string.
> + */
> + public String getValue() {
> + return value;
> + }
> +
> + /**
> + * {@inheritDoc}
> + */
> + @Override
> + public int hashCode() {
> + return value.hashCode();
> + }
> +
> + /**
> + * {@inheritDoc}
> + */
> + @Override
> + public boolean equals(Object o) {
> + if (this == o) {
> + return true;
> + }
> +
> + if (!(o instanceof LineDelimiter)) {
> + return false;
> + }
> +
> + LineDelimiter that = (LineDelimiter) o;
> +
> + return this.value.equals(that.value);
> + }
> +
> + /**
> + * {@inheritDoc}
> + */
> + @Override
> + public String toString() {
> + if (value.length() == 0) {
> + return "delimiter: auto";
> + } else {
> + StringBuilder buf = new StringBuilder();
> + buf.append("delimiter:");
> +
> + for (int i = 0; i < value.length(); i++) {
> + buf.append(" 0x");
> + buf.append(Integer.toHexString(value.charAt(i)));
> + }
> +
> + return buf.toString();
> + }
> + }
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/main/java/org/apache/mina/codec/textline/TextLineDecoder.java
> ----------------------------------------------------------------------
> diff --git a/codec/src/main/java/org/apache/mina/codec/textline/TextLineDecoder.java b/codec/src/main/java/org/apache/mina/codec/textline/TextLineDecoder.java
> new file mode 100644
> index 0000000..845ee24
> --- /dev/null
> +++ b/codec/src/main/java/org/apache/mina/codec/textline/TextLineDecoder.java
> @@ -0,0 +1,407 @@
> +/*
> + * 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.textline;
> +
> +import java.nio.ByteBuffer;
> +import java.nio.CharBuffer;
> +import java.nio.charset.CharacterCodingException;
> +import java.nio.charset.Charset;
> +import java.nio.charset.CharsetDecoder;
> +import java.util.ArrayList;
> +import java.util.List;
> +
> +import org.apache.mina.codec.ProtocolDecoder;
> +
> +/**
> + * A {@link ProtocolDecoder} which decodes a text line into a string.
> + *
> + * @author <a href="http://mina.apache.org">Apache MINA Project</a>
> + */
> +public class TextLineDecoder implements ProtocolDecoder<ByteBuffer, String, TextLineDecoder.Context> {
> + private final Charset charset;
> +
> + /** The delimiter used to determinate when a line has been fully decoded */
> + private final LineDelimiter delimiter;
> +
> + /** An ByteBuffer containing the delimiter */
> + private ByteBuffer delimBuf;
> +
> + /** The default maximum Line length. Default to 1024. */
> + private int maxLineLength = 1024;
> +
> + /** The default maximum buffer length. Default to 128 chars. */
> + private int bufferLength = 128;
> +
> + /**
> + * Creates a new instance with the current default {@link Charset}
> + * and {@link LineDelimiter#AUTO} delimiter.
> + */
> + public TextLineDecoder() {
> + this(LineDelimiter.AUTO);
> + }
> +
> + /**
> + * Creates a new instance with the current default {@link Charset}
> + * and the specified <tt>delimiter</tt>.
> + */
> + public TextLineDecoder(String delimiter) {
> + this(new LineDelimiter(delimiter));
> + }
> +
> + /**
> + * Creates a new instance with the current default {@link Charset}
> + * and the specified <tt>delimiter</tt>.
> + */
> + public TextLineDecoder(LineDelimiter delimiter) {
> + this(Charset.defaultCharset(), delimiter);
> + }
> +
> + /**
> + * Creates a new instance with the spcified <tt>charset</tt>
> + * and {@link LineDelimiter#AUTO} delimiter.
> + */
> + public TextLineDecoder(Charset charset) {
> + this(charset, LineDelimiter.AUTO);
> + }
> +
> + /**
> + * Creates a new instance with the spcified <tt>charset</tt>
> + * and the specified <tt>delimiter</tt>.
> + */
> + public TextLineDecoder(Charset charset, String delimiter) {
> + this(charset, new LineDelimiter(delimiter));
> + }
> +
> + /**
> + * Creates a new instance with the specified <tt>charset</tt>
> + * and the specified <tt>delimiter</tt>.
> + */
> + public TextLineDecoder(Charset charset, LineDelimiter delimiter) {
> + if (charset == null) {
> + throw new IllegalArgumentException("charset parameter shuld not be null");
> + }
> +
> + if (delimiter == null) {
> + throw new IllegalArgumentException("delimiter parameter should not be null");
> + }
> +
> + this.charset = charset;
> + this.delimiter = delimiter;
> +
> + // Convert delimiter to ByteBuffer if not done yet.
> + if (delimBuf == null) {
> + ByteBuffer tmp = charset.encode(CharBuffer.wrap(delimiter.getValue()));
> + tmp.rewind();
> + delimBuf = tmp;
> + }
> + }
> +
> + /**
> + * Returns the allowed maximum size of the line to be decoded.
> + * If the size of the line to be decoded exceeds this value, the
> + * decoder will throw a {@link BufferDataException}. The default
> + * value is <tt>1024</tt> (1KB).
> + */
> + public int getMaxLineLength() {
> + return maxLineLength;
> + }
> +
> + /**
> + * Sets the allowed maximum size of the line to be decoded.
> + * If the size of the line to be decoded exceeds this value, the
> + * decoder will throw a {@link BufferDataException}. The default
> + * value is <tt>1024</tt> (1KB).
> + */
> + public void setMaxLineLength(int maxLineLength) {
> + if (maxLineLength <= 0) {
> + throw new IllegalArgumentException("maxLineLength (" + maxLineLength + ") should be a positive value");
> + }
> +
> + this.maxLineLength = maxLineLength;
> + }
> +
> + /**
> + * Sets the default buffer size. This buffer is used in the Context
> + * to store the decoded line.
> + *
> + * @param bufferLength The default bufer size
> + */
> + public void setBufferLength(int bufferLength) {
> + if (bufferLength <= 0) {
> + throw new IllegalArgumentException("bufferLength (" + maxLineLength + ") should be a positive value");
> +
> + }
> +
> + this.bufferLength = bufferLength;
> + }
> +
> + /**
> + * Returns the allowed buffer size used to store the decoded line
> + * in the Context instance.
> + */
> + public int getBufferLength() {
> + return bufferLength;
> + }
> +
> + @Override
> + public Context createDecoderState() {
> + return new Context(bufferLength);
> + }
> +
> + /**
> + * {@inheritDoc}
> + */
> + public String[] decode(ByteBuffer in, Context ctx) {
> + if (LineDelimiter.AUTO.equals(delimiter)) {
> + return decodeAuto(ctx, in);
> + } else {
> + return decodeNormal(ctx, in);
> + }
> + }
> +
> + /**
> + * {@inheritDoc}
> + */
> + public void finishDecode(Context ctx) {
> + }
> +
> + /**
> + * Decode a line using the default delimiter on the current system
> + */
> + private String[] decodeAuto(Context ctx, ByteBuffer in) {
> + List<String> decoded = new ArrayList<String>();
> + int matchCount = ctx.getMatchCount();
> +
> + // Try to find a match
> + int oldPos = in.position();
> + int oldLimit = in.limit();
> +
> + while (in.hasRemaining()) {
> + byte b = in.get();
> + boolean matched = false;
> +
> + switch (b) {
> + case '\r':
> + // Might be Mac, but we don't auto-detect Mac EOL
> + // to avoid confusion.
> + matchCount++;
> + break;
> +
> + case '\n':
> + // UNIX
> + matchCount++;
> + matched = true;
> + break;
> +
> + default:
> + matchCount = 0;
> + }
> +
> + if (matched) {
> + // Found a match.
> + int pos = in.position();
> + in.limit(pos);
> + in.position(oldPos);
> +
> + ctx.append(in);
> +
> + in.limit(oldLimit);
> + in.position(pos);
> +
> + try {
> + if (ctx.getOverflowLength() == 0) {
> + ByteBuffer buf = ctx.getBuffer();
> + buf.flip();
> + buf.limit(buf.limit() - matchCount);
> +
> + CharsetDecoder decoder = ctx.getDecoder();
> + CharBuffer buffer = decoder.decode(buf);
> + String str = new String(buffer.array());
> + decoded.add(str);
> + } else {
> + int overflowPosition = ctx.getOverflowLength();
> + throw new IllegalStateException("Line is too long: " + overflowPosition);
> + }
> + } catch (CharacterCodingException cce) {
> + throw new RuntimeException(cce);
> + } finally {
> + ctx.reset();
> + }
> + oldPos = pos;
> + matchCount = 0;
> + }
> + }
> +
> + // Put remainder to buf.
> + in.position(oldPos);
> + ctx.append(in);
> +
> + ctx.setMatchCount(matchCount);
> + return decoded.toArray(new String[decoded.size()]);
> + }
> +
> + /**
> + * Decode a line using the delimiter defined by the caller
> + * @return
> + */
> + private String[] decodeNormal(Context ctx, ByteBuffer in) {
> + List<String> decoded = new ArrayList<String>();
> + int matchCount = ctx.getMatchCount();
> +
> + // Try to find a match
> + int oldPos = in.position();
> + int oldLimit = in.limit();
> +
> + while (in.hasRemaining()) {
> + byte b = in.get();
> +
> + if (delimBuf.get(matchCount) == b) {
> + matchCount++;
> +
> + if (matchCount == delimBuf.limit()) {
> + // Found a match.
> + int pos = in.position();
> + in.limit(pos);
> + in.position(oldPos);
> +
> + ctx.append(in);
> +
> + in.limit(oldLimit);
> + in.position(pos);
> +
> + try {
> + if (ctx.getOverflowLength() == 0) {
> + ByteBuffer buf = ctx.getBuffer();
> + buf.flip();
> + buf.limit(buf.limit() - matchCount);
> +
> + CharsetDecoder decoder = ctx.getDecoder();
> + CharBuffer buffer = decoder.decode(buf);
> + String str = new String(buffer.array());
> + decoded.add(str);
> + } else {
> + int overflowLength = ctx.getOverflowLength();
> + throw new IllegalStateException("Line is too long: " + overflowLength);
> + }
> + } catch (CharacterCodingException cce) {
> + throw new RuntimeException(cce);
> + } finally {
> + ctx.reset();
> + }
> +
> +
> + oldPos = pos;
> + matchCount = 0;
> + }
> + } else {
> + // fix for DIRMINA-506 & DIRMINA-536
> + in.position(Math.max(0, in.position() - matchCount));
> + matchCount = 0;
> + }
> + }
> +
> + // Put remainder to buf.
> + in.position(oldPos);
> + ctx.append(in);
> +
> + ctx.setMatchCount(matchCount);
> + return decoded.toArray(new String[decoded.size()]);
> + }
> +
> + /**
> + * A Context used during the decoding of a lin. It stores the decoder,
> + * the temporary buffer containing the decoded line, and other status flags.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
> + * @version $Rev$, $Date$
> + */
> + public class Context {
> + /** The decoder */
> + private final CharsetDecoder decoder;
> +
> + /** The temporary buffer containing the decoded line */
> + private ByteBuffer buf;
> +
> + /** The number of lines found so far */
> + private int matchCount = 0;
> +
> + /**
> + * Overflow length
> + */
> + private int overflowLength = 0;
> +
> + /** Create a new Context object with a default buffer */
> + private Context(int bufferLength) {
> + decoder = charset.newDecoder();
> + buf = ByteBuffer.allocate(bufferLength);
> + }
> +
> + public CharsetDecoder getDecoder() {
> + return decoder;
> + }
> +
> + public ByteBuffer getBuffer() {
> + return buf;
> + }
> +
> + public int getMatchCount() {
> + return matchCount;
> + }
> +
> + public void setMatchCount(int matchCount) {
> + this.matchCount = matchCount;
> + }
> +
> + public int getOverflowLength() {
> + return overflowLength;
> + }
> +
> + public void reset() {
> + overflowLength = 0;
> + matchCount = 0;
> + decoder.reset();
> + buf.clear();
> + }
> +
> + private void ensureSpace(int size) {
> + if (buf.position() + size > buf.capacity()) {
> + ByteBuffer b = ByteBuffer.allocate(buf.position() + size + bufferLength);
> + buf.flip();
> + b.put(buf);
> + buf = b;
> + }
> + }
> + public void append(ByteBuffer in) {
> + if (buf.position() > maxLineLength - in.remaining()) {
> + overflowLength = buf.position() + in.remaining();
> + buf.clear();
> + discard(in);
> + } else {
> + ensureSpace(in.remaining());
> + getBuffer().put(in);
> + }
> + }
> +
> + private void discard(ByteBuffer in) {
> + in.position(in.limit());
> + }
> + }
> +
> +}
> \ No newline at end of file
>
> http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/main/java/org/apache/mina/codec/textline/TextLineEncoder.java
> ----------------------------------------------------------------------
> diff --git a/codec/src/main/java/org/apache/mina/codec/textline/TextLineEncoder.java b/codec/src/main/java/org/apache/mina/codec/textline/TextLineEncoder.java
> new file mode 100644
> index 0000000..6ce02c3
> --- /dev/null
> +++ b/codec/src/main/java/org/apache/mina/codec/textline/TextLineEncoder.java
> @@ -0,0 +1,147 @@
> +/*
> + * 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.textline;
> +
> +import java.nio.ByteBuffer;
> +import java.nio.CharBuffer;
> +import java.nio.charset.CharacterCodingException;
> +import java.nio.charset.Charset;
> +import java.nio.charset.CharsetEncoder;
> +
> +import org.apache.mina.codec.ProtocolEncoder;
> +import org.apache.mina.codec.StatelessProtocolEncoder;
> +
> +
> +/**
> + * A {@link ProtocolEncoder} which encodes a string into a text line
> + * which ends with the delimiter.
> + *
> + * @author <a href="http://mina.apache.org">Apache MINA Project</a>
> + */
> +public class TextLineEncoder implements StatelessProtocolEncoder<String, ByteBuffer> {
> + private final CharsetEncoder charsetEncoder;
> +
> + private final LineDelimiter delimiter;
> +
> + private int maxLineLength = Integer.MAX_VALUE;
> +
> + /**
> + * Creates a new instance with the current default {@link Charset}
> + * and {@link LineDelimiter#UNIX} delimiter.
> + */
> + public TextLineEncoder() {
> + this(Charset.defaultCharset(), LineDelimiter.UNIX);
> + }
> +
> + /**
> + * Creates a new instance with the current default {@link Charset}
> + * and the specified <tt>delimiter</tt>.
> + */
> + public TextLineEncoder(String delimiter) {
> + this(new LineDelimiter(delimiter));
> + }
> +
> + /**
> + * Creates a new instance with the current default {@link Charset}
> + * and the specified <tt>delimiter</tt>.
> + */
> + public TextLineEncoder(LineDelimiter delimiter) {
> + this(Charset.defaultCharset(), delimiter);
> + }
> +
> + /**
> + * Creates a new instance with the spcified <tt>charset</tt>
> + * and {@link LineDelimiter#UNIX} delimiter.
> + */
> + public TextLineEncoder(Charset charset) {
> + this(charset, LineDelimiter.UNIX);
> + }
> +
> + /**
> + * Creates a new instance with the spcified <tt>charset</tt>
> + * and the specified <tt>delimiter</tt>.
> + */
> + public TextLineEncoder(Charset charset, String delimiter) {
> + this(charset, new LineDelimiter(delimiter));
> + }
> +
> + /**
> + * Creates a new instance with the spcified <tt>charset</tt>
> + * and the specified <tt>delimiter</tt>.
> + */
> + public TextLineEncoder(Charset charset, LineDelimiter delimiter) {
> + if (charset == null) {
> + throw new IllegalArgumentException("charset");
> + }
> + if (delimiter == null) {
> + throw new IllegalArgumentException("delimiter");
> + }
> + if (LineDelimiter.AUTO.equals(delimiter)) {
> + throw new IllegalArgumentException("AUTO delimiter is not allowed for encoder.");
> + }
> +
> + this.charsetEncoder = charset.newEncoder();
> + this.delimiter = delimiter;
> + }
> +
> + /**
> + * Returns the allowed maximum size of the encoded line.
> + * If the size of the encoded line exceeds this value, the encoder
> + * will throw a {@link IllegalArgumentException}. The default value
> + * is {@link Integer#MAX_VALUE}.
> + */
> + public int getMaxLineLength() {
> + return maxLineLength;
> + }
> +
> + /**
> + * Sets the allowed maximum size of the encoded line.
> + * If the size of the encoded line exceeds this value, the encoder
> + * will throw a {@link IllegalArgumentException}. The default value
> + * is {@link Integer#MAX_VALUE}.
> + */
> + public void setMaxLineLength(int maxLineLength) {
> + if (maxLineLength <= 0) {
> + throw new IllegalArgumentException("maxLineLength: " + maxLineLength);
> + }
> +
> + this.maxLineLength = maxLineLength;
> + }
> +
> + @Override
> + public Void createEncoderState() {
> + return null;
> + }
> +
> + @Override
> + public ByteBuffer encode(String message, Void context) {
> + try {
> + String value = (message == null ? "" : message);
> +
> + if (value.length() > maxLineLength) {
> + throw new IllegalArgumentException("Line length: " + message.length());
> + }
> + return charsetEncoder.encode(CharBuffer.wrap(value).append(CharBuffer.wrap(delimiter.getValue())));
> + } catch (CharacterCodingException e) {
> + throw new RuntimeException(e);
> + }
> + }
> +
> +}
> \ No newline at end of file
>
> http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/test/java/org/apache/mina/codec/textline/AutoTextLineDecoderTest.java
> ----------------------------------------------------------------------
> diff --git a/codec/src/test/java/org/apache/mina/codec/textline/AutoTextLineDecoderTest.java b/codec/src/test/java/org/apache/mina/codec/textline/AutoTextLineDecoderTest.java
> new file mode 100644
> index 0000000..ca087c4
> --- /dev/null
> +++ b/codec/src/test/java/org/apache/mina/codec/textline/AutoTextLineDecoderTest.java
> @@ -0,0 +1,123 @@
> +/*
> + * 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.textline;
> +
> +import static org.junit.Assert.assertEquals;
> +import static org.junit.Assert.assertNotNull;
> +
> +import java.nio.ByteBuffer;
> +
> +import org.apache.mina.codec.textline.TextLineDecoder.Context;
> +import org.junit.Test;
> +
> +/**
> + * A {@link TextLineDecoder} test.
> + *
> + * @author <a href="http://mina.apache.org">Apache MINA Project</a>
> + */
> +public class AutoTextLineDecoderTest {
> +
> + @Test
> + public void testThatEmptyBufferReturnsEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder();
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.allocate(0), context);
> + assertNotNull(results);
> + assertEquals(0, results.length);
> + }
> +
> + @Test
> + public void testThatNonLineTerminatedStringReturnsEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder();
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(0, results.length);
> + assertEquals(8, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatUnixLineTerminatedStringReturnsNonEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder();
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string\n".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string", results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatWindowsLineTerminatedStringReturnsNonEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder();
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string\r\n".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string", results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatContextIsMaintainedBetweenMessages() {
> + TextLineDecoder decoder = new TextLineDecoder();
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string\na".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string", results[0]);
> + assertEquals(1, context.getBuffer().position());
> + results = decoder.decode(ByteBuffer.wrap(" string\n".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string", results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatUnixLineTerminatedLongStringReturnsNonEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder();
> + Context context = decoder.createDecoderState();
> + StringBuffer sb = new StringBuffer();
> + for(int i=0; i < 100;++i) {
> + sb.append("a string");
> + }
> + String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\n").getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals(sb.toString(), results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatWindowsLineTerminatedLongStringReturnsNonEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder();
> + Context context = decoder.createDecoderState();
> + StringBuffer sb = new StringBuffer();
> + for(int i=0; i < 100;++i) {
> + sb.append("a string");
> + }
> + String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\r\n").getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals(sb.toString(), results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/test/java/org/apache/mina/codec/textline/UnixTextLineDecoderTest.java
> ----------------------------------------------------------------------
> diff --git a/codec/src/test/java/org/apache/mina/codec/textline/UnixTextLineDecoderTest.java b/codec/src/test/java/org/apache/mina/codec/textline/UnixTextLineDecoderTest.java
> new file mode 100644
> index 0000000..2023187
> --- /dev/null
> +++ b/codec/src/test/java/org/apache/mina/codec/textline/UnixTextLineDecoderTest.java
> @@ -0,0 +1,123 @@
> +/*
> + * 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.textline;
> +
> +import static org.junit.Assert.assertEquals;
> +import static org.junit.Assert.assertNotNull;
> +
> +import java.nio.ByteBuffer;
> +
> +import org.apache.mina.codec.textline.TextLineDecoder.Context;
> +import org.junit.Test;
> +
> +/**
> + * A {@link TextLineDecoder} test.
> + *
> + * @author <a href="http://mina.apache.org">Apache MINA Project</a>
> + */
> +public class UnixTextLineDecoderTest {
> +
> + @Test
> + public void testThatEmptyBufferReturnsEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.allocate(0), context);
> + assertNotNull(results);
> + assertEquals(0, results.length);
> + }
> +
> + @Test
> + public void testThatNonLineTerminatedStringReturnsEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(0, results.length);
> + assertEquals(8, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatUnixLineTerminatedStringReturnsNonEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string\n".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string", results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatWindowsLineTerminatedStringReturnsNonEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string\r\n".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string\r", results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatContextIsMaintainedBetweenMessages() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string\na".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string", results[0]);
> + assertEquals(1, context.getBuffer().position());
> + results = decoder.decode(ByteBuffer.wrap(" string\n".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string", results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatUnixLineTerminatedLongStringReturnsNonEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
> + Context context = decoder.createDecoderState();
> + StringBuffer sb = new StringBuffer();
> + for(int i=0; i < 100;++i) {
> + sb.append("a string");
> + }
> + String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\n").getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals(sb.toString(), results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatWindowsLineTerminatedLongStringReturnsNonEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.UNIX);
> + Context context = decoder.createDecoderState();
> + StringBuffer sb = new StringBuffer();
> + for(int i=0; i < 100;++i) {
> + sb.append("a string");
> + }
> + String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\r\n").getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals(sb.toString() + "\r", results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina/blob/653d1a5f/codec/src/test/java/org/apache/mina/codec/textline/WindowsTextLineDecoderTest.java
> ----------------------------------------------------------------------
> diff --git a/codec/src/test/java/org/apache/mina/codec/textline/WindowsTextLineDecoderTest.java b/codec/src/test/java/org/apache/mina/codec/textline/WindowsTextLineDecoderTest.java
> new file mode 100644
> index 0000000..727fd17
> --- /dev/null
> +++ b/codec/src/test/java/org/apache/mina/codec/textline/WindowsTextLineDecoderTest.java
> @@ -0,0 +1,121 @@
> +/*
> + * 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.textline;
> +
> +import static org.junit.Assert.assertEquals;
> +import static org.junit.Assert.assertNotNull;
> +
> +import java.nio.ByteBuffer;
> +
> +import org.apache.mina.codec.textline.TextLineDecoder.Context;
> +import org.junit.Test;
> +
> +/**
> + * A {@link TextLineDecoder} test.
> + *
> + * @author <a href="http://mina.apache.org">Apache MINA Project</a>
> + */
> +public class WindowsTextLineDecoderTest {
> +
> + @Test
> + public void testThatEmptyBufferReturnsEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.allocate(0), context);
> + assertNotNull(results);
> + assertEquals(0, results.length);
> + }
> +
> + @Test
> + public void testThatNonLineTerminatedStringReturnsEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(0, results.length);
> + assertEquals(8, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatUnixLineTerminatedStringReturnsEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string\n".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(0, results.length);
> + assertEquals(9, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatWindowsLineTerminatedStringReturnsNonEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string\r\n".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string", results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatContextIsMaintainedBetweenMessages() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
> + Context context = decoder.createDecoderState();
> + String[] results = decoder.decode(ByteBuffer.wrap("a string\r\na".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string", results[0]);
> + assertEquals(1, context.getBuffer().position());
> + results = decoder.decode(ByteBuffer.wrap(" string\r\n".getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals("a string", results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatUnixLineTerminatedLongStringReturnsEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
> + Context context = decoder.createDecoderState();
> + StringBuffer sb = new StringBuffer();
> + for(int i=0; i < 100;++i) {
> + sb.append("a string");
> + }
> + String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\n").getBytes()), context);
> + assertNotNull(results);
> + assertEquals(0, results.length);
> + assertEquals(801, context.getBuffer().position());
> + }
> +
> + @Test
> + public void testThatWindowsLineTerminatedLongStringReturnsNonEmptyResult() {
> + TextLineDecoder decoder = new TextLineDecoder(LineDelimiter.WINDOWS);
> + Context context = decoder.createDecoderState();
> + StringBuffer sb = new StringBuffer();
> + for(int i=0; i < 100;++i) {
> + sb.append("a string");
> + }
> + String[] results = decoder.decode(ByteBuffer.wrap((sb.toString() + "\r\n").getBytes()), context);
> + assertNotNull(results);
> + assertEquals(1, results.length);
> + assertEquals(sb.toString(), results[0]);
> + assertEquals(0, context.getBuffer().position());
> + }
> +}
>
--
Regards,
Cordialement,
Emmanuel Lécharny
www.iktek.com