001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.xml.internal.stream.writers;
027:
028: import java.io.IOException;
029: import java.io.Writer;
030: import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
031:
032: /**
033: * XMLWriter
034: *
035: * <code>XMLWriter</code> is not thread safe.
036: *
037: * For efficiency this writer buffers the input. Use <code>flush()</code> function
038: * to explicitly write the data to underlying stream.
039: *
040: * This writer is designed in such a way that it atleast buffers the input to the
041: * <code>size</code> specified. Unless <code>flush</code> is called, it guarantees that
042: * data in chunks of size equal to or more than <code>size</code> specified will be written.
043: *
044: *
045: * <code>XMLWriter</code> instance can be reused. <code>setWriter()</code> internally clears the
046: * buffer and stores the reference to newly supplied <code>Writer</code> instance.
047: *
048: * @author Neeraj Bajaj Sun Microsystems, inc.
049: */
050: public class XMLWriter extends Writer {
051:
052: private Writer writer;
053: private int size;
054: //keep the size of internal buffer more than 'size' required to avoid resizing
055: private XMLStringBuffer buffer = new XMLStringBuffer(6 * (1 << 11)); // 6 KB
056: private static final int THRESHHOLD_LENGTH = 1 << 12; // 4 KB
057: private static final boolean DEBUG = false;
058:
059: /** Creates the instance of <code>XMLWriter</code>
060: */
061:
062: public XMLWriter(Writer writer) {
063: this (writer, THRESHHOLD_LENGTH);
064: }
065:
066: /**
067: * Creates the instnace of <code>XMLWriter</code>.
068: *
069: * atleast buffers the input to the
070: * <code>size</code> specified.
071: */
072: public XMLWriter(Writer writer, int size) {
073: this .writer = writer;
074: this .size = size;
075: }
076:
077: /**
078: * Write a single character. The character to be written is contained in
079: * the 16 low-order bits of the given integer value; the 16 high-order bits
080: * are ignored.
081: *
082: * <p> Subclasses that intend to support efficient single-character output
083: * should override this method.
084: *
085: * @param c int specifying a character to be written.
086: * @exception IOException If an I/O error occurs
087: */
088:
089: public void write(int c) throws IOException {
090: ensureOpen();
091: buffer.append((char) c);
092: conditionalWrite();
093: }
094:
095: /**
096: * Write an array of characters.
097: *
098: * @param cbuf Array of characters to be written
099: *
100: * @exception IOException If an I/O error occurs
101: */
102:
103: public void write(char cbuf[]) throws IOException {
104: write(cbuf, 0, cbuf.length);
105: }
106:
107: /**
108: * Write a portion of an array of characters.
109: *
110: * @param cbuf Array of characters
111: * @param off Offset from which to start writing characters
112: * @param len Number of characters to write
113: *
114: * @exception IOException If an I/O error occurs
115: */
116:
117: public void write(char cbuf[], int off, int len) throws IOException {
118: ensureOpen();
119: //optimization: if data size to be written is more than the 'size' specified,
120: //do not buffer the data but write the data straight to the underlying stream
121: if (len > size) {
122: //first write the data that may be present in the buffer
123: writeBufferedData();
124: //write directly to stream
125: writer.write(cbuf, off, len);
126: } else {
127: buffer.append(cbuf, off, len);
128: conditionalWrite();
129: }
130: }
131:
132: /**
133: * Write a portion of a string.
134: *
135: * @param str A String
136: * @param off Offset from which to start writing characters
137: * @param len Number of characters to write
138: *
139: * @exception IOException If an I/O error occurs
140: */
141: public void write(String str, int off, int len) throws IOException {
142: write(str.toCharArray(), off, len);
143: }
144:
145: /**
146: * Write a string.
147: *
148: * @param str String to be written
149: *
150: * @exception IOException If an I/O error occurs
151: */
152: public void write(String str) throws IOException {
153: //optimization: if data size to be written is more than the 'size' specified,
154: //do not buffer the data but write the data straight to the underlying stream - nb.
155: if (str.length() > size) {
156: //first write the data that may be present in the buffer
157: writeBufferedData();
158: //write directly to stream
159: writer.write(str);
160: } else {
161: buffer.append(str);
162: conditionalWrite();
163: }
164: }
165:
166: /**
167: * Close the stream, flushing it first. Once a stream has been closed,
168: * further write() or flush() invocations will cause an IOException to be
169: * thrown. Closing a previously-closed stream, however, has no effect.
170: *
171: * @exception IOException If an I/O error occurs
172: */
173: public void close() throws IOException {
174: if (writer == null)
175: return;
176: //flush it first
177: flush();
178: writer.close();
179: writer = null;
180: }
181:
182: /**
183: * Flush the stream. If the stream has saved any characters from the
184: * various write() methods in a buffer, write them immediately to their
185: * intended destination. Then, if that destination is another character or
186: * byte stream, flush it. Thus one flush() invocation will flush all the
187: * buffers in a chain of Writers and OutputStreams.
188: *
189: * @exception IOException If an I/O error occurs
190: */
191:
192: public void flush() throws IOException {
193: ensureOpen();
194: //write current data present in the buffer
195: writeBufferedData();
196: writer.flush();
197: }
198:
199: /** Reset this Writer.
200: *
201: * see @setWriter()
202: */
203: public void reset() {
204: this .writer = null;
205: buffer.clear();
206: this .size = THRESHHOLD_LENGTH;
207: }
208:
209: /**
210: * Set the given <code>Writer</code>.
211: *
212: * @param Writer Writer.
213: */
214: public void setWriter(Writer writer) {
215: this .writer = writer;
216: buffer.clear();
217: this .size = THRESHHOLD_LENGTH;
218: }
219:
220: /** Set the given <code>Writer</code>
221: *
222: * @param Writer Writer.
223: * @param int Writer will buffer the character data size, after that data is written to stream.
224: */
225: public void setWriter(Writer writer, int size) {
226: this .writer = writer;
227: this .size = size;
228: }
229:
230: /**
231: * Returns underlying <code>Writer</code>
232: */
233: protected Writer getWriter() {
234: return writer;
235: }
236:
237: /** write the buffer data, if the buffer size has increased the size specified
238: */
239: private void conditionalWrite() throws IOException {
240: if (buffer.length > size) {
241: if (DEBUG) {
242: System.out.println("internal buffer length "
243: + buffer.length + " increased size limit : "
244: + size);
245: System.out.println("Data: ('"
246: + new String(buffer.ch, buffer.offset,
247: buffer.length) + "')");
248: }
249: writeBufferedData();
250: }
251: }
252:
253: /** Write the data present in the buffer to the writer.
254: * buffer is cleared after write operation.
255: */
256: private void writeBufferedData() throws IOException {
257: writer.write(buffer.ch, buffer.offset, buffer.length);
258: buffer.clear();
259: }
260:
261: /** Check to make sure that the stream has not been closed */
262: private void ensureOpen() throws IOException {
263: if (writer == null)
264: throw new IOException("Stream closed");
265: }
266: }
|