adding some VE2 report infrastructure; work-in-progress.

git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@3008 348d0f76-0448-11de-a6fe-93d51630548a
This commit is contained in:
aaron 2010-03-16 03:57:42 +00:00
parent 586f87fa35
commit 10e76abbbc
11 changed files with 696 additions and 0 deletions

View File

@ -0,0 +1,110 @@
package org.broadinstitute.sting.playground.utils.report;
import org.broadinstitute.sting.playground.utils.report.tags.Analysis;
import org.broadinstitute.sting.playground.utils.report.tags.Datum;
import org.broadinstitute.sting.playground.utils.report.tags.Param;
import org.broadinstitute.sting.playground.utils.report.tags.Table;
import org.broadinstitute.sting.utils.StingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* @author aaron
* <p/>
* Class AnalysisModuleScanner
* <p/>
* Given an analysis, find the annotated fields and methods. Given this module and
* the object, a Mashalling object can serialize or deserialize a analysis module.
*/
public class AnalysisModuleScanner {
// what we extracted from the class
private Map<Param, Field> parameters = new HashMap<Param, Field>(); // the parameter annotations
private Map<Table, Field> tables = new HashMap<Table, Field>(); // the table annotations
private Map<Datum, Field> datums = new HashMap<Datum, Field>(); // the data we've discovered
private Analysis analysis; // the analysis annotation
// private storage of the class type
private final Class cls;
/**
* create a report scanner from the passed in class
* @param cls the target class, annotated with the @Analysis annotation
*/
public AnalysisModuleScanner(Class cls) {
this.cls = cls;
scan(); // scan the passed in class
}
/**
* create a report scanner from the passed in class
* @param obj the target object, annotated with the @Analysis annotation
*/
public AnalysisModuleScanner(Object obj) {
this.cls = obj.getClass();
scan(); // scan the passed in class
}
/** scan the class and find all appropriate fields and tables */
public void scan() {
if (cls == null || !cls.isAnnotationPresent(Analysis.class))
throw new StingException("The class passed in cannot be null, " + "" +
"and must contain the @Analysis annotation, class " + cls + " was the input");
// get the annotation off of the class
analysis = (Analysis) cls.getAnnotation(Analysis.class);
scanFields();
}
/**
* scan the fields of the class, extracting parameters and table annotations and their associated fields
*/
private void scanFields() {
// get the fields from the class, and extract
for (Field f : cls.getDeclaredFields())
for (Annotation annotation : f.getAnnotations()) {
if (annotation.annotationType().equals(Param.class))
parameters.put((Param) annotation, f);
if (annotation.annotationType().equals(Table.class))
tables.put((Table) annotation, f);
if (annotation.annotationType().equals(Datum.class))
datums.put((Datum) annotation, f);
}
}
/**
*
* @return get the list of parameters we found
*/
public Map<Param, Field> getParameters() {
return parameters;
}
/**
*
* @return a list of table annotations found
*/
public Map<Table, Field> getTables() {
return tables;
}
/**
*
* @return a map of the datum annotations found
*/
public Map<Datum, Field> getData() {
return datums;
}
/**
*
* @return the analysis annotation found
*/
public Analysis getAnalysis() {
return analysis;
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2010. The Broad Institute
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.broadinstitute.sting.playground.utils.report;
import org.broadinstitute.sting.playground.utils.report.formats.OutputFormater;
import org.broadinstitute.sting.playground.utils.report.tags.*;
import org.broadinstitute.sting.utils.StingException;
import java.util.Collection;
/**
* @author aaron
* <p/>
* Class Marshaller
* <p/>
* Given an analysis scan, an object, and a formatter, this class emits
* a report to disk (or other source).
*/
public class Marshaller {
private String report;
private OutputFormater formatter;
/**
* create a report
* @param reportName the report name
* @param formater the formater to use
*/
public void createReport(String reportName, OutputFormater formater) {
this.formatter = formater;
report = reportName;
formatter.startReport(report);
}
/**
* add an analysis module to the output source
* @param toMarshall the object to marshall
*/
public void write(Object toMarshall) {
AnalysisModuleScanner moduleScanner = new AnalysisModuleScanner(toMarshall);
formatter.addAnalysis(moduleScanner.getAnalysis());
for (Param p : moduleScanner.getParameters().keySet())
try {
formatter.addParam(p, moduleScanner.getParameters().get(p).get(toMarshall).toString());
} catch (IllegalAccessException e) {
throw new StingException("Unable to access variable " + moduleScanner.getParameters().get(p), e);
}
for (Datum d : moduleScanner.getData().keySet())
try {
formatter.addDatum(d, moduleScanner.getData().get(d).get(toMarshall).toString());
} catch (IllegalAccessException e) {
throw new StingException("Unable to access variable " + moduleScanner.getParameters().get(d), e);
}
for (Table t : moduleScanner.getTables().keySet())
try {
formatter.addTable(t, new TableContainer((Collection<Object>) moduleScanner.getTables().get(t).get(toMarshall),t.columns()));
} catch (IllegalAccessException e) {
throw new StingException("Unable to access variable " + moduleScanner.getParameters().get(t), e);
}
}
public void endReport() {
formatter.endReport();
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2010. The Broad Institute
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.broadinstitute.sting.playground.utils.report;
import java.util.*;
/**
*
* @author aaron
*
* Class TableContainer
*
* represents a table of data, and formats according to column count. Do not use,
* needs improvement. This is a stand-in for something better.
*/
public class TableContainer {
private List<Object> tableEntries;
private int columns = 2; // default to two
public TableContainer(Collection<Object> tbl, int columns) {
tableEntries = new ArrayList<Object>();
if (tbl instanceof List || tbl instanceof Vector || tbl instanceof Set)
tableEntries.addAll(tbl);
if (tbl instanceof Map)
for (Object key : ((Map)tbl).keySet()) {
tableEntries.add(key);
tableEntries.add(((Map) tbl).get(key));
}
this.columns = columns;
}
public List<List<Object>> toRows() {
ArrayList<List<Object>> list = new ArrayList<List<Object>>();
List<Object> currentRow = new ArrayList<Object>();
for (Object obj : tableEntries) {
if (currentRow.size() >= columns) {
list.add(currentRow);
currentRow = new ArrayList<Object>();
}
currentRow.add(obj);
}
list.add(currentRow);
return list;
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2010. The Broad Institute
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.broadinstitute.sting.playground.utils.report.formats;
import org.broadinstitute.sting.playground.utils.report.TableContainer;
import org.broadinstitute.sting.playground.utils.report.tags.*;
/**
*
* @author aaron
*
* Class OutputFormater
*
* The formatter defines a perticular output format style. The formatter methods
* are required to be called in the following order:
*
* 1. startReport()
* 2. for each analysis module:
* addAnalysis()
* with many addParam(), addTable(), and addDatum() in no particular order promised
* 3. endReport()
*/
public interface OutputFormater {
/**
* start the report, given the report tag
* @param reportName the report name.
*/
public void startReport(String reportName);
/**
* add an analysis to the report
* @param analysisTag the analysis tag
*/
public void addAnalysis(Analysis analysisTag);
/**
* add a parameter value to the output location
* @param value
*/
public void addParam(Param paramTag, String value);
/**
* add a parameter value to the output location
* @param value
*/
public void addTable(Table tableTag, TableContainer value);
/**
* add a datum object to the output location
* @param value
*/
public void addDatum(Datum datumTag, String value);
/**
* end the report
*/
public void endReport();
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2010. The Broad Institute
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.broadinstitute.sting.playground.utils.report.formats;
import org.broadinstitute.sting.playground.utils.report.TableContainer;
import org.broadinstitute.sting.playground.utils.report.tags.*;
import org.broadinstitute.sting.utils.StingException;
import java.io.*;
import java.util.List;
/**
*
* @author aaron
*
* Class SimpleTextOutputer
*
* a very small demo of text output, just to use for testing and development
*/
public class SimpleTextOutputer implements OutputFormater {
protected PrintWriter out;
protected String terminator = "\n";
protected String spacer = "\t\t\t";
/**
* create a simple text output format given the output file
* @param outputFile
*/
public SimpleTextOutputer(File outputFile) {
try {
FileOutputStream stream = new FileOutputStream(outputFile);
out = new PrintWriter(stream);
} catch (FileNotFoundException e) {
throw new StingException("Unable to find file ",e);
}
}
/**
* start the report, given the report tag
*
* @param reportTag the report tag, which describes the basics of the report
*/
@Override
public void startReport(String reportTag) {
out.write("----------------" + reportTag + "----------------" + terminator);
}
/**
* add an analysis to the report
*
* @param analysisTag the analysis tag
*/
@Override
public void addAnalysis(Analysis analysisTag) {
out.write("----------------" + analysisTag.name() + "----------------" + terminator);
out.write(String.format("Name%s%s%s",spacer,analysisTag.name(),terminator));
out.write(String.format("Description\t\t%s%s",analysisTag.description(),terminator));
out.write(String.format("Version%s%s%s",spacer,analysisTag.version(),terminator));
}
/**
* add a parameter value to the output location
*
* @param value
*/
@Override
public void addParam(Param paramTag, String value) {
out.write(String.format("Param %s%s%s%s",paramTag.name(),spacer,value,terminator));
}
/**
* add a parameter value to the output location
*
* @param value
*/
@Override
public void addTable(Table tableTag, TableContainer value) {
out.write(tableTag.name());
boolean first = false;
for (List<Object> row : value.toRows()) {
if (!first) first = true;
else out.write("\t");
out.write("\t\t");
for (Object obj: row) out.write(obj+",");
out.write(terminator);
}
}
/**
* add a datum object to the output location
*
* @param value
*/
@Override
public void addDatum(Datum datumTag, String value) {
out.write("Datum "+datumTag.name()+spacer+value+terminator);
}
/**
* end the report
*
*/
@Override
public void endReport() {
out.write("----------------" + "----------------" + terminator);
out.close();
}
}

View File

@ -0,0 +1,18 @@
package org.broadinstitute.sting.playground.utils.report.tags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author aaron
* <p/>
* Annotation Analysis
* <p/>
* the main annotation for analysis objects in the report system
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Analysis {
String name(); // the name of the analysis
String description(); // its description, required
String version() default "unversioned"; // the version, not always used
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2010. The Broad Institute
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.broadinstitute.sting.playground.utils.report.tags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author aaron
* <p/>
* Annotation Datum
* <p/>
* The basic Datum annotation, for fields in an analysis that
* are to be output as data.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Datum {
String name(); // the name, required
String description(); // a description
}

View File

@ -0,0 +1,19 @@
package org.broadinstitute.sting.playground.utils.report.tags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author aaron
* <p/>
* Annotation Param
* <p/>
* a description annotation for a parameter; a variable used as input to the
* analysis, but not (nessasarally) an output. Some formats will store this
* information in comments, others will not include it.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Param {
String name() default ""; // the name, defaulted to the variable name
String description(); // the description of the parameter
}

View File

@ -0,0 +1,20 @@
package org.broadinstitute.sting.playground.utils.report.tags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author aaron
* <p/>
* Annotation Table
* <p/>
* tells the report system to make a table out of the annotated field. The field
* can be of type List<>, Map<>, Vector<>, Collection<> or primative array.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String name(); // the name
String header() default ""; // any text representing the table header
String description(); // a description of the table
int columns() default -1; // the number of columns to divide the data into
}

View File

@ -0,0 +1,64 @@
package org.broadinstitute.sting.playground.utils.report;
import org.broadinstitute.sting.BaseTest;
import org.broadinstitute.sting.playground.utils.report.tags.Analysis;
import org.broadinstitute.sting.playground.utils.report.tags.Param;
import org.broadinstitute.sting.playground.utils.report.tags.Table;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* @author aaron
* <p/>
* Class AnalysisModuleScannerTest
* <p/>
* Test out the analysis scanner, which takes an analysis module and extracts out basic data
*/
public class AnalysisModuleScannerTest extends BaseTest {
@Test
public void testBasicScan() {
AnalysisModuleScanner scanner = new AnalysisModuleScanner(FakeAnalysis.class);
// check we found one param, and check its description
Assert.assertEquals(1, scanner.getParameters().size());
Assert.assertTrue("basic description".equals(scanner.getParameters().keySet().iterator().next().description()));
// check that we've found a table, and check its description
Assert.assertEquals(1, scanner.getTables().size());
Assert.assertTrue("Generate a table from this data".equals(scanner.getTables().keySet().iterator().next().description()));
// check that the analysis name and description were set
Assert.assertTrue("testAnalysis".equals(scanner.getAnalysis().name()));
Assert.assertTrue("The is just a simple description".equals(scanner.getAnalysis().description()));
}
}
// --------------------------------------------------------------------------------
// my fake analysis class
// --------------------------------------------------------------------------------
@Analysis(name = "testAnalysis", description = "The is just a simple description")
class FakeAnalysis {
@Param(description = "basic description")
public String text = "GRRR";
@Table(name="FakeTable", description = "Generate a table from this data",columns=3)
public List<Integer> values = new ArrayList<Integer>();
public FakeAnalysis() {
values.add(1);
values.add(2);
values.add(3);
values.add(4);
values.add(5);
values.add(6);
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2010. The Broad Institute
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.broadinstitute.sting.playground.utils.report;
import org.broadinstitute.sting.BaseTest;
import org.broadinstitute.sting.playground.utils.report.formats.SimpleTextOutputer;
import org.junit.Test;
import java.io.File;
/**
*
* @author aaron
*
* Class MarshallerTest
*
* test out the marshaller
*/
public class MarshallerTest extends BaseTest {
@Test
public void testMarshalling() {
// output file
/*File fl = new File("testfile.txt");
fl.deleteOnExit();
Marshaller m = new Marshaller();
SimpleTextOutputer format = new SimpleTextOutputer(fl);
FakeAnalysis fa = new FakeAnalysis();
// start the marshall
m.createReport("Fake Report",format);
m.write(fa);
m.write(fa);
m.write(fa);
m.endReport();*/
}
}