jlibs.core.io.PumpedReader Maven / Gradle / Ivy
/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license this file to you under the Apache 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://www.apache.org/licenses/LICENSE-2.0
*
* 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 jlibs.core.io;
import jlibs.core.lang.ImpossibleException;
import java.io.*;
/**
* This class simplifies usage of {@link java.io.PipedReader} and {@link java.io.PipedWriter}
*
* Using {@link java.io.PipedReader} and {@link java.io.PipedWriter} looks cumbersome.
*
* PipedReader pipedReader = new PipedReader();
* final PipedWriter pipedWriter = new PipedWriter(pipedReader);
* final IOException ioEx[] = { null };
* new Thread(){
* @Override
* public void run(){
* try{
* writeDataTo(pipedWriter);
* pipedWriter.close();
* }catch(IOException ex){
* ioEx[0] = ex;
* }
* }
* }.start();
* readDataFrom(pipedReader);
* pipedReader.close();
* if(ioEx[0]!=null)
* throw new RuntimeException("something gone wrong", ioEx[0]);
*
* The same can be achieved using {@link PumpedReader} as follows:
*
* PumpedReader reader = new PumpedReader(){
* @Override
* protected void {@link #pump(java.io.PipedWriter) pump}(PipedWriter writer) throws Exception{
* writeDataTo(writer);
* }
* }.{@link #start()}; // start() will spawn new thread
* readDataFrom(reader);
* reader.{@link #close()}; // any exceptions occurred in pump(...) are thrown by close()
*
*
* {@link PumpedReader} is an abstract class with following abstract method:
*
* protected abstract void {@link #pump(java.io.PipedWriter) pump}(PipedWriter writer) throws Exception;
*
* This method implementation should write data into {@code writer} which is passed as argument and close it.
* Any exception thrown by {@link #pump(java.io.PipedWriter) pump(...)} are wrapped in {@link java.io.IOException} and rethrown by PumpedReader.{@link #close()}.
*
* {@link PumpedReader} implements {@link Runnable} which is supposed to be run in thread.
* You can use PumpedReader.{@link #start()} method to start thread or spawn thread implicitly.
* {@link #start()} method returns self reference.
*
* public PumpedReader {@link #start()};
*
* The advantage of {@link PumpedReader} over {@link java.io.PipedReader}/{@link java.io.PipedWriter}/{@link Thread} is:
*
* - it doesn't clutter the exising flow of code
* - exception handling is better
*
*
* @see PumpedInputStream
*
* @author Santhosh Kumar T
*/
public abstract class PumpedReader extends PipedReader implements Runnable{
private PipedWriter writer = new PipedWriter();
public PumpedReader(){
try{
super.connect(writer);
}catch(IOException ex){
throw new ImpossibleException();
}
}
private IOException exception;
private void setException(Exception ex){
if(ex instanceof IOException)
exception = (IOException)ex;
else
exception = new IOException(ex);
}
@Override
public void run(){
try{
pump(writer);
}catch(Exception ex){
setException(ex);
}finally{
try{
writer.close();
}catch(IOException ex){
this.exception = ex;
}
}
}
/**
* Starts a thread with this instance as runnable.
*
* @return self reference
*/
public PumpedReader start(){
new Thread(this).start();
return this;
}
/**
* Closes this stream and releases any system resources
* associated with the stream.
*
* Any exception thrown by {@link #pump(java.io.PipedWriter)}
* are cached and rethrown by this method
*
* @exception IOException if an I/O error occurs.
*/
@Override
@SuppressWarnings({"ThrowFromFinallyBlock"})
public void close() throws IOException{
try{
super.close();
}finally{
if(exception!=null)
throw exception;
}
}
/**
* Subclasse implementation should write data into writer
.
*
* @param writer writer into which data should be written
*/
protected abstract void pump(PipedWriter writer) throws Exception;
}