Coverage report

  %line %branch
org.apache.commons.net.io.DotTerminatedMessageReader
0% 
0% 

 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;
 19  
 import java.io.PushbackReader;
 20  
 import java.io.Reader;
 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
 38  
 {
 39  
     private static final String LS;
 40  
     private static final char[] LS_CHARS;
 41  
 
 42  
     static
 43  
     {
 44  0
         LS = System.getProperty("line.separator");
 45  0
         LS_CHARS = LS.toCharArray();
 46  0
     }
 47  
 
 48  
     private boolean atBeginning;
 49  
     private boolean eof;
 50  
     private int pos;
 51  
     private char[] internalBuffer;
 52  
     private PushbackReader 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 reader)
 60  
     {
 61  0
         super(reader);
 62  0
         internalBuffer = new char[LS_CHARS.length + 3];
 63  0
         pos = internalBuffer.length;
 64  
         // Assumes input is at start of message
 65  0
         atBeginning = true;
 66  0
         eof = false;
 67  0
         internalReader = new PushbackReader(reader);
 68  0
     }
 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
 83  
     {
 84  
         int ch;
 85  
 
 86  0
         synchronized (lock)
 87  
         {
 88  0
             if (pos < internalBuffer.length)
 89  
             {
 90  0
                 return internalBuffer[pos++];
 91  
             }
 92  
 
 93  0
             if (eof)
 94  
             {
 95  0
                 return -1;
 96  
             }
 97  
 
 98  0
             if ((ch = internalReader.read()) == -1)
 99  
             {
 100  0
                 eof = true;
 101  0
                 return -1;
 102  
             }
 103  
 
 104  0
             if (atBeginning)
 105  
             {
 106  0
                 atBeginning = false;
 107  0
                 if (ch == '.')
 108  
                 {
 109  0
                     ch = internalReader.read();
 110  
 
 111  0
                     if (ch != '.')
 112  
                     {
 113  
                         // read newline
 114  0
                         eof = true;
 115  0
                         internalReader.read();
 116  0
                         return -1;
 117  
                     }
 118  
                     else
 119  
                     {
 120  0
                         return '.';
 121  
                     }
 122  
                 }
 123  
             }
 124  
 
 125  0
             if (ch == '\r')
 126  
             {
 127  0
                 ch = internalReader.read();
 128  
 
 129  0
                 if (ch == '\n')
 130  
                 {
 131  0
                     ch = internalReader.read();
 132  
 
 133  0
                     if (ch == '.')
 134  
                     {
 135  0
                         ch = internalReader.read();
 136  
 
 137  0
                         if (ch != '.')
 138  
                         {
 139  
                             // read newline and indicate end of file
 140  0
                             internalReader.read();
 141  0
                             eof = true;
 142  
                         }
 143  
                         else
 144  
                         {
 145  0
                             internalBuffer[--pos] = (char) ch;
 146  
                         }
 147  
                     }
 148  
                     else
 149  
                     {
 150  0
                         internalReader.unread(ch);
 151  
                     }
 152  
 
 153  0
                     pos -= LS_CHARS.length;
 154  0
                     System.arraycopy(LS_CHARS, 0, internalBuffer, pos,
 155  
                                      LS_CHARS.length);
 156  0
                     ch = internalBuffer[pos++];
 157  
                 }
 158  
                 else
 159  
                 {
 160  0
                     internalBuffer[--pos] = (char) ch;
 161  0
                     return '\r';
 162  
                 }
 163  
             }
 164  
 
 165  0
             return ch;
 166  0
         }
 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
 180  
     {
 181  0
         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, class="keyword">int offset, class="keyword">int length) throws IOException
 199  
     {
 200  
         int ch, off;
 201  0
         synchronized (lock)
 202  
         {
 203  0
             if (length < 1)
 204  
             {
 205  0
                 return 0;
 206  
             }
 207  0
             if ((ch = read()) == -1)
 208  
             {
 209  0
                 return -1;
 210  
             }
 211  0
             off = offset;
 212  
 
 213  
             do
 214  
             {
 215  0
                 buffer[offset++] = (char) ch;
 216  
             }
 217  0
             while (--length > 0 && (ch = read()) != -1);
 218  
 
 219  0
             return (offset - off);
 220  0
         }
 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
 230  
     {
 231  0
         synchronized (lock)
 232  
         {
 233  0
             return (pos < internalBuffer.length || internalReader.ready());
 234  0
         }
 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
 252  
     {
 253  0
         synchronized (lock)
 254  
         {
 255  0
             if (internalReader == null)
 256  
             {
 257  0
                 return;
 258  
             }
 259  
 
 260  0
             if (!eof)
 261  
             {
 262  0
                 while (read() != -1)
 263  
                 {
 264  0
                     ;
 265  
                 }
 266  
             }
 267  0
             eof = true;
 268  0
             atBeginning = false;
 269  0
             pos = internalBuffer.length;
 270  0
             internalReader = null;
 271  0
         }
 272  0
     }
 273  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.