1/* 2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.xml.internal.stream.writers; 27 28import java.io.IOException; 29import java.io.Writer; 30import com.sun.org.apache.xerces.internal.util.XMLStringBuffer; 31 32/** 33 * XMLWriter 34 * 35 * <code>XMLWriter</code> is not thread safe. 36 * 37 * For efficiency this writer buffers the input. Use <code>flush()</code> function 38 * to explicitly write the data to underlying stream. 39 * 40 * This writer is designed in such a way that it atleast buffers the input to the 41 * <code>size</code> specified. Unless <code>flush</code> is called, it guarantees that 42 * data in chunks of size equal to or more than <code>size</code> specified will be written. 43 * 44 * 45 * <code>XMLWriter</code> instance can be reused. <code>setWriter()</code> internally clears the 46 * buffer and stores the reference to newly supplied <code>Writer</code> instance. 47 * 48 * @author Neeraj Bajaj Sun Microsystems, inc. 49 */ 50public class XMLWriter extends Writer { 51 52 private Writer writer ; 53 private int size ; 54 //keep the size of internal buffer more than 'size' required to avoid resizing 55 private XMLStringBuffer buffer = new XMLStringBuffer(6 * (1 << 11) ); // 6 KB 56 private static final int THRESHHOLD_LENGTH = 1 << 12 ; // 4 KB 57 private static final boolean DEBUG = false; 58 59 /** Creates the instance of <code>XMLWriter</code> 60 */ 61 62 public XMLWriter(Writer writer){ 63 this(writer, THRESHHOLD_LENGTH); 64 } 65 66 /** 67 * Creates the instnace of <code>XMLWriter</code>. 68 * 69 * atleast buffers the input to the 70 * <code>size</code> specified. 71 */ 72 public XMLWriter(Writer writer, int size){ 73 this.writer = writer ; 74 this.size = size; 75 } 76 77 /** 78 * Write a single character. The character to be written is contained in 79 * the 16 low-order bits of the given integer value; the 16 high-order bits 80 * are ignored. 81 * 82 * <p> Subclasses that intend to support efficient single-character output 83 * should override this method. 84 * 85 * @param c int specifying a character to be written. 86 * @exception IOException If an I/O error occurs 87 */ 88 89 public void write(int c) throws IOException { 90 ensureOpen(); 91 buffer.append((char)c); 92 conditionalWrite(); 93 } 94 95 /** 96 * Write an array of characters. 97 * 98 * @param cbuf Array of characters to be written 99 * 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) return; 175 //flush it first 176 flush(); 177 writer.close(); 178 writer = null ; 179 } 180 181 /** 182 * Flush the stream. If the stream has saved any characters from the 183 * various write() methods in a buffer, write them immediately to their 184 * intended destination. Then, if that destination is another character or 185 * byte stream, flush it. Thus one flush() invocation will flush all the 186 * buffers in a chain of Writers and OutputStreams. 187 * 188 * @exception IOException If an I/O error occurs 189 */ 190 191 public void flush() throws IOException { 192 ensureOpen(); 193 //write current data present in the buffer 194 writeBufferedData(); 195 writer.flush(); 196 } 197 198 /** Reset this Writer. 199 * 200 * see @setWriter() 201 */ 202 public void reset(){ 203 this.writer = null; 204 buffer.clear(); 205 this.size = THRESHHOLD_LENGTH; 206 } 207 208 /** 209 * Set the given <code>Writer</code>. 210 * 211 * @param Writer Writer. 212 */ 213 public void setWriter(Writer writer){ 214 this.writer = writer; 215 buffer.clear(); 216 this.size = THRESHHOLD_LENGTH; 217 } 218 219 /** Set the given <code>Writer</code> 220 * 221 * @param Writer Writer. 222 * @param int Writer will buffer the character data size, after that data is written to stream. 223 */ 224 public void setWriter(Writer writer, int size){ 225 this.writer = writer; 226 this.size = size; 227 } 228 229 /** 230 * Returns underlying <code>Writer</code> 231 */ 232 protected Writer getWriter() { 233 return writer; 234 } 235 236 /** write the buffer data, if the buffer size has increased the size specified 237 */ 238 private void conditionalWrite() throws IOException { 239 if(buffer.length > size){ 240 if(DEBUG){ 241 System.out.println("internal buffer length " + buffer.length + " increased size limit : " + size); 242 System.out.println("Data: ('" + new String(buffer.ch, buffer.offset, buffer.length) + "')"); 243 } 244 writeBufferedData(); 245 } 246 } 247 248 /** Write the data present in the buffer to the writer. 249 * buffer is cleared after write operation. 250 */ 251 private void writeBufferedData() throws IOException { 252 writer.write(buffer.ch, buffer.offset, buffer.length); 253 buffer.clear(); 254 } 255 256 /** Check to make sure that the stream has not been closed */ 257 private void ensureOpen() throws IOException { 258 if (writer == null)throw new IOException("Stream closed"); 259 } 260} 261