All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.ac.starlink.util.PipeReaderThread Maven / Gradle / Ivy

There is a newer version: 4.3
Show newest version
package uk.ac.starlink.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Thread which reads data from a pipe.  Having got an instance
 * of this class, you can call its getOutputStream method to 
 * acquire a stream to write into, and then implement its 
 * {@link #doReading} method to process the data; this method runs
 * in the new thread.
 * 

* Here is an example of using the class to count the bytes written down * a stream: *

 *     PipeReaderThread reader = new PipeReaderThread() {
 *        protected void doReading( InputStream dataIn ) throws IOException {
 *            int i;
 *            while ( dataIn.read() >= 0 ) i++;
 *            System.out.println( i );
 *        }
 *     };
 *     reader.start();
 *     OutputStream dataOut = reader.getOutputStream();
 *     // write bytes down dataOut ...
 *     dataOut.close();
 *     reader.finishReading();
 * 
* Other uses will look pretty similar, but just override doReading * in different ways. Note that any exceptions thrown by doReading * are caught and eventually thrown in the reader thread by * finishReading. The same exception may also be thrown by * the write method of the writer thread. *

* This class serves two purposes. Firstly it copes with IOExceptions * encountered during the read, and makes sure they get thrown at the * writing end of the pipe (doReading is declared to * throw IOException). * Secondly it shields the user from the implementation of the piped * connection. * Performance of the * {@link java.io.PipedInputStream}/{@link java.io.PipedOutputStream} * is dismal - this class may be able to do better. *

* The current implementation uses a couple of drop-in Piped*Stream * replacements, but performance still isn't great - it may be possible * to do better in future. You can provide your own paired pipes * by overriding both {@link #getInputStream} and {@link #getOutputStream}. * * @author Mark Taylor (Starlink) */ public abstract class PipeReaderThread extends Thread { private final FastPipedInputStream pipeIn; private final OutputStream pipeOut; private Throwable caught; /** * Constructs a new reader thread. */ public PipeReaderThread() throws IOException { super( "Stream reader" ); /* Set up the reader stream. */ pipeIn = new FastPipedInputStream(); /* Set up the writer stream. If there is an error at the read end, * arrange that any writes to this stream will throw the same * exception. */ pipeOut = new FastPipedOutputStream( pipeIn ) { public void write( byte[] b, int off, int len ) throws IOException { if ( caught == null ) { try { super.write( b, off, len ); return; } catch ( Throwable e ) { if ( caught == null ) { caught = e; } } } assert caught != null; if ( caught instanceof IOException ) { throw (IOException) caught; } else if ( caught instanceof RuntimeException ) { throw (RuntimeException) caught; } else if ( caught instanceof Error ) { throw (Error) caught; } else { throw (IOException) new IOException( caught.getMessage() ) .initCause( caught ); } } }; } /** * Returns the stream at the input end of the pipe. * * @return input stream */ protected InputStream getInputStream() { return pipeIn; } /** * Returns the stream at the output end of the pipe. * * @return output stream */ public OutputStream getOutputStream() { return pipeOut; } /** * Implements the thread's run method to invoke doReading, * catching and saving IOExceptions. */ public void run() { InputStream in = null; try { in = getInputStream(); doReading( in ); } catch ( Throwable e ) { caught = e; } } /** * This method should be implemented to consume all the bytes in * the given input stream. It is probably a good idea for implementations * to buffer the supplied input stream for efficiency. * Note that any implementation of this method which does not read * dataIn to the end of the stream (either closing it early or * just stopping reading) may cause an IOException to be thrown in * the thread which is writing to the PipedOutputStream. * Implementations should not close the supplied input stream. * * @param dataIn stream which will supply bytes * @throws IOException if any I/O error occurs; this exception will * be saved and thrown later by the finishReading method */ protected abstract void doReading( InputStream dataIn ) throws IOException; /** * Waits until the doReading method has finished reading * the bytes written down the output stream, closes the input stream, * and returns. * Any IOException which has occurred during the read will be thrown * by this method. */ public void finishReading() throws IOException { try { join(); pipeIn.close(); } catch ( InterruptedException e ) { if ( caught == null ) { caught = new IOException( "Thread trouble joining stream reader" ); } } if ( caught instanceof IOException ) { throw (IOException) caught; } else if ( caught instanceof RuntimeException ) { throw (RuntimeException) caught; } else if ( caught instanceof Error ) { throw (Error) caught; } else if ( caught != null ) { throw (IOException) new IOException( caught.getMessage() ) .initCause( caught ); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy