KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > net > io > DotTerminatedMessageReader


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

16 package org.apache.commons.net.io;
17
18 import java.io.IOException JavaDoc;
19 import java.io.PushbackReader JavaDoc;
20 import java.io.Reader JavaDoc;
21
22 /**
23  * DotTerminatedMessageReader is a class used to read messages from a
24  * server that are terminated by a single dot followed by a
25  * <CR><LF>
26  * sequence and with double dots appearing at the begining of lines which
27  * do not signal end of message yet start with a dot. Various Internet
28  * protocols such as NNTP and POP3 produce messages of this type.
29  * <p>
30  * This class handles stripping of the duplicate period at the beginning
31  * of lines starting with a period, converts NETASCII newlines to the
32  * local line separator format, truncates the end of message indicator,
33  * and ensures you cannot read past the end of the message.
34  * @author <a HREF="mailto:savarese@apache.org">Daniel F. Savarese</a>
35  * @version $Id: DotTerminatedMessageReader.java 165675 2005-05-02 20:09:55Z rwinston $
36  */

37 public final class DotTerminatedMessageReader extends Reader JavaDoc
38 {
39     private static final String JavaDoc LS;
40     private static final char[] LS_CHARS;
41
42     static
43     {
44         LS = System.getProperty("line.separator");
45         LS_CHARS = LS.toCharArray();
46     }
47
48     private boolean atBeginning;
49     private boolean eof;
50     private int pos;
51     private char[] internalBuffer;
52     private PushbackReader JavaDoc internalReader;
53
54     /**
55      * Creates a DotTerminatedMessageReader that wraps an existing Reader
56      * input source.
57      * @param reader The Reader input source containing the message.
58      */

59     public DotTerminatedMessageReader(Reader JavaDoc reader)
60     {
61         super(reader);
62         internalBuffer = new char[LS_CHARS.length + 3];
63         pos = internalBuffer.length;
64         // Assumes input is at start of message
65
atBeginning = true;
66         eof = false;
67         internalReader = new PushbackReader JavaDoc(reader);
68     }
69
70     /**
71      * Reads and returns the next character in the message. If the end of the
72      * message has been reached, returns -1. Note that a call to this method
73      * may result in multiple reads from the underlying input stream to decode
74      * the message properly (removing doubled dots and so on). All of
75      * this is transparent to the programmer and is only mentioned for
76      * completeness.
77      * @return The next character in the message. Returns -1 if the end of the
78      * message has been reached.
79      * @exception IOException If an error occurs while reading the underlying
80      * stream.
81      */

82     public int read() throws IOException JavaDoc
83     {
84         int ch;
85
86         synchronized (lock)
87         {
88             if (pos < internalBuffer.length)
89             {
90                 return internalBuffer[pos++];
91             }
92
93             if (eof)
94             {
95                 return -1;
96             }
97
98             if ((ch = internalReader.read()) == -1)
99             {
100                 eof = true;
101                 return -1;
102             }
103
104             if (atBeginning)
105             {
106                 atBeginning = false;
107                 if (ch == '.')
108                 {
109                     ch = internalReader.read();
110
111                     if (ch != '.')
112                     {
113                         // read newline
114
eof = true;
115                         internalReader.read();
116                         return -1;
117                     }
118                     else
119                     {
120                         return '.';
121                     }
122                 }
123             }
124
125             if (ch == '\r')
126             {
127                 ch = internalReader.read();
128
129                 if (ch == '\n')
130                 {
131                     ch = internalReader.read();
132
133                     if (ch == '.')
134                     {
135                         ch = internalReader.read();
136
137                         if (ch != '.')
138                         {
139                             // read newline and indicate end of file
140
internalReader.read();
141                             eof = true;
142                         }
143                         else
144                         {
145                             internalBuffer[--pos] = (char) ch;
146                         }
147                     }
148                     else
149                     {
150                         internalReader.unread(ch);
151                     }
152
153                     pos -= LS_CHARS.length;
154                     System.arraycopy(LS_CHARS, 0, internalBuffer, pos,
155                                      LS_CHARS.length);
156                     ch = internalBuffer[pos++];
157                 }
158                 else
159                 {
160                     internalBuffer[--pos] = (char) ch;
161                     return '\r';
162                 }
163             }
164
165             return ch;
166         }
167     }
168
169     /**
170      * Reads the next characters from the message into an array and
171      * returns the number of characters read. Returns -1 if the end of the
172      * message has been reached.
173      * @param buffer The character array in which to store the characters.
174      * @return The number of characters read. Returns -1 if the
175      * end of the message has been reached.
176      * @exception IOException If an error occurs in reading the underlying
177      * stream.
178      */

179     public int read(char[] buffer) throws IOException JavaDoc
180     {
181         return read(buffer, 0, buffer.length);
182     }
183
184     /**
185      * Reads the next characters from the message into an array and
186      * returns the number of characters read. Returns -1 if the end of the
187      * message has been reached. The characters are stored in the array
188      * starting from the given offset and up to the length specified.
189      * @param buffer The character array in which to store the characters.
190      * @param offset The offset into the array at which to start storing
191      * characters.
192      * @param length The number of characters to read.
193      * @return The number of characters read. Returns -1 if the
194      * end of the message has been reached.
195      * @exception IOException If an error occurs in reading the underlying
196      * stream.
197      */

198     public int read(char[] buffer, int offset, int length) throws IOException JavaDoc
199     {
200         int ch, off;
201         synchronized (lock)
202         {
203             if (length < 1)
204             {
205                 return 0;
206             }
207             if ((ch = read()) == -1)
208             {
209                 return -1;
210             }
211             off = offset;
212
213             do
214             {
215                 buffer[offset++] = (char) ch;
216             }
217             while (--length > 0 && (ch = read()) != -1);
218
219             return (offset - off);
220         }
221     }
222
223     /**
224      * Determines if the message is ready to be read.
225      * @return True if the message is ready to be read, false if not.
226      * @exception IOException If an error occurs while checking the underlying
227      * stream.
228      */

229     public boolean ready() throws IOException JavaDoc
230     {
231         synchronized (lock)
232         {
233             return (pos < internalBuffer.length || internalReader.ready());
234         }
235     }
236
237     /**
238      * Closes the message for reading. This doesn't actually close the
239      * underlying stream. The underlying stream may still be used for
240      * communicating with the server and therefore is not closed.
241      * <p>
242      * If the end of the message has not yet been reached, this method
243      * will read the remainder of the message until it reaches the end,
244      * so that the underlying stream may continue to be used properly
245      * for communicating with the server. If you do not fully read
246      * a message, you MUST close it, otherwise your program will likely
247      * hang or behave improperly.
248      * @exception IOException If an error occurs while reading the
249      * underlying stream.
250      */

251     public void close() throws IOException JavaDoc
252     {
253         synchronized (lock)
254         {
255             if (internalReader == null)
256             {
257                 return;
258             }
259
260             if (!eof)
261             {
262                 while (read() != -1)
263                 {
264                     ;
265                 }
266             }
267             eof = true;
268             atBeginning = false;
269             pos = internalBuffer.length;
270             internalReader = null;
271         }
272     }
273 }
274
Popular Tags