/*
 
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
 
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
*
 
* This code is free software; you can redistribute it and/or modify it
 
* under the terms of the GNU General Public License version 2 only, as
 
* published by the Free Software Foundation.
  
Oracle designates this
 
* particular file as subject to the "Classpath" exception as provided
 
* by Oracle in the LICENSE file that accompanied this code.
 
*
 
* This code is distributed in the hope that it will be useful, but WITHOUT
 
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
* FITNESS FOR A PARTICULAR PURPOSE.
  
See the GNU General Public License
 
* version 2 for more details (a copy is included in the LICENSE file that
 
* accompanied this code).
 
*
 
* You should have received a copy of the GNU General Public License version
 
* 2 along with this work; if not, write to the Free Software Foundation,
 
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
*
 
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 
* or visit www.oracle.com if you need additional information or have any
 
* questions.
 
*/

package java.io;


/**
 
* Abstract class for writing to character streams.
  
The only methods that a
 
* subclass must implement are write(char[], int, int), flush(), and close().
 
* Most subclasses, however, will override some of the methods defined here in
 
* order to provide higher efficiency, additional functionality, or both.
 
*
 
* @see Writer
 
* @see
   
BufferedWriter
 
* @see
   
CharArrayWriter
 
* @see
   
FilterWriter
 
* @see
   
OutputStreamWriter
 
* @see
     
FileWriter
 
* @see
   
PipedWriter
 
* @see
   
PrintWriter
 
* @see
   
StringWriter
 
* @see Reader
 
*
 
* @author
      
Mark Reinhold
 
* @since
       
JDK1.1
 
*/


public abstract class Writer implements Appendable, Closeable, Flushable {

    
/**
     
* Temporary buffer used to hold writes of strings and single characters
     
*/

    
private char[] writeBuffer;

    
/**
     
* Size of writeBuffer, must be >= 1
     
*/
    
private static final int WRITE_BUFFER_SIZE = 1024;

    
/**
     
* The object used to synchronize operations on this stream.
  
For
     
* efficiency, a character-stream object may use an object other than
     
* itself to protect critical sections.
  
A subclass should therefore use
     
* the object in this field rather than <tt>this</tt> or a synchronized
     
* method.
     
*/

    
protected Object lock;

    
/**
     
* Creates a new character-stream writer whose critical sections will
     
* synchronize on the writer itself.
     
*/

    
protected Writer() {
        
this.lock = this;
    
}

    
/**
     
* Creates a new character-stream writer whose critical sections will
     
* synchronize on the given object.
     
*
     
* @param
  
lock
     
*
         
Object to synchronize on
     
*/

    
protected Writer(Object lock) {
        
if (lock == null) {
            
throw new NullPointerException();
        
}
        
this.lock = lock;
    
}

    
/**
     
* Writes a single character.
  
The character to be written is contained in
     
* the 16 low-order bits of the given integer value; the 16 high-order bits
     
* are ignored.
     
*
     
* <p> Subclasses that intend to support efficient single-character output
     
* should override this method.
     
*
     
* @param
  
c
     
*
         
int specifying a character to be written
     
*
     
* @throws
  
IOException
     
*
          
If an I/O error occurs
     
*/

    
public void write(int c) throws IOException {
        
synchronized (lock) {
            
if (writeBuffer == null){
                
writeBuffer = new char[WRITE_BUFFER_SIZE];
            
}
            
writeBuffer[0] = (char) c;
            
write(writeBuffer, 0, 1);
        
}
    
}

    
/**
     
* Writes an array of characters.
     
*
     
* @param
  
cbuf
     
*
         
Array of characters to be written
     
*
     
* @throws
  
IOException
     
*
          
If an I/O error occurs
     
*/

    
public void write(char cbuf[]) throws IOException {
        
write(cbuf, 0, cbuf.length);
    
}

    
/**
     
* Writes a portion of an array of characters.
     
*
     
* @param
  
cbuf
     
*
         
Array of characters
     
*
     
* @param
  
off
     
*
         
Offset from which to start writing characters
     
*
     
* @param
  
len
     
*
         
Number of characters to write
     
*
     
* @throws
  
IOException
     
*
          
If an I/O error occurs
     
*/

    
abstract public void write(char cbuf[], int off, int len) throws IOException;

    
/**
     
* Writes a string.
     
*
     
* @param
  
str
     
*
         
String to be written
     
*
     
* @throws
  
IOException
     
*
          
If an I/O error occurs
     
*/

    
public void write(String str) throws IOException {
        
write(str, 0, str.length());
    
}

    
/**
     
* Writes a portion of a string.
     
*
     
* @param
  
str
     
*
         
A String
     
*
     
* @param
  
off
     
*
         
Offset from which to start writing characters
     
*
     
* @param
  
len
     
*
         
Number of characters to write
     
*
     
* @throws
  
IndexOutOfBoundsException
     
*
          
If <tt>off</tt> is negative, or <tt>len</tt> is negative,
     
*
          
or <tt>off+len</tt> is negative or greater than the length
     
*
          
of the given string
     
*
     
* @throws
  
IOException
     
*
          
If an I/O error occurs
     
*/

    
public void write(String str, int off, int len) throws IOException {
        
synchronized (lock) {
            
char cbuf[];
            
if (len <= WRITE_BUFFER_SIZE) {
                
if (writeBuffer == null) {
                    
writeBuffer = new char[WRITE_BUFFER_SIZE];
                
}
                
cbuf = writeBuffer;
            
} else {
    
// Don't permanently allocate very large buffers.
                
cbuf = new char[len];
            
}
            
str.getChars(off, (off + len), cbuf, 0);
            
write(cbuf, 0, len);
        
}
    
}

    
/**
     
* Appends the specified character sequence to this writer.
     
*
     
* <p> An invocation of this method of the form <tt>out.append(csq)</tt>
     
* behaves in exactly the same way as the invocation
     
*
     
* <pre>
     
*out.write(csq.toString()) </pre>
     
*
     
* <p> Depending on the specification of <tt>toString</tt> for the
     
* character sequence <tt>csq</tt>, the entire sequence may not be
     
* appended. For instance, invoking the <tt>toString</tt> method of a
     
* character buffer will return a subsequence whose content depends upon
     
* the buffer's position and limit.
     
*
     
* @param
  
csq
     
*
         
The character sequence to append.
  
If <tt>csq</tt> is
     
*
         
<tt>null</tt>, then the four characters <tt>"null"</tt> are
     
*
         
appended to this writer.
     
*
     
* @return
  
This writer
     
*
     
* @throws
  
IOException
     
*
          
If an I/O error occurs
     
*
     
* @since
  
1.5
     
*/

    
public Writer append(CharSequence csq) throws IOException {
        
if (csq == null)
            
write("null");
        
else
            
write(csq.toString());
        
return this;
    
}

    
/**
     
* Appends a subsequence of the specified character sequence to this writer.
     
* <tt>Appendable</tt>.
     
*
     
* <p> An invocation of this method of the form <tt>out.append(csq, start,
     
* end)</tt> when <tt>csq</tt> is not <tt>null</tt> behaves in exactly the
     
* same way as the invocation
     
*
     
* <pre>
     
*out.write(csq.subSequence(start, end).toString()) </pre>
     
*
     
* @param
  
csq
     
*
         
The character sequence from which a subsequence will be
     
*
         
appended.
  
If <tt>csq</tt> is <tt>null</tt>, then characters
     
*
         
will be appended as if <tt>csq</tt> contained the four
     
*
         
characters <tt>"null"</tt>.
     
*
     
* @param
  
start
     
*
         
The index of the first character in the subsequence
     
*
     
* @param
  
end
     
*
         
The index of the character following the last character in the
     
*
         
subsequence
     
*
     
* @return
  
This writer
     
*
     
* @throws
  
IndexOutOfBoundsException
     
*
          
If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
     
*
          
is greater than <tt>end</tt>, or <tt>end</tt> is greater than
     
*
          
<tt>csq.length()</tt>
     
*
     
* @throws
  
IOException
     
*
          
If an I/O error occurs
     
*
     
* @since
  
1.5
     
*/

    
public Writer append(CharSequence csq, int start, int end) throws IOException {
        
CharSequence cs = (csq == null ? "null" : csq);
        
write(cs.subSequence(start, end).toString());
        
return this;
    
}

    
/**
     
* Appends the specified character to this writer.
     
*
     
* <p> An invocation of this method of the form <tt>out.append(c)</tt>
     
* behaves in exactly the same way as the invocation
     
*
     
* <pre>
     
*out.write(c) </pre>
     
*
     
* @param
  
c
     
*
         
The 16-bit character to append
     
*
     
* @return
  
This writer
     
*
     
* @throws
  
IOException
     
*
          
If an I/O error occurs
     
*
     
* @since 1.5
     
*/

    
public Writer append(char c) throws IOException {
        
write(c);
        
return this;
    
}

    
/**
     
* Flushes the stream.
  
If the stream has saved any characters from the
     
* various write() methods in a buffer, write them immediately to their
     
* intended destination.
  
Then, if that destination is another character or
     
* byte stream, flush it.
  
Thus one flush() invocation will flush all the
     
* buffers in a chain of Writers and OutputStreams.
     
*
     
* <p> If the intended destination of this stream is an abstraction provided
     
* by the underlying operating system, for example a file, then flushing the
     
* stream guarantees only that bytes previously written to the stream are
     
* passed to the operating system for writing; it does not guarantee that
     
* they are actually written to a physical device such as a disk drive.
     
*
     
* @throws
  
IOException
     
*
          
If an I/O error occurs
     
*/

    
abstract public void flush() throws IOException;

    
/**
     
* Closes the stream, flushing it first. Once the stream has been closed,
     
* further write() or flush() invocations will cause an IOException to be
     
* thrown. Closing a previously closed stream has no effect.
     
*
     
* @throws
  
IOException
     
*
          
If an I/O error occurs
     
*/

    
abstract public void close() throws IOException;

}