Skip to content

Commit b21c2ac

Browse files
committed
Add PollingQueueInputStream and TakingQueueInputStream to replace
QueueInputStream
1 parent 7b53642 commit b21c2ac

6 files changed

Lines changed: 397 additions & 125 deletions

File tree

src/changes/changes.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,9 @@ The <action> type attribute can be add,update,fix,remove.
471471
<action dev="ggregory" type="add" due-to="Gary Gregory">
472472
Add builders and avoid creating more constructors for all permutations of current options.
473473
</action>
474+
<action dev="ggregory" type="add" due-to="Gary Gregory, maxxedev">
475+
Add PollingQueueInputStream and TakingQueueInputStream to replace QueueInputStream. See also #447.
476+
</action>
474477
<!-- UPDATE -->
475478
<action dev="kinow" type="update" due-to="Dependabot, Gary Gregory">
476479
Bump actions/cache from 2.1.6 to 3.0.10 #307, #337, #393.
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
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+
package org.apache.commons.io.input;
19+
20+
import static org.apache.commons.io.IOUtils.EOF;
21+
22+
import java.io.IOException;
23+
import java.io.InputStream;
24+
import java.io.InterruptedIOException;
25+
import java.io.PipedInputStream;
26+
import java.io.PipedOutputStream;
27+
import java.util.Objects;
28+
import java.util.concurrent.BlockingQueue;
29+
import java.util.concurrent.LinkedBlockingQueue;
30+
31+
import org.apache.commons.io.output.QueueOutputStream;
32+
33+
/**
34+
* Alternative to {@link java.io.PipedInputStream}, where this queue input stream provides what's written in a queue output stream.
35+
* <p>
36+
* Example usage, see {@link PollingQueueInputStream} and {@link TakingQueueInputStream}.
37+
* </p>
38+
*
39+
* @see PollingQueueInputStream
40+
* @see TakingQueueInputStream
41+
* @since 2.12.0
42+
*/
43+
public abstract class AbstractBlockingQueueInputStream extends InputStream {
44+
45+
/**
46+
* Simple alternative to JDK {@link java.io.PipedInputStream}; queue input stream provides what's written in queue output stream.
47+
*
48+
* <p>
49+
* Example usage:
50+
* </p>
51+
*
52+
* <pre>
53+
* BlockingQueueInputStream inputStream = new BlockingQueueInputStream();
54+
* QueueOutputStream outputStream = inputStream.newQueueOutputStream();
55+
*
56+
* outputStream.write("hello world".getBytes(UTF_8));
57+
* inputStream.read();
58+
* </pre>
59+
* <p>
60+
* Unlike JDK {@link PipedInputStream} and {@link PipedOutputStream}, queue input/output streams may be used safely in a single thread or multiple threads.
61+
* Also, unlike JDK classes, no special meaning is attached to initial or current thread. Instances can be used longer after initial threads exited.
62+
* </p>
63+
* <p>
64+
* Closing a {@link PollingQueueInputStream} has no effect. The methods in this class can be called after the stream has been closed without generating an
65+
* {@link IOException}.
66+
* </p>
67+
*
68+
* @see QueueOutputStream
69+
* @since 2.12.0
70+
*/
71+
public static class PollingQueueInputStream extends AbstractBlockingQueueInputStream {
72+
73+
/**
74+
* Constructs a new instance.
75+
*/
76+
public PollingQueueInputStream() {
77+
}
78+
79+
/**
80+
* Constructs a new instance with given queue.
81+
*
82+
* @param blockingQueue backing queue for the stream.
83+
*/
84+
public PollingQueueInputStream(final BlockingQueue<Integer> blockingQueue) {
85+
super(blockingQueue);
86+
}
87+
88+
@Override
89+
public int read() throws IOException {
90+
final Integer value = getBlockingQueue().poll();
91+
return value == null ? EOF : 0xFF & value;
92+
}
93+
}
94+
95+
/**
96+
* Simple alternative to JDK {@link java.io.PipedInputStream}; queue input stream provides what's written in queue output stream.
97+
*
98+
* <p>
99+
* Example usage:
100+
* </p>
101+
*
102+
* <pre>
103+
* TakingQueueInputStream inputStream = new TakingQueueInputStream();
104+
* QueueOutputStream outputStream = inputStream.newQueueOutputStream();
105+
*
106+
* outputStream.write("hello world".getBytes(UTF_8));
107+
* inputStream.read();
108+
* </pre>
109+
* <p>
110+
* Unlike JDK {@link PipedInputStream} and {@link PipedOutputStream}, queue input/output streams may be used safely in a single thread or multiple threads.
111+
* Also, unlike JDK classes, no special meaning is attached to initial or current thread. Instances can be used longer after initial threads exited.
112+
* </p>
113+
* <p>
114+
* Closing a {@link TakingQueueInputStream} has no effect. The methods in this class can be called after the stream has been closed without generating an
115+
* {@link IOException}.
116+
* </p>
117+
*
118+
* @see QueueOutputStream
119+
* @since 2.12.0
120+
*/
121+
public static class TakingQueueInputStream extends AbstractBlockingQueueInputStream {
122+
123+
/**
124+
* Constructs a new instance.
125+
*/
126+
public TakingQueueInputStream() {
127+
}
128+
129+
/**
130+
* Constructs a new instance with given queue.
131+
*
132+
* @param blockingQueue backing queue for the stream.
133+
*/
134+
public TakingQueueInputStream(final BlockingQueue<Integer> blockingQueue) {
135+
super(blockingQueue);
136+
}
137+
138+
/**
139+
* Reads and returns a single byte.
140+
*
141+
* @return either the byte read or {@code -1} if the end of the stream has been reached
142+
* @throws InterruptedIOException if interrupted while waiting to take.
143+
*/
144+
@Override
145+
public int read() throws InterruptedIOException {
146+
try {
147+
return getBlockingQueue().take();
148+
} catch (final InterruptedException e) {
149+
Thread.currentThread().interrupt();
150+
final InterruptedIOException ioException = new InterruptedIOException();
151+
ioException.initCause(e);
152+
throw ioException;
153+
}
154+
}
155+
}
156+
157+
private final BlockingQueue<Integer> blockingQueue;
158+
159+
/**
160+
* Constructs a new instance with no limit to its internal buffer size.
161+
*/
162+
protected AbstractBlockingQueueInputStream() {
163+
this(new LinkedBlockingQueue<>());
164+
}
165+
166+
/**
167+
* Constructs a new instance with given buffer
168+
*
169+
* @param blockingQueue backing queue for the stream
170+
*/
171+
protected AbstractBlockingQueueInputStream(final BlockingQueue<Integer> blockingQueue) {
172+
this.blockingQueue = Objects.requireNonNull(blockingQueue, "blockingQueue");
173+
}
174+
175+
/**
176+
* Gets the underlying BlockingQueue.
177+
*
178+
* @return the underlying BlockingQueue.
179+
*/
180+
protected BlockingQueue<Integer> getBlockingQueue() {
181+
return blockingQueue;
182+
}
183+
184+
/**
185+
* Creates a new QueueOutputStream instance connected to this. Writes to the output stream will be visible to this input stream.
186+
*
187+
* @return QueueOutputStream connected to this stream
188+
*/
189+
public QueueOutputStream newQueueOutputStream() {
190+
return new QueueOutputStream(blockingQueue);
191+
}
192+
193+
}

src/main/java/org/apache/commons/io/input/QueueInputStream.java

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@
1919
import static org.apache.commons.io.IOUtils.EOF;
2020

2121
import java.io.IOException;
22-
import java.io.InputStream;
2322
import java.io.PipedInputStream;
2423
import java.io.PipedOutputStream;
25-
import java.util.Objects;
2624
import java.util.concurrent.BlockingQueue;
2725
import java.util.concurrent.LinkedBlockingQueue;
2826

@@ -54,10 +52,10 @@
5452
*
5553
* @see QueueOutputStream
5654
* @since 2.9.0
55+
* @deprecated Use {@link AbstractBlockingQueueInputStream.PollingQueueInputStream}
5756
*/
58-
public class QueueInputStream extends InputStream {
59-
60-
private final BlockingQueue<Integer> blockingQueue;
57+
@Deprecated
58+
public class QueueInputStream extends AbstractBlockingQueueInputStream {
6159

6260
/**
6361
* Constructs a new instance with no limit to its internal buffer size.
@@ -67,22 +65,12 @@ public QueueInputStream() {
6765
}
6866

6967
/**
70-
* Constructs a new instance with given buffer
68+
* Constructs a new instance with given queue.
7169
*
72-
* @param blockingQueue backing queue for the stream
70+
* @param blockingQueue backing queue for the stream.
7371
*/
7472
public QueueInputStream(final BlockingQueue<Integer> blockingQueue) {
75-
this.blockingQueue = Objects.requireNonNull(blockingQueue, "blockingQueue");
76-
}
77-
78-
/**
79-
* Creates a new QueueOutputStream instance connected to this. Writes to the output stream will be visible to this
80-
* input stream.
81-
*
82-
* @return QueueOutputStream connected to this stream
83-
*/
84-
public QueueOutputStream newQueueOutputStream() {
85-
return new QueueOutputStream(blockingQueue);
73+
super(blockingQueue);
8674
}
8775

8876
/**
@@ -92,7 +80,7 @@ public QueueOutputStream newQueueOutputStream() {
9280
*/
9381
@Override
9482
public int read() {
95-
final Integer value = blockingQueue.poll();
83+
final Integer value = getBlockingQueue().poll();
9684
return value == null ? EOF : 0xFF & value;
9785
}
9886

0 commit comments

Comments
 (0)