package htsjdk.samtools;
import htsjdk.samtools.util.RuntimeIOException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/**
* OutputStream implementation that writes output to an underlying output stream while also copying the
* same bytes to a PipedOutputStream that routes the data back into an Indexer to generate a BAMIndex
* by inflating and decoding the stream and feeding the SAMRecords to a BAMIndexer.
*/
class StreamInflatingIndexingOutputStream extends OutputStream {
private final OutputStream s1;
private final PipedOutputStream s2;
private final Thread thread;
public StreamInflatingIndexingOutputStream(final OutputStream s1, final File indexFile) {
try {
this.s1 = s1;
this.s2 = new PipedOutputStream();
final PipedInputStream pin = new PipedInputStream(this.s2, Defaults.NON_ZERO_BUFFER_SIZE);
this.thread = new Thread(new Indexer(indexFile, pin), "BamIndexingThread");
this.thread.start();
}
catch (final IOException ioe) {
throw new RuntimeIOException(ioe);
}
}
@Override public final void write(final int b) throws IOException { this.s1.write(b); this.s2.write(b); }
@Override public final void write(final byte[] b) throws IOException { this.s1.write(b); this.s2.write(b); }
@Override public final void write(final byte[] b, final int off, final int len) throws IOException { this.s1.write(b, off, len); this.s2.write(b, off, len); }
@Override public final void flush() throws IOException { this.s1.flush(); this.s2.flush(); }
@Override public final void close() throws IOException {
this.s1.close();
this.s2.close();
try { this.thread.join(); }
catch (final InterruptedException ie) { throw new RuntimeException(ie); }
}
}
/**
* A little class that takes an InputStream from which it reads a BAM file, generates
* a BAMIndex and then writes the index to the File provided. All operations are designed
* to be carried out in a separate thread.
*/
class Indexer implements Runnable {
private final File index;
private final InputStream stream;
/** Constructs an indexer that reads from the stream provided and writes an index to the File provided. */
Indexer(final File index, final InputStream stream) {
this.index = index;
this.stream = stream;
}
/** Runnable implementation that reads the entire stream and writes the index. */
@Override
public void run() {
final SAMFileReader in = new SAMFileReader(this.stream);
in.enableFileSource(true);
in.setValidationStringency(ValidationStringency.SILENT);
in.enableCrcChecking(false);
final BAMIndexer indexer = new BAMIndexer(this.index, in.getFileHeader());
for (final SAMRecord rec : in) {
indexer.processAlignment(rec);
}
indexer.finish();
in.close();
}
}