1. /*
  2. * @(#)PipedWriter.java 1.15 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.io;
  8. /**
  9. * Piped character-output streams.
  10. *
  11. * @version 1.15, 03/01/23
  12. * @author Mark Reinhold
  13. * @since JDK1.1
  14. */
  15. public class PipedWriter extends Writer {
  16. /* REMIND: identification of the read and write sides needs to be
  17. more sophisticated. Either using thread groups (but what about
  18. pipes within a thread?) or using finalization (but it may be a
  19. long time until the next GC). */
  20. private PipedReader sink;
  21. /* This flag records the open status of this particular writer. It
  22. * is independent of the status flags defined in PipedReader. It is
  23. * used to do a sanity check on connect.
  24. */
  25. private boolean closed = false;
  26. /**
  27. * Creates a piped writer connected to the specified piped
  28. * reader. Data characters written to this stream will then be
  29. * available as input from <code>snk</code>.
  30. *
  31. * @param snk The piped reader to connect to.
  32. * @exception IOException if an I/O error occurs.
  33. */
  34. public PipedWriter(PipedReader snk) throws IOException {
  35. connect(snk);
  36. }
  37. /**
  38. * Creates a piped writer that is not yet connected to a
  39. * piped reader. It must be connected to a piped reader,
  40. * either by the receiver or the sender, before being used.
  41. *
  42. * @see java.io.PipedReader#connect(java.io.PipedWriter)
  43. * @see java.io.PipedWriter#connect(java.io.PipedReader)
  44. */
  45. public PipedWriter() {
  46. }
  47. /**
  48. * Connects this piped writer to a receiver. If this object
  49. * is already connected to some other piped reader, an
  50. * <code>IOException</code> is thrown.
  51. * <p>
  52. * If <code>snk</code> is an unconnected piped reader and
  53. * <code>src</code> is an unconnected piped writer, they may
  54. * be connected by either the call:
  55. * <blockquote><pre>
  56. * src.connect(snk)</pre></blockquote>
  57. * or the call:
  58. * <blockquote><pre>
  59. * snk.connect(src)</pre></blockquote>
  60. * The two calls have the same effect.
  61. *
  62. * @param snk the piped reader to connect to.
  63. * @exception IOException if an I/O error occurs.
  64. */
  65. public synchronized void connect(PipedReader snk) throws IOException {
  66. if (snk == null) {
  67. throw new NullPointerException();
  68. } else if (sink != null || snk.connected) {
  69. throw new IOException("Already connected");
  70. } else if (snk.closedByReader || closed) {
  71. throw new IOException("Pipe closed");
  72. }
  73. sink = snk;
  74. snk.in = -1;
  75. snk.out = 0;
  76. snk.connected = true;
  77. }
  78. /**
  79. * Writes the specified <code>char</code> to the piped output stream.
  80. * If a thread was reading data characters from the connected piped input
  81. * stream, but the thread is no longer alive, then an
  82. * <code>IOException</code> is thrown.
  83. * <p>
  84. * Implements the <code>write</code> method of <code>Writer</code>.
  85. *
  86. * @param c the <code>char</code> to be written.
  87. * @exception IOException if an I/O error occurs.
  88. */
  89. public void write(int c) throws IOException {
  90. if (sink == null) {
  91. throw new IOException("Pipe not connected");
  92. }
  93. sink.receive(c);
  94. }
  95. /**
  96. * Writes <code>len</code> characters from the specified character array
  97. * starting at offset <code>off</code> to this piped output stream.
  98. * If a thread was reading data characters from the connected piped input
  99. * stream, but the thread is no longer alive, then an
  100. * <code>IOException</code> is thrown.
  101. *
  102. * @param cbuf the data.
  103. * @param off the start offset in the data.
  104. * @param len the number of characters to write.
  105. * @exception IOException if an I/O error occurs.
  106. */
  107. public void write(char cbuf[], int off, int len) throws IOException {
  108. if (sink == null) {
  109. throw new IOException("Pipe not connected");
  110. } else if ((off | len | (off + len) | (cbuf.length - (off + len))) < 0) {
  111. throw new IndexOutOfBoundsException();
  112. }
  113. sink.receive(cbuf, off, len);
  114. }
  115. /**
  116. * Flushes this output stream and forces any buffered output characters
  117. * to be written out.
  118. * This will notify any readers that characters are waiting in the pipe.
  119. *
  120. * @exception IOException if an I/O error occurs.
  121. */
  122. public synchronized void flush() throws IOException {
  123. if (sink != null) {
  124. if (sink.closedByReader || closed) {
  125. throw new IOException("Pipe closed");
  126. }
  127. synchronized (sink) {
  128. sink.notifyAll();
  129. }
  130. }
  131. }
  132. /**
  133. * Closes this piped output stream and releases any system resources
  134. * associated with this stream. This stream may no longer be used for
  135. * writing characters.
  136. *
  137. * @exception IOException if an I/O error occurs.
  138. */
  139. public void close() throws IOException {
  140. closed = true;
  141. if (sink != null) {
  142. sink.receivedLast();
  143. }
  144. }
  145. }