diff --git a/playground/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisTK.java b/playground/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisTK.java index 64fe01628..1f98da4ff 100644 --- a/playground/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisTK.java +++ b/playground/java/src/org/broadinstitute/sting/gatk/GenomeAnalysisTK.java @@ -28,26 +28,8 @@ public class GenomeAnalysisTK extends CommandLineProgram { @Option(shortName="U", doc="If true, enables unsafe operations, nothing will be checked at runtime. You better know what you are doing if you set this flag.", optional=false) public String UNSAFE = "false"; @Option(shortName="SORT_ON_FLY", doc="If true, enables on fly sorting of reads file.", optional=false) public String ENABLED_SORT_ON_FLY = "false"; - public static HashMap MODULES = new HashMap(); - public static void addModule(final String name, final Object walker) { - System.out.printf("* Adding module %s%n", name); - MODULES.put(name, walker); - } - - static { - addModule("CountLoci", new CountLociWalker()); - addModule("Pileup", new PileupWalker()); - addModule("CountReads", new CountReadsWalker()); - addModule("PrintReads", new PrintReadsWalker()); - addModule("Base_Quality_Histogram", new BaseQualityHistoWalker()); - addModule("Aligned_Reads_Histogram", new AlignedReadsHistoWalker()); - addModule("AlleleFrequency", new AlleleFrequencyWalker()); - addModule("SingleSampleGenotyper", new SingleSampleGenotyper()); - addModule("Null", new NullWalker()); - addModule("DepthOfCoverage", new DepthOfCoverageWalker()); - addModule("CountMismatches", new MismatchCounterWalker()); - } - + private WalkerManager walkerManager = new WalkerManager(); + private TraversalEngine engine = null; public boolean DEBUGGING = false; @@ -111,22 +93,22 @@ public class GenomeAnalysisTK extends CommandLineProgram { //LocusWalker walker = new PileupWalker(); - // Try to get the module specified - Object my_module; - if (MODULES.containsKey(Analysis_Name)) { - my_module = MODULES.get(Analysis_Name); + // Try to get the walker specified + Object my_walker; + if (walkerManager.doesWalkerExist(Analysis_Name)) { + my_walker = walkerManager.getWalkerByName(Analysis_Name); } else { - System.out.println("Could not find module "+Analysis_Name); + System.out.println("Could not find walker "+Analysis_Name); return 0; } try { - LocusWalker walker = (LocusWalker)my_module; + LocusWalker walker = (LocusWalker)my_walker; engine.traverseByLoci(walker); } catch ( java.lang.ClassCastException e ) { // I guess we're a read walker LOL - ReadWalker walker = (ReadWalker)my_module; + ReadWalker walker = (ReadWalker)my_walker; engine.traverseByRead(walker); } diff --git a/playground/java/src/org/broadinstitute/sting/gatk/WalkerManager.java b/playground/java/src/org/broadinstitute/sting/gatk/WalkerManager.java new file mode 100755 index 000000000..e3db4525e --- /dev/null +++ b/playground/java/src/org/broadinstitute/sting/gatk/WalkerManager.java @@ -0,0 +1,147 @@ +package org.broadinstitute.sting.gatk; + +import java.lang.reflect.Modifier; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; + +import org.broadinstitute.sting.gatk.walkers.Walker; + +/** + * Created by IntelliJ IDEA. + * User: hanna + * Date: Mar 17, 2009 + * Time: 3:14:28 PM + * To change this template use File | Settings | File Templates. + */ +public class WalkerManager { + private Map walkers = null; + + public WalkerManager() { + try { + final File jarFile = getThisJarFile(); + List walkerClasses = loadClassesOfType( jarFile, Walker.class ); + + if(walkerClasses.isEmpty()) + throw new RuntimeException("No walkers were found."); + + walkers = instantiateWalkers( walkerClasses ); + } + // IOExceptions here are suspect; they indicate that the WalkerManager can't open its containing jar. + // Wrap in a RuntimeException. + catch(IOException ex) { + throw new RuntimeException(ex); + } + // The following two catches are more 'expected'; someone might add a walker that can't be instantiated. + // TODO: Should these exceptions be handled differently? Handling them like IOExceptions for the moment. + catch(InstantiationException ex) { + throw new RuntimeException(ex); + } + catch(IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Does a walker with the given name exist? + * @param walkerName Name of the walker for which to search. + * @return True if the walker exists, false otherwise. + */ + public boolean doesWalkerExist(String walkerName) { + return walkers.containsKey(walkerName); + } + + /** + * Gets a walker with the given name, or null if no walker exists. + * @param walkerName Name of the walker to retrieve. + * @return The walker object if found; null otherwise. + */ + public Walker getWalkerByName(String walkerName) { + return walkers.get(walkerName); + } + + /** + * Determines which jar file contains the WalkerManager class. + * @return Jar file containing the WalkerManager class. + */ + private File getThisJarFile() throws IOException { + try { + java.net.URI jarURI = getClass().getProtectionDomain().getCodeSource().getLocation().toURI(); + return new File( jarURI ); + } + catch(java.net.URISyntaxException ex) { + // a URISyntaxException here must be an IO error; wrap as such. + throw new IOException(ex); + } + } + + /** + * Loads concrete classes from a jar which are both in the same package or 'sub-package' of baseClass, + * and which extend from baseClass. + * @param jarFile The jar file to search. + * @param baseClass The base class / interface for + * @return A list of classes derived from baseClass. + */ + private List loadClassesOfType(final File jarFile, final Class baseClass) + throws IOException { + final String PACKAGE_JAR_PREFIX = baseClass.getPackage().getName().replace('.','/'); + + List subclasses = new ArrayList(); + + JarInputStream jarInputStream = new JarInputStream(new FileInputStream( jarFile ) ); + + try { + JarEntry jarEntry = jarInputStream.getNextJarEntry(); + + while(jarEntry != null) { + String jarEntryName = jarEntry.getName(); + if(jarEntryName.startsWith(PACKAGE_JAR_PREFIX) && jarEntryName.endsWith(".class")) + { + String className = jarEntryName.substring(0,jarEntryName.lastIndexOf(".class")).replace('/','.'); + Class clazz = Class.forName(className); + if( baseClass.isAssignableFrom( clazz ) && + !Modifier.isAbstract(clazz.getModifiers()) && + !Modifier.isInterface(clazz.getModifiers())) + subclasses.add( clazz ); + } + jarEntry = jarInputStream.getNextJarEntry(); + } + } + catch(ClassNotFoundException ex) { + // A ClassNotFoundException here must be an IO error; wrap as such. + throw new IOException(ex); + } + finally { + jarInputStream.close(); + } + + return subclasses; + } + + /** + * Instantiate the list of walker classes. Add them to the walker hashmap. + * @param walkerClasses Classes to instantiate. + * @throws InstantiationException + * @throws IllegalAccessException + */ + private Map instantiateWalkers(List walkerClasses) + throws InstantiationException, IllegalAccessException { + Map walkers = new HashMap(); + + for(Class walkerClass : walkerClasses) { + Walker walker = (Walker)walkerClass.newInstance(); + String walkerName = walker.getName(); + + System.out.printf("* Adding module %s%n", walkerName); + walkers.put(walkerName,walker); + } + + return walkers; + } +} diff --git a/playground/java/src/org/broadinstitute/sting/gatk/walkers/AlignedReadsHistoWalker.java b/playground/java/src/org/broadinstitute/sting/gatk/walkers/AlignedReadsHistoWalker.java index ae1a82f8b..982cf7f12 100755 --- a/playground/java/src/org/broadinstitute/sting/gatk/walkers/AlignedReadsHistoWalker.java +++ b/playground/java/src/org/broadinstitute/sting/gatk/walkers/AlignedReadsHistoWalker.java @@ -14,6 +14,10 @@ import org.broadinstitute.sting.gatk.LocusContext; public class AlignedReadsHistoWalker extends BasicReadWalker { long[] alignCounts = new long[51]; + public String getName() { + return "Aligned_Reads_Histogram"; + } + public void initialize() { for ( int i = 0; i < this.alignCounts.length; i++ ) { this.alignCounts[i] = 0; diff --git a/playground/java/src/org/broadinstitute/sting/gatk/walkers/BaseQualityHistoWalker.java b/playground/java/src/org/broadinstitute/sting/gatk/walkers/BaseQualityHistoWalker.java index 569a172ed..f1b84cac8 100755 --- a/playground/java/src/org/broadinstitute/sting/gatk/walkers/BaseQualityHistoWalker.java +++ b/playground/java/src/org/broadinstitute/sting/gatk/walkers/BaseQualityHistoWalker.java @@ -14,6 +14,10 @@ import org.broadinstitute.sting.gatk.LocusContext; public class BaseQualityHistoWalker extends BasicReadWalker { long[] qualCounts = new long[100]; + public String getName() { + return "Base_Quality_Histogram"; + } + public void initialize() { for ( int i = 0; i < this.qualCounts.length; i++ ) { this.qualCounts[i] = 0; diff --git a/playground/java/src/org/broadinstitute/sting/gatk/walkers/BasicLociWalker.java b/playground/java/src/org/broadinstitute/sting/gatk/walkers/BasicLociWalker.java index 3a42d18fe..63cb4c1a9 100755 --- a/playground/java/src/org/broadinstitute/sting/gatk/walkers/BasicLociWalker.java +++ b/playground/java/src/org/broadinstitute/sting/gatk/walkers/BasicLociWalker.java @@ -14,12 +14,20 @@ import java.util.List; * To change this template use File | Settings | File Templates. */ public abstract class BasicLociWalker implements LocusWalker { + public String getName() { + // Return name of class, trimming 'Walker' from the end if present. + // TODO: Duplicate of BasicReadWalker.getName(). Eliminate duplication. + String className = getClass().getSimpleName(); + if(className.endsWith(Walker.class.getSimpleName())) + return className.substring(0,className.lastIndexOf(Walker.class.getSimpleName())); + else + return className; + } + public void initialize() { ; } - public String walkerType() { return "ByLocus"; } - // Do we actually want to operate on the context? public boolean filter(List rodData, char ref, LocusContext context) { return true; // We are keeping all the reads diff --git a/playground/java/src/org/broadinstitute/sting/gatk/walkers/BasicReadWalker.java b/playground/java/src/org/broadinstitute/sting/gatk/walkers/BasicReadWalker.java index fc7e9448d..5180768d4 100755 --- a/playground/java/src/org/broadinstitute/sting/gatk/walkers/BasicReadWalker.java +++ b/playground/java/src/org/broadinstitute/sting/gatk/walkers/BasicReadWalker.java @@ -12,8 +12,17 @@ import org.broadinstitute.sting.gatk.walkers.ReadWalker; * To change this template use File | Settings | File Templates. */ public abstract class BasicReadWalker implements ReadWalker { + public String getName() { + // Return name of class, trimming 'Walker' from the end if present. + // TODO: Duplicate of BasicLociWalker.getName(). Eliminate duplication. + String className = getClass().getSimpleName(); + if(className.endsWith(Walker.class.getSimpleName())) + return className.substring(0,className.lastIndexOf(Walker.class.getSimpleName())); + else + return className; + } + public void initialize() { } - public String walkerType() { return "ByRead"; } public boolean requiresOrderedReads() { return false; } public boolean filter(LocusContext context, SAMRecord read) { diff --git a/playground/java/src/org/broadinstitute/sting/gatk/walkers/LocusWalker.java b/playground/java/src/org/broadinstitute/sting/gatk/walkers/LocusWalker.java index 2f563f752..72eac2973 100755 --- a/playground/java/src/org/broadinstitute/sting/gatk/walkers/LocusWalker.java +++ b/playground/java/src/org/broadinstitute/sting/gatk/walkers/LocusWalker.java @@ -12,10 +12,7 @@ import java.util.List; * Time: 2:52:28 PM * To change this template use File | Settings | File Templates. */ -public interface LocusWalker { - void initialize(); - public String walkerType(); - +public interface LocusWalker extends Walker { // Do we actually want to operate on the context? boolean filter(List rodData, char ref, LocusContext context); @@ -25,6 +22,4 @@ public interface LocusWalker { // Given result of map function ReduceType reduceInit(); ReduceType reduce(MapType value, ReduceType sum); - - void onTraversalDone(); } diff --git a/playground/java/src/org/broadinstitute/sting/gatk/walkers/MismatchCounterWalker.java b/playground/java/src/org/broadinstitute/sting/gatk/walkers/MismatchCounterWalker.java index ec7911166..64ae49dbf 100755 --- a/playground/java/src/org/broadinstitute/sting/gatk/walkers/MismatchCounterWalker.java +++ b/playground/java/src/org/broadinstitute/sting/gatk/walkers/MismatchCounterWalker.java @@ -10,6 +10,10 @@ import java.util.Arrays; import java.util.List; public class MismatchCounterWalker extends BasicReadWalker { + public String getName() { + return "CountMismatches"; + } + public Integer map(LocusContext context, SAMRecord read) { int nMismatches = 0; diff --git a/playground/java/src/org/broadinstitute/sting/gatk/walkers/NullWalker.java b/playground/java/src/org/broadinstitute/sting/gatk/walkers/NullWalker.java index 5b0347f4b..47e675608 100644 --- a/playground/java/src/org/broadinstitute/sting/gatk/walkers/NullWalker.java +++ b/playground/java/src/org/broadinstitute/sting/gatk/walkers/NullWalker.java @@ -10,10 +10,12 @@ import java.util.List; // j.maguire 3-7-2009 public class NullWalker implements LocusWalker { - public void initialize() { + public String getName() { + return "Null"; } - public String walkerType() { return "ByLocus"; } + public void initialize() { + } // Do we actually want to operate on the context? public boolean filter(List rodData, char ref, LocusContext context) { diff --git a/playground/java/src/org/broadinstitute/sting/gatk/walkers/ReadWalker.java b/playground/java/src/org/broadinstitute/sting/gatk/walkers/ReadWalker.java index 7ee90c6c5..94c9434c7 100755 --- a/playground/java/src/org/broadinstitute/sting/gatk/walkers/ReadWalker.java +++ b/playground/java/src/org/broadinstitute/sting/gatk/walkers/ReadWalker.java @@ -10,10 +10,8 @@ import org.broadinstitute.sting.gatk.LocusContext; * Time: 2:52:28 PM * To change this template use File | Settings | File Templates. */ -public interface ReadWalker { - void initialize(); - public String walkerType(); - public boolean requiresOrderedReads(); +public interface ReadWalker extends Walker { + boolean requiresOrderedReads(); // Do we actually want to operate on the context? boolean filter(LocusContext context, SAMRecord read); @@ -24,6 +22,4 @@ public interface ReadWalker { // Given result of map function ReduceType reduceInit(); ReduceType reduce(MapType value, ReduceType sum); - - void onTraversalDone(); } diff --git a/playground/java/src/org/broadinstitute/sting/gatk/walkers/Walker.java b/playground/java/src/org/broadinstitute/sting/gatk/walkers/Walker.java new file mode 100755 index 000000000..e7d67532a --- /dev/null +++ b/playground/java/src/org/broadinstitute/sting/gatk/walkers/Walker.java @@ -0,0 +1,15 @@ +package org.broadinstitute.sting.gatk.walkers; + +/** + * Created by IntelliJ IDEA. + * User: hanna + * Date: Mar 17, 2009 + * Time: 1:53:31 PM + * To change this template use File | Settings | File Templates. + */ +public interface Walker { + // TODO: Can a walker be templatized so that map and reduce live here? + String getName(); + void initialize(); + void onTraversalDone(); +}