View Javadoc

    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.Writer;
    20
    21  /****
    22   * DotTerminatedMessageWriter is a class used to write messages to a
    23   * server that are terminated by a single dot followed by a
    24   * &lt;CR&gt;&lt;LF&gt;
    25   * sequence and with double dots appearing at the begining of lines which
    26   * do not signal end of message yet start with a dot.  Various Internet
    27   * protocols such as NNTP and POP3 produce messages of this type.
    28   * <p>
    29   * This class handles the doubling of line-starting periods,
    30   * converts single linefeeds to NETASCII newlines, and on closing
    31   * will send the final message terminator dot and NETASCII newline
    32   * sequence.
    33   * <p>
    34   * <p>
    35   * @author Daniel F. Savarese
    36   ***/
    37
    38  public final class DotTerminatedMessageWriter extends Writer
    39  {
    40      private static final int __NOTHING_SPECIAL_STATE = 0;
    41      private static final int __LAST_WAS_CR_STATE = 1;
    42      private static final int __LAST_WAS_NL_STATE = 2;
    43
    44      private int __state;
    45      private Writer __output;
    46
    47
    48      /****
    49       * Creates a DotTerminatedMessageWriter that wraps an existing Writer
    50       * output destination.
    51       * <p>
    52       * @param output  The Writer output destination to write the message.
    53       ***/
    54      public DotTerminatedMessageWriter(Writer output)
    55      {
    56          super(output);
    57          __output = output;
    58          __state = __NOTHING_SPECIAL_STATE;
    59      }
    60
    61
    62      /****
    63       * Writes a character to the output.  Note that a call to this method
    64       * may result in multiple writes to the underling Writer in order to
    65       * convert naked linefeeds to NETASCII line separators and to double
    66       * line-leading periods.  This is transparent to the programmer and
    67       * is only mentioned for completeness.
    68       * <p>
    69       * @param ch  The character to write.
    70       * @exception IOException  If an error occurs while writing to the
    71       *            underlying output.
    72       ***/
    73      public void write(int ch) throws IOException
    74      {
    75          synchronized (lock)
    76          {
    77              switch (ch)
    78              {
    79              case '\r':
    80                  __state = __LAST_WAS_CR_STATE;
    81                  __output.write('\r');
    82                  return ;
    83              case '\n':
    84                  if (__state != __LAST_WAS_CR_STATE)
    85                      __output.write('\r');
    86                  __output.write('\n');
    87                  __state = __LAST_WAS_NL_STATE;
    88                  return ;
    89              case '.':
    90                  // Double the dot at the beginning of a line
    91                  if (__state == __LAST_WAS_NL_STATE)
    92                      __output.write('.');
    93                  // Fall through
    94              default:
    95                  __state = __NOTHING_SPECIAL_STATE;
    96                  __output.write(ch);
    97                  return ;
    98              }
    99          }
    100     }
    101
    102
    103     /****
    104      * Writes a number of characters from a character array to the output
    105      * starting from a given offset.
    106      * <p>
    107      * @param buffer  The character array to write.
    108      * @param offset  The offset into the array at which to start copying data.
    109      * @param length  The number of characters to write.
    110      * @exception IOException If an error occurs while writing to the underlying
    111      *            output.
    112      ***/
    113     public void write(char[] buffer, int offset, int length) throws IOException
    114     {
    115         synchronized (lock)
    116         {
    117             while (length-- > 0)
    118                 write(buffer[offset++]);
    119         }
    120     }
    121
    122
    123     /****
    124      * Writes a character array to the output.
    125      * <p>
    126      * @param buffer  The character array to write.
    127      * @exception IOException If an error occurs while writing to the underlying
    128      *            output.
    129      ***/
    130     public void write(char[] buffer) throws IOException
    131     {
    132         write(buffer, 0, buffer.length);
    133     }
    134
    135
    136     /****
    137      * Writes a String to the output.
    138      * <p>
    139      * @param string  The String to write.
    140      * @exception IOException If an error occurs while writing to the underlying
    141      *            output.
    142      ***/
    143     public void write(String string) throws IOException
    144     {
    145         write(string.toCharArray());
    146     }
    147
    148
    149     /****
    150      * Writes part of a String to the output starting from a given offset.
    151      * <p>
    152      * @param string  The String to write.
    153      * @param offset  The offset into the String at which to start copying data.
    154      * @param length  The number of characters to write.
    155      * @exception IOException If an error occurs while writing to the underlying
    156      *            output.
    157      ***/
    158     public void write(String string, int offset, int length) throws IOException
    159     {
    160         write(string.toCharArray(), offset, length);
    161     }
    162
    163
    164     /****
    165      * Flushes the underlying output, writing all buffered output.
    166      * <p>
    167      * @exception IOException If an error occurs while writing to the underlying
    168      *            output.
    169      ***/
    170     public void flush() throws IOException
    171     {
    172         synchronized (lock)
    173         {
    174             __output.flush();
    175         }
    176     }
    177
    178
    179     /****
    180      * Flushes the underlying output, writing all buffered output, but doesn't
    181      * actually close the underlying stream.  The underlying stream may still
    182      * be used for communicating with the server and therefore is not closed.
    183      * <p>
    184      * @exception IOException If an error occurs while writing to the underlying
    185      *            output or closing the Writer.
    186      ***/
    187     public void close() throws IOException
    188     {
    189         synchronized (lock)
    190         {
    191             if (__output == null)
    192                 return ;
    193
    194             if (__state == __LAST_WAS_CR_STATE)
    195                 __output.write('\n');
    196             else if (__state != __LAST_WAS_NL_STATE)
    197                 __output.write("\r\n");
    198
    199             __output.write(".\r\n");
    200
    201             __output.flush();
    202             __output = null;
    203         }
    204     }
    205
    206 }