/* |
|
* Copyright (c) 2006, 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 com.sun.xml.internal.stream.writers; |
|
import java.io.IOException; |
|
import java.io.Writer; |
|
import com.sun.org.apache.xerces.internal.util.XMLStringBuffer; |
|
/** |
|
* XMLWriter |
|
* |
|
* <code>XMLWriter</code> is not thread safe. |
|
* |
|
* For efficiency this writer buffers the input. Use <code>flush()</code> function |
|
* to explicitly write the data to underlying stream. |
|
* |
|
* This writer is designed in such a way that it atleast buffers the input to the |
|
* <code>size</code> specified. Unless <code>flush</code> is called, it guarantees that |
|
* data in chunks of size equal to or more than <code>size</code> specified will be written. |
|
* |
|
* |
|
* <code>XMLWriter</code> instance can be reused. <code>setWriter()</code> internally clears the |
|
* buffer and stores the reference to newly supplied <code>Writer</code> instance. |
|
* |
|
* @author Neeraj Bajaj Sun Microsystems, inc. |
|
*/ |
|
public class XMLWriter extends Writer { |
|
private Writer writer ; |
|
private int size ; |
|
//keep the size of internal buffer more than 'size' required to avoid resizing |
|
private XMLStringBuffer buffer = new XMLStringBuffer(6 * (1 << 11) ); // 6 KB |
|
private static final int THRESHHOLD_LENGTH = 1 << 12 ; // 4 KB |
|
private static final boolean DEBUG = false; |
|
/** Creates the instance of <code>XMLWriter</code> |
|
*/ |
|
public XMLWriter(Writer writer){ |
|
this(writer, THRESHHOLD_LENGTH); |
|
} |
|
/** |
|
* Creates the instnace of <code>XMLWriter</code>. |
|
* |
|
* atleast buffers the input to the |
|
* <code>size</code> specified. |
|
*/ |
|
public XMLWriter(Writer writer, int size){ |
|
this.writer = writer ; |
|
this.size = size; |
|
} |
|
/** |
|
* Write 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. |
|
* @exception IOException If an I/O error occurs |
|
*/ |
|
public void write(int c) throws IOException { |
|
ensureOpen(); |
|
buffer.append((char)c); |
|
conditionalWrite(); |
|
} |
|
/** |
|
* Write an array of characters. |
|
* |
|
* @param cbuf Array of characters to be written |
|
* |
|
* @exception IOException If an I/O error occurs |
|
*/ |
|
public void write(char cbuf[]) throws IOException { |
|
write(cbuf, 0, cbuf.length); |
|
} |
|
/** |
|
* Write 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 |
|
* |
|
* @exception IOException If an I/O error occurs |
|
*/ |
|
public void write(char cbuf[], int off, int len) throws IOException{ |
|
ensureOpen(); |
|
//optimization: if data size to be written is more than the 'size' specified, |
|
//do not buffer the data but write the data straight to the underlying stream |
|
if(len > size){ |
|
//first write the data that may be present in the buffer |
|
writeBufferedData(); |
|
//write directly to stream |
|
writer.write(cbuf, off, len); |
|
}else{ |
|
buffer.append(cbuf, off, len); |
|
conditionalWrite(); |
|
} |
|
} |
|
/** |
|
* Write 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 |
|
* |
|
* @exception IOException If an I/O error occurs |
|
*/ |
|
public void write(String str, int off, int len) throws IOException { |
|
write(str.toCharArray(), off, len); |
|
} |
|
/** |
|
* Write a string. |
|
* |
|
* @param str String to be written |
|
* |
|
* @exception IOException If an I/O error occurs |
|
*/ |
|
public void write(String str) throws IOException { |
|
//optimization: if data size to be written is more than the 'size' specified, |
|
//do not buffer the data but write the data straight to the underlying stream - nb. |
|
if(str.length() > size){ |
|
//first write the data that may be present in the buffer |
|
writeBufferedData(); |
|
//write directly to stream |
|
writer.write(str); |
|
}else{ |
|
buffer.append(str); |
|
conditionalWrite(); |
|
} |
|
} |
|
/** |
|
* Close the stream, flushing it first. Once a stream has been closed, |
|
* further write() or flush() invocations will cause an IOException to be |
|
* thrown. Closing a previously-closed stream, however, has no effect. |
|
* |
|
* @exception IOException If an I/O error occurs |
|
*/ |
|
public void close() throws IOException { |
|
if(writer == null) return; |
|
//flush it first |
|
flush(); |
|
writer.close(); |
|
writer = null ; |
|
} |
|
/** |
|
* Flush 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. |
|
* |
|
* @exception IOException If an I/O error occurs |
|
*/ |
|
public void flush() throws IOException { |
|
ensureOpen(); |
|
//write current data present in the buffer |
|
writeBufferedData(); |
|
writer.flush(); |
|
} |
|
/** Reset this Writer. |
|
* |
|
* see @setWriter() |
|
*/ |
|
public void reset(){ |
|
this.writer = null; |
|
buffer.clear(); |
|
this.size = THRESHHOLD_LENGTH; |
|
} |
|
/** |
|
* Set the given <code>Writer</code>. |
|
* |
|
* @param Writer Writer. |
|
*/ |
|
public void setWriter(Writer writer){ |
|
this.writer = writer; |
|
buffer.clear(); |
|
this.size = THRESHHOLD_LENGTH; |
|
} |
|
/** Set the given <code>Writer</code> |
|
* |
|
* @param Writer Writer. |
|
* @param int Writer will buffer the character data size, after that data is written to stream. |
|
*/ |
|
public void setWriter(Writer writer, int size){ |
|
this.writer = writer; |
|
this.size = size; |
|
} |
|
/** |
|
* Returns underlying <code>Writer</code> |
|
*/ |
|
protected Writer getWriter() { |
|
return writer; |
|
} |
|
/** write the buffer data, if the buffer size has increased the size specified |
|
*/ |
|
private void conditionalWrite() throws IOException { |
|
if(buffer.length > size){ |
|
if(DEBUG){ |
|
System.out.println("internal buffer length " + buffer.length + " increased size limit : " + size); |
|
System.out.println("Data: ('" + new String(buffer.ch, buffer.offset, buffer.length) + "')"); |
|
} |
|
writeBufferedData(); |
|
} |
|
} |
|
/** Write the data present in the buffer to the writer. |
|
* buffer is cleared after write operation. |
|
*/ |
|
private void writeBufferedData() throws IOException { |
|
writer.write(buffer.ch, buffer.offset, buffer.length); |
|
buffer.clear(); |
|
} |
|
/** Check to make sure that the stream has not been closed */ |
|
private void ensureOpen() throws IOException { |
|
if (writer == null)throw new IOException("Stream closed"); |
|
} |
|
} |