org.opencastproject.util.StreamConsumer Maven / Gradle / Ivy
/*
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License
* at:
*
* http://opensource.org/licenses/ecl2.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.opencastproject.util;
import static com.entwinemedia.fn.Prelude.chuck;
import com.entwinemedia.fn.Fn;
import com.entwinemedia.fn.Fx;
import com.entwinemedia.fn.Unit;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.CountDownLatch;
/**
* A StreamConsumer helps to asynchronously consume a text input stream line by line.
* The consumer guarantees the closing of the stream.
*/
public class StreamConsumer implements Runnable {
private final CountDownLatch running = new CountDownLatch(1);
private final CountDownLatch ready = new CountDownLatch(1);
private final CountDownLatch finished = new CountDownLatch(1);
private final Fn consumer;
private boolean stopped = false;
private InputStream stream;
private BufferedReader reader;
/**
* Create a new stream consumer.
*
* @param consumer
* a predicate function that may stop reading further lines by returning false
*/
public StreamConsumer(Fn consumer) {
this.consumer = consumer;
}
@Override public void run() {
try {
running.countDown();
ready.await();
// also save a reference to the reader to able to close it in stopReading
// otherwise the read loop may continue reading from the buffer
reader = new BufferedReader(new InputStreamReader(stream));
IoSupport.withResource(reader, consumeBuffered);
finished.countDown();
} catch (InterruptedException e) {
chuck(e);
}
}
/** Wait for the executing thread to run. */
public void waitUntilRunning() {
try {
running.await();
} catch (InterruptedException e) {
chuck(e);
}
}
/** Wait until the stream has been fully consumed. */
public void waitUntilFinished() {
try {
finished.await();
} catch (InterruptedException e) {
chuck(e);
}
}
/** Forcibly stop consuming the stream. */
public void stopConsuming() {
if (stream != null) {
stopped = true;
IoSupport.closeQuietly(stream);
IoSupport.closeQuietly(reader);
}
}
/** Start consuming stream
. It is guaranteed that the stream gets closed. */
public void consume(InputStream stream) {
waitUntilRunning();
this.stream = stream;
ready.countDown();
}
private final Fn consumeBuffered = new Fx() {
@Override public void apply(BufferedReader reader) {
String line;
try {
while ((line = reader.readLine()) != null) {
if (!consumer.apply(line)) {
stopConsuming();
}
}
} catch (IOException e) {
if (!stopped) {
chuck(e);
}
}
}
}.toFn();
}