PipedWriter.java revision da1bdbd09a1f6c394fa9d4210de9db0b570ac1fd
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
18// BEGIN android-note
19// We've made several changes including:
20//  - move checks into the synchronized method in PipedReader
21//  - reply on PipedReader's isClosed field (rather than having 2 flags)
22//  - avoid shallow concurrency problems
23//  - improved consistency with PipedOutputStream
24// END android-note
25
26package java.io;
27
28import org.apache.harmony.luni.util.Msg;
29
30/**
31 * Places information on a communications pipe. When two threads want to pass
32 * data back and forth, one creates a piped writer and the other creates a piped
33 * reader.
34 *
35 * @see PipedReader
36 */
37public class PipedWriter extends Writer {
38    /**
39     * The destination PipedReader
40     */
41    private PipedReader dest;
42
43    /**
44     * Constructs a new unconnected {@code PipedWriter}. The resulting writer
45     * must be connected to a {@code PipedReader} before data may be written to
46     * it.
47     *
48     * @see PipedReader
49     */
50    public PipedWriter() {
51        super();
52    }
53
54    /**
55     * Constructs a new {@code PipedWriter} connected to the {@link PipedReader}
56     * {@code dest}. Any data written to this writer can be read from {@code
57     * dest}.
58     *
59     * @param dest
60     *            the {@code PipedReader} to connect to.
61     * @throws IOException
62     *             if {@code dest} is already connected.
63     */
64    public PipedWriter(PipedReader dest) throws IOException {
65        super(dest);
66        connect(dest);
67    }
68
69    /**
70     * Closes this writer. If a {@link PipedReader} is connected to this writer,
71     * it is closed as well and the pipe is disconnected. Any data buffered in
72     * the reader can still be read.
73     *
74     * @throws IOException
75     *             if an error occurs while closing this writer.
76     */
77    @Override
78    public void close() throws IOException {
79        PipedReader reader = dest;
80        if (reader != null) {
81            reader.done();
82            dest = null;
83        }
84    }
85
86    /**
87     * Connects this {@code PipedWriter} to a {@link PipedReader}. Any data
88     * written to this writer becomes readable in the reader.
89     *
90     * @param reader
91     *            the reader to connect to.
92     * @throws IOException
93     *             if this writer is closed or already connected, or if {@code
94     *             reader} is already connected.
95     */
96    public void connect(PipedReader reader) throws IOException {
97        if (reader == null) {
98            throw new NullPointerException();
99        }
100        synchronized (reader) {
101            if (this.dest != null) {
102                throw new IOException(Msg.getString("K0079")); //$NON-NLS-1$
103            }
104            if (reader.isConnected) {
105                throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
106            }
107            reader.establishConnection();
108            this.lock = reader;
109            this.dest = reader;
110        }
111    }
112
113    /**
114     * Notifies the readers of this {@code PipedReader} that characters can be read. This
115     * method does nothing if this Writer is not connected.
116     *
117     * @throws IOException
118     *             if an I/O error occurs while flushing this writer.
119     */
120    @Override
121    public void flush() throws IOException {
122        PipedReader reader = dest;
123        if (reader == null) {
124            return;
125        }
126
127        synchronized (reader) {
128            reader.notifyAll();
129        }
130    }
131
132    /**
133     * Writes {@code count} characters from the character array {@code buffer}
134     * starting at offset {@code index} to this writer. The written data can
135     * then be read from the connected {@link PipedReader} instance.
136     * <p>
137     * Separate threads should be used to write to a {@code PipedWriter} and to
138     * read from the connected {@code PipedReader}. If the same thread is used,
139     * a deadlock may occur.
140     *
141     * @param buffer
142     *            the buffer to write.
143     * @param offset
144     *            the index of the first character in {@code buffer} to write.
145     * @param count
146     *            the number of characters from {@code buffer} to write to this
147     *            writer.
148     * @throws IndexOutOfBoundsException
149     *             if {@code offset < 0} or {@code count < 0}, or if {@code
150     *             offset + count} is bigger than the length of {@code buffer}.
151     * @throws InterruptedIOException
152     *             if the pipe is full and the current thread is interrupted
153     *             waiting for space to write data. This case is not currently
154     *             handled correctly.
155     * @throws IOException
156     *             if this writer is closed or not connected, if the target
157     *             reader is closed or if the thread reading from the target
158     *             reader is no longer alive. This case is currently not handled
159     *             correctly.
160     * @throws NullPointerException
161     *             if {@code buffer} is {@code null}.
162     */
163    @Override
164    public void write(char[] buffer, int offset, int count) throws IOException {
165        PipedReader reader = dest;
166        if (reader == null) {
167            // K007b=Pipe Not Connected
168            throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
169        }
170        reader.receive(buffer, offset, count);
171    }
172
173    /**
174     * Writes a single character {@code c} to this writer. This character can
175     * then be read from the connected {@link PipedReader} instance.
176     * <p>
177     * Separate threads should be used to write to a {@code PipedWriter} and to
178     * read from the connected {@code PipedReader}. If the same thread is used,
179     * a deadlock may occur.
180     *
181     * @param c
182     *            the character to write.
183     * @throws InterruptedIOException
184     *             if the pipe is full and the current thread is interrupted
185     *             waiting for space to write data. This case is not currently
186     *             handled correctly.
187     * @throws IOException
188     *             if this writer is closed or not connected, if the target
189     *             reader is closed or if the thread reading from the target
190     *             reader is no longer alive. This case is currently not handled
191     *             correctly.
192     */
193    @Override
194    public void write(int c) throws IOException {
195        PipedReader reader = dest;
196        if (reader == null) {
197            // K007b=Pipe Not Connected
198            throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
199        }
200        reader.receive((char) c);
201    }
202}
203