diff --git a/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisTK.java b/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisTK.java index 063b5e643..0879b21d0 100644 --- a/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisTK.java +++ b/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisTK.java @@ -45,7 +45,7 @@ public class GenomeAnalysisTK extends CommandLineProgram { public String DOWNSAMPLE_COVERAGE = null; public String INTERVALS_FILE = null; - + // our walker manager private WalkerManager walkerManager = null; @@ -73,19 +73,12 @@ public class GenomeAnalysisTK extends CommandLineProgram { /** * How many threads should be allocated to this analysis. */ - public int numThreads = 1; + public int numThreads = 1; /** - * The output stream, initialized from OUTFILENAME / OUTERRFILENAME. - * Used by the walker. + * Collection of output streams used by the walker. */ - public PrintStream out = System.out; - - /** - * The output stream, initialized from ERRFILENAME / OUTERRFILENAME. - * Used by the walker. - */ - public PrintStream err = System.err; + private OutputTracker outputTracker = null; /** * our log, which we want to capture anything from this class @@ -121,7 +114,7 @@ public class GenomeAnalysisTK extends CommandLineProgram { m_parser.addOptionalArg("out", "o", "An output file presented to the walker. Will overwrite contents if file exists.", "outFileName" ); m_parser.addOptionalArg("err", "e", "An error output file presented to the walker. Will overwrite contents if file exists.", "errFileName" ); m_parser.addOptionalArg("outerr", "oe", "A joint file for 'normal' and error output presented to the walker. Will overwrite contents if file exists.", "outErrFileName"); - + m_parser.addOptionalArg("numthreads", "nt", "How many threads should be allocated to running this analysis.", "numThreads"); m_parser.addOptionalFlag("disablethreading", "dt", "Disable experimental threading support.", "DISABLE_THREADING"); @@ -179,7 +172,7 @@ public class GenomeAnalysisTK extends CommandLineProgram { /** * Convenience function that binds RODs using the old-style command line parser to the new style list for * a uniform processing. - * + * * @param name * @param type * @param file @@ -227,7 +220,7 @@ public class GenomeAnalysisTK extends CommandLineProgram { if ( HAPMAP_CHIP_FILE != null ) bindConvenienceRods("hapmap-chip", "GFF", HAPMAP_CHIP_FILE); ReferenceOrderedData.parseBindings(logger, ROD_BINDINGS, rods); - + initializeOutputStreams(); Walker my_walker = null; @@ -267,7 +260,7 @@ public class GenomeAnalysisTK extends CommandLineProgram { this.engine = microScheduler.getTraversalEngine(); } else { - logger.warn("Preliminary threading support DISABLED"); + logger.warn("Preliminary threading support DISABLED"); this.engine = new TraverseByLociByReference(INPUT_FILES, REF_FILE_ARG, rods); } } @@ -345,30 +338,24 @@ public class GenomeAnalysisTK extends CommandLineProgram { * Initialize the output streams as specified by the user. */ private void initializeOutputStreams() { - out = System.out; - err = System.err; + outputTracker = (outErrFileName != null) ? new OutputTracker( outErrFileName, outErrFileName ) + : new OutputTracker( outFileName, errFileName ); + } - if( outErrFileName != null && (outFileName != null || errFileName != null) ) - throw new IllegalArgumentException("Can't set output/error output file with either out file name or err file name"); + /** + * Get the output stream to be used with this walker. + * @return Output stream used with this walker. + */ + public PrintStream getWalkerOutputStream() { + return outputTracker.getOutStream(); + } - try { - if( outErrFileName != null ) { - PrintStream outErrStream = new PrintStream( outErrFileName ); - out = outErrStream; - err = outErrStream; - } - - if ( outFileName != null ) { - out = new PrintStream( outFileName ); - } - - if( errFileName != null ) { - err = new PrintStream( errFileName ); - } - } - catch( FileNotFoundException ex ) { - throw new RuntimeException("Unable to open a walker output file.", ex); - } + /** + * Get the output stream to be used with this walker. + * @return Output stream used with this walker. + */ + public PrintStream getWalkerErrorStream() { + return outputTracker.getErrStream(); } diff --git a/java/src/org/broadinstitute/sting/gatk/OutputTracker.java b/java/src/org/broadinstitute/sting/gatk/OutputTracker.java new file mode 100755 index 000000000..412bab677 --- /dev/null +++ b/java/src/org/broadinstitute/sting/gatk/OutputTracker.java @@ -0,0 +1,120 @@ +package org.broadinstitute.sting.gatk; + +import org.broadinstitute.sting.utils.StingException; + +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.io.FileNotFoundException; +/** + * User: hanna + * Date: Apr 30, 2009 + * Time: 9:40:09 AM + * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT + * Software and documentation are copyright 2005 by the Broad Institute. + * All rights are reserved. + * + * Users acknowledge that this software is supplied without any warranty or support. + * The Broad Institute is not responsible for its use, misuse, or + * functionality. + */ + +/** + * Manages the output and err streams that are created specifically for walker + * output. + */ + +public class OutputTracker { + /** + * The streams to which walker users should be writing directly. + */ + private PrintStream out; + private PrintStream err; + + /** + * Cache the file streams so that reassemblers can use nio to do fast file transfers. + */ + private FileOutputStream outFileStream; + private FileOutputStream errFileStream; + + + /** + * Create an object to manage output given filenames for the output and error files. + * If no files are specified, returns null. + * @param outFileName Name of the output file. + * @param errFileName Name of the error file. + */ + public OutputTracker( String outFileName, String errFileName ) { + // If the two output streams match and are non-null, initialize them identically. + // Otherwise, initialize them separately. + if( outFileName != null && outFileName.equals(errFileName) ) { + FileOutputStream outputFile = prepareOutputFile( outFileName ); + outFileStream = errFileStream = outputFile; + out = err = new PrintStream( outputFile ); + } + else { + if( outFileName != null ) { + outFileStream = prepareOutputFile( outFileName ); + out = new PrintStream( outFileStream ); + } + else + out = System.out; + + if( errFileName != null ) { + errFileStream = prepareOutputFile( errFileName ); + err = new PrintStream( errFileStream ); + } + else + err = System.err; + } + } + + /** + * Gets the output stream for the walker. + * @return Output stream; should be either file-backed or System.out. + */ + public PrintStream getOutStream() { + return out; + } + + /** + * Gets the error stream for the walker. + * @return Error stream; should be either file-backed or System.err. + */ + public PrintStream getErrStream() { + return err; + } + + /** + * Gets the filestream associated with normal output. + * @return FileStream associated with the output; null if not backed by a file. + */ + public FileOutputStream getOutFile() { + return outFileStream; + } + + /** + * Gets the filestream associated with error output. + * @return stream associated with error output; null if not backed by a file. + */ + public FileOutputStream getErrFile() { + return errFileStream; + } + + /** + * Given a (non-null) filename, open a file for output. + * @param fileName Filename for the stream. Should not be null. + * @return An open output stream associated with the given file. + */ + private FileOutputStream prepareOutputFile( String fileName ) { + FileOutputStream outputFile = null; + + try { + outputFile = new FileOutputStream( fileName ); + } + catch( FileNotFoundException ex ) { + throw new StingException("Unable to open output file " + fileName, ex); + } + + return outputFile; + } +} diff --git a/java/src/org/broadinstitute/sting/gatk/walkers/Walker.java b/java/src/org/broadinstitute/sting/gatk/walkers/Walker.java index b5ee85c7e..6f47d3b32 100755 --- a/java/src/org/broadinstitute/sting/gatk/walkers/Walker.java +++ b/java/src/org/broadinstitute/sting/gatk/walkers/Walker.java @@ -35,8 +35,8 @@ public abstract class Walker { protected Walker() { if( GenomeAnalysisTK.Instance != null ) { GenomeAnalysisTK.Instance.loadArgumentsIntoObject(this); - out = GenomeAnalysisTK.Instance.out; - err = GenomeAnalysisTK.Instance.err; + out = GenomeAnalysisTK.Instance.getWalkerOutputStream(); + err = GenomeAnalysisTK.Instance.getWalkerErrorStream(); } else { out = System.out; diff --git a/java/test/org/broadinstitute/sting/gatk/OutputTrackerTest.java b/java/test/org/broadinstitute/sting/gatk/OutputTrackerTest.java new file mode 100755 index 000000000..3b9bcae7b --- /dev/null +++ b/java/test/org/broadinstitute/sting/gatk/OutputTrackerTest.java @@ -0,0 +1,104 @@ +package org.broadinstitute.sting.gatk; + +import org.junit.Test; +import org.junit.After; +import org.junit.Assert; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; /** + * User: hanna + * Date: Apr 30, 2009 + * Time: 10:20:18 AM + * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT + * Software and documentation are copyright 2005 by the Broad Institute. + * All rights are reserved. + * + * Users acknowledge that this software is supplied without any warranty or support. + * The Broad Institute is not responsible for its use, misuse, or + * functionality. + */ + +/** + * For the file opening and closing mechanisms. + */ + +public class OutputTrackerTest { + public static final String OUTPUT_FILENAME = "OutputTrackerTest.out"; + public static final String ERROR_FILENAME = "OutputTrackerTest.err"; + + @After + public void cleanupTestFiles() { + File outFile = new File( OUTPUT_FILENAME ); + File errFile = new File( ERROR_FILENAME ); + + if( outFile.exists() ) outFile.delete(); + if( errFile.exists() ) errFile.delete(); + } + + @Test + public void testNullInputs() { + OutputTracker ot = new OutputTracker(null,null); + Assert.assertSame("OutputTracker: Output stream incorrectly initialized.", System.out, ot.getOutStream()); + Assert.assertSame("OutputTracker: Error stream incorrectly initialized.", System.err, ot.getErrStream()); + } + + @Test + public void testOutputStreamAlone() throws FileNotFoundException { + OutputTracker ot = new OutputTracker(OUTPUT_FILENAME,null); + + final String OUTPUT_TEXT = "out stream test"; + ot.getOutStream().append(OUTPUT_TEXT); + + Scanner outScanner = new Scanner(new File(OUTPUT_FILENAME)); + String outText = outScanner.nextLine(); + Assert.assertFalse("Out stream has too much data", outScanner.hasNext()); + + Assert.assertEquals("OutputTracker: Written output is incorrect", outText, OUTPUT_TEXT); + Assert.assertSame("OutputTracker: Error stream incorrectly initialized.", System.err, ot.getErrStream()); + } + + @Test + public void testErrorStreamAlone() throws FileNotFoundException { + OutputTracker ot = new OutputTracker(null,ERROR_FILENAME); + + final String ERROR_TEXT = "err stream test"; + ot.getErrStream().append(ERROR_TEXT); + + Scanner errScanner = new Scanner(new File(ERROR_FILENAME)); + String errText = errScanner.nextLine(); + Assert.assertFalse("Err stream has too much data", errScanner.hasNext()); + + Assert.assertSame("OutputTracker: Output stream incorrectly initialized.", System.out, ot.getOutStream()); + Assert.assertEquals("OutputTracker: Written error text is incorrect", errText, ERROR_TEXT); + } + + @Test + public void testIndependentStreams() throws FileNotFoundException { + OutputTracker ot = new OutputTracker(OUTPUT_FILENAME,ERROR_FILENAME); + + final String OUTPUT_TEXT = "out stream test"; + ot.getOutStream().append(OUTPUT_TEXT); + + final String ERROR_TEXT = "err stream test"; + ot.getErrStream().append(ERROR_TEXT); + + Scanner outScanner = new Scanner(new File(OUTPUT_FILENAME)); + String outText = outScanner.nextLine(); + Assert.assertFalse("Out stream has too much data", outScanner.hasNext()); + + Scanner errScanner = new Scanner(new File(ERROR_FILENAME)); + String errText = errScanner.nextLine(); + Assert.assertFalse("Err stream has too much data", errScanner.hasNext()); + + Assert.assertEquals("OutputTracker: Written output text is incorrect", outText, OUTPUT_TEXT); + Assert.assertEquals("OutputTracker: Written error text is incorrect", errText, ERROR_TEXT); + } + + @Test + public void testIdenticalInputsGetIdenticalResults() { + OutputTracker ot = new OutputTracker(OUTPUT_FILENAME,OUTPUT_FILENAME); + Assert.assertSame("OutputTracker: FileOutputStreams don't match", ot.getOutFile(), ot.getErrFile()); + Assert.assertSame("OutputTracker: PrintStreams don't match", ot.getOutStream(), ot.getErrStream()); + } +}