1 // ========================================================================
2 // Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // All rights reserved. This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v1.0
6 // and Apache License v2.0 which accompanies this distribution.
7 // The Eclipse Public License is available at
8 // http://www.eclipse.org/legal/epl-v10.html
9 // The Apache License v2.0 is available at
10 // http://www.opensource.org/licenses/apache2.0.php
11 // You may elect to redistribute this code under either of these licenses.
12 // ========================================================================
13
14
15 package org.mortbay.io;
16
17 import java.io.BufferedWriter;
18 import java.io.InterruptedIOException;
19 import java.io.IOException;
20 import java.io.OutputStream;
21 import java.io.OutputStreamWriter;
22 import java.io.PrintWriter;
23 import java.io.Writer;
24
25 import org.mortbay.log.Log;
26
27 /* ------------------------------------------------------------ */
28 /**
29 * A wrapper for the {@link java.io.PrintWriter} that re-throws the instances of
30 * {@link java.io.IOException} thrown by the underlying implementation of
31 * {@link java.io.Writer} as {@link RunimeIOException} instances.
32 */
33 public class UncheckedPrintWriter extends PrintWriter
34 {
35 private boolean autoFlush = false;
36
37 /* ------------------------------------------------------------ */
38 /**
39 * Line separator string. This is the value of the line.separator
40 * property at the moment that the stream was created.
41 */
42 private String lineSeparator;
43
44 public UncheckedPrintWriter (Writer out)
45 {
46 this(out, false);
47 }
48
49 /* ------------------------------------------------------------ */
50 /**
51 * Create a new PrintWriter.
52 *
53 * @param out A character-output stream
54 * @param autoFlush A boolean; if true, the println() methods will flush
55 * the output buffer
56 */
57 public UncheckedPrintWriter(Writer out, boolean autoFlush)
58 {
59 super(out, autoFlush);
60 this.autoFlush = autoFlush;
61 this.lineSeparator = System.getProperty("line.separator");
62 }
63
64 /* ------------------------------------------------------------ */
65 /**
66 * Create a new PrintWriter, without automatic line flushing, from an
67 * existing OutputStream. This convenience constructor creates the
68 * necessary intermediate OutputStreamWriter, which will convert characters
69 * into bytes using the default character encoding.
70 *
71 * @param out An output stream
72 *
73 * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
74 */
75 public UncheckedPrintWriter(OutputStream out)
76 {
77 this(out, false);
78 }
79
80 /* ------------------------------------------------------------ */
81 /**
82 * Create a new PrintWriter from an existing OutputStream. This
83 * convenience constructor creates the necessary intermediate
84 * OutputStreamWriter, which will convert characters into bytes using the
85 * default character encoding.
86 *
87 * @param out An output stream
88 * @param autoFlush A boolean; if true, the println() methods will flush
89 * the output buffer
90 *
91 * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
92 */
93 public UncheckedPrintWriter(OutputStream out, boolean autoFlush)
94 {
95 this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
96 }
97
98 /* ------------------------------------------------------------ */
99 /** Check to make sure that the stream has not been closed */
100 private void isOpen() throws IOException
101 {
102 if (super.out == null)
103 throw new IOException("Stream closed");
104 }
105
106 /* ------------------------------------------------------------ */
107 /**
108 * Flush the stream.
109 */
110 public void flush() {
111 try {
112 synchronized (lock) {
113 isOpen();
114 out.flush();
115 }
116 }
117 catch (IOException ex) {
118 Log.debug(ex);
119 setError();
120 throw new RuntimeIOException(ex);
121 }
122 }
123
124 /* ------------------------------------------------------------ */
125 /**
126 * Close the stream.
127 */
128 public void close() {
129 try {
130 synchronized (lock) {
131 out.close();
132 }
133 }
134 catch (IOException ex) {
135 Log.debug(ex);
136 setError();
137 throw new RuntimeIOException(ex);
138 }
139 }
140
141 /* ------------------------------------------------------------ */
142 /**
143 * Write a single character.
144 * @param c int specifying a character to be written.
145 */
146 public void write(int c) {
147 try {
148 synchronized (lock) {
149 isOpen();
150 out.write(c);
151 }
152 }
153 catch (InterruptedIOException x) {
154 Thread.currentThread().interrupt();
155 }
156 catch (IOException ex) {
157 Log.debug(ex);
158 setError();
159 throw new RuntimeIOException(ex);
160 }
161 }
162
163 /* ------------------------------------------------------------ */
164 /**
165 * Write a portion of an array of characters.
166 * @param buf Array of characters
167 * @param off Offset from which to start writing characters
168 * @param len Number of characters to write
169 */
170 public void write(char buf[], int off, int len) {
171 try {
172 synchronized (lock) {
173 isOpen();
174 out.write(buf, off, len);
175 }
176 }
177 catch (InterruptedIOException x) {
178 Thread.currentThread().interrupt();
179 }
180 catch (IOException ex) {
181 Log.debug(ex);
182 setError();
183 throw new RuntimeIOException(ex);
184 }
185 }
186
187 /* ------------------------------------------------------------ */
188 /**
189 * Write an array of characters. This method cannot be inherited from the
190 * Writer class because it must suppress I/O exceptions.
191 * @param buf Array of characters to be written
192 */
193 public void write(char buf[]) {
194 this.write(buf, 0, buf.length);
195 }
196
197 /* ------------------------------------------------------------ */
198 /**
199 * Write a portion of a string.
200 * @param s A String
201 * @param off Offset from which to start writing characters
202 * @param len Number of characters to write
203 */
204 public void write(String s, int off, int len) {
205 try {
206 synchronized (lock) {
207 isOpen();
208 out.write(s, off, len);
209 }
210 }
211 catch (InterruptedIOException x) {
212 Thread.currentThread().interrupt();
213 }
214 catch (IOException ex) {
215 Log.debug(ex);
216 setError();
217 throw new RuntimeIOException(ex);
218 }
219 }
220
221 /* ------------------------------------------------------------ */
222 /**
223 * Write a string. This method cannot be inherited from the Writer class
224 * because it must suppress I/O exceptions.
225 * @param s String to be written
226 */
227 public void write(String s) {
228 this.write(s, 0, s.length());
229 }
230
231 private void newLine() {
232 try {
233 synchronized (lock) {
234 isOpen();
235 out.write(lineSeparator);
236 if (autoFlush)
237 out.flush();
238 }
239 }
240 catch (InterruptedIOException x) {
241 Thread.currentThread().interrupt();
242 }
243 catch (IOException ex) {
244 Log.debug(ex);
245 setError();
246 throw new RuntimeIOException(ex);
247 }
248 }
249
250
251 /* Methods that do not terminate lines */
252
253 /* ------------------------------------------------------------ */
254 /**
255 * Print a boolean value. The string produced by <code>{@link
256 * java.lang.String#valueOf(boolean)}</code> is translated into bytes
257 * according to the platform's default character encoding, and these bytes
258 * are written in exactly the manner of the <code>{@link
259 * #write(int)}</code> method.
260 *
261 * @param b The <code>boolean</code> to be printed
262 */
263 public void print(boolean b) {
264 this.write(b ? "true" : "false");
265 }
266
267 /* ------------------------------------------------------------ */
268 /**
269 * Print a character. The character is translated into one or more bytes
270 * according to the platform's default character encoding, and these bytes
271 * are written in exactly the manner of the <code>{@link
272 * #write(int)}</code> method.
273 *
274 * @param c The <code>char</code> to be printed
275 */
276 public void print(char c) {
277 this.write(c);
278 }
279
280 /* ------------------------------------------------------------ */
281 /**
282 * Print an integer. The string produced by <code>{@link
283 * java.lang.String#valueOf(int)}</code> is translated into bytes according
284 * to the platform's default character encoding, and these bytes are
285 * written in exactly the manner of the <code>{@link #write(int)}</code>
286 * method.
287 *
288 * @param i The <code>int</code> to be printed
289 * @see java.lang.Integer#toString(int)
290 */
291 public void print(int i) {
292 this.write(String.valueOf(i));
293 }
294
295 /* ------------------------------------------------------------ */
296 /**
297 * Print a long integer. The string produced by <code>{@link
298 * java.lang.String#valueOf(long)}</code> is translated into bytes
299 * according to the platform's default character encoding, and these bytes
300 * are written in exactly the manner of the <code>{@link #write(int)}</code>
301 * method.
302 *
303 * @param l The <code>long</code> to be printed
304 * @see java.lang.Long#toString(long)
305 */
306 public void print(long l) {
307 this.write(String.valueOf(l));
308 }
309
310 /* ------------------------------------------------------------ */
311 /**
312 * Print a floating-point number. The string produced by <code>{@link
313 * java.lang.String#valueOf(float)}</code> is translated into bytes
314 * according to the platform's default character encoding, and these bytes
315 * are written in exactly the manner of the <code>{@link #write(int)}</code>
316 * method.
317 *
318 * @param f The <code>float</code> to be printed
319 * @see java.lang.Float#toString(float)
320 */
321 public void print(float f) {
322 this.write(String.valueOf(f));
323 }
324
325 /* ------------------------------------------------------------ */
326 /**
327 * Print a double-precision floating-point number. The string produced by
328 * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
329 * bytes according to the platform's default character encoding, and these
330 * bytes are written in exactly the manner of the <code>{@link
331 * #write(int)}</code> method.
332 *
333 * @param d The <code>double</code> to be printed
334 * @see java.lang.Double#toString(double)
335 */
336 public void print(double d) {
337 this.write(String.valueOf(d));
338 }
339
340 /* ------------------------------------------------------------ */
341 /**
342 * Print an array of characters. The characters are converted into bytes
343 * according to the platform's default character encoding, and these bytes
344 * are written in exactly the manner of the <code>{@link #write(int)}</code>
345 * method.
346 *
347 * @param s The array of chars to be printed
348 *
349 * @throws NullPointerException If <code>s</code> is <code>null</code>
350 */
351 public void print(char s[]) {
352 this.write(s);
353 }
354
355 /* ------------------------------------------------------------ */
356 /**
357 * Print a string. If the argument is <code>null</code> then the string
358 * <code>"null"</code> is printed. Otherwise, the string's characters are
359 * converted into bytes according to the platform's default character
360 * encoding, and these bytes are written in exactly the manner of the
361 * <code>{@link #write(int)}</code> method.
362 *
363 * @param s The <code>String</code> to be printed
364 */
365 public void print(String s) {
366 if (s == null) {
367 s = "null";
368 }
369 this.write(s);
370 }
371
372 /* ------------------------------------------------------------ */
373 /**
374 * Print an object. The string produced by the <code>{@link
375 * java.lang.String#valueOf(Object)}</code> method is translated into bytes
376 * according to the platform's default character encoding, and these bytes
377 * are written in exactly the manner of the <code>{@link #write(int)}</code>
378 * method.
379 *
380 * @param obj The <code>Object</code> to be printed
381 * @see java.lang.Object#toString()
382 */
383 public void print(Object obj) {
384 this.write(String.valueOf(obj));
385 }
386
387
388 /* Methods that do terminate lines */
389
390 /* ------------------------------------------------------------ */
391 /**
392 * Terminate the current line by writing the line separator string. The
393 * line separator string is defined by the system property
394 * <code>line.separator</code>, and is not necessarily a single newline
395 * character (<code>'\n'</code>).
396 */
397 public void println() {
398 this.newLine();
399 }
400
401 /* ------------------------------------------------------------ */
402 /**
403 * Print a boolean value and then terminate the line. This method behaves
404 * as though it invokes <code>{@link #print(boolean)}</code> and then
405 * <code>{@link #println()}</code>.
406 *
407 * @param x the <code>boolean</code> value to be printed
408 */
409 public void println(boolean x) {
410 synchronized (lock) {
411 this.print(x);
412 this.println();
413 }
414 }
415
416 /* ------------------------------------------------------------ */
417 /**
418 * Print a character and then terminate the line. This method behaves as
419 * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
420 * #println()}</code>.
421 *
422 * @param x the <code>char</code> value to be printed
423 */
424 public void println(char x) {
425 synchronized (lock) {
426 this.print(x);
427 this.println();
428 }
429 }
430
431 /* ------------------------------------------------------------ */
432 /**
433 * Print an integer and then terminate the line. This method behaves as
434 * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
435 * #println()}</code>.
436 *
437 * @param x the <code>int</code> value to be printed
438 */
439 public void println(int x) {
440 synchronized (lock) {
441 this.print(x);
442 this.println();
443 }
444 }
445
446 /* ------------------------------------------------------------ */
447 /**
448 * Print a long integer and then terminate the line. This method behaves
449 * as though it invokes <code>{@link #print(long)}</code> and then
450 * <code>{@link #println()}</code>.
451 *
452 * @param x the <code>long</code> value to be printed
453 */
454 public void println(long x) {
455 synchronized (lock) {
456 this.print(x);
457 this.println();
458 }
459 }
460
461 /* ------------------------------------------------------------ */
462 /**
463 * Print a floating-point number and then terminate the line. This method
464 * behaves as though it invokes <code>{@link #print(float)}</code> and then
465 * <code>{@link #println()}</code>.
466 *
467 * @param x the <code>float</code> value to be printed
468 */
469 public void println(float x) {
470 synchronized (lock) {
471 this.print(x);
472 this.println();
473 }
474 }
475
476 /* ------------------------------------------------------------ */
477 /**
478 * Print a double-precision floating-point number and then terminate the
479 * line. This method behaves as though it invokes <code>{@link
480 * #print(double)}</code> and then <code>{@link #println()}</code>.
481 *
482 * @param x the <code>double</code> value to be printed
483 */
484 /* ------------------------------------------------------------ */
485 public void println(double x) {
486 synchronized (lock) {
487 this.print(x);
488 this.println();
489 }
490 }
491
492 /* ------------------------------------------------------------ */
493 /**
494 * Print an array of characters and then terminate the line. This method
495 * behaves as though it invokes <code>{@link #print(char[])}</code> and then
496 * <code>{@link #println()}</code>.
497 *
498 * @param x the array of <code>char</code> values to be printed
499 */
500 public void println(char x[]) {
501 synchronized (lock) {
502 this.print(x);
503 this.println();
504 }
505 }
506
507 /* ------------------------------------------------------------ */
508 /**
509 * Print a String and then terminate the line. This method behaves as
510 * though it invokes <code>{@link #print(String)}</code> and then
511 * <code>{@link #println()}</code>.
512 *
513 * @param x the <code>String</code> value to be printed
514 */
515 public void println(String x) {
516 synchronized (lock) {
517 this.print(x);
518 this.println();
519 }
520 }
521
522 /* ------------------------------------------------------------ */
523 /**
524 * Print an Object and then terminate the line. This method behaves as
525 * though it invokes <code>{@link #print(Object)}</code> and then
526 * <code>{@link #println()}</code>.
527 *
528 * @param x the <code>Object</code> value to be printed
529 */
530 public void println(Object x) {
531 synchronized (lock) {
532 this.print(x);
533 this.println();
534 }
535 }
536 }