package org.seqcode.data.seqdata;
import java.util.*;
import java.io.*;
import java.sql.*;
import org.seqcode.data.connections.DatabaseConnectionManager;
import org.seqcode.data.connections.DatabaseException;
import org.seqcode.genome.Genome;
import org.seqcode.genome.location.Region;
import org.seqcode.gseutils.NotFoundException;
/**
* A SeqAnalysis represents the results of running some binding-call or
* peak finding program on a set of SeqAlignments. The name and version of
* the analysis are independent of the name and version of the alignments, though
* in practice they should be related; the name and version are
* used as they DB key.
*
* The analysis stores a set of parameters (Map<String,String>) that can be
* any relevant data about how the binding calls were generated.
*/
public class SeqAnalysis implements Comparable<SeqAnalysis> {
private Map<String,String> params;
private Set<SeqAlignment> foreground, background;
private String name, version, program;
private Integer dbid;
private List<SeqAnalysisResult> results;
private boolean active;
/* these methods (through store()) are primarily for constructing a
SeqAnalysis and saving it to the DB */
public SeqAnalysis (String name, String version, String program) {
this.name = name;
this.version = version;
this.program = program;
dbid = null;
params = null;
foreground = null;
background = null;
results = new ArrayList<SeqAnalysisResult>();
this.active = true;
}
public SeqAnalysis (String name, String version, String program, boolean active) {
this.name = name;
this.version = version;
this.program = program;
dbid = null;
params = null;
foreground = null;
background = null;
results = new ArrayList<SeqAnalysisResult>();
this.active = active;
}
public void setActive(boolean b) {active = b;}
public void setParameters(Map<String,String> params) {
this.params = params;
}
public void setInputs(Set<SeqAlignment> foreground,
Set<SeqAlignment> background) {
this.foreground = foreground;
this.background = background;
}
public void addResult(SeqAnalysisResult result) {
results.add(result);
}
private void storeinputs(PreparedStatement ps,
String type,
int analysis,
int alignment) throws SQLException {
ps.setInt(1,analysis);
ps.setInt(2,alignment);
ps.setString(3, type);
ps.execute();
}
public void store() throws SQLException {
java.sql.Connection cxn = DatabaseConnectionManager.getConnection(SeqDataLoader.role);
cxn.setAutoCommit(false);
String q = "insert into chipseqanalysis (id, name, version, program, active) values (%s,?,?,?,?)";
PreparedStatement ps = cxn.prepareStatement(String.format(q,org.seqcode.data.connections.DatabaseSequence.getInsertSQL(cxn, "chipseqanalysis_id")));
ps.setString(1, name);
ps.setString(2, version);
ps.setString(3, program);
ps.setInt(4,active ? 1 : 0);
ps.execute();
ps.close();
String sql = org.seqcode.data.connections.DatabaseSequence.getLastSQLStatement(cxn, "chipseqanalysis_id");
ps = cxn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
rs.next();
dbid = rs.getInt(1);
rs.close();
ps.close();
ps = null;
if (params != null && params.size() > 0) {
ps = cxn.prepareStatement("insert into analysisparameters(analysis,name,value) values (?,?,?)");
ps.setInt(1,dbid);
for (String k : params.keySet()) {
ps.setString(2,k);
ps.setString(3,params.get(k));
ps.execute();
}
ps.close();
}
ps = null;
if (foreground != null && foreground.size() > 0) {
ps = cxn.prepareStatement("insert into analysisinputs(analysis, alignment, inputtype) values (?,?,?)");
for (SeqAlignment a : foreground) {
storeinputs(ps, "foreground", dbid, a.getDBID());
}
}
if (background != null && background.size() > 0) {
if (ps == null) {
ps = cxn.prepareStatement("insert into analysisinputs(analysis, alignment, inputtype) values (?,?,?)");
}
for (SeqAlignment a : background) {
storeinputs(ps, "background", dbid, a.getDBID());
}
}
if (ps != null) {
ps.close();
}
if (results != null && results.size() > 0) {
ps = cxn.prepareStatement("insert into analysisresults(analysis,chromosome,startpos,stoppos,position,fgcount,bgcount,strength,peak_shape,pvalue,fold_enrichment) " +
" values (?,?,?,?,?,?,?,?,?,?,?)");
ps.setInt(1,dbid);
for (SeqAnalysisResult r : results) {
ps.setInt(2, r.getGenome().getChromID(r.getChrom()));
ps.setInt(3, r.getStart());
ps.setInt(4, r.getEnd());
if (r.position == null) {
ps.setNull(5, java.sql.Types.INTEGER);
} else {
ps.setInt(5, r.position);
}
if (r.foregroundReadCount == null) {
ps.setNull(6,java.sql.Types.DOUBLE);
} else {
ps.setDouble(6,r.foregroundReadCount);
}
if (r.backgroundReadCount == null) {
ps.setNull(7,java.sql.Types.DOUBLE);
} else {
ps.setDouble(7,r.backgroundReadCount);
}
if (r.strength == null) {
ps.setNull(8,java.sql.Types.DOUBLE);
} else {
ps.setDouble(8,r.strength);
}
if (r.shape == null) {
ps.setNull(9,java.sql.Types.DOUBLE);
} else {
ps.setDouble(9,r.shape);
}
if (r.pvalue == null) {
ps.setNull(10,java.sql.Types.DOUBLE);
} else {
ps.setDouble(10,r.pvalue);
}
if (r.foldEnrichment == null) {
ps.setNull(11,java.sql.Types.DOUBLE);
} else {
ps.setDouble(11,r.foldEnrichment);
}
ps.execute();
}
ps.close();
}
cxn.commit();
if(cxn!=null) try {cxn.close();}catch (Exception ex) {throw new DatabaseException("Couldn't close connection with role "+SeqDataLoader.role, ex); }
}
/* stores the active flag to the database. Must be done
on an object that has already been stored such that it has a DBID */
public void storeActiveDB() throws SQLException {
if (dbid == null) {
throw new RuntimeException("Must have a dbid");
}
String sql = "update chipseqanalysis set active = ? where id = ?";
java.sql.Connection cxn = DatabaseConnectionManager.getConnection(SeqDataLoader.role);
cxn.setAutoCommit(false);
PreparedStatement ps = cxn.prepareStatement(sql);
ps.setInt(1, active ? 1 : 0);
ps.setInt(2, dbid);
ps.execute();
cxn.commit();
if(cxn!=null) try {cxn.close();}catch (Exception ex) {throw new DatabaseException("Couldn't close connection with role "+SeqDataLoader.role, ex); }
}
/* these methods are primarily for querying an object that you've gotten back
from the database */
public String toString() {
return name + ";" + version + ";" + program;
}
public Integer getDBID() {return dbid;}
public String getName() {return name;}
public String getVersion() {return version;}
public String getProgramName() {return program;}
public boolean isActive() {return active;}
public Map<String,String> getParams() {
if (params == null) {
try {
loadParams();
} catch (SQLException e) {
throw new DatabaseException(e.toString(),e);
}
}
return params;
}
public Set<SeqAlignment> getForeground() {
if (foreground == null) {
try {
loadInputs();
} catch (SQLException e) {
throw new DatabaseException(e.toString(),e);
}
}
return foreground;
}
public Set<SeqAlignment> getBackground() {
if (background == null) {
try {
loadInputs();
} catch (SQLException e) {
throw new DatabaseException(e.toString(),e);
}
}
return background;
}
/** fills in the parameters from the database */
private void loadParams() throws SQLException {
java.sql.Connection cxn = DatabaseConnectionManager.getConnection(SeqDataLoader.role);
PreparedStatement ps = cxn.prepareStatement("select name,value from analysisparameters where analysis = ?");
ps.setInt(1,dbid);
ResultSet rs = ps.executeQuery();
HashMap<String,String> params = new HashMap<String,String>();
while (rs.next()) {
params.put(rs.getString(1), rs.getString(2));
}
setParameters(params);
rs.close();
ps.close();
if(cxn!=null) try {cxn.close();}catch (Exception ex) {throw new DatabaseException("Couldn't close connection with role "+SeqDataLoader.role, ex); }
}
/** fills in the input experiment fields from the database */
private void loadInputs() throws SQLException {
java.sql.Connection cxn = DatabaseConnectionManager.getConnection(SeqDataLoader.role);
PreparedStatement ps = cxn.prepareStatement("select alignment, inputtype from analysisinputs where analysis = ?");
ps.setInt(1,dbid);
HashSet<SeqAlignment> fg = new HashSet<SeqAlignment>();
HashSet<SeqAlignment> bg = new HashSet<SeqAlignment>();
ResultSet rs = ps.executeQuery();
try {
SeqDataLoader loader = new SeqDataLoader(false, true);
while (rs.next()) {
if (rs.getString(2).equals("foreground")) {
fg.add(loader.loadAlignment(rs.getInt(1)));
} else if (rs.getString(2).equals("background")) {
bg.add(loader.loadAlignment(rs.getInt(1)));
}
}
setInputs(fg,bg);
rs.close();
ps.close();
loader.close();
} catch (IOException e) {
/* IOException comes from the loader trying to connect to readdb,
but we told it not to do that. So this shouldn't
happen
*/
throw new RuntimeException(e.toString(),e);
} catch (NotFoundException e) {
/* the loader throws a NotFoundException if it can't
find the alignment. But the database constraints should
have prevented us from getting an invalid alignment id back.
*/
throw new DatabaseException(e.toString(),e);
}
if(cxn!=null) try {cxn.close();}catch (Exception ex) {throw new DatabaseException("Couldn't close connection with role "+SeqDataLoader.role, ex); }
}
public List<SeqAnalysisResult> getResults(Genome g) throws SQLException {
return getResults(g,null);
}
public List<SeqAnalysisResult> getResults(Region queryRegion) throws SQLException {
return getResults(queryRegion.getGenome(), queryRegion);
}
private Integer isnullint(ResultSet r, int index) throws SQLException {
Integer i = r.getInt(index);
if (i == 0 && r.wasNull()) {
return null;
} else {
return i;
}
}
private Double isnulldouble(ResultSet r, int index) throws SQLException {
Double i = r.getDouble(index);
if (i == 0 && r.wasNull()) {
return null;
} else {
return i;
}
}
public List<SeqAnalysisResult> getResults(Genome genome, Region queryRegion) throws SQLException {
java.sql.Connection cxn = DatabaseConnectionManager.getConnection(SeqDataLoader.role);
String query = "select chromosome, startpos, stoppos, position, fgcount, bgcount, strength, peak_shape, pvalue, fold_enrichment " +
" from analysisresults where analysis = ? ";
if (queryRegion != null) {
query += " and chromosome = ? and startpos >= ? and stoppos <= ?";
}
PreparedStatement ps = cxn.prepareStatement(query);
ps.setInt(1, dbid);
if (queryRegion != null) {
ps.setInt(2, queryRegion.getGenome().getChromID(queryRegion.getChrom()));
ps.setInt(3, queryRegion.getStart());
ps.setInt(4, queryRegion.getEnd());
}
ResultSet rs = ps.executeQuery();
List<SeqAnalysisResult> result = new ArrayList<SeqAnalysisResult>();
while (rs.next()) {
SeqAnalysisResult r = new SeqAnalysisResult(genome,
genome.getChromName(rs.getInt(1)),
rs.getInt(2),
rs.getInt(3),
isnullint(rs,4),
isnulldouble(rs,5),
isnulldouble(rs,6),
isnulldouble(rs,7),
isnulldouble(rs,8),
isnulldouble(rs,9),
isnulldouble(rs,10));
if (Double.isInfinite(r.foldEnrichment)) {
r.foldEnrichment = r.foregroundReadCount / Math.max(.1, r.backgroundReadCount);
}
result.add(r);
}
rs.close();
ps.close();
if(cxn!=null) try {cxn.close();}catch (Exception ex) {throw new DatabaseException("Couldn't close connection with role "+SeqDataLoader.role, ex); }
return result;
}
/** retrieves all ChipSeqAnalysis objects from the database */
public static Collection<SeqAnalysis> getAll() throws DatabaseException, SQLException {
return getAll(true);
}
public static Collection<SeqAnalysis> getAll(Boolean active) throws DatabaseException, SQLException {
ArrayList<SeqAnalysis> output = new ArrayList<SeqAnalysis>();
java.sql.Connection cxn = DatabaseConnectionManager.getConnection(SeqDataLoader.role);
String sql = "select id, name, version, program, active from chipseqanalysis";
if (active != null) {
sql = sql + " where active = " + (active ? 1 : 0);
}
PreparedStatement ps = cxn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
SeqAnalysis a = new SeqAnalysis(rs.getString(2),
rs.getString(3),
rs.getString(4),
rs.getInt(5) != 0 ? true : false);
a.dbid = rs.getInt(1);
output.add(a);
}
rs.close();
ps.close();
if(cxn!=null) try {cxn.close();}catch (Exception ex) {throw new DatabaseException("Couldn't close connection with role "+SeqDataLoader.role, ex); }
return output;
}
/** Retrieves the ChipSeqAnalysis with the specified name and version */
public static SeqAnalysis get(SeqDataLoader loader, String name, String version) throws NotFoundException, DatabaseException, SQLException {
return get(loader,name,version,true);
}
public static SeqAnalysis get(SeqDataLoader loader, String name, String version, Boolean active) throws NotFoundException, DatabaseException, SQLException {
java.sql.Connection cxn = DatabaseConnectionManager.getConnection(SeqDataLoader.role);
String sql = "select id, program, active from chipseqanalysis where name = ? and version = ?";
if (active != null) {
sql = sql + " and active = " + (active ? 1 : 0);
}
PreparedStatement ps = cxn.prepareStatement(sql);
ps.setString(1,name);
ps.setString(2,version);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
throw new NotFoundException("Couldn't find analysis " + name + "," + version);
}
SeqAnalysis result = new SeqAnalysis(name,version, rs.getString(2), rs.getInt(3) != 0 ? true : false);
result.dbid = rs.getInt(1);
rs.close();
ps.close();
if(cxn!=null) try {cxn.close();}catch (Exception ex) {throw new DatabaseException("Couldn't close connection with role "+SeqDataLoader.role, ex); }
return result;
}
/** returns the collection of active analyses that have a result in the specified region
*/
public static Collection<SeqAnalysis> withResultsIn(SeqDataLoader loader, Region r) throws SQLException {
java.sql.Connection cxn = DatabaseConnectionManager.getConnection(SeqDataLoader.role);
String sql = "select id, name, version, program, active from chipseqanalysis where id in (select unique(analysis) from analysisresults where chromosome = ? and startpos >= ? and stoppos <= ?) and active = 1";
ArrayList<SeqAnalysis> output = new ArrayList<SeqAnalysis>();
PreparedStatement ps = cxn.prepareStatement(sql);
ps.setInt(1, r.getGenome().getChromID(r.getChrom()));
ps.setInt(2, r.getStart());
ps.setInt(3, r.getEnd());
ResultSet rs = ps.executeQuery();
while (rs.next()) {
SeqAnalysis a = new SeqAnalysis(rs.getString(2),
rs.getString(3),
rs.getString(4),
rs.getInt(5) != 0 ? true : false);
a.dbid = rs.getInt(1);
output.add(a);
}
rs.close();
ps.close();
if(cxn!=null) try {cxn.close();}catch (Exception ex) {throw new DatabaseException("Couldn't close connection with role "+SeqDataLoader.role, ex); }
return output;
}
public int compareTo(SeqAnalysis other) {
int c = name.compareTo(other.name);
if (c == 0) {
c = version.compareTo(other.version);
if (c == 0) {
c = program.compareTo(other.program);
}
}
return c;
}
}