diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java index fb7e6b579..b679f967a 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java @@ -35,6 +35,7 @@ import org.broadinstitute.sting.gatk.walkers.RodWalker; import java.io.File; import java.io.PrintStream; +import java.util.Arrays; import java.util.List; /** @@ -182,11 +183,11 @@ public class DiffObjectsWalker extends RodWalker { @Argument(fullName="showItemizedDifferences", shortName="SID", doc="Should we enumerate all differences between the files?", required=false) boolean showItemizedDifferences = false; - final DiffEngine diffEngine = new DiffEngine(); + DiffEngine diffEngine; @Override public void initialize() { - + this.diffEngine = new DiffEngine(); } @Override diff --git a/public/java/src/org/broadinstitute/sting/utils/help/GATKDoclet.java b/public/java/src/org/broadinstitute/sting/utils/help/GATKDoclet.java index b4ab3b98e..0b4c69e3c 100644 --- a/public/java/src/org/broadinstitute/sting/utils/help/GATKDoclet.java +++ b/public/java/src/org/broadinstitute/sting/utils/help/GATKDoclet.java @@ -31,6 +31,7 @@ import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; import freemarker.template.TemplateException; import org.apache.commons.io.FileUtils; +import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; @@ -56,6 +57,7 @@ public class GATKDoclet { * @throws java.io.IOException if output can't be written. */ public static boolean start(RootDoc rootDoc) throws IOException { + logger.setLevel(Level.INFO); // load arguments for(String[] options: rootDoc.options()) { if(options[0].equals("-build-timestamp")) @@ -91,11 +93,12 @@ public class GATKDoclet { TreeSet m = new TreeSet(); for ( ClassDoc doc : rootDoc.classes() ) { - System.out.printf("Considering %s%n", doc); + logger.debug("Considering " + doc); Class clazz = getClassForClassDoc(doc); DocumentedGATKFeature feature = getFeatureForClassDoc(doc); DocumentedGATKFeatureHandler handler = createHandler(doc, feature); if ( handler != null && handler.shouldBeProcessed(doc) ) { + logger.info("Going to generate documentation for class " + doc); String filename = handler.getDestinationFilename(doc); GATKDocWorkUnit unit = new GATKDocWorkUnit(doc.name(), filename, feature.groupName(), @@ -246,7 +249,7 @@ public class GATKDoclet { private void processDocWorkUnit(Configuration cfg, GATKDocWorkUnit unit, Set all) throws IOException { - System.out.printf("Processing documentation for class %s%n", unit.classDoc); + //System.out.printf("Processing documentation for class %s%n", unit.classDoc); unit.handler.processOne(rootDoc, unit, all); diff --git a/public/java/src/org/broadinstitute/sting/utils/help/GenericDocumentationHandler.java b/public/java/src/org/broadinstitute/sting/utils/help/GenericDocumentationHandler.java index 8773fc4f8..fd1048844 100644 --- a/public/java/src/org/broadinstitute/sting/utils/help/GenericDocumentationHandler.java +++ b/public/java/src/org/broadinstitute/sting/utils/help/GenericDocumentationHandler.java @@ -29,9 +29,11 @@ import com.sun.javadoc.ClassDoc; import com.sun.javadoc.FieldDoc; import com.sun.javadoc.RootDoc; import com.sun.javadoc.Tag; +import org.apache.log4j.Logger; import org.broadinstitute.sting.commandline.*; import org.broadinstitute.sting.gatk.CommandLineGATK; import org.broadinstitute.sting.utils.Utils; +import org.broadinstitute.sting.utils.classloader.JVMUtils; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; import java.io.*; @@ -42,6 +44,7 @@ import java.util.*; * */ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler { + private static Logger logger = Logger.getLogger(GenericDocumentationHandler.class); GATKDocWorkUnit toProcess; ClassDoc classdoc; Set all; @@ -71,7 +74,7 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler { this.all = allArg; this.classdoc = toProcess.classDoc; - System.out.printf("%s class %s%n", toProcess.group, toProcess.classDoc); + //System.out.printf("%s class %s%n", toProcess.group, toProcess.classDoc); Map root = new HashMap(); addHighLevelBindings(root); @@ -87,7 +90,7 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler { // Extract overrides from the doc tags. StringBuilder summaryBuilder = new StringBuilder(); for(Tag tag: classdoc.firstSentenceTags()) - summaryBuilder.append(tag.text()); + summaryBuilder.append(tag.text()); root.put("summary", summaryBuilder.toString()); root.put("description", classdoc.commentText()); root.put("timestamp", toProcess.buildTimestamp); @@ -101,6 +104,9 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler { protected void addArgumentBindings(Map root) { ParsingEngine parsingEngine = createStandardGATKParsingEngine(); + // attempt to instantiate the class + Object instance = makeInstanceIfPossible(toProcess.clazz); + Map> args = new HashMap>(); root.put("arguments", args); args.put("all", new ArrayList()); @@ -114,15 +120,23 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler { FieldDoc fieldDoc = getFieldDoc(classdoc, argumentSource.field.getName()); Map argBindings = docForArgument(fieldDoc, argumentSource, argDef); // todo -- why can you have multiple ones? if ( ! argumentSource.isHidden() || getDoclet().showHiddenFeatures() ) { - System.out.printf("Processing %s%n", argumentSource); + logger.debug(String.format("Processing %s", argumentSource)); String kind = "optional"; if ( argumentSource.isRequired() ) kind = "required"; else if ( argumentSource.isHidden() ) kind = "hidden"; else if ( argumentSource.isDeprecated() ) kind = "depreciated"; + + // get the value of the field + if ( instance != null ) { + Object value = getFieldValue(toProcess.clazz, instance, fieldDoc.name()); + if ( value != null ) + argBindings.put("defaultValue", prettyPrintValueString(value)); + } + args.get(kind).add(argBindings); args.get("all").add(argBindings); } else { - System.out.printf("Skipping hidden feature %s%n", argumentSource); + logger.debug(String.format("Skipping hidden feature %s", argumentSource)); } } } catch ( ClassNotFoundException e ) { @@ -130,6 +144,90 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler { } } + private Object getFieldValue(Class c, Object instance, String fieldName) { + Field field = JVMUtils.findField(c, fieldName); + if ( field != null ) { + Object value = JVMUtils.getFieldValue(field, instance); + //System.out.printf("Fetched value of field %s in class %s: %s%n", fieldName, c, value); + return value; + } else { + return findFieldValueInArgumentCollections(c, instance, fieldName); + } + } + + private Object findFieldValueInArgumentCollections(Class c, Object instance, String fieldName) { + for ( Field field : JVMUtils.getAllFields(c) ) { + if ( field.isAnnotationPresent(ArgumentCollection.class) ) { + //System.out.printf("Searching for %s in argument collection field %s%n", fieldName, field); + Object fieldValue = JVMUtils.getFieldValue(field, instance); + Object value = getFieldValue(fieldValue.getClass(), fieldValue, fieldName); + if ( value != null ) + return value; + } + } + + return null; + } + + /** + * Assumes value != null + * @param value + * @return + */ + private Object prettyPrintValueString(Object value) { + if ( value.getClass().isArray() ) { + Class type = value.getClass().getComponentType(); + if ( boolean.class.isAssignableFrom(type) ) + return Arrays.toString((boolean[])value); + if ( byte.class.isAssignableFrom(type) ) + return Arrays.toString((byte[])value); + if ( char.class.isAssignableFrom(type) ) + return Arrays.toString((char[])value); + if ( double.class.isAssignableFrom(type) ) + return Arrays.toString((double[])value); + if ( float.class.isAssignableFrom(type) ) + return Arrays.toString((float[])value); + if ( int.class.isAssignableFrom(type) ) + return Arrays.toString((int[])value); + if ( long.class.isAssignableFrom(type) ) + return Arrays.toString((long[])value); + if ( short.class.isAssignableFrom(type) ) + return Arrays.toString((short[])value); + if ( Object.class.isAssignableFrom(type) ) + return Arrays.toString((Object[])value); + else + throw new RuntimeException("Unexpected array type in prettyPrintValue. Value was " + value + " type is " + type); + } else + return value.toString(); + } + + private Object makeInstanceIfPossible(Class c) { + Object instance = null; + try { + // don't try to make something where we will obviously fail + if (! c.isEnum() && ! c.isAnnotation() && ! c.isAnonymousClass() && + ! c.isArray() && ! c.isPrimitive() & JVMUtils.isConcrete(c) ) { + instance = c.newInstance(); + //System.out.printf("Created object of class %s => %s%n", c, instance); + return instance; + } else + return null; + } + catch (IllegalAccessException e ) { } + catch (InstantiationException e ) { } + catch (ExceptionInInitializerError e ) { } + catch (SecurityException e ) { } + // this last one is super dangerous, but some of these methods catch ClassNotFoundExceptions + // and rethrow then as RuntimeExceptions + catch (RuntimeException e) {} + finally { + if ( instance == null ) + logger.warn(String.format("Unable to create instance of class %s => %s", c, instance)); + } + + return instance; + } + protected void addRelatedBindings(Map root) { List> extraDocsData = new ArrayList>(); diff --git a/settings/helpTemplates/generic.template.html b/settings/helpTemplates/generic.template.html index d2468214c..ca0d1e76f 100644 --- a/settings/helpTemplates/generic.template.html +++ b/settings/helpTemplates/generic.template.html @@ -2,11 +2,12 @@ <#macro argumentlist name myargs> <#if myargs?size != 0> - ${name} + ${name} <#list myargs as arg> ${arg.name} ${arg.type} + ${arg.defaultValue!"No default"} ${arg.summary} <#-- @@ -18,7 +19,7 @@ <#macro argumentDetails arg>

${arg.name}<#if arg.synonyms??> / ${arg.synonyms} - (<#if arg.attributes??>${arg.attributes} ${arg.type})

+ (<#if arg.attributes??>${arg.attributes} ${arg.type}<#if arg.defaultValue??> with default value ${arg.defaultValue}) ${arg.summary}. ${arg.fulltext}
<#if arg.options??>

The ${arg.name} argument is an enumerated type (${arg.type}), which can have one of the following values:

@@ -70,6 +71,7 @@ Name Type + Default value Summary