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