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
This commit is contained in:
hanna 2009-03-17 23:22:37 +00:00
parent d9fa04f65c
commit bb94c853f8
11 changed files with 210 additions and 44 deletions

View File

@ -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<String, Object> MODULES = new HashMap<String,Object>();
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<Integer,Integer> 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);
}

View File

@ -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<String,Walker> walkers = null;
public WalkerManager() {
try {
final File jarFile = getThisJarFile();
List<Class> 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<Class> loadClassesOfType(final File jarFile, final Class baseClass)
throws IOException {
final String PACKAGE_JAR_PREFIX = baseClass.getPackage().getName().replace('.','/');
List<Class> subclasses = new ArrayList<Class>();
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<String,Walker> instantiateWalkers(List<Class> walkerClasses)
throws InstantiationException, IllegalAccessException {
Map<String,Walker> walkers = new HashMap<String,Walker>();
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;
}
}

View File

@ -14,6 +14,10 @@ import org.broadinstitute.sting.gatk.LocusContext;
public class AlignedReadsHistoWalker extends BasicReadWalker<Integer, Integer> {
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;

View File

@ -14,6 +14,10 @@ import org.broadinstitute.sting.gatk.LocusContext;
public class BaseQualityHistoWalker extends BasicReadWalker<Integer, Integer> {
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;

View File

@ -14,12 +14,20 @@ import java.util.List;
* To change this template use File | Settings | File Templates.
*/
public abstract class BasicLociWalker<MapType, ReduceType> implements LocusWalker<MapType, ReduceType> {
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<ReferenceOrderedDatum> rodData, char ref, LocusContext context) {
return true; // We are keeping all the reads

View File

@ -12,8 +12,17 @@ import org.broadinstitute.sting.gatk.walkers.ReadWalker;
* To change this template use File | Settings | File Templates.
*/
public abstract class BasicReadWalker<MapType, ReduceType> implements ReadWalker<MapType, ReduceType> {
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) {

View File

@ -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<MapType, ReduceType> {
void initialize();
public String walkerType();
public interface LocusWalker<MapType, ReduceType> extends Walker {
// Do we actually want to operate on the context?
boolean filter(List<ReferenceOrderedDatum> rodData, char ref, LocusContext context);
@ -25,6 +22,4 @@ public interface LocusWalker<MapType, ReduceType> {
// Given result of map function
ReduceType reduceInit();
ReduceType reduce(MapType value, ReduceType sum);
void onTraversalDone();
}

View File

@ -10,6 +10,10 @@ import java.util.Arrays;
import java.util.List;
public class MismatchCounterWalker extends BasicReadWalker<Integer, Integer> {
public String getName() {
return "CountMismatches";
}
public Integer map(LocusContext context, SAMRecord read) {
int nMismatches = 0;

View File

@ -10,10 +10,12 @@ import java.util.List;
// j.maguire 3-7-2009
public class NullWalker implements LocusWalker<Integer, Integer> {
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<ReferenceOrderedDatum> rodData, char ref, LocusContext context) {

View File

@ -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<MapType, ReduceType> {
void initialize();
public String walkerType();
public boolean requiresOrderedReads();
public interface ReadWalker<MapType, ReduceType> 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<MapType, ReduceType> {
// Given result of map function
ReduceType reduceInit();
ReduceType reduce(MapType value, ReduceType sum);
void onTraversalDone();
}

View File

@ -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();
}