001: /*
002: * $Id: XMLWriter.java,v 1.3 2006/05/12 13:30:52 sunithareddy Exp $
003: */
004:
005: /*
006: * The contents of this file are subject to the terms
007: * of the Common Development and Distribution License
008: * (the License). You may not use this file except in
009: * compliance with the License.
010: *
011: * You can obtain a copy of the license at
012: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
013: * See the License for the specific language governing
014: * permissions and limitations under the License.
015: *
016: * When distributing Covered Code, include this CDDL
017: * Header Notice in each file and include the License file
018: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
019: * If applicable, add the following below the CDDL Header,
020: * with the fields enclosed by brackets [] replaced by
021: * you own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * [Name of File] [ver.__] [Date]
025: *
026: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
027: */
028:
029: package com.sun.xml.stream.writers;
030:
031: import java.io.IOException;
032: import java.io.Writer;
033: import com.sun.xml.stream.xerces.util.XMLStringBuffer;
034:
035: /**
036: * XMLWriter.
037: *
038: * <code>XMLWriter</code> is not thread safe.
039: *
040: * For efficiency this writer buffers the input. Use <code>flush()</code> function
041: * to explicitly write the data to underlying stream.
042: *
043: * This writer is designed in such a way that it atleast buffers the input to the
044: * <code>size</code> specified. Unless <code>flush</code> is called, it guarantees that
045: * data in chunks of size equal to or more than <code>size</code> specified will be written.
046: *
047: *
048: * <code>XMLWriter</code> instance can be reused. <code>setWriter()</code> internally clears the
049: * buffer and stores the reference to newly supplied <code>Writer</code> instance.
050: *
051: * @author Neeraj Bajaj Sun Microsystems, inc.
052: * @author Sunitha Reddy Sun Microsystems, inc.
053: */
054: public class XMLWriter extends Writer {
055:
056: private Writer writer;
057: private int size;
058: //keep the size of internal buffer more than 'size' required to avoid resizing
059: private XMLStringBuffer buffer = new XMLStringBuffer(6 * (1 << 11)); // 6 KB
060: private static final int THRESHHOLD_LENGTH = 1 << 12; // 4 KB
061: private static final boolean DEBUG = false;
062:
063: /** Creates the instance of <code>XMLWriter</code>
064: */
065:
066: public XMLWriter(Writer writer) {
067: this (writer, THRESHHOLD_LENGTH);
068: }
069:
070: /**
071: * Creates the instnace of <code>XMLWriter</code>.
072: *
073: * atleast buffers the input to the
074: * <code>size</code> specified.
075: */
076: public XMLWriter(Writer writer, int size) {
077: this .writer = writer;
078: this .size = size;
079: }
080:
081: /**
082: * Write a single character. The character to be written is contained in
083: * the 16 low-order bits of the given integer value; the 16 high-order bits
084: * are ignored.
085: *
086: * <p> Subclasses that intend to support efficient single-character output
087: * should override this method.
088: *
089: * @param c int specifying a character to be written.
090: * @exception IOException If an I/O error occurs
091: */
092:
093: public void write(int c) throws IOException {
094: ensureOpen();
095: buffer.append((char) c);
096: conditionalWrite();
097: }
098:
099: /**
100: * Write an array of characters.
101: *
102: * @param cbuf Array of characters to be written
103: *
104: * @exception IOException If an I/O error occurs
105: */
106:
107: public void write(char cbuf[]) throws IOException {
108: write(cbuf, 0, cbuf.length);
109: }
110:
111: /**
112: * Write a portion of an array of characters.
113: *
114: * @param cbuf Array of characters
115: * @param off Offset from which to start writing characters
116: * @param len Number of characters to write
117: *
118: * @exception IOException If an I/O error occurs
119: */
120:
121: public void write(char cbuf[], int off, int len) throws IOException {
122: ensureOpen();
123: //optimization: if data size to be written is more than the 'size' specified,
124: //do not buffer the data but write the data straight to the underlying stream
125: if (len > size) {
126: //first write the data that may be present in the buffer
127: writeBufferedData();
128: //write directly to stream
129: writer.write(cbuf, off, len);
130: } else {
131: buffer.append(cbuf, off, len);
132: conditionalWrite();
133: }
134: }
135:
136: /**
137: * Write a portion of a string.
138: *
139: * @param str A String
140: * @param off Offset from which to start writing characters
141: * @param len Number of characters to write
142: *
143: * @exception IOException If an I/O error occurs
144: */
145: public void write(String str, int off, int len) throws IOException {
146: write(str.toCharArray(), off, len);
147: }
148:
149: /**
150: * Write a string.
151: *
152: * @param str String to be written
153: *
154: * @exception IOException If an I/O error occurs
155: */
156: public void write(String str) throws IOException {
157: //optimization: if data size to be written is more than the 'size' specified,
158: //do not buffer the data but write the data straight to the underlying stream - nb.
159: if (str.length() > size) {
160: //first write the data that may be present in the buffer
161: writeBufferedData();
162: //write directly to stream
163: writer.write(str);
164: } else {
165: buffer.append(str);
166: conditionalWrite();
167: }
168: }
169:
170: /**
171: * Close the stream, flushing it first. Once a stream has been closed,
172: * further write() or flush() invocations will cause an IOException to be
173: * thrown. Closing a previously-closed stream, however, has no effect.
174: *
175: * @exception IOException If an I/O error occurs
176: */
177: public void close() throws IOException {
178: if (writer == null)
179: return;
180: //flush it first
181: flush();
182: writer.close();
183: writer = null;
184: }
185:
186: /**
187: * Flush the stream. If the stream has saved any characters from the
188: * various write() methods in a buffer, write them immediately to their
189: * intended destination. Then, if that destination is another character or
190: * byte stream, flush it. Thus one flush() invocation will flush all the
191: * buffers in a chain of Writers and OutputStreams.
192: *
193: * @exception IOException If an I/O error occurs
194: */
195:
196: public void flush() throws IOException {
197: ensureOpen();
198: //write current data present in the buffer
199: writeBufferedData();
200: writer.flush();
201: }
202:
203: /** Reset this Writer.
204: *
205: * see @setWriter()
206: */
207: public void reset() {
208: this .writer = null;
209: buffer.clear();
210: this .size = THRESHHOLD_LENGTH;
211: }
212:
213: /**
214: * Set the given <code>Writer</code>.
215: *
216: * @param Writer Writer.
217: */
218: public void setWriter(Writer writer) {
219: this .writer = writer;
220: buffer.clear();
221: this .size = THRESHHOLD_LENGTH;
222: }
223:
224: /** Set the given <code>Writer</code>
225: *
226: * @param Writer Writer.
227: * @param int Writer will buffer the character data size, after that data is written to stream.
228: */
229: public void setWriter(Writer writer, int size) {
230: this .writer = writer;
231: this .size = size;
232: }
233:
234: /**
235: * Returns underlying <code>Writer</code>
236: */
237: protected Writer getWriter() {
238: return writer;
239: }
240:
241: /** write the buffer data, if the buffer size has increased the size specified
242: */
243: private void conditionalWrite() throws IOException {
244: if (buffer.length > size) {
245: if (DEBUG) {
246: System.out.println("internal buffer length "
247: + buffer.length + " increased size limit : "
248: + size);
249: System.out.println("Data: ('"
250: + new String(buffer.ch, buffer.offset,
251: buffer.length) + "')");
252: }
253: writeBufferedData();
254: }
255: }
256:
257: /** Write the data present in the buffer to the writer.
258: * buffer is cleared after write operation.
259: */
260: private void writeBufferedData() throws IOException {
261: writer.write(buffer.ch, buffer.offset, buffer.length);
262: buffer.clear();
263: }
264:
265: /** Check to make sure that the stream has not been closed */
266: private void ensureOpen() throws IOException {
267: if (writer == null)
268: throw new IOException("Stream closed");
269: }
270: }
|