Semi-working version of extraDocs tag in annotation to refer to one capability being accessible in another

Required a significant refactoring of the GATKDoclet, which now has a unified place where the ClassDoc, class, annotation, and handler are all stored together.
This commit is contained in:
Mark DePristo 2011-07-23 22:07:30 -04:00
parent 999acacfa1
commit 7420ed098e
8 changed files with 163 additions and 121 deletions

View File

@ -468,7 +468,7 @@
</javadoc>
</target>
<target name="gatkdocs" unless="uptodate.extracthelp"
<target name="gatkdocs" depends="gatk.compile"
description="Extract help key/value pair file from the JavaDoc tags.">
<path id="doclet.classpath">
<path refid="external.dependencies" />

View File

@ -30,6 +30,7 @@ import org.broadinstitute.sting.commandline.Argument;
import org.broadinstitute.sting.commandline.ArgumentCollection;
import org.broadinstitute.sting.commandline.CommandLineProgram;
import org.broadinstitute.sting.gatk.arguments.GATKArgumentCollection;
import org.broadinstitute.sting.gatk.filters.ReadFilter;
import org.broadinstitute.sting.gatk.walkers.Attribution;
import org.broadinstitute.sting.gatk.walkers.Walker;
import org.broadinstitute.sting.utils.exceptions.UserException;
@ -40,12 +41,8 @@ import org.broadinstitute.sting.utils.text.TextFormattingUtils;
import java.util.*;
/**
* @author aaron
* @version 1.0
* @date May 8, 2009
* <p/>
* Class CommandLineGATK
* <p/>
* The GATK engine itself. Manages map/reduce data access and runs walkers.
*
* We run command line GATK programs using this class. It gets the command line args, parses them, and hands the
* gatk all the parsed out information. Pretty much anything dealing with the underlying system should go here,
* the gatk engine should deal with any data related information.
@ -53,6 +50,8 @@ import java.util.*;
@DocumentedGATKFeature(
groupName = "GATK Engine",
summary = "Features and arguments for the GATK engine itself, available to all walkers." )
//,
// extraDocs = { ReadFilter.class, UserException.class })
public class CommandLineGATK extends CommandLineExecutable {
@Argument(fullName = "analysis_type", shortName = "T", doc = "Type of analysis to run")
private String analysisName = null;

View File

@ -26,6 +26,7 @@
package org.broadinstitute.sting.gatk.walkers;
import org.apache.log4j.Logger;
import org.broadinstitute.sting.gatk.CommandLineGATK;
import org.broadinstitute.sting.gatk.GenomeAnalysisEngine;
import org.broadinstitute.sting.gatk.filters.MalformedReadFilter;
import org.broadinstitute.sting.utils.GenomeLoc;
@ -48,7 +49,8 @@ import java.util.List;
@BAQMode(QualityMode = BAQ.QualityMode.OVERWRITE_QUALS, ApplicationTime = BAQ.ApplicationTime.ON_INPUT)
@DocumentedGATKFeature(
groupName = "GATK walkers",
summary = "General tools available for running on the command line as part of the GATK package" )
summary = "General tools available for running on the command line as part of the GATK package",
extraDocs = {CommandLineGATK.class})
public abstract class Walker<MapType, ReduceType> {
final protected static Logger logger = Logger.getLogger(Walker.class);
private GenomeAnalysisEngine toolkit;

View File

@ -36,8 +36,9 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DocumentedGATKFeature {
boolean enable() default true;
String groupName();
String summary() default "";
Class<? extends DocumentedGATKFeatureHandler> handler() default GenericDocumentationHandler.class;
public boolean enable() default true;
public String groupName();
public String summary() default "";
public Class<? extends DocumentedGATKFeatureHandler> handler() default GenericDocumentationHandler.class;
public Class[] extraDocs() default {};
}

View File

@ -28,14 +28,13 @@ import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.RootDoc;
import java.io.*;
import java.util.Map;
/**
*
*/
public abstract class DocumentedGATKFeatureHandler {
private GATKDoclet doclet;
private String groupName;
private DocumentedGATKFeature annotation;
protected RootDoc getRootDoc() {
return this.doclet.rootDoc;
@ -45,28 +44,12 @@ public abstract class DocumentedGATKFeatureHandler {
this.doclet = doclet;
}
public DocumentedGATKFeature getAnnotation() {
return annotation;
}
public void setAnnotation(DocumentedGATKFeature annotation) {
this.annotation = annotation;
}
public boolean shouldBeProcessed(ClassDoc doc) { return true; }
public String getDestinationFilename(ClassDoc doc) {
return HelpUtils.getClassName(doc).replace(".", "_") + ".html";
}
final public String getGroupName() {
return groupName;
}
final public void setGroupName(String groupName) {
this.groupName = groupName;
}
public abstract String getTemplateName(ClassDoc doc) throws IOException;
public abstract GATKDoclet.DocumentationData processOne(ClassDoc doc);
public abstract void processOne(GATKDoclet.DocWorkUnit toProcess, Map<Class, GATKDoclet.DocWorkUnit> all);
}

View File

@ -42,25 +42,34 @@ import java.util.*;
public class GATKDoclet extends ResourceBundleExtractorDoclet {
final protected static Logger logger = Logger.getLogger(GATKDoclet.class);
public static class DocumentationData implements Comparable<DocumentationData> {
String name, summary, filename;
Map<String, Object> forTemplate;
String group;
public static class DocWorkUnit implements Comparable<DocWorkUnit> {
// known at the start
String name, filename, group;
DocumentedGATKFeatureHandler handler;
ClassDoc classDoc;
Class clazz;
DocumentedGATKFeature annotation;
public DocumentationData(String name, String summary, Map<String, Object> forTemplate) {
// set by the handler
String summary;
Map<String, Object> forTemplate;
public DocWorkUnit(DocumentedGATKFeature annotation, String name, String filename, String group,
DocumentedGATKFeatureHandler handler, ClassDoc classDoc, Class clazz) {
this.annotation = annotation;
this.name = name;
this.filename = filename;
this.group = group;
this.handler = handler;
this.classDoc = classDoc;
this.clazz = clazz;
}
public void setHandlerContent(String summary, Map<String, Object> forTemplate) {
this.summary = summary;
this.forTemplate = forTemplate;
}
public void setGroup(String group) {
this.group = group;
}
public void setFilename(String filename) {
this.filename = filename;
}
public Map<String, String> toMap() {
Map<String, String> data = new HashMap<String, String>();
data.put("name", name);
@ -70,7 +79,7 @@ public class GATKDoclet extends ResourceBundleExtractorDoclet {
return data;
}
public int compareTo(DocumentationData other) {
public int compareTo(DocWorkUnit other) {
return this.name.compareTo(other.name);
}
}
@ -93,6 +102,26 @@ public class GATKDoclet extends ResourceBundleExtractorDoclet {
return ResourceBundleExtractorDoclet.optionLength(option);
}
public Map<Class, DocWorkUnit> workUnits() {
Map<Class, DocWorkUnit> m = new HashMap<Class, DocWorkUnit>();
for ( ClassDoc doc : rootDoc.classes() ) {
System.out.printf("Considering %s%n", doc);
Class clazz = getClassForClassDoc(doc);
DocumentedGATKFeature feature = getFeatureForClassDoc(doc);
DocumentedGATKFeatureHandler handler = createHandler(doc, feature);
if ( handler != null && handler.shouldBeProcessed(doc) ) {
String filename = handler.getDestinationFilename(doc);
DocWorkUnit unit = new DocWorkUnit(feature,
doc.name(), filename, feature.groupName(),
handler, doc, clazz );
m.put(clazz, unit);
}
}
return m;
}
@Override
protected void processDocs(RootDoc rootDoc, PrintStream ignore) {
// setup the global access to the root
@ -108,19 +137,12 @@ public class GATKDoclet extends ResourceBundleExtractorDoclet {
// Specify how templates will see the data-model. This is an advanced topic...
cfg.setObjectWrapper(new DefaultObjectWrapper());
List<DocumentationData> indexData = new ArrayList<DocumentationData>();
Set<DocumentedGATKFeature> docFeatures = new HashSet<DocumentedGATKFeature>();
for ( ClassDoc doc : rootDoc.classes() ) {
System.out.printf("Considering %s%n", doc);
DocumentedGATKFeatureHandler handler = getHandlerForClassDoc(doc);
if ( handler != null && handler.shouldBeProcessed(doc) ) {
DocumentationData docData = processDocumentationWithHandler(cfg, handler, doc);
docFeatures.add(handler.getAnnotation());
indexData.add(docData);
}
Map<Class, DocWorkUnit> workUnitMap = workUnits();
for ( DocWorkUnit workUnit : workUnitMap.values() ) {
processDocWorkUnit(cfg, workUnit, workUnitMap);
}
processIndex(cfg, indexData, new ArrayList<DocumentedGATKFeature>(docFeatures));
processIndex(cfg, new ArrayList<DocWorkUnit>(workUnitMap.values()));
} catch ( FileNotFoundException e ) {
throw new RuntimeException(e);
} catch ( IOException e ) {
@ -128,53 +150,66 @@ public class GATKDoclet extends ResourceBundleExtractorDoclet {
}
}
private DocumentedGATKFeatureHandler getHandlerForClassDoc(ClassDoc doc) {
private DocumentedGATKFeatureHandler createHandler(ClassDoc doc, DocumentedGATKFeature feature) {
try {
// todo -- what do I need the ? extends Object to pass the compiler?
Class<? extends Object> docClass = HelpUtils.getClassForDoc(doc);
if ( docClass.isAnnotationPresent(DocumentedGATKFeature.class) ) {
DocumentedGATKFeature feature = docClass.getAnnotation(DocumentedGATKFeature.class);
if ( feature != null ) {
if ( feature.enable() ) {
DocumentedGATKFeatureHandler handler = feature.handler().newInstance();
handler.setGroupName(feature.groupName());
handler.setDoclet(this);
handler.setAnnotation(feature);
return handler;
} else {
logger.info("Skipping disabled Documentation for " + doc);
return null;
}
} else {
return null; // not annotated so it shouldn't be documented
}
} catch ( ClassNotFoundException e) {
//logger.warn("Couldn't find class for ClassDoc " + doc);
// we got a classdoc for a class we can't find. Maybe in a library or something
return null;
} catch ( IllegalAccessException e) {
throw new RuntimeException(e); // the constructor is now private -- this is an error
} catch ( InstantiationException e) {
throw new RuntimeException(e); // the constructor is now private -- this is an error
}
return null;
}
private DocumentedGATKFeature getFeatureForClassDoc(ClassDoc doc) {
// todo -- what do I need the ? extends Object to pass the compiler?
Class<? extends Object> docClass = getClassForClassDoc(doc);
if ( docClass != null && docClass.isAnnotationPresent(DocumentedGATKFeature.class) ) {
return docClass.getAnnotation(DocumentedGATKFeature.class);
} else {
return null; // not annotated so it shouldn't be documented
}
}
private Class<? extends Object> getClassForClassDoc(ClassDoc doc) {
try {
// todo -- what do I need the ? extends Object to pass the compiler?
return (Class<? extends Object>)HelpUtils.getClassForDoc(doc);
} catch ( ClassNotFoundException e) {
//logger.warn("Couldn't find class for ClassDoc " + doc);
// we got a classdoc for a class we can't find. Maybe in a library or something
return null;
} catch ( NoClassDefFoundError e ) {
return null;
} catch ( UnsatisfiedLinkError e) {
return null; // naughty BWA bindings
}
}
private void processIndex(Configuration cfg, List<DocumentationData> indexData, List<DocumentedGATKFeature> docFeatures) throws IOException {
private void processIndex(Configuration cfg, List<DocWorkUnit> indexData) throws IOException {
/* Get or create a template */
Template temp = cfg.getTemplate("generic.index.template.html");
/* Merge data-model with template */
Writer out = new OutputStreamWriter(new FileOutputStream(new File("testdoc/index.html")));
try {
temp.process(groupIndexData(indexData, docFeatures), out);
temp.process(groupIndexData(indexData), out);
out.flush();
} catch ( TemplateException e ) {
throw new ReviewedStingException("Failed to create GATK documentation", e);
}
}
private Map<String, Object> groupIndexData(List<DocumentationData> indexData, List<DocumentedGATKFeature> docFeatures) {
private Map<String, Object> groupIndexData(List<DocWorkUnit> indexData) {
//
// root -> data -> { summary -> y, filename -> z }, etc
// -> groups -> group1, group2, etc.
@ -182,9 +217,11 @@ public class GATKDoclet extends ResourceBundleExtractorDoclet {
Collections.sort(indexData);
Set<DocumentedGATKFeature> docFeatures = new HashSet<DocumentedGATKFeature>();
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
for ( DocumentationData indexDatum : indexData ) {
data.add(indexDatum.toMap());
for ( DocWorkUnit workUnit : indexData ) {
data.add(workUnit.toMap());
docFeatures.add(workUnit.annotation);
}
List<Map<String, String>> groups = new ArrayList<Map<String, String>>();
@ -205,30 +242,23 @@ public class GATKDoclet extends ResourceBundleExtractorDoclet {
return root;
}
private DocumentationData processDocumentationWithHandler(Configuration cfg,
DocumentedGATKFeatureHandler handler,
ClassDoc doc)
private void processDocWorkUnit(Configuration cfg, DocWorkUnit unit, Map<Class, DocWorkUnit> all)
throws IOException {
System.out.printf("Processing documentation for class %s%n", doc);
System.out.printf("Processing documentation for class %s%n", unit.classDoc);
DocumentationData docData = handler.processOne(doc);
docData.setGroup(handler.getGroupName());
unit.handler.processOne(unit, all);
// Get or create a template
Template temp = cfg.getTemplate(handler.getTemplateName(doc));
Template temp = cfg.getTemplate(unit.handler.getTemplateName(unit.classDoc));
// Merge data-model with template
String filename = handler.getDestinationFilename(doc);
docData.setFilename(filename);
File outputPath = new File("testdoc/" + filename);
File outputPath = new File("testdoc/" + unit.filename);
try {
Writer out = new OutputStreamWriter(new FileOutputStream(outputPath));
temp.process(docData.forTemplate, out);
temp.process(unit.forTemplate, out);
out.flush();
} catch ( TemplateException e ) {
throw new ReviewedStingException("Failed to create GATK documentation", e);
}
return docData;
}
}

View File

@ -35,10 +35,7 @@ import org.broadinstitute.sting.utils.exceptions.ReviewedStingException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
*
@ -54,20 +51,16 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
}
}
@Override
public String getTemplateName(ClassDoc doc) throws IOException {
return "generic.template.html";
}
@Override
public GATKDoclet.DocumentationData processOne(ClassDoc doc) {
System.out.printf("%s class %s%n", getGroupName(), doc);
Map<String, Object> root = buildWalkerDataModel(doc); // Create the root hash
return new GATKDoclet.DocumentationData(doc.name(), (String)root.get("summary"), root);
}
private Map<String, Object> buildWalkerDataModel(ClassDoc classdoc) {
public void processOne(GATKDoclet.DocWorkUnit toProcess, Map<Class, GATKDoclet.DocWorkUnit> all) {
System.out.printf("%s class %s%n", toProcess.group, toProcess.classDoc);
ClassDoc classdoc = toProcess.classDoc;
Map<String, Object> root = new HashMap<String, Object>();
root.put("name", classdoc.name());
@ -109,8 +102,21 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
throw new RuntimeException(e);
}
List<Map<String, Object>> extraDocsData = new ArrayList<Map<String, Object>>();
for ( Class extraDocClass : toProcess.annotation.extraDocs() ) {
final GATKDoclet.DocWorkUnit otherUnit = all.get(extraDocClass);
if ( otherUnit == null )
throw new ReviewedStingException("Requested extraDocs for class without any documentation: " + extraDocClass);
extraDocsData.add(
new HashMap<String, Object>(){{
put("filename", otherUnit.filename);
put("name", otherUnit.name);}});
}
root.put("extradocs", extraDocsData);
//System.out.printf("Root is %s%n", root);
return root;
toProcess.setHandlerContent(summaryBuilder.toString(), root);
}
protected ParsingEngine createStandardGATKParsingEngine() {

View File

@ -38,26 +38,47 @@
</#if>
<h2>Description</h2>
${description}
<#-- Create the argument summary -->
<h2>Arguments</h2>
<table border="1" cellpadding="2">
<tr>
<th>Name</th>
<th>Synonyms</th>
<th>Type</th>
<th>Summary</th>
</tr>
<@argumentlist name="Required" myargs=arguments.required/>
<@argumentlist name="Optional" myargs=arguments.optional/>
<@argumentlist name="Hidden" myargs=arguments.hidden/>
<@argumentlist name="Depreciated" myargs=arguments.depreciated/>
</table>
<#-- Create the argument details -->
<h2>Argument details</h2>
<#list arguments.all as arg>
<@argumentDetails arg=arg/>
</#list>
<#-- Create the argument summary -->
<#if arguments.all?size != 0>
<hr>
<h2>Feature specific arguments</h2>
<table border="1" cellpadding="2">
<tr>
<th>Name</th>
<th>Synonyms</th>
<th>Type</th>
<th>Summary</th>
</tr>
<@argumentlist name="Required" myargs=arguments.required/>
<@argumentlist name="Optional" myargs=arguments.optional/>
<@argumentlist name="Hidden" myargs=arguments.hidden/>
<@argumentlist name="Depreciated" myargs=arguments.depreciated/>
</table>
</#if>
<#-- Create references to related capabilities if appropriate -->
<#if extradocs?size != 0>
<hr>
<h2>Related capabilities</h2>
The arguments described in the entries below can be supplied to this tool to modify
its behavior. For example, the -L argument directs the GATK engine restricts processing
to specific genomic intervals. This capability is available to all GATK walkers.
<ul>
<#list extradocs as extradoc>
<li><a href="${extradoc.filename}">${extradoc.name}</a></li>
</#list>
</ul>
</#if>
<#-- List all of the -->
<#if arguments.all?size != 0>
<hr>
<#-- Create the argument details -->
<h2>Argument details</h2>
<#list arguments.all as arg>
<@argumentDetails arg=arg/>
</#list>
</#if>
</body>
</html>