KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > mina > filter > codec > textline > TextLineDecoder


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  *
19  */

20 package org.apache.mina.filter.codec.textline;
21
22 import java.nio.charset.CharacterCodingException JavaDoc;
23 import java.nio.charset.Charset JavaDoc;
24 import java.nio.charset.CharsetDecoder JavaDoc;
25
26 import org.apache.mina.common.BufferDataException;
27 import org.apache.mina.common.ByteBuffer;
28 import org.apache.mina.common.IoSession;
29 import org.apache.mina.filter.codec.ProtocolDecoder;
30 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
31
32 /**
33  * A {@link ProtocolDecoder} which decodes a text line into a string.
34  *
35  * @author The Apache Directory Project (mina-dev@directory.apache.org)
36  * @version $Rev: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (금, 13 7월 2007) $,
37  */

38 public class TextLineDecoder implements ProtocolDecoder {
39     private static final String JavaDoc CONTEXT = TextLineDecoder.class.getName()
40             + ".context";
41
42     private final Charset JavaDoc charset;
43
44     private final LineDelimiter delimiter;
45
46     private ByteBuffer delimBuf;
47
48     private int maxLineLength = 1024;
49
50     /**
51      * Creates a new instance with the current default {@link Charset}
52      * and {@link LineDelimiter#AUTO} delimiter.
53      */

54     public TextLineDecoder() {
55         this(Charset.defaultCharset(), LineDelimiter.AUTO);
56     }
57
58     /**
59      * Creates a new instance with the spcified <tt>charset</tt>
60      * and {@link LineDelimiter#AUTO} delimiter.
61      */

62     public TextLineDecoder(Charset JavaDoc charset) {
63         this(charset, LineDelimiter.AUTO);
64     }
65
66     /**
67      * Creates a new instance with the specified <tt>charset</tt>
68      * and the specified <tt>delimiter</tt>.
69      */

70     public TextLineDecoder(Charset JavaDoc charset, LineDelimiter delimiter) {
71         if (charset == null) {
72             throw new NullPointerException JavaDoc("charset");
73         }
74         if (delimiter == null) {
75             throw new NullPointerException JavaDoc("delimiter");
76         }
77
78         this.charset = charset;
79         this.delimiter = delimiter;
80     }
81
82     /**
83      * Returns the allowed maximum size of the line to be decoded.
84      * If the size of the line to be decoded exceeds this value, the
85      * decoder will throw a {@link BufferDataException}. The default
86      * value is <tt>1024</tt> (1KB).
87      */

88     public int getMaxLineLength() {
89         return maxLineLength;
90     }
91
92     /**
93      * Sets the allowed maximum size of the line to be decoded.
94      * If the size of the line to be decoded exceeds this value, the
95      * decoder will throw a {@link BufferDataException}. The default
96      * value is <tt>1024</tt> (1KB).
97      */

98     public void setMaxLineLength(int maxLineLength) {
99         if (maxLineLength <= 0) {
100             throw new IllegalArgumentException JavaDoc("maxLineLength: "
101                     + maxLineLength);
102         }
103
104         this.maxLineLength = maxLineLength;
105     }
106
107     public void decode(IoSession session, ByteBuffer in,
108             ProtocolDecoderOutput out) throws Exception JavaDoc {
109         Context ctx = getContext(session);
110
111         if (LineDelimiter.AUTO.equals(delimiter)) {
112             ctx.setMatchCount(decodeAuto(in, ctx.getBuffer(), ctx
113                     .getMatchCount(), ctx.getDecoder(), out));
114         } else {
115             ctx.setMatchCount(decodeNormal(in, ctx.getBuffer(), ctx
116                     .getMatchCount(), ctx.getDecoder(), out));
117         }
118     }
119
120     private Context getContext(IoSession session) {
121         Context ctx = (Context) session.getAttribute(CONTEXT);
122         if (ctx == null) {
123             ctx = new Context();
124             session.setAttribute(CONTEXT, ctx);
125         }
126         return ctx;
127     }
128
129     public void finishDecode(IoSession session, ProtocolDecoderOutput out)
130             throws Exception JavaDoc {
131     }
132
133     public void dispose(IoSession session) throws Exception JavaDoc {
134         Context ctx = (Context) session.getAttribute(CONTEXT);
135         if (ctx != null) {
136             ctx.getBuffer().release();
137             session.removeAttribute(CONTEXT);
138         }
139     }
140
141     private int decodeAuto(ByteBuffer in, ByteBuffer buf, int matchCount,
142             CharsetDecoder JavaDoc decoder, ProtocolDecoderOutput out)
143             throws CharacterCodingException JavaDoc {
144         // Try to find a match
145
int oldPos = in.position();
146         int oldLimit = in.limit();
147         while (in.hasRemaining()) {
148             byte b = in.get();
149             boolean matched = false;
150             switch (b) {
151             case '\r':
152                 // Might be Mac, but we don't auto-detect Mac EOL
153
// to avoid confusion.
154
matchCount++;
155                 break;
156             case '\n':
157                 // UNIX
158
matchCount++;
159                 matched = true;
160                 break;
161             default:
162                 matchCount = 0;
163             }
164
165             if (matched) {
166                 // Found a match.
167
int pos = in.position();
168                 in.limit(pos);
169                 in.position(oldPos);
170
171                 buf.put(in);
172                 if (buf.position() > maxLineLength) {
173                     throw new BufferDataException("Line is too long: "
174                             + buf.position());
175                 }
176                 buf.flip();
177                 buf.limit(buf.limit() - matchCount);
178                 out.write(buf.getString(decoder));
179                 buf.clear();
180
181                 in.limit(oldLimit);
182                 in.position(pos);
183                 oldPos = pos;
184                 matchCount = 0;
185             }
186         }
187
188         // Put remainder to buf.
189
in.position(oldPos);
190         buf.put(in);
191
192         return matchCount;
193     }
194
195     private int decodeNormal(ByteBuffer in, ByteBuffer buf, int matchCount,
196             CharsetDecoder JavaDoc decoder, ProtocolDecoderOutput out)
197             throws CharacterCodingException JavaDoc {
198         // Convert delimiter to ByteBuffer if not done yet.
199
if (delimBuf == null) {
200             ByteBuffer tmp = ByteBuffer.allocate(2).setAutoExpand(true);
201             tmp.putString(delimiter.getValue(), charset.newEncoder());
202             tmp.flip();
203             delimBuf = tmp;
204         }
205
206         // Try to find a match
207
int oldPos = in.position();
208         int oldLimit = in.limit();
209         while (in.hasRemaining()) {
210             byte b = in.get();
211             if (delimBuf.get(matchCount) == b) {
212                 matchCount++;
213                 if (matchCount == delimBuf.limit()) {
214                     // Found a match.
215
int pos = in.position();
216                     in.limit(pos);
217                     in.position(oldPos);
218
219                     buf.put(in);
220                     if (buf.position() > maxLineLength) {
221                         throw new BufferDataException("Line is too long: "
222                                 + buf.position());
223                     }
224                     buf.flip();
225                     buf.limit(buf.limit() - matchCount);
226                     out.write(buf.getString(decoder));
227                     buf.clear();
228
229                     in.limit(oldLimit);
230                     in.position(pos);
231                     oldPos = pos;
232                     matchCount = 0;
233                 }
234             } else {
235                 matchCount = 0;
236             }
237         }
238
239         // Put remainder to buf.
240
in.position(oldPos);
241         buf.put(in);
242
243         return matchCount;
244     }
245
246     private class Context {
247         private final CharsetDecoder JavaDoc decoder;
248
249         private final ByteBuffer buf;
250
251         private int matchCount = 0;
252
253         private Context() {
254             decoder = charset.newDecoder();
255             buf = ByteBuffer.allocate(80).setAutoExpand(true);
256         }
257
258         public CharsetDecoder JavaDoc getDecoder() {
259             return decoder;
260         }
261
262         public ByteBuffer getBuffer() {
263             return buf;
264         }
265
266         public int getMatchCount() {
267             return matchCount;
268         }
269
270         public void setMatchCount(int matchCount) {
271             this.matchCount = matchCount;
272         }
273     }
274 }
Popular Tags