001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.io;
019:
020: import java.nio.charset.Charset;
021: import java.nio.charset.IllegalCharsetNameException;
022: import java.security.AccessController;
023: import java.util.Formatter;
024: import java.util.IllegalFormatException;
025: import java.util.Locale;
026:
027: import org.apache.harmony.luni.util.Msg;
028: import org.apache.harmony.luni.util.PriviAction;
029:
030: /**
031: * PrintStream is a class which takes an OutputStream and provides convenience
032: * methods for printing common data types in a human readable format on the
033: * stream. This is not to be confused with DataOutputStream which is used for
034: * encoding common data types so that they can be read back in. No IOExceptions
035: * are thrown by this class. Instead, callers should call checkError() to see if
036: * a problem has been encountered in this Stream.
037: *
038: */
039: public class PrintStream extends FilterOutputStream implements
040: Appendable, Closeable {
041:
042: private static final String TOKEN_NULL = "null"; //$NON-NLS-1$
043:
044: /**
045: * indicates whether or not this PrintStream has incurred an error.
046: */
047: private boolean ioError;
048:
049: /**
050: * indicates whether or not this PrintStream should flush its contents after
051: * printing a new line.
052: */
053: private boolean autoflush;
054:
055: private String encoding;
056:
057: private final String lineSeparator = AccessController
058: .doPrivileged(new PriviAction<String>("line.separator")); //$NON-NLS-1$
059:
060: // private Formatter formatter;
061:
062: /**
063: * Constructs a new PrintStream on the OutputStream <code>out</code>. All
064: * writes to the target can now take place through this PrintStream. By
065: * default, the PrintStream is set to not autoflush when a newline is
066: * encountered.
067: *
068: * @param out
069: * the OutputStream to provide convenience methods on.
070: */
071: public PrintStream(OutputStream out) {
072: super (out);
073: if (out == null) {
074: throw new NullPointerException();
075: }
076: }
077:
078: /**
079: * Constructs a new PrintStream on the OutputStream <code>out</code>. All
080: * writes to the target can now take place through this PrintStream. The
081: * PrintStream is set to not autoflush if <code>autoflush</code> is
082: * <code>true</code>.
083: *
084: * @param out
085: * the OutputStream to provide convenience methods on.
086: * @param autoflush
087: * indicates whether or not to flush contents upon encountering a
088: * newline sequence.
089: */
090: public PrintStream(OutputStream out, boolean autoflush) {
091: super (out);
092: if (out == null) {
093: throw new NullPointerException();
094: }
095: this .autoflush = autoflush;
096: }
097:
098: /**
099: * Constructs a new PrintStream on the OutputStream <code>out</code>. All
100: * writes to the target can now take place through this PrintStream. The
101: * PrintStream is set to not autoflush if <code>autoflush</code> is
102: * <code>true</code>.
103: *
104: * @param out
105: * the OutputStream to provide convenience methods on.
106: * @param autoflush
107: * indicates whether or not to flush contents upon encountering a
108: * newline sequence.
109: * @param enc
110: * the non-null String describing the desired character encoding.
111: *
112: * @throws UnsupportedEncodingException
113: * If the chosen encoding is not supported
114: */
115: public PrintStream(OutputStream out, boolean autoflush, String enc)
116: throws UnsupportedEncodingException {
117: super (out);
118: if (out == null || enc == null) {
119: throw new NullPointerException();
120: }
121: this .autoflush = autoflush;
122: try {
123: if (!Charset.isSupported(enc)) {
124: throw new UnsupportedEncodingException(enc);
125: }
126: } catch (IllegalCharsetNameException e) {
127: throw new UnsupportedEncodingException(enc);
128: }
129: encoding = enc;
130: }
131:
132: /**
133: * Constructs a new PrintStream on the file <code>file</code>. All writes
134: * to the target can now take place through this PrintStream. Its encoding
135: * character set is the default charset in the VM.
136: *
137: * @param file
138: * the file to provide convenience methods on.
139: * @throws FileNotFoundException
140: * if the file does not exist or cannot be opened to write. Or
141: * the file cannot be created or any problem when open the file
142: * to write.
143: * @throws SecurityException
144: * if the security manager exists and denies the write to the
145: * file.
146: */
147: public PrintStream(File file) throws FileNotFoundException {
148: super (new FileOutputStream(file));
149: }
150:
151: /**
152: * Constructs a new PrintStream on the file <code>file</code>. All writes
153: * to the target can now take place through this PrintStream. Its encoding
154: * character set name is <code>csn</code>.
155: *
156: * @param file
157: * the file to provide convenience methods on.
158: * @param csn
159: * the character set name
160: * @throws FileNotFoundException
161: * if the file does not exist or cannot be opened to write. Or
162: * the file cannot be created or any problem when open the file
163: * to write.
164: * @throws SecurityException
165: * if the security manager exists and denies the write to the
166: * file.
167: * @throws UnsupportedEncodingException
168: * if the chosen character set is not supported
169: */
170: public PrintStream(File file, String csn)
171: throws FileNotFoundException, UnsupportedEncodingException {
172: super (new FileOutputStream(file));
173: if (csn == null) {
174: throw new NullPointerException();
175: }
176: if (!Charset.isSupported(csn)) {
177: throw new UnsupportedEncodingException();
178: }
179: encoding = csn;
180: }
181:
182: /**
183: * Constructs a new PrintStream on the file the name of which is<code>fileName</code>.
184: * All writes to the target can now take place through this PrintStream. Its
185: * encoding character set is the default charset in the VM.
186: *
187: * @param fileName
188: * the file to provide convenience methods on.
189: * @throws FileNotFoundException
190: * if the file does not exist or cannot be opened to write. Or
191: * the file cannot be created or any problem when open the file
192: * to write.
193: * @throws SecurityException
194: * if the security manager exists and denies the write to the
195: * file.
196: */
197: public PrintStream(String fileName) throws FileNotFoundException {
198: this (new File(fileName));
199: }
200:
201: /**
202: * Constructs a new PrintStream on the file the name of which is<code>fileName</code>.
203: * All writes to the target can now take place through this PrintStream. Its
204: * encoding character set name is <code>csn</code>.
205: *
206: * @param fileName
207: * the file to provide convenience methods on.
208: * @param csn
209: * the character set name
210: * @throws FileNotFoundException
211: * if the file does not exist or cannot be opened to write. Or
212: * the file cannot be created or any problem when open the file
213: * to write.
214: * @throws SecurityException
215: * if the security manager exists and denies the write to the
216: * file.
217: * @throws UnsupportedEncodingException
218: * if the chosen character set is not supported
219: */
220: public PrintStream(String fileName, String csn)
221: throws FileNotFoundException, UnsupportedEncodingException {
222: this (new File(fileName), csn);
223: }
224:
225: /**
226: * Answers a boolean indicating whether or not this PrintStream has
227: * encountered an error. If so, the receiver should probably be closed since
228: * further writes will not actually take place. A side effect of calling
229: * checkError is that the target OutputStream is flushed.
230: *
231: * @return <code>true</code> if an error occurred in this PrintStream,
232: * <code>false</code> otherwise.
233: */
234: public boolean checkError() {
235: if (out != null) {
236: flush();
237: }
238: return ioError;
239: }
240:
241: /**
242: * Close this PrintStream. This implementation flushes and then closes the
243: * target stream. If an error occurs, set an error in this PrintStream to
244: * <code>true</code>.
245: */
246: @Override
247: public synchronized void close() {
248: flush();
249: if (out != null) {
250: try {
251: out.close();
252: out = null;
253: } catch (IOException e) {
254: setError();
255: }
256: }
257: }
258:
259: /**
260: * Flush this PrintStream to ensure all pending data is sent out to the
261: * target OutputStream. This implementation flushes the target OutputStream.
262: * If an error occurs, set an error in this PrintStream to <code>true</code>.
263: */
264: @Override
265: public synchronized void flush() {
266: if (out != null) {
267: try {
268: out.flush();
269: return;
270: } catch (IOException e) {
271: // Ignored, fall through to setError
272: }
273: }
274: setError();
275: }
276:
277: /**
278: * Writes a string formatted by an intermediate <code>Formatter</code> to
279: * this stream using the given format string and arguments.
280: * <p>
281: * The method uses the default for the current JVM instance locale, as if it
282: * is specified by the <code>Locale.getDefault()</code> call.
283: *
284: * @param format
285: * A format string.
286: * @param args
287: * The arguments list. If there are more arguments than those
288: * specified by the format string, then the additional arguments
289: * are ignored.
290: * @return This stream.
291: * @throws IllegalFormatException
292: * If the format string is illegal or incompatible with the
293: * arguments or the arguments are less than those required by
294: * the format string or any other illegal situation.
295: * @throws NullPointerException
296: * If the given format is null.
297: */
298: public PrintStream format(String format, Object... args) {
299: return format(Locale.getDefault(), format, args);
300: }
301:
302: /**
303: * Writes a string formatted by an intermediate <code>Formatter</code> to
304: * this stream using the given format string and arguments.
305: *
306: * @param l
307: * The locale used in the method. If locale is null, then no
308: * localization will be applied.
309: * @param format
310: * A format string.
311: * @param args
312: * The arguments list. If there are more arguments than those
313: * specified by the format string, then the additional arguments
314: * are ignored.
315: * @return This stream.
316: * @throws IllegalFormatException
317: * If the format string is illegal or incompatible with the
318: * arguments or the arguments are less than those required by
319: * the format string or any other illegal situation.
320: * @throws NullPointerException
321: * If the given format is null.
322: */
323: public PrintStream format(Locale l, String format, Object... args) {
324: if (format == null) {
325: throw new NullPointerException(Msg.getString("K0351")); //$NON-NLS-1$
326: }
327: new Formatter(this , l).format(format, args);
328: return this ;
329: }
330:
331: /**
332: * Prints a formatted string. The behavior of this method is the same as
333: * this stream's <code>format(String format, Object... args)</code>
334: * method.
335: * <p>
336: * The method uses the default for the current JVM instance locale, as if it
337: * is specified by the <code>Locale.getDefault()</code> call.
338: *
339: * @param format
340: * A format string.
341: * @param args
342: * The arguments list. If there are more arguments than those
343: * specified by the format string, then the additional arguments
344: * are ignored.
345: * @return This stream.
346: * @throws IllegalFormatException
347: * If the format string is illegal or incompatible with the
348: * arguments or the arguments are less than those required by
349: * the format string or any other illegal situation.
350: * @throws NullPointerException
351: * If the given format is null.
352: */
353: public PrintStream printf(String format, Object... args) {
354: return format(format, args);
355: }
356:
357: /**
358: * Prints a formatted string. The behavior of this method is the same as
359: * this writer's
360: * <code>format(Locale l, String format, Object... args)</code> method.
361: *
362: * @param l
363: * The locale used in the method. If locale is null, then no
364: * localization will be applied.
365: * @param format
366: * A format string.
367: * @param args
368: * The arguments list. If there are more arguments than those
369: * specified by the format string, then the additional arguments
370: * are ignored.
371: * @return This stream.
372: * @throws IllegalFormatException
373: * If the format string is illegal or incompatible with the
374: * arguments or the arguments are less than those required by
375: * the format string or any other illegal situation.
376: * @throws NullPointerException
377: * If the given format is null.
378: */
379: public PrintStream printf(Locale l, String format, Object... args) {
380: return format(l, format, args);
381: }
382:
383: /**
384: * Put the line separator String onto the print stream.
385: */
386: private void newline() {
387: print(lineSeparator);
388: }
389:
390: /**
391: * Prints the String representation of the character array parameter
392: * <code>charArray</code> to the target OutputStream.
393: *
394: * @param charArray
395: * the character array to print on this PrintStream.
396: */
397: public void print(char[] charArray) {
398: print(new String(charArray, 0, charArray.length));
399: }
400:
401: /**
402: * Prints the String representation of the character parameter
403: * <code>ch</code> to the target OutputStream.
404: *
405: * @param ch
406: * the character to print on this PrintStream.
407: */
408: public void print(char ch) {
409: print(String.valueOf(ch));
410: }
411:
412: /**
413: * Prints the String representation of the <code>double</code> parameter
414: * <code>dnum</code> to the target OutputStream.
415: *
416: * @param dnum
417: * the <code>double</code> to print on this PrintStream.
418: */
419: public void print(double dnum) {
420: print(String.valueOf(dnum));
421: }
422:
423: /**
424: * Prints the String representation of the <code>float</code> parameter
425: * <code>fnum</code> to the target OutputStream.
426: *
427: * @param fnum
428: * the <code>float</code> to print on this PrintStream.
429: */
430: public void print(float fnum) {
431: print(String.valueOf(fnum));
432: }
433:
434: /**
435: * Obtains the <code>int</code> argument as a <code>String</code> and
436: * prints it to the target {@link OutputStream}.
437: *
438: * @param inum
439: * the <code>int</code> to print on this PrintStream.
440: */
441: public void print(int inum) {
442: print(String.valueOf(inum));
443: }
444:
445: /**
446: * Prints the String representation of the <code>long</code> parameter
447: * <code>lnum</code> to the target OutputStream.
448: *
449: * @param lnum
450: * the <code>long</code> to print on this PrintStream.
451: */
452: public void print(long lnum) {
453: print(String.valueOf(lnum));
454: }
455:
456: /**
457: * Prints the String representation of the Object parameter <code>obj</code>
458: * to the target OutputStream.
459: *
460: * @param obj
461: * the Object to print on this PrintStream.
462: */
463: public void print(Object obj) {
464: print(String.valueOf(obj));
465: }
466:
467: /**
468: * Prints the String representation of the <code>String</code> parameter
469: * <code>str</code> to the target OutputStream.
470: *
471: * @param str
472: * the <code>String</code> to print on this PrintStream.
473: */
474: public synchronized void print(String str) {
475: if (out == null) {
476: setError();
477: return;
478: }
479: if (str == null) {
480: print("null"); //$NON-NLS-1$
481: return;
482: }
483:
484: try {
485: if (encoding == null) {
486: write(str.getBytes());
487: } else {
488: write(str.getBytes(encoding));
489: }
490: } catch (IOException e) {
491: setError();
492: }
493: }
494:
495: /**
496: * Prints the String representation of the <code>boolean</code> parameter
497: * <code>bool</code> to the target OutputStream.
498: *
499: * @param bool
500: * the <code>boolean</code> to print on this PrintStream.
501: */
502: public void print(boolean bool) {
503: print(String.valueOf(bool));
504: }
505:
506: /**
507: * Prints the String representation of the System property
508: * <code>"line.separator"</code> to the target OutputStream.
509: *
510: */
511: public void println() {
512: newline();
513: }
514:
515: /**
516: * Prints the String representation of the character array parameter
517: * <code>charArray</code> to the target OutputStream followed by the
518: * System property <code>"line.separator"</code>.
519: *
520: * @param charArray
521: * the character array to print on this PrintStream.
522: */
523: public void println(char[] charArray) {
524: println(new String(charArray, 0, charArray.length));
525: }
526:
527: /**
528: * Prints the String representation of the character parameter
529: * <code>ch</code> to the target OutputStream followed by the System
530: * property <code>"line.separator"</code>.
531: *
532: * @param ch
533: * the character to print on this PrintStream.
534: */
535: public void println(char ch) {
536: println(String.valueOf(ch));
537: }
538:
539: /**
540: * Prints the String representation of the <code>double</code> parameter
541: * <code>dnum</code> to the target OutputStream followed by the System
542: * property <code>"line.separator"</code>.
543: *
544: * @param dnum
545: * the double to print on this PrintStream.
546: */
547: public void println(double dnum) {
548: println(String.valueOf(dnum));
549: }
550:
551: /**
552: * Prints the String representation of the <code>float</code> parameter
553: * <code>fnum</code> to the target OutputStream followed by the System
554: * property <code>"line.separator"</code>.
555: *
556: * @param fnum
557: * the float to print on this PrintStream.
558: */
559: public void println(float fnum) {
560: println(String.valueOf(fnum));
561: }
562:
563: /**
564: * Obtains the <code>int</code> argument as a <code>String</code> and
565: * prints it to the target {@link OutputStream} followed by the System
566: * property <code>"line.separator"</code>.
567: *
568: * @param inum
569: * the int to print on this PrintStream.
570: */
571: public void println(int inum) {
572: println(String.valueOf(inum));
573: }
574:
575: /**
576: * Prints the String representation of the <code>long</code> parameter
577: * <code>lnum</code> to the target OutputStream followed by the System
578: * property <code>"line.separator"</code>.
579: *
580: * @param lnum
581: * the long to print on this PrintStream.
582: */
583: public void println(long lnum) {
584: println(String.valueOf(lnum));
585: }
586:
587: /**
588: * Prints the String representation of the <code>Object</code> parameter
589: * <code>obj</code> to the target OutputStream followed by the System
590: * property <code>"line.separator"</code>.
591: *
592: * @param obj
593: * the <code>Object</code> to print on this PrintStream.
594: */
595: public void println(Object obj) {
596: println(String.valueOf(obj));
597: }
598:
599: /**
600: * Prints the String representation of the <code>String</code> parameter
601: * <code>str</code> to the target OutputStream followed by the System
602: * property <code>"line.separator"</code>.
603: *
604: * @param str
605: * the <code>String</code> to print on this PrintStream.
606: */
607: public synchronized void println(String str) {
608: print(str);
609: newline();
610: }
611:
612: /**
613: * Prints the String representation of the <code>boolean</code> parameter
614: * <code>bool</code> to the target OutputStream followed by the System
615: * property <code>"line.separator"</code>.
616: *
617: * @param bool
618: * the boolean to print on this PrintStream.
619: */
620: public void println(boolean bool) {
621: println(String.valueOf(bool));
622: }
623:
624: protected void setError() {
625: ioError = true;
626: }
627:
628: /**
629: * Writes <code>count</code> <code>bytes</code> from the byte array
630: * <code>buffer</code> starting at <code>offset</code> to this
631: * PrintStream. This implementation writes the <code>buffer</code> to the
632: * target OutputStream and if this PrintStream is set to autoflush, flushes
633: * it. If an error occurs, set an error in this PrintStream to
634: * <code>true</code>.
635: *
636: * @param buffer
637: * the buffer to be written
638: * @param offset
639: * offset in buffer to get bytes
640: * @param count
641: * number of bytes in buffer to write
642: *
643: * @throws IndexOutOfBoundsException
644: * If offset or count are outside of bounds.
645: */
646: @Override
647: public void write(byte[] buffer, int offset, int count) {
648: if (buffer == null) {
649: throw new NullPointerException();
650: }
651: // avoid int overflow
652: if (offset < 0 || offset > buffer.length || count < 0
653: || count > buffer.length - offset) {
654: throw new ArrayIndexOutOfBoundsException(Msg
655: .getString("K002f")); //$NON-NLS-1$
656: }
657: synchronized (this ) {
658: if (out == null) {
659: setError();
660: return;
661: }
662: try {
663: out.write(buffer, offset, count);
664: if (autoflush) {
665: flush();
666: }
667: } catch (IOException e) {
668: setError();
669: }
670: }
671: }
672:
673: /**
674: * Writes the specified byte <code>oneByte</code> to this PrintStream.
675: * Only the low order byte of <code>oneByte</code> is written. This
676: * implementation writes <code>oneByte</code> to the target OutputStream.
677: * If <code>oneByte</code> is equal to the character <code>'\n'</code>
678: * and this PrintSteam is set to autoflush, the target OutputStream is
679: * flushed.
680: *
681: * @param oneByte
682: * the byte to be written
683: */
684: @Override
685: public synchronized void write(int oneByte) {
686: if (out == null) {
687: setError();
688: return;
689: }
690: try {
691: out.write(oneByte);
692: if (autoflush && (oneByte & 0xFF) == '\n') {
693: flush();
694: }
695: } catch (IOException e) {
696: setError();
697: }
698: }
699:
700: /**
701: * Append a char <code>c</code> to the PrintStream. The
702: * PrintStream.append(<code>c</code>) works the same way as
703: * PrintStream.print(<code>c</code>).
704: *
705: * @param c
706: * The character appended to the PrintStream.
707: * @return The PrintStream.
708: */
709: public PrintStream append(char c) {
710: print(c);
711: return this ;
712: }
713:
714: /**
715: * Append a CharSequence <code>csq</code> to the PrintStream. The
716: * PrintStream.append(<code>csq</code>) works the same way as
717: * PrintStream.print(<code>csq</code>.toString()). If <code>csq</code>
718: * is null, then a CharSequence just contains then "null" will be
719: * substituted for <code>csq</code>.
720: *
721: * @param csq
722: * The CharSequence appended to the PrintStream.
723: * @return The PrintStream.
724: */
725: public PrintStream append(CharSequence csq) {
726: if (null == csq) {
727: print(TOKEN_NULL);
728: } else {
729: print(csq.toString());
730: }
731: return this ;
732: }
733:
734: /**
735: * Append a subsequence of a CharSequence <code>csq</code> to the
736: * PrintStream. The first char and the last char of the subsequnce is
737: * specified by the parameter <code>start</code> and <code>end</code>.
738: * The PrintStream.append(<code>csq</code>) works the same way as
739: * PrintStream.print (<code>csq</code>csq.subSequence(<code>start</code>,
740: * <code>end</code>).toString). If <code>csq</code> is null, then
741: * "null" will be substituted for <code>csq</code>.
742: *
743: * @param csq
744: * The CharSequence appended to the PrintStream.
745: * @param start
746: * The index of the first char in the CharSequence appended to
747: * the PrintStream.
748: * @param end
749: * The index of the char after the last one in the CharSequence
750: * appended to the PrintStream.
751: * @return The PrintStream.
752: * @throws IndexOutOfBoundsException
753: * If start is less than end, end is greater than the length of
754: * the CharSequence, or start or end is negative.
755: */
756: public PrintStream append(CharSequence csq, int start, int end) {
757: if (null == csq) {
758: print(TOKEN_NULL.substring(start, end));
759: } else {
760: print(csq.subSequence(start, end).toString());
761: }
762: return this;
763: }
764: }
|