Return-Path: Delivered-To: apmail-directory-commits-archive@www.apache.org Received: (qmail 74388 invoked from network); 7 Dec 2005 15:49:53 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 7 Dec 2005 15:49:53 -0000 Received: (qmail 24301 invoked by uid 500); 7 Dec 2005 15:49:52 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 24248 invoked by uid 500); 7 Dec 2005 15:49:51 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 24221 invoked by uid 99); 7 Dec 2005 15:49:51 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 07 Dec 2005 07:49:51 -0800 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Wed, 07 Dec 2005 07:49:49 -0800 Received: (qmail 74053 invoked by uid 65534); 7 Dec 2005 15:49:29 -0000 Message-ID: <20051207154929.74025.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r354780 - in /directory/network: branches/0.8/src/java/org/apache/mina/common/ trunk/src/examples/org/apache/mina/examples/reverser/ trunk/src/java/org/apache/mina/common/ trunk/src/java/org/apache/mina/filter/codec/textline/ trunk/src/test... Date: Wed, 07 Dec 2005 15:49:24 -0000 To: commits@directory.apache.org From: trustin@apache.org X-Mailer: svnmailer-1.0.5 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: trustin Date: Wed Dec 7 07:49:02 2005 New Revision: 354780 URL: http://svn.apache.org/viewcvs?rev=354780&view=rev Log: Resolved issue: DIRMINA-141 (Infinite loop in ByteBuffer.get/putString()) * Added 1 to expectedLength variable Resovled issue: DIRMINA-142 (Codec for text protocols) * Added TextLineDecoder * Added TextLineEncoder * Added TextLineCodecFactory Added: directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/ directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/LineDelimiter.java (with props) directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineCodecFactory.java (with props) directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java (with props) directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java (with props) directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/ directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineDecoderTest.java (with props) directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineEncoderTest.java (with props) Removed: directory/network/trunk/src/examples/org/apache/mina/examples/reverser/TextLineDecoder.java directory/network/trunk/src/examples/org/apache/mina/examples/reverser/TextLineEncoder.java Modified: directory/network/branches/0.8/src/java/org/apache/mina/common/ByteBuffer.java directory/network/trunk/src/examples/org/apache/mina/examples/reverser/ReverseProtocolHandler.java directory/network/trunk/src/java/org/apache/mina/common/ByteBuffer.java Modified: directory/network/branches/0.8/src/java/org/apache/mina/common/ByteBuffer.java URL: http://svn.apache.org/viewcvs/directory/network/branches/0.8/src/java/org/apache/mina/common/ByteBuffer.java?rev=354780&r1=354779&r2=354780&view=diff ============================================================================== --- directory/network/branches/0.8/src/java/org/apache/mina/common/ByteBuffer.java (original) +++ directory/network/branches/0.8/src/java/org/apache/mina/common/ByteBuffer.java Wed Dec 7 07:49:02 2005 @@ -1092,7 +1092,7 @@ } decoder.reset(); - int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() ); + int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() ) + 1; CharBuffer out = CharBuffer.allocate( expectedLength ); for( ;; ) { @@ -1207,7 +1207,7 @@ } decoder.reset(); - int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() ); + int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() ) + 1; CharBuffer out = CharBuffer.allocate( expectedLength ); for( ;; ) { @@ -1333,7 +1333,7 @@ } CharBuffer in = CharBuffer.wrap( val ); - int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar()); + int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar()) + 1; encoder.reset(); Modified: directory/network/trunk/src/examples/org/apache/mina/examples/reverser/ReverseProtocolHandler.java URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/examples/org/apache/mina/examples/reverser/ReverseProtocolHandler.java?rev=354780&r1=354779&r2=354780&view=diff ============================================================================== --- directory/network/trunk/src/examples/org/apache/mina/examples/reverser/ReverseProtocolHandler.java (original) +++ directory/network/trunk/src/examples/org/apache/mina/examples/reverser/ReverseProtocolHandler.java Wed Dec 7 07:49:02 2005 @@ -23,10 +23,8 @@ import org.apache.mina.common.IoHandlerAdapter; import org.apache.mina.common.IoSession; import org.apache.mina.filter.LoggingFilter; -import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolCodecFilter; -import org.apache.mina.filter.codec.ProtocolDecoder; -import org.apache.mina.filter.codec.ProtocolEncoder; +import org.apache.mina.filter.codec.textline.TextLineCodecFactory; /** * {@link IoHandler} implementation of reverser server protocol. @@ -37,28 +35,13 @@ public class ReverseProtocolHandler extends IoHandlerAdapter { private static IoFilter LOGGING_FILTER = new LoggingFilter(); - - private static ProtocolCodecFactory CODEC_FACTORY = new ProtocolCodecFactory() - { - public ProtocolEncoder getEncoder() - { - // Create a new encoder. - return new TextLineEncoder(); - } - - public ProtocolDecoder getDecoder() - { - // Create a new decoder. - return new TextLineDecoder(); - } - }; - - private static IoFilter CODEC_FILTER = new ProtocolCodecFilter( CODEC_FACTORY ); + private static IoFilter CODEC_FILTER = + new ProtocolCodecFilter( new TextLineCodecFactory() ); public void sessionCreated( IoSession session ) throws Exception { - session.getFilterChain().addLast( "codec", CODEC_FILTER ); session.getFilterChain().addLast( "logger", LOGGING_FILTER ); + session.getFilterChain().addLast( "codec", CODEC_FILTER ); } public void exceptionCaught( IoSession session, Throwable cause ) Modified: directory/network/trunk/src/java/org/apache/mina/common/ByteBuffer.java URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/common/ByteBuffer.java?rev=354780&r1=354779&r2=354780&view=diff ============================================================================== --- directory/network/trunk/src/java/org/apache/mina/common/ByteBuffer.java (original) +++ directory/network/trunk/src/java/org/apache/mina/common/ByteBuffer.java Wed Dec 7 07:49:02 2005 @@ -972,7 +972,7 @@ } decoder.reset(); - int expectedLength = (int) ( remaining() * decoder.averageCharsPerByte() ); + int expectedLength = (int) ( remaining() * decoder.averageCharsPerByte() ) + 1; CharBuffer out = CharBuffer.allocate( expectedLength ); for( ;; ) { @@ -1093,7 +1093,7 @@ } decoder.reset(); - int expectedLength = (int) ( remaining() * decoder.averageCharsPerByte() ); + int expectedLength = (int) ( remaining() * decoder.averageCharsPerByte() ) + 1; CharBuffer out = CharBuffer.allocate( expectedLength ); for( ;; ) { @@ -1145,7 +1145,7 @@ } CharBuffer in = CharBuffer.wrap( val ); - int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar()); + int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar()) + 1; encoder.reset(); @@ -1330,7 +1330,7 @@ limit( end ); decoder.reset(); - int expectedLength = (int) ( remaining() * decoder.averageCharsPerByte() ); + int expectedLength = (int) ( remaining() * decoder.averageCharsPerByte() ) + 1; CharBuffer out = CharBuffer.allocate( expectedLength ); for( ;; ) { @@ -1478,7 +1478,7 @@ } CharBuffer in = CharBuffer.wrap( val ); - int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar()); + int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar()) + 1; skip( prefixLength ); // make a room for the length field int oldPos = position(); Added: directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/LineDelimiter.java URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/LineDelimiter.java?rev=354780&view=auto ============================================================================== --- directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/LineDelimiter.java (added) +++ directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/LineDelimiter.java Wed Dec 7 07:49:02 2005 @@ -0,0 +1,125 @@ +/* + * @(#) $Id$ + * + * Copyright 2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.mina.filter.codec.textline; + +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; + +/** + * A delimiter which is appended to the end of a text line, such as + * CR/LF. + * + * @author The Apache Directory Project (dev@directory.apache.org) + * @version $Rev$, $Date$ + */ +public class LineDelimiter +{ + /** + * the line delimiter constant of the current O/S. + */ + public static final LineDelimiter DEFAULT; + + static + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + PrintWriter out = new PrintWriter( bout ); + 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 '\r' and + * '\n' as a delimiter. + */ + public static final LineDelimiter AUTO = new LineDelimiter( "" ); + + /** + * The line delimiter constant of UNIX ("\n") + */ + public static final LineDelimiter UNIX = new LineDelimiter( "\n" ); + + /** + * The line delimiter constant of MS Windows/DOS ("\r\n") + */ + public static final LineDelimiter WINDOWS = new LineDelimiter( "\r\n" ); + + /** + * The line delimiter constant of Mac OS ("\r") + */ + public static final LineDelimiter MAC = new LineDelimiter( "\r" ); + + private final String value; + + /** + * Creates a new line delimiter with the specified value. + */ + public LineDelimiter( String value ) + { + if( value == null ) + { + throw new NullPointerException( "delimiter" ); + } + this.value = value; + } + + /** + * Return the delimiter string. + */ + public String getValue() + { + return value; + } + + public int hashCode() + { + return value.hashCode(); + } + + public boolean equals( Object o ) + { + if( !( o instanceof LineDelimiter ) ) + { + return false; + } + + LineDelimiter that = ( LineDelimiter ) o; + return this.value.equals( that.value ); + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + buf.append( "delimiter:" ); + if( value.length() == 0 ) + { + buf.append( " auto" ); + } + else + { + for( int i = 0; i < value.length(); i ++ ) + { + buf.append( " 0x" ); + buf.append( Integer.toHexString( value.charAt( i ) ) ); + } + } + return buf.toString(); + } +} Propchange: directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/LineDelimiter.java ------------------------------------------------------------------------------ svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision Added: directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineCodecFactory.java URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineCodecFactory.java?rev=354780&view=auto ============================================================================== --- directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineCodecFactory.java (added) +++ directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineCodecFactory.java Wed Dec 7 07:49:02 2005 @@ -0,0 +1,121 @@ +/* + * @(#) $Id$ + * + * Copyright 2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.mina.filter.codec.textline; + +import java.nio.charset.Charset; + +import org.apache.mina.common.BufferDataException; +import org.apache.mina.filter.codec.ProtocolCodecFactory; +import org.apache.mina.filter.codec.ProtocolDecoder; +import org.apache.mina.filter.codec.ProtocolEncoder; +import org.apache.mina.filter.codec.serialization.ObjectSerializationDecoder; +import org.apache.mina.filter.codec.serialization.ObjectSerializationEncoder; + +/** + * A {@link ProtocolCodecFactory} that serializes and deserializes Java objects. + * This codec is very useful when you have to prototype your application rapidly + * without any specific codec. + * + * @author The Apache Directory Project (dev@directory.apache.org) + * @version $Rev$, $Date$ + */ +public class TextLineCodecFactory implements ProtocolCodecFactory +{ + private final TextLineEncoder encoder; + private final TextLineDecoder decoder; + + /** + * Creates a new instance with the current default {@link Charset}. + */ + public TextLineCodecFactory() + { + this( Charset.defaultCharset() ); + } + + /** + * Creates a new instance with the specified {@link Charset}. + */ + public TextLineCodecFactory( Charset charset ) + { + encoder = new TextLineEncoder( charset, LineDelimiter.WINDOWS ); + decoder = new TextLineDecoder( charset, LineDelimiter.WINDOWS ); + } + + public ProtocolEncoder getEncoder() + { + return encoder; + } + + public ProtocolDecoder getDecoder() + { + return decoder; + } + + /** + * Returns the allowed maximum size of the encoded object. + * If the size of the encoded object exceeds this value, the encoder + * will throw a {@link IllegalArgumentException}. The default value + * is {@link Integer#MAX_VALUE}. + *

+ * This method does the same job with {@link ObjectSerializationEncoder#setMaxObjectSize(int)}. + */ + public int gerEncoderMaxLineLength() + { + return encoder.getMaxLineLength(); + } + + /** + * Sets the allowed maximum size of the encoded object. + * If the size of the encoded object exceeds this value, the encoder + * will throw a {@link IllegalArgumentException}. The default value + * is {@link Integer#MAX_VALUE}. + *

+ * This method does the same job with {@link ObjectSerializationEncoder#setMaxObjectSize(int)}. + */ + public void setEncoderMaxLineLength( int maxLineLength ) + { + encoder.setMaxLineLength( maxLineLength ); + } + + /** + * Returns the allowed maximum size of the object to be decoded. + * If the size of the object to be decoded exceeds this value, the + * decoder will throw a {@link BufferDataException}. The default + * value is 1048576 (1MB). + *

+ * This method does the same job with {@link ObjectSerializationDecoder#getMaxObjectSize()}. + */ + public int gerDecoderMaxLineLength() + { + return decoder.getMaxLineLength(); + } + + /** + * Sets the allowed maximum size of the object to be decoded. + * If the size of the object to be decoded exceeds this value, the + * decoder will throw a {@link BufferDataException}. The default + * value is 1048576 (1MB). + *

+ * This method does the same job with {@link ObjectSerializationDecoder#setMaxObjectSize(int)}. + */ + public void setDecoderMaxLineLength( int maxLineLength ) + { + decoder.setMaxLineLength( maxLineLength ); + } +} Propchange: directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineCodecFactory.java ------------------------------------------------------------------------------ svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision Added: directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java?rev=354780&view=auto ============================================================================== --- directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java (added) +++ directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java Wed Dec 7 07:49:02 2005 @@ -0,0 +1,277 @@ +/* + * @(#) $Id$ + * + * Copyright 2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.mina.filter.codec.textline; + +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; + +import org.apache.mina.common.BufferDataException; +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IoSession; +import org.apache.mina.filter.codec.ProtocolDecoderAdapter; +import org.apache.mina.filter.codec.ProtocolDecoderOutput; + +/** + * Decodes a text line into a string. + * + * @author The Apache Directory Project (dev@directory.apache.org) + * @version $Rev$, $Date$, + */ +public class TextLineDecoder extends ProtocolDecoderAdapter +{ + private static final String CONTEXT = TextLineDecoder.class.getName() + ".context"; + + private final Charset charset; + private final LineDelimiter delimiter; + private ByteBuffer delimBuf; + private int maxLineLength = 1024; + + public TextLineDecoder() + { + this( Charset.defaultCharset(), LineDelimiter.AUTO ); + } + + public TextLineDecoder( Charset charset ) + { + this( charset, LineDelimiter.AUTO ); + } + + public TextLineDecoder( Charset charset, LineDelimiter delimiter ) + { + if( charset == null ) + { + throw new NullPointerException( "charset" ); + } + if( delimiter == null ) + { + throw new NullPointerException( "delimiter" ); + } + + this.charset = charset; + this.delimiter = delimiter; + } + + /** + * Returns the allowed maximum size of the line to be encoded. + * If the length of the line to be encoded exceeds this value, this + * decoder will throw a {@link BufferDataException}. The default + * value is 1024 (1KB). + */ + public int getMaxLineLength() + { + return maxLineLength; + } + + /** + * Sets the allowed maximum size of the object to be decoded. + * If the size of the object to be decoded exceeds this value, this + * decoder will throw a {@link BufferDataException}. The default + * value is 1024 (1KB). + */ + public void setMaxLineLength( int maxLineLength ) + { + if( maxLineLength <= 0 ) + { + throw new IllegalArgumentException( "maxLineLength: " + maxLineLength ); + } + + this.maxLineLength = maxLineLength; + } + + public void decode( IoSession session, ByteBuffer in, + ProtocolDecoderOutput out ) + throws Exception + { + Context ctx = ( Context ) session.getAttribute( CONTEXT ); + if( ctx == null ) + { + ctx = new Context(); + session.setAttribute( CONTEXT, ctx ); + } + + if( LineDelimiter.AUTO.equals( delimiter ) ) + { + ctx.setMatchCount( + decodeAuto( + in, + ctx.getBuffer(), + ctx.getMatchCount(), + ctx.getDecoder(), + out ) ); + } + else + { + ctx.setMatchCount( + decodeNormal( + in, + ctx.getBuffer(), + ctx.getMatchCount(), + ctx.getDecoder(), + out ) ); + } + } + + private int decodeAuto( ByteBuffer in, ByteBuffer buf, int matchCount, CharsetDecoder decoder, ProtocolDecoderOutput out ) throws CharacterCodingException + { + // Try to find a match + int oldMatchCount = matchCount; + 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 - matchCount + oldMatchCount ); + in.position( oldPos ); + + buf.put( in ); + if( buf.position() > maxLineLength ) + { + throw new BufferDataException( "Line is too long: " + buf.position() ); + } + buf.flip(); + out.write( buf.getString( decoder ) ); + buf.clear(); + + in.limit( oldLimit ); + in.position( pos ); + oldPos = pos; + matchCount = 0; + } + } + + // Put remainder to buf. + in.position( oldPos ); + in.limit( in.limit() - matchCount + oldMatchCount ); + buf.put( in ); + + return matchCount; + } + + private int decodeNormal( ByteBuffer in, ByteBuffer buf, int matchCount, CharsetDecoder decoder, ProtocolDecoderOutput out ) throws CharacterCodingException + { + // Convert delimiter to ByteBuffer if not done yet. + if( delimBuf == null ) + { + ByteBuffer tmp = ByteBuffer.allocate( 2 ).setAutoExpand( true ); + tmp.putString( delimiter.getValue(), charset.newEncoder() ); + tmp.flip(); + delimBuf = tmp; + } + + // Try to find a match + int oldMatchCount = matchCount; + 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 - matchCount + oldMatchCount ); + in.position( oldPos ); + + buf.put( in ); + if( buf.position() > maxLineLength ) + { + throw new BufferDataException( "Line is too long: " + buf.position() ); + } + buf.flip(); + out.write( buf.getString( decoder ) ); + buf.clear(); + + in.limit( oldLimit ); + in.position( pos ); + oldPos = pos; + matchCount = 0; + } + } + else + { + matchCount = 0; + } + } + + // Put remainder to buf. + in.position( oldPos ); + in.limit( in.limit() - matchCount + oldMatchCount ); + buf.put( in ); + + return matchCount; + } + + private class Context + { + private final CharsetDecoder decoder; + private final ByteBuffer buf; + private int matchCount = 0; + + private Context() + { + decoder = charset.newDecoder(); + buf = ByteBuffer.allocate( 80 ).setAutoExpand( true ); + } + + public CharsetDecoder getDecoder() + { + return decoder; + } + + public ByteBuffer getBuffer() + { + return buf; + } + + public int getMatchCount() + { + return matchCount; + } + + public void setMatchCount( int matchCount ) + { + this.matchCount = matchCount; + } + } +} \ No newline at end of file Propchange: directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineDecoder.java ------------------------------------------------------------------------------ svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision Added: directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java?rev=354780&view=auto ============================================================================== --- directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java (added) +++ directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java Wed Dec 7 07:49:02 2005 @@ -0,0 +1,132 @@ +/* + * @(#) $Id$ + * + * Copyright 2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.mina.filter.codec.textline; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; + +import org.apache.mina.common.BufferDataException; +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IoSession; +import org.apache.mina.filter.codec.ProtocolEncoderAdapter; +import org.apache.mina.filter.codec.ProtocolEncoderOutput; + +/** + * Encodes a string into a text line which ends with "\r\n". + * + * @author The Apache Directory Project (dev@directory.apache.org) + * @version $Rev$, $Date$, + */ +public class TextLineEncoder extends ProtocolEncoderAdapter +{ + private static final String ENCODER = TextLineEncoder.class.getName() + ".encoder"; + + private final Charset charset; + private final LineDelimiter delimiter; + private int maxLineLength = 1024; + + public TextLineEncoder() + { + this( Charset.defaultCharset(), LineDelimiter.UNIX ); + } + + public TextLineEncoder( LineDelimiter delimiter ) + { + this( Charset.defaultCharset(), delimiter ); + } + + public TextLineEncoder( Charset charset ) + { + this( charset, LineDelimiter.UNIX ); + } + + public TextLineEncoder( Charset charset, LineDelimiter delimiter ) + { + if( charset == null ) + { + throw new NullPointerException( "charset" ); + } + if( delimiter == null ) + { + throw new NullPointerException( "delimiter" ); + } + if( LineDelimiter.AUTO.equals( delimiter ) ) + { + throw new IllegalArgumentException( "AUTO delimiter is not allowed for encoder." ); + } + + + this.charset = charset; + this.delimiter = delimiter; + } + + /** + * Returns the allowed maximum size of the line to be encoded. + * If the length of the line to be encoded exceeds this value, this + * decoder will throw a {@link BufferDataException}. The default + * value is 1024 (1KB). + */ + public int getMaxLineLength() + { + return maxLineLength; + } + + /** + * Sets the allowed maximum size of the object to be decoded. + * If the size of the object to be decoded exceeds this value, this + * decoder will throw a {@link BufferDataException}. The default + * value is 1024 (1KB). + */ + public void setMaxLineLength( int maxLineLength ) + { + if( maxLineLength <= 0 ) + { + throw new IllegalArgumentException( "maxLineLength: " + maxLineLength ); + } + + this.maxLineLength = maxLineLength; + } + + public void encode( IoSession session, Object message, + ProtocolEncoderOutput out ) + throws Exception + { + CharsetEncoder encoder = ( CharsetEncoder ) session.getAttribute( ENCODER ); + if( encoder == null ) + { + encoder = charset.newEncoder(); + session.setAttribute( ENCODER, encoder ); + } + + String value = message.toString(); + ByteBuffer buf = ByteBuffer.allocate( value.length() ).setAutoExpand( true ); + buf.putString( value, encoder ); + if( buf.position() > maxLineLength ) + { + throw new IllegalArgumentException( "Line length: " + buf.position() ); + } + buf.putString( delimiter.getValue(), encoder ); + buf.flip(); + out.write( buf ); + } + + public void dispose() throws Exception + { + } +} \ No newline at end of file Propchange: directory/network/trunk/src/java/org/apache/mina/filter/codec/textline/TextLineEncoder.java ------------------------------------------------------------------------------ svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision Added: directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineDecoderTest.java URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineDecoderTest.java?rev=354780&view=auto ============================================================================== --- directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineDecoderTest.java (added) +++ directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineDecoderTest.java Wed Dec 7 07:49:02 2005 @@ -0,0 +1,198 @@ +package org.apache.mina.filter.codec.textline; + +import java.net.SocketAddress; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IoFilterChain; +import org.apache.mina.common.IoHandler; +import org.apache.mina.common.IoSession; +import org.apache.mina.common.IoSessionManager; +import org.apache.mina.common.TransportType; +import org.apache.mina.common.support.BaseIoSession; +import org.apache.mina.filter.codec.support.SimpleProtocolDecoderOutput; + +public class TextLineDecoderTest extends TestCase +{ + public static void main( String[] args ) + { + junit.textui.TestRunner.run( TextLineDecoderTest.class ); + } + + public void testNormalDecode() throws Exception + { + TextLineDecoder decoder = + new TextLineDecoder( + Charset.forName( "UTF-8" ), LineDelimiter.WINDOWS ); + + CharsetEncoder encoder = Charset.forName( "UTF-8" ).newEncoder(); + IoSession session = new DummySession(); + SimpleProtocolDecoderOutput out = new SimpleProtocolDecoderOutput(); + ByteBuffer in = ByteBuffer.allocate( 16 ); + + // Test one decode and one output + in.putString( "ABC\r\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 1, out.getMessageQueue().size() ); + Assert.assertEquals( "ABC", out.getMessageQueue().pop() ); + + // Test two decode and one output + in.clear(); + in.putString( "DEF", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 0, out.getMessageQueue().size() ); + in.clear(); + in.putString( "GHI\r\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 1, out.getMessageQueue().size() ); + Assert.assertEquals( "DEFGHI", out.getMessageQueue().pop() ); + + // Test one decode and two output + in.clear(); + in.putString( "JKL\r\nMNO\r\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 2, out.getMessageQueue().size() ); + Assert.assertEquals( "JKL", out.getMessageQueue().pop() ); + Assert.assertEquals( "MNO", out.getMessageQueue().pop() ); + + // Test splitted long delimiter + decoder = new TextLineDecoder( + Charset.forName( "UTF-8" ), + new LineDelimiter( "\n\n\n" ) ); + in.clear(); + in.putString( "PQR\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 0, out.getMessageQueue().size() ); + in.clear(); + in.putString( "\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 0, out.getMessageQueue().size() ); + in.clear(); + in.putString( "\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 1, out.getMessageQueue().size() ); + Assert.assertEquals( "PQR", out.getMessageQueue().pop() ); + } + + public void testAutoDecode() throws Exception + { + TextLineDecoder decoder = + new TextLineDecoder( + Charset.forName( "UTF-8" ), LineDelimiter.AUTO ); + + CharsetEncoder encoder = Charset.forName( "UTF-8" ).newEncoder(); + IoSession session = new DummySession(); + SimpleProtocolDecoderOutput out = new SimpleProtocolDecoderOutput(); + ByteBuffer in = ByteBuffer.allocate( 16 ); + + // Test one decode and one output + in.putString( "ABC\r\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 1, out.getMessageQueue().size() ); + Assert.assertEquals( "ABC", out.getMessageQueue().pop() ); + + // Test two decode and one output + in.clear(); + in.putString( "DEF", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 0, out.getMessageQueue().size() ); + in.clear(); + in.putString( "GHI\r\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 1, out.getMessageQueue().size() ); + Assert.assertEquals( "DEFGHI", out.getMessageQueue().pop() ); + + // Test one decode and two output + in.clear(); + in.putString( "JKL\r\nMNO\r\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 2, out.getMessageQueue().size() ); + Assert.assertEquals( "JKL", out.getMessageQueue().pop() ); + Assert.assertEquals( "MNO", out.getMessageQueue().pop() ); + + // Test multiple '\n's + in.clear(); + in.putString( "\n\n\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 3, out.getMessageQueue().size() ); + Assert.assertEquals( "", out.getMessageQueue().pop() ); + Assert.assertEquals( "", out.getMessageQueue().pop() ); + Assert.assertEquals( "", out.getMessageQueue().pop() ); + + // Test splitted long delimiter (\r\r\n) + in.clear(); + in.putString( "PQR\r", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 0, out.getMessageQueue().size() ); + in.clear(); + in.putString( "\r", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 0, out.getMessageQueue().size() ); + in.clear(); + in.putString( "\n", encoder ); + in.flip(); + decoder.decode( session, in, out ); + Assert.assertEquals( 1, out.getMessageQueue().size() ); + Assert.assertEquals( "PQR", out.getMessageQueue().pop() ); + } + + private static class DummySession extends BaseIoSession + { + protected void updateTrafficMask() + { + } + + public IoSessionManager getManager() + { + return null; + } + + public IoHandler getHandler() + { + return null; + } + + public IoFilterChain getFilterChain() + { + return null; + } + + public TransportType getTransportType() + { + return null; + } + + public SocketAddress getRemoteAddress() + { + return null; + } + + public SocketAddress getLocalAddress() + { + return null; + } + + public int getScheduledWriteRequests() + { + return 0; + } + } +} Propchange: directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineDecoderTest.java ------------------------------------------------------------------------------ svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision Added: directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineEncoderTest.java URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineEncoderTest.java?rev=354780&view=auto ============================================================================== --- directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineEncoderTest.java (added) +++ directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineEncoderTest.java Wed Dec 7 07:49:02 2005 @@ -0,0 +1,92 @@ +package org.apache.mina.filter.codec.textline; + +import java.net.SocketAddress; +import java.nio.charset.Charset; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IoFilterChain; +import org.apache.mina.common.IoHandler; +import org.apache.mina.common.IoSession; +import org.apache.mina.common.IoSessionManager; +import org.apache.mina.common.TransportType; +import org.apache.mina.common.WriteFuture; +import org.apache.mina.common.support.BaseIoSession; +import org.apache.mina.filter.codec.support.SimpleProtocolEncoderOutput; + +public class TextLineEncoderTest extends TestCase +{ + public static void main( String[] args ) + { + junit.textui.TestRunner.run( TextLineEncoderTest.class ); + } + + public void testEncode() throws Exception + { + TextLineEncoder encoder = new TextLineEncoder( + Charset.forName( "UTF-8" ), LineDelimiter.WINDOWS ); + IoSession session = new DummySession(); + SimpleProtocolEncoderOutput out = + new SimpleProtocolEncoderOutput() + { + protected WriteFuture doFlush( ByteBuffer buf ) + { + return null; + } + }; + + encoder.encode( session, "ABC", out ); + Assert.assertEquals( 1, out.getBufferQueue().size() ); + ByteBuffer buf = ( ByteBuffer ) out.getBufferQueue().pop(); + Assert.assertEquals( 5, buf.remaining() ); + Assert.assertEquals( 'A', buf.get() ); + Assert.assertEquals( 'B', buf.get() ); + Assert.assertEquals( 'C', buf.get() ); + Assert.assertEquals( '\r', buf.get() ); + Assert.assertEquals( '\n', buf.get() ); + } + + private static class DummySession extends BaseIoSession + { + protected void updateTrafficMask() + { + } + + public IoSessionManager getManager() + { + return null; + } + + public IoHandler getHandler() + { + return null; + } + + public IoFilterChain getFilterChain() + { + return null; + } + + public TransportType getTransportType() + { + return null; + } + + public SocketAddress getRemoteAddress() + { + return null; + } + + public SocketAddress getLocalAddress() + { + return null; + } + + public int getScheduledWriteRequests() + { + return 0; + } + } +} Propchange: directory/network/trunk/src/test/org/apache/mina/filter/codec/textline/TextLineEncoderTest.java ------------------------------------------------------------------------------ svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision