PipedWriter.java revision 4fefecee9d4a5d2a4510f516b4015607b19e8d09
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.io;
19
20import org.apache.harmony.luni.util.Msg;
21
22/**
23 * Places information on a communications pipe. When two threads want to pass
24 * data back and forth, one creates a piped writer and the other creates a piped
25 * reader.
26 *
27 * @see PipedReader
28 */
29public class PipedWriter extends Writer {
30    /**
31     * The destination PipedReader
32     */
33    private PipedReader dest;
34
35    private boolean closed;
36
37    /**
38     * Constructs a new unconnected {@code PipedWriter}. The resulting writer
39     * must be connected to a {@code PipedReader} before data may be written to
40     * it.
41     *
42     * @see PipedReader
43     */
44    public PipedWriter() {
45        super();
46    }
47
48    /**
49     * Constructs a new {@code PipedWriter} connected to the {@link PipedReader}
50     * {@code dest}. Any data written to this writer can be read from {@code
51     * dest}.
52     *
53     * @param dest
54     *            the {@code PipedReader} to connect to.
55     * @throws IOException
56     *             if {@code dest} is already connected.
57     */
58    public PipedWriter(PipedReader dest) throws IOException {
59        super(dest);
60        connect(dest);
61    }
62
63    /**
64     * Closes this writer. If a {@link PipedReader} is connected to this writer,
65     * it is closed as well and the pipe is disconnected. Any data buffered in
66     * the reader can still be read.
67     *
68     * @throws IOException
69     *             if an error occurs while closing this writer.
70     */
71    @Override
72    public void close() throws IOException {
73        synchronized (lock) {
74            /* Is the pipe connected? */
75            if (dest != null) {
76                dest.done();
77                dest = null;
78            }
79            closed = true;
80        }
81    }
82
83    /**
84     * Connects this {@code PipedWriter} to a {@link PipedReader}. Any data
85     * written to this writer becomes readable in the reader.
86     *
87     * @param stream
88     *            the reader to connect to.
89     * @throws IOException
90     *             if this writer is closed or already connected, or if {@code
91     *             stream} is already connected.
92     */
93    public void connect(PipedReader stream) throws IOException {
94        synchronized (lock) {
95            if (this.dest != null) {
96                throw new IOException(Msg.getString("K0079")); //$NON-NLS-1$
97            }
98            if (closed) {
99                throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
100            }
101            stream.establishConnection();
102            this.dest = stream;
103        }
104    }
105
106    /**
107     * Notifies the readers of this {@code PipedReader} that characters can be read. This
108     * method does nothing if this Writer is not connected.
109     *
110     * @throws IOException
111     *             if an I/O error occurs while flushing this writer.
112     */
113    @Override
114    public void flush() throws IOException {
115        if (dest != null) {
116            dest.flush();
117        }
118    }
119
120    /**
121     * Writes {@code count} characters from the character array {@code buffer}
122     * starting at offset {@code index} to this writer. The written data can
123     * then be read from the connected {@link PipedReader} instance.
124     * <p>
125     * Separate threads should be used to write to a {@code PipedWriter} and to
126     * read from the connected {@code PipedReader}. If the same thread is used,
127     * a deadlock may occur.
128     *
129     * @param buffer
130     *            the buffer to write.
131     * @param offset
132     *            the index of the first character in {@code buffer} to write.
133     * @param count
134     *            the number of characters from {@code buffer} to write to this
135     *            writer.
136     * @throws IndexOutOfBoundsException
137     *             if {@code offset < 0} or {@code count < 0}, or if {@code
138     *             offset + count} is bigger than the length of {@code buffer}.
139     * @throws InterruptedIOException
140     *             if the pipe is full and the current thread is interrupted
141     *             waiting for space to write data. This case is not currently
142     *             handled correctly.
143     * @throws IOException
144     *             if this writer is closed or not connected, if the target
145     *             reader is closed or if the thread reading from the target
146     *             reader is no longer alive. This case is currently not handled
147     *             correctly.
148     * @throws NullPointerException
149     *             if {@code buffer} is {@code null}.
150     */
151    @Override
152    public void write(char[] buffer, int offset, int count) throws IOException {
153        // BEGIN android-note
154        // changed array notation to be consistent with the rest of harmony
155        // END android-note
156        synchronized (lock) {
157            if (closed) {
158                throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
159            }
160            if (dest == null) {
161                throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
162            }
163            if (buffer == null) {
164                throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
165            }
166
167            // avoid int overflow
168            // BEGIN android-changed
169            // Exception priorities (in case of multiple errors) differ from
170            // RI, but are spec-compliant.
171            // removed redundant check, used (offset | count) < 0
172            // instead of (offset < 0) || (count < 0) to safe one operation
173            if ((offset | count) < 0 || count > buffer.length - offset) {
174                throw new IndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$
175            }
176            // END android-changed
177            dest.receive(buffer, offset, count);
178        }
179    }
180
181    /**
182     * Writes a single character {@code c} to this writer. This character can
183     * then be read from the connected {@link PipedReader} instance.
184     * <p>
185     * Separate threads should be used to write to a {@code PipedWriter} and to
186     * read from the connected {@code PipedReader}. If the same thread is used,
187     * a deadlock may occur.
188     *
189     * @param c
190     *            the character to write.
191     * @throws InterruptedIOException
192     *             if the pipe is full and the current thread is interrupted
193     *             waiting for space to write data. This case is not currently
194     *             handled correctly.
195     * @throws IOException
196     *             if this writer is closed or not connected, if the target
197     *             reader is closed or if the thread reading from the target
198     *             reader is no longer alive. This case is currently not handled
199     *             correctly.
200     */
201    @Override
202    public void write(int c) throws IOException {
203        synchronized (lock) {
204            if (closed) {
205                throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
206            }
207            if (dest == null) {
208                throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
209            }
210            dest.receive((char) c);
211        }
212    }
213}
214