From bb94c853f8e66c6846a11c02769d41afc1ff46d8 Mon Sep 17 00:00:00 2001 From: hanna Date: Tue, 17 Mar 2009 23:22:37 +0000 Subject: [PATCH] Added WalkerManager -- a class that dynamically loads available walkers from the jar file. For now, added placeholder Walker interface so that WalkerManager could work with classes of type Walker rather than classes of type Object. git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@85 348d0f76-0448-11de-a6fe-93d51630548a --- .../sting/gatk/GenomeAnalysisTK.java | 36 ++--- .../sting/gatk/WalkerManager.java | 147 ++++++++++++++++++ .../gatk/walkers/AlignedReadsHistoWalker.java | 4 + .../gatk/walkers/BaseQualityHistoWalker.java | 4 + .../sting/gatk/walkers/BasicLociWalker.java | 12 +- .../sting/gatk/walkers/BasicReadWalker.java | 11 +- .../sting/gatk/walkers/LocusWalker.java | 7 +- .../gatk/walkers/MismatchCounterWalker.java | 4 + .../sting/gatk/walkers/NullWalker.java | 6 +- .../sting/gatk/walkers/ReadWalker.java | 8 +- .../sting/gatk/walkers/Walker.java | 15 ++ 11 files changed, 210 insertions(+), 44 deletions(-) create mode 100755 playground/java/src/org/broadinstitute/sting/gatk/WalkerManager.java create mode 100755 playground/java/src/org/broadinstitute/sting/gatk/walkers/Walker.java 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(); +}