/* The Broad Institute SOFTWARE COPYRIGHT NOTICE AGREEMENT This software and its documentation are copyright (2006) by the Broad Institute/Massachusetts Institute of Technology. All rights are reserved. This software is supplied without any warranty or guaranteed support whatsoever. Neither the Broad Institute nor MIT can be responsible for its use, misuse, or functionality. */ package calhoun.gebo.internal.db; import java.awt.Color; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.prefs.Preferences; import oracle.jdbc.driver.OracleResultSet; import oracle.sql.CLOB; import calhoun.bean.AnalysisRun; import calhoun.bean.Repeat; import calhoun.bean.RepeatCluster; import calhoun.gebo.api.AlignmentManager; import calhoun.gebo.api.EditableTrackManager; import calhoun.gebo.db.DataAccessException; import calhoun.gebo.db.DynamicPropertyCriterion; import calhoun.gebo.db.EditManager; import calhoun.gebo.model.Alignment; import calhoun.gebo.model.AlignmentTrack; import calhoun.gebo.model.AnnotatedGene; import calhoun.gebo.model.Criterion; import calhoun.gebo.model.CurationFlag; import calhoun.gebo.model.Feature; import calhoun.gebo.model.FeatureLink; import calhoun.gebo.model.FeatureTrack; import calhoun.gebo.model.Helpful; import calhoun.gebo.model.Identified; import calhoun.gebo.model.Property; import calhoun.gebo.model.RangeTrack; import calhoun.gebo.model.RetirementCode; import calhoun.gebo.model.Segment; import calhoun.gebo.model.Sequence; import calhoun.gebo.model.SequenceGroup; import calhoun.gebo.model.SimpleSegment; import calhoun.gebo.model.SortCriterion; import calhoun.gebo.model.Strand; import calhoun.gebo.model.SubFeature; import calhoun.gebo.model.TranscriptType; import calhoun.gebo.util.C; import calhoun.gebo.util.Informer; import calhoun.gebo.util.P; import calhoun.gebo.util.Q; import calhoun.gebo.util.S; import calhoun.gebo.util.U; import calhoun.gebo.util.W; /** * The TrackManager for the Calhoun Oracle Database. * * @author Reinhard Engels */ public class CalhounTrackManager extends CalhounGuts implements AlignmentManager, EditableTrackManager, Helpful { private static Informer I = new Informer(CalhounTrackManager.class); // ///////////////////////////////////////////////////////////////////////// // Constructors. // ///////////////////////////////////////////////////////////////////////// /** * Creates a new CalhounTrackManager instance. * * @param connection * a Connection value */ private CalhounTrackManager() { super("CalhounTM", "Calhoun"); m_columnPositionByName.put(AP.FEATURE_ID, new Integer(1)); m_columnPositionByName.put(AP.START, new Integer(2)); m_columnPositionByName.put(AP.STOP, new Integer(3)); m_columnPositionByName.put(AP.LABEL, new Integer(4)); m_columnPositionByName.put(AP.STRAND, new Integer(5)); loadVirtualTrackIdsByTrackId(); } // ///////////////////////////////////////////////////////////////////////// // Static Factory Methods. // ///////////////////////////////////////////////////////////////////////// public static CalhounTrackManager getInstance() { if (INSTANCE == null) { INSTANCE = new CalhounTrackManager(); } return INSTANCE; } // AlignmentManager Interface. public Property[] getProperties(Alignment alignment) { return new Property[] {}; } public String[] getPropertyKeys() { return new String[] {}; } public int getMaxOverlaps() { return m_maxOverlaps; } public void setMaxOverlaps(int maxOverlaps) { m_maxOverlaps = maxOverlaps; } public static List getNucleotideAlignmentSpanTracks( Sequence sequence) { List tracks = new ArrayList(); for (FeatureTrack t : sequence.getTracks()) { if (t instanceof CalhounTrack) { CalhounTrack ct = (CalhounTrack) t; if (ct.getTrackType().isAlignmentSpan() && ct.getOntologyTerm().getId().equals("348")) { tracks.add(ct); } } } return tracks; } public AlignmentTrack loadAlignmentUri(String uri, Segment reference, Segment query, int order) throws Exception { throw new Exception("Calhoun alignment uris not yet supported.\n" + "Unable to find matching alingment track for uri:\n" + uri); } /** * Not a great place to put this... */ public static List getAlignmentTracks(Segment reference, List tracks, Map> queryIdSetByTrack) { List alignmentTracks = C.list(); Map queryById = new HashMap(); Map trackByQueryTrackId = new HashMap(); Map alignmentsByQueryTrackId = new HashMap(); for (CalhounTrack t : tracks) { if (t.isVisible() && t.getTrackType().isAlignmentSpan()) { for (Feature as : t.getFeatures(reference)) { String queryId = as.getPropertyValue(AP.ALT_SEQUENCE_ID); if (queryIdSetByTrack != null && !queryIdSetByTrack.get(t).contains(queryId)) { continue; } String queryTrackId = queryId + "_" + t.getId(); if (queryId != null) { Segment xSeg = new SimpleSegment(reference .getSequence(), as.getStrand(), as.getStart(), as.getStop()); if (!queryById.containsKey(queryId)) { queryById.put(queryId, new SimpleSegment( CalhounSequenceManager.getInstance() .getSequence(queryId))); } if (!alignmentsByQueryTrackId.containsKey(queryTrackId)) { alignmentsByQueryTrackId.put(queryTrackId, new ArrayList()); trackByQueryTrackId.put(queryTrackId, t); } Segment query = (Segment) queryById.get(queryId); if (query.getSequence().getPrimarySequenceGroup() != null && query.getSequence() .getPrimarySequenceGroup() .isGenomeAssembly()) { List alignments = (List) alignmentsByQueryTrackId .get(queryTrackId); Segment ySeg = new SimpleSegment(query .getSequence(), Strand.parseStrand(as .getPropertyValue(AP.ALT_STRAND)), Integer.parseInt(as .getPropertyValue(AP.ALT_START)), Integer.parseInt(as .getPropertyValue(AP.ALT_STOP))); as.setProperty("FEATURE_ID", as.getId()); Alignment alignment = new CalhounAlignment(xSeg, ySeg, as.getProperties()); alignments.add(alignment); } else { I.warn("Query not on a genome assembly. Skipping."); } } } } } for (CalhounTrack t : tracks) { for (Object queryId : queryById.keySet()) { Segment query = (Segment) queryById.get(queryId); String queryTrackId = queryId + "_" + t.getId(); if (query.getSequence().getPrimarySequenceGroup() != null) { List alignmentSet = (List) alignmentsByQueryTrackId .get(queryTrackId); CalhounTrack track = (CalhounTrack) trackByQueryTrackId .get(queryTrackId); if (alignmentSet != null && alignmentSet.size() > 0) { CalhounAlignmentTrack alignmentTrack = new CalhounAlignmentTrack( track, reference, query, null, alignmentTracks .size() + 1); for (Alignment a : alignmentSet) { a.setTrack(alignmentTrack); } alignmentTrack.setAlignments(alignmentSet); alignmentTracks.add(alignmentTrack); } } } } return alignmentTracks; } // ///////////////////////////////////////////////////////////////////////// // Helpful Interface. // ///////////////////////////////////////////////////////////////////////// public String getHelpId() { return "calhoun"; } public String getHelpLabel() { return "Calhoun Database Tracks"; } // ///////////////////////////////////////////////////////////////////////// // TrackManager Interface. // ///////////////////////////////////////////////////////////////////////// public FeatureLink getFeatureLink() { return null; } public Property[] getProperties(Feature feature) { List propertyList = C.list(); if (feature.getId().matches("\\d+")) { // hack to avoid error when clicking on pending subfeatures. addOrdinaryProperties(feature, propertyList); addDynamicProperties(feature, propertyList); } return propertyList.toArray(new Property[0]); } public Feature[] getFeatures(Segment segment) { FeatureTrack[] tracks = getTracks(segment.getSequence()); List featureList = C.list(); for (FeatureTrack t : tracks) { if (t.isVisible()) { featureList.addAll(Arrays.asList(getFeatures(segment, t))); } } return featureList.toArray(new Feature[0]); } public Feature[] getFeatures(Segment segment, FeatureTrack track) { if (!(segment.getSequence().getSequenceManager() instanceof CalhounSequenceManager)) { return new Feature[0]; } CalhounTrack ct = (CalhounTrack) track; List featureList = C.list(); if (ct.isExplodedMultiAlignmentSpanTrack()) { if (ct.getFeatures(segment.getSequence()) == null) { I.warn("exploding tracks on an existing track"); // TODO screwed up rethink // MultiAlignmentSpan.explodeMultipleAlignmentTrack(ct.get, // segment // .getSequence()); } I.warn("mact(2): " + ct); featureList.addAll(ct.getFeatures(segment.getSequence())); } else { addTopLevelFeatures(segment, (CalhounTrack) track, new Criterion[0], featureList); if (((CalhounTrack) track).getTrackType().isCompound()) { addComponentFeatures((CalhounTrack) track, segment, featureList); } } return featureList.toArray(new Feature[0]); } public CalhounTrackType getTrackType(String trackTypeId) { getTrackTypes(); if (m_trackTypeMap.containsKey(trackTypeId)) { return (CalhounTrackType) m_trackTypeMap.get(trackTypeId); } I.warn("Unable to find trackTypeId: " + trackTypeId); return null; } public CalhounTrack getTrack(String subclass, String ontologyTermId, String analysisEventId) { CalhounTrackType trackType = CalhounTrackManager.getInstance() .getTrackType(subclass, ontologyTermId); String trackId = trackType.getId() + "_" + analysisEventId; return (CalhounTrack) CalhounTrackManager.getInstance().getTrack( trackId); } public CalhounTrackType getTrackType(String subclass, String ontologyTermId) { CalhounTrackType[] trackTypes = getTrackTypes(); for (int i = 0; i < trackTypes.length; i++) { if (trackTypes[i].getSubclass().equals(subclass) && trackTypes[i].getOntologyTerm().getId().equals( ontologyTermId)) { return trackTypes[i]; } } return CalhounTrackType.getGenericTrackType(); } public FeatureTrack getTrack(String trackId) { String[] parts = trackId.split("_"); if (parts.length == 2) { String trackTypeId = parts[0]; String analysisEventId = parts[1]; CalhounTrackType trackType = getTrackType(trackTypeId); CalhounTrack track = CalhounTrack.intern(trackType, trackType .getSubclass(), trackType.getOntologyTerm(), analysisEventId); return track; } // TODO: this is going to break with virtual tracks. I.warn("Unable to find track for track id " + trackId); return null; } public Identified getOntologyTerm(String ontologyTermId) throws SQLException { if (!m_ontologyTermMap.containsKey(ontologyTermId)) { String sql = "select ap_name from ap_ontology_term where ap_id= ?"; PreparedStatement statement = getConnection().prepareStatement(sql); Q.setLongOrNull(1, ontologyTermId, statement); ResultSet resultSet = statement.executeQuery(); if (resultSet.next()) { Identified ontologyTerm = new Identified(ontologyTermId, resultSet.getString(1)); m_ontologyTermMap.put(ontologyTermId, ontologyTerm); } } return (Identified) m_ontologyTermMap.get(ontologyTermId); } public CalhounTrackType[] getTrackTypes() { if (m_trackTypeMap == null) { m_trackTypeMap = new HashMap(); String sql = "select ap_id,ap_name,ap_feature_subclass,ap_ontology_term_id,ap_ontology_term_name,ap_color,ap_sort_key,ap_view,ap_component_view,ap_url from ap_track_type_view"; try { Q.startStopWatch(sql); PreparedStatement statement = getConnection().prepareStatement( sql); ResultSet resultSet = statement.executeQuery(); m_trackTypeMap.put("0", CalhounTrackType.getGenericTrackType()); while (resultSet.next()) { String trackId = resultSet.getString(1); Identified ontologyTerm = getOntologyTerm(resultSet .getString(4)); CalhounTrackType trackType = new CalhounTrackType(this, resultSet.getString(1), resultSet.getString(2), resultSet.getString(3), ontologyTerm, Q.colorFromHexString(resultSet.getString(6)), resultSet.getInt(7), resultSet.getString(8), resultSet.getString(9), resultSet.getString(10)); m_trackTypeMap.put(trackType.getId(), trackType); } statement.close(); resultSet.close(); } catch (SQLException e) { I.error("Error getting track types. SQL:\n" + sql, e); } finally { Q.stopStopWatch(sql); } } return (CalhounTrackType[]) m_trackTypeMap.values().toArray( new CalhounTrackType[0]); } private int getTrackTypeCount(Set trackTypeSet, String trackTypeId) { int count = 0; for (Iterator it = trackTypeSet.iterator(); it.hasNext();) { CalhounTrack track = (CalhounTrack) it.next(); if (track.getTrackType().getId().equals(trackTypeId)) { count++; } } return count; } private Object getTrackCacheKey(Sequence sequence) { Object key = sequence.getPrimarySequenceGroup(); if (key == null) { key = sequence; } return key; } public void clearTracksForSequenceIfNoTranscriptsYet(Sequence sequence) { // TODO: hack Object key = getTrackCacheKey(sequence); if (sequence.getCellType().equals("E")) { if (m_trackCache.containsKey(key)) { Set trackSet = (Set) m_trackCache.get(key); int count = getTrackTypeCount(trackSet, "5"); if (count == 1) { I.warn("Clearing tracks for sequence..."); m_trackCache.remove(key); return; } } } else if (sequence.getCellType().equals("P")) {} } public FeatureTrack[] getTracks(Sequence sequence) { return getTracks(sequence.getPrimarySequenceGroup(), sequence); } public FeatureTrack[] getTracks(SequenceGroup sequenceGroup) { return getTracks(sequenceGroup, null); } public RangeTrack[] getRangeTracks(SequenceGroup sequenceGroup) { List rangeTracks = C.list(); for (FeatureTrack t : getTracks(sequenceGroup)) { if (t instanceof CalhounTrack) { if (!t.isPending()) { CalhounTrack ct = (CalhounTrack) t; rangeTracks.add(ct.getRangeTrack()); } } } return rangeTracks.toArray(new RangeTrack[0]); } public void clearTracks(Sequence sequence) { m_trackCache.remove(sequence.getPrimarySequenceGroup()); } private FeatureTrack[] getTracks(SequenceGroup sequenceGroup, Sequence sequence) { buildCriterionDefaultMaps(); if (m_trackCache.containsKey(sequenceGroup)) { Set trackSet = m_trackCache.get(sequenceGroup); // hack to check for saved transcripts. return (FeatureTrack[]) trackSet.toArray(new FeatureTrack[0]); } List trackList = C.list(); // ae.parentRun String hql = "select ae,t" + " from FeatureTrack t join t.analysisRun ae " + " where ae.sequenceGroupVersion.group=? and ae.process !='retire' and t.featureClass not in ('EGENE','EXON','ALSEG')"; Map mostRecentTrackByTruncatedName = new HashMap(); try { Q.startStopWatch(hql); calhoun.util.DbSession s = CalhounConnectionManager.getInstance() .getDbSession(); List rows = s.find(hql, sequenceGroup.getId()); for (Object row : rows) { // ae.process,ae.version,ae.id,ae.name,ae.admissibleEvidence,ae.notes,t.featureClass,t.ontologyTerm.id // Object[] fields = (Object[]) row; AnalysisRun ae = (AnalysisRun) ((Object[]) row)[0]; calhoun.bean.FeatureTrack ft = (calhoun.bean.FeatureTrack) ((Object[]) row)[1]; String process = ae.getProcess(); int version = ae.getVersion(); String analysisEventId = ae.getId(); String analysisEventName = ae.getName(); boolean admissibleEvidence = ae.getAdmissibleEvidence(); String notes = ae.getNotes(); String subclass = CalhounTrack.getDbSubclass(ft .getFeatureClass()); String ontologyTermId = ft.getOntologyTerm().getId(); analysisEventName = analysisEventName.replaceFirst( sequenceGroup.getId() + "_", ""); CalhounTrackType trackType = getTrackType(subclass, ontologyTermId); String trackLabel = trackType.getLabel() + ": " + analysisEventName; Identified ontologyTerm = getOntologyTerm(ontologyTermId); if (trackType == CalhounTrackType.getGenericTrackType()) { trackLabel += ": " + subclass + ": " + ontologyTerm.dump(); } boolean updatable = false; boolean deletable = false; CalhounTrack track = null; track = CalhounTrack.intern(trackType, subclass, ontologyTerm, analysisEventId, trackLabel, version, notes); if (ae.getParentRun() != null) { track.setParentAnalysisEventId(ae.getParentRun().getId()); } if (trackType.getURL() != null) { track.setFeatureLink(new FeatureLink(new String[] { track .getId() }, "", trackType.getURL())); } track.setAdmissibleEvidence(admissibleEvidence); registerTrack(track, sequenceGroup, trackList); registerVirtualTracks(track, sequenceGroup, trackList); String truncatedTrackName = getTruncatedName(track); if (mostRecentTrackByTruncatedName .containsKey(truncatedTrackName)) { CalhounTrack otherTrack = (CalhounTrack) mostRecentTrackByTruncatedName .get(truncatedTrackName); if (track.getVersion() > otherTrack.getVersion()) { mostRecentTrackByTruncatedName.put(truncatedTrackName, track); } } else { mostRecentTrackByTruncatedName.put(truncatedTrackName, track); } } } catch (Throwable t) { I.error("Could not retrieve tracks. HQL:\n" + hql, t); } finally { Q.stopStopWatch(hql); } for (CalhounTrack t : trackList) { if (t instanceof VirtualCalhounTrack) { continue; } FeatureTrack mostRecentTrack = (FeatureTrack) mostRecentTrackByTruncatedName .get(getTruncatedName(t)); if (t.getTrackType().equals(CalhounTrackType.getGenericTrackType())) { t.setDefaultVisible(false); } else if (t.getLabel().matches(".*LEGACY.*")) { t.setDefaultVisible(false); } else if (t.getId().equals(mostRecentTrack.getId())) { t.setDefaultVisible(true); } else { t.setDefaultVisible(false); } if (!t.isAdmissibleEvidence()) { t.setDefaultVisible(false); } t.loadPrefs(); } if (sequence != null) { try { if (sequence.getCellType().equals("E")) { registerTrack(CalhounPendingInsertTrackFactory .getAnnotatedTranscript().getTrack(), sequenceGroup, trackList); } else if (sequence.getCellType().equals("P")) { registerTrack(CalhounPendingInsertTrackFactory .getProGeneOld().getTrack(), sequenceGroup, trackList); registerTrack(CalhounPendingInsertTrackFactory .getProGeneNew().getTrack(), sequenceGroup, trackList); } else { I.warn("Unknown cell type: " + sequence.getCellType()); } registerTrack(CalhounPendingInsertTrackFactory.getPolyA() .getTrack(), sequenceGroup, trackList); } catch (Throwable t) { I.error("Error adding Pending Calhoun Track", t); } } List explodedTracks = C.list(); Set explodingTracks = C.set(); try { // Map analysisEventIdToBioSampleId = // CalhounPolymorphicTrackManager.getAnalysisEventIdToBioSampleMap(trackList); for (CalhounTrack ct : trackList) { if (ct.getSubclass().equals("MALSPN")) { explodingTracks.add(ct); explodedTracks.addAll(MultiAlignmentSpan .explodeMultipleAlignmentTrack(ct, sequence)); } else if (ct.getSubclass().equals("POLYS")) { // explodingTracks.add(ct); CalhounTrack nqsbTrack = null; for (CalhounTrack ct2 : trackList) { if (ct2.getSubclass().equals("NQSB") && ct.getAnalysisEventId().equals( ct2.getAnalysisEventId())) { explodingTracks.add(ct2); nqsbTrack = ct2; nqsbTrack.setPrefsEnabled(false); nqsbTrack.setColor(Color.GRAY); } } if (ct.getParentAnalysisEventId() != null) { explodingTracks.add(ct); // String bioSampleId = // analysisEventIdToBioSampleId.get(ct.getAnalysisEventId()); SequenceGroup sg = null; if (sequence != null) { sg = sequence.getPrimarySequenceGroup(); } else { sg = sequenceGroup; } // if (sequence != null) { // I.warn("sequence: " + sequence); // I.warn("sg: " + sequence.getPrimarySequenceGroup()); CalhounPolymorphicTrackManager.getInstance().explode( ct, nqsbTrack, sg); // } } } } // I.warn("Adding this many explodedTracks: " + // explodedTracks.size()); // trackList.addAll(explodedTracks); for (CalhounTrack ct : explodedTracks) { registerTrack(ct, sequenceGroup, trackList); } for (CalhounTrack ct : explodingTracks) { unregisterTrack(ct, sequenceGroup, trackList); } } catch (Throwable t) { I.error("Error added exploded multiple alignment tracks", t); } return (FeatureTrack[]) trackList.toArray(new FeatureTrack[0]); } private String getTruncatedName(FeatureTrack track) { String name = track.getLabel(); name = name.replaceFirst("_\\d+$", ""); return name; } public FeatureTrack[] getTracks() { I.warn("calhoun getTracks requires a sequence, returning empty array."); return new FeatureTrack[0];// (Track[]) m_trackSet.toArray(new } private void unregisterTrack(CalhounTrack track, SequenceGroup sequenceGroup, List trackList) { trackList.remove(track); m_trackById.remove(track.getId()); m_trackCache.get(sequenceGroup).remove(track); } private void registerTrack(CalhounTrack track, SequenceGroup sequenceGroup, List trackList) throws Exception { if (track.getSortCriteria().length == 0) { track.setSortCriteria(new SortCriterion[] { new SortCriterion( "LENGTH", false) }); } trackList.add(track); trackHacks(track); // DATAHACK! addCriteria(track); m_trackById.put(track.getId(), track); if (!m_trackCache.containsKey(sequenceGroup)) { m_trackCache.put(sequenceGroup, new HashSet()); } Set set = (Set) m_trackCache.get(sequenceGroup); set.add(track); } // ///////////////////////////////////////////////////////////////////////// // EditableTrackManager Interface. // ///////////////////////////////////////////////////////////////////////// public void commit(Feature[] features) throws DataAccessException { // one day we can probably batch these more efficiently. // for now, enough to support batch interface. for (int i = 0; i < features.length; i++) { Feature feature = features[i]; int editFlag = feature.getEditFlag(); if (editFlag == EditManager.DELETE_FLAG) { deleteFeature(feature); } else if (editFlag == EditManager.UPDATE_FLAG) { updateFeature(feature); } else if (editFlag == EditManager.INSERT_FLAG) { insertFeature(feature); } else if (editFlag == EditManager.REVIEW_FLAG) { reviewFeature(feature); } else { throw new DataAccessException("Unknown Edit Flag: " + editFlag); } // Don't wait for the batch status update. EditManager.getInstance().removeEdit(feature); } } // ///////////////////////////////////////////////////////////////////////// // Formerly part of EditableTrackManager interface... now private. // ///////////////////////////////////////////////////////////////////////// private void deleteFeature(Feature feature) throws DataAccessException { FeatureTrack track = feature.getTrack(); try { if (feature instanceof CalhounDeletableFeature) { ((CalhounDeletableFeature) feature).delete(); } else if (feature instanceof SubFeature && ((SubFeature) feature).getParent() instanceof AnnotatedTranscript) { Feature parent = ((SubFeature) feature).getParent(); if (parent.getSubFeatures().length == 1) { deleteFeature(parent); } else { parent.removeSubFeature((SubFeature) feature); updateFeature(parent); } } else { throw new DataAccessException( "Can't delete features of track: " + track); } } catch (Throwable t) { t.printStackTrace(); throw new DataAccessException(t); } } private void insertFeature(Feature feature) throws DataAccessException { if (feature instanceof CalhounInsertableFeature) { ((CalhounInsertableFeature) feature).insert(); } else { throw new DataAccessException("Can not insert features of type: " + feature.getTrack()); } } private void updateFeature(Feature feature) throws DataAccessException { if (feature instanceof CalhounAnnotatedFeature) { ((CalhounAnnotatedFeature) feature).update(); } else { throw new DataAccessException("Can not update features of type: " + feature.getTrack()); } } private void reviewFeature(Feature feature) throws DataAccessException { if (feature instanceof CalhounAnnotatedFeature) { ((CalhounAnnotatedFeature) feature).review(); } else { throw new DataAccessException("Can not review features of type: " + feature.getTrack()); } } // ///////////////////////////////////////////////////////////////////////// // CalhounTrackManager Interface. (i.e., hacks) // ///////////////////////////////////////////////////////////////////////// public Feature[] getSupplementalEvidence(Feature feature) { Set set = new HashSet(); String sql = "select ap_evidence_feature_id from ap_supplemental_evidence where ap_feature_id =" + feature.getId(); try { Q.startStopWatch(sql); Statement statement = getConnection().prepareStatement(sql); ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()) { set.add(resultSet.getString(1)); } statement.close(); resultSet.close(); return CalhounFeatureFinder.getInstance().getSimpleFeatures( (String[]) set.toArray(new String[0]), feature.getSequence()); } catch (SQLException e) { I.error("Error getting supplemental evidence for feature " + feature.getId() + "SQL:\n" + sql, e); } finally { Q.stopStopWatch(sql); } return new Feature[0]; } public AnnotatedGene[] getGenes(Segment segment, Strand strand) { List geneList = new ArrayList(); String sql = "SELECT ap_accession_number, ap_id, ap_start, ap_stop from ap_annotated_gene_view where " + " ap_sequence_id = ? and ap_start <= ? and ap_stop >= ? and " + " ap_strand = ? order by ap_start"; try { Q.startStopWatch(sql); PreparedStatement statement = getConnection().prepareStatement(sql); Q.setLongOrNull(1, segment.getSequence().getId(), statement); Q.setIntOrNull(2, segment.getStop(), statement); Q.setIntOrNull(3, segment.getStart(), statement); Q.setStringOrNull(4, strand.toString(), statement); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { AnnotatedGene gene = new AnnotatedGene(segment.getSequence(), resultSet.getString(1), resultSet.getString(2), resultSet.getInt(3), resultSet.getInt(4), resultSet .getString(1), strand); geneList.add(gene); } statement.close(); resultSet.close(); } catch (SQLException e) { I.error("Error getting genes. SQL: " + sql, e); } finally { Q.stopStopWatch(sql); } return (AnnotatedGene[]) geneList.toArray(new AnnotatedGene[0]); } public AnnotatedGene[] getGenes(Segment segment) { List geneList = new ArrayList(); String sql = "SELECT ap_accession_number, ap_id, ap_start, ap_stop, ap_strand from ap_annotated_gene_view where " + " ap_sequence_id = ? and ap_start <= ? and ap_stop >= ? order by ap_start"; try { Q.startStopWatch(sql); PreparedStatement statement = getConnection().prepareStatement(sql); Q.setLongOrNull(1, segment.getSequence().getId(), statement); Q.setIntOrNull(2, segment.getStop(), statement); Q.setIntOrNull(3, segment.getStart(), statement); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { AnnotatedGene gene = new AnnotatedGene(segment.getSequence(), resultSet.getString(1), resultSet.getString(2), resultSet.getInt(3), resultSet.getInt(4), resultSet .getString(1), Strand.parseStrand(resultSet .getString(5))); geneList.add(gene); } statement.close(); resultSet.close(); } catch (SQLException e) { I.error("Error getting sequenceGroups. SQL:\n" + sql, e); } finally { Q.stopStopWatch(sql); } return (AnnotatedGene[]) geneList.toArray(new AnnotatedGene[0]); } public AnnotatedGene getGene(String geneFeatureId) { List geneList = new ArrayList(); AnnotatedGene gene = null; String sql = "SELECT ap_accession_number, ap_id, ap_start, ap_stop,ap_strand,ap_sequence_id from ap_annotated_gene_view " + "where ap_id= ?"; try { Q.startStopWatch(sql); PreparedStatement statement = getConnection().prepareStatement(sql); Q.setStringOrNull(1, geneFeatureId, statement); ResultSet resultSet = statement.executeQuery(); if (resultSet.next()) { gene = new AnnotatedGene(CalhounSequenceManager.getInstance() .getSequence(resultSet.getString(6)), resultSet .getString(1), resultSet.getString(2), resultSet .getInt(3), resultSet.getInt(4), resultSet.getString(1), Strand.parseStrand(resultSet .getString(5))); geneList.add(gene); } else { I.error("Unable to find gene " + geneFeatureId + " using statement " + sql); } statement.close(); resultSet.close(); } catch (SQLException e) { I .error("Error getting gene '" + geneFeatureId + " SQL:\n" + sql, e); } finally { Q.stopStopWatch(sql); } return gene; } // ///////////////////////////////////////////////////////////////////////// // Private Methods. // ///////////////////////////////////////////////////////////////////////// private void addTopLevelFeatures(Segment segment, CalhounTrack track, Criterion[] criteria, java.util.List featureList) { if (track.isPending()) { return; } // I.warn("getting top level features for track: " + track); String sql = generateGetFeaturesSql(segment, track, criteria); // I.warn("sql: " + sql); try { Q.startStopWatch(sql); PreparedStatement statement = getConnection().prepareStatement(sql); statement.setInt(1, segment.getStart()); statement.setInt(2, segment.getStop()); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { Feature feature = createFeature(segment.getSequence(), track, resultSet); featureList.add(feature); } statement.close(); resultSet.close(); Q.stopStopWatch(sql); } catch (SQLException e) { I.error("Error getting features of track " + track + ". SQL: \n" + sql, e); } } private void addComponentFeatures(CalhounTrack track, Segment segment, java.util.List featureList) { java.util.Map featureById = new HashMap(); for (Iterator i = featureList.iterator(); i.hasNext();) { Feature f = (Feature) i.next(); featureById.put(f.getId(), f); } if (featureList.size() == 0) { return; } String[] sqls = generateAddComponentFeaturesSqls(track, featureById .keySet()); String sql = ""; try { for (int i = 0; i < sqls.length; i++) { sql = sqls[i]; executeSubFeatureSqlAndAttachToParent(sql, featureById, segment, track); } } catch (SQLException e) { I.error("Error gettting subfeatures for features of track " + track + ". SQL:\n" + sql, e); } } private void trackHacks(CalhounTrack track) { if (track.getTrackType().getView().equals(AP.ANNOTATED_TRANSCRIPT_VIEW) || track.getTrackType().getView().equals(AP.PRO_GENE_VIEW_NEW)) { track.setPrefsEnabled(false); track.setMutablyEditable(true); track.setReviewable(true); track.setUpdatable(true); track.setDeletable(true); track.setRetiredOnDeletion(true); track.setEvidence(true); track.setMutablyEditable(false); track.setPrefsEnabled(true); } else if (track.getTrackType().getView().equals(AP.UTR_ELEMENT_VIEW)) { track.setPrefsEnabled(false); track.setMutablyEditable(true); track.setDeletable(true); track.setMutablyEditable(false); track.setPrefsEnabled(true); } } private void addCriteria(CalhounTrack ct) throws SQLException { Set criterionSet = C.set(); CalhounDatabaseColumn[] columns = ct.getTrackType() .getDatabaseColumns(); for (int i = 0; i < columns.length; i++) { String key = columns[i].getCriterionKey(); String dataType = columns[i].getCriterionDataType(); if (dataType != null) { if (m_criterionDefaultValueMap.containsKey(ct.getTrackType() .getView() + key)) { // Has default values. criterionSet.add(new Criterion(ct.getPrefPath(), // this, key, (String) m_criterionDefaultValueMap.get(ct .getTrackType().getView() + key), (String) m_criterionDefaultOperatorMap.get(ct .getTrackType().getView() + key), dataType)); } else { // Has no default values. criterionSet.add(new Criterion(ct.getPrefPath(), // this, key, "", dataType)); } } } if (ct.getTrackType().hasDynamicProperties()) { DynamicPropertyCriterion.load(ct, criterionSet); } ct.setCriteria((Criterion[]) criterionSet.toArray(new Criterion[0])); } private void loadVirtualTrackIdsByTrackId() { // read virtual track ids from prefs. // done once. try { Preferences p = P.getPrefs("calhoun/gebo/db/" + getId()); for (String vtid : p.childrenNames()) { if (vtid.matches(".*_v.*")) { Preferences vp = P.getPrefs("calhoun/gebo/db/" + getId() + "/" + vtid); String btid = vp.get("bt", ""); if (btid.length() > 0) { if (!m_virtualTrackIdsByTrackId.containsKey(btid)) { m_virtualTrackIdsByTrackId.put(btid, new HashSet()); } m_virtualTrackIdsByTrackId.get(btid).add(vtid); } else { I .warn("Unable to find base track (bt) for virtual track: " + vtid); } } } } catch (Throwable t) { I.warn("Error loading virtual track ids by track id", t); } } private void registerVirtualTracks(CalhounTrack t, SequenceGroup sg, List trackList) throws Exception { if (m_virtualTrackIdsByTrackId.containsKey(t.getId())) { // I.warn("registerVirtualTracks"); for (String vtid : m_virtualTrackIdsByTrackId.get(t.getId())) { trackList.add(createVirtualTrack(sg, t, t.getId(), vtid)); } } } public VirtualCalhounTrack createVirtualTrack(SequenceGroup sg, CalhounTrack t, String label, String id) throws Exception { VirtualCalhounTrack vt = new VirtualCalhounTrack(t, label, id); registerTrack(vt, sg, new ArrayList()); return vt; } public void clearVirtualTrack(VirtualCalhounTrack vt) { ; m_trackById.remove(vt); for (Object sg : m_trackCache.keySet()) { ((Set) m_trackCache.get(sg)).remove(vt); vt.clearPrefs(); } } private void addDynamicProperties(Feature f, List properties) { try { if (((CalhounTrack) f.getTrack()).getTrackType().getSubclass() .equals("GFTR")) { // I.warn("GFTR: adding dynamic properties!"); String sql = "select ap_property_name, ap_string_value, ap_double_value, ap_long_value,ap_date_value " + " from AP_FEATURE_DYN_PROPERTY where ap_feature_id = ?"; PreparedStatement statement = getConnection().prepareStatement( sql); // I.warn("GFTR: fid: " + f.getId() + " sql: " + sql); Q.setLongOrNull(1, f.getId(), statement); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { String name = resultSet.getString(1); String stringValue = resultSet.getString(2); double doubleValue = resultSet.getDouble(3); long longValue = resultSet.getLong(4); Date dateValue = resultSet.getDate(5); String value = stringValue; if (S.isEmpty(value)) { value = doubleValue + ""; if (doubleValue == 0.0) { value = longValue + ""; if (longValue == 0) { if (dateValue != null) { value = dateValue + ""; } } } } properties.add(new Property(name, value)); } } } catch (Throwable t) { I .error("Unable to get dynamic properties for feature " + f.getId(), t); } } private void addOrdinaryProperties(Feature feature, List propertyList) { String sql = generateGetPropertiesSql(feature); if (sql == null) { U .println("Feature without a name. Without an id.. what's going on?"); return; } Q.startStopWatch(sql); try { Statement statement = getConnection().createStatement(); // OracleResultSet handles CLOB bullshit. OracleResultSet resultSet = (OracleResultSet) statement .executeQuery(sql); while (resultSet.next()) { addResultSetProperties(resultSet, null, propertyList); } statement.close(); resultSet.close(); } catch (SQLException e) { I.error("Error getting properties for feature " + feature.getId() + ". SQL:\n" + sql, e); } finally { Q.stopStopWatch(sql); } } protected void addResultSetProperties(ResultSet resultSet, Feature feature) throws SQLException { addResultSetProperties(resultSet, feature, null); } public String getClob(CalhounFeature feature, String key) { String sql = "SELECT AP_" + key + " FROM " + ((CalhounTrack) feature.getTrack()).getTrackType().getView() + " WHERE ap_feature_id = ?"; String value = ""; Q.startStopWatch(sql); try { PreparedStatement statement = getConnection().prepareStatement(sql); Q.setLongOrNull(1, feature.getId(), statement); // OracleResultSet handles CLOB bullshit. OracleResultSet resultSet = (OracleResultSet) statement .executeQuery(); resultSet.next(); ResultSetMetaData metaData = resultSet.getMetaData(); if (metaData.getColumnType(1) == java.sql.Types.CLOB) { CLOB clob = ((CLOB) ((OracleResultSet) resultSet) .getOracleObject(1)); if (clob != null) { value = clob.getSubString((long) 1, (int) clob.length()); } } else { value = resultSet.getString(1); } statement.close(); resultSet.close(); } catch (SQLException e) { I.error("Error gettng CLOB for feature " + feature.getId() + " property key " + key + " SQL:\n" + sql, e); } finally { Q.stopStopWatch(sql); } return value; } private void addResultSetProperties(ResultSet resultSet, Feature feature, List propertyList) throws SQLException { ResultSetMetaData metaData = resultSet.getMetaData(); Set IGNORE_COLUMN_SET = new HashSet(); IGNORE_COLUMN_SET.add("AP_SEQUENCE_ID"); IGNORE_COLUMN_SET.add("AP_SUBTYPE"); IGNORE_COLUMN_SET.add("AP_FEATURE_ID"); IGNORE_COLUMN_SET.add("AP_STRAND"); IGNORE_COLUMN_SET.add("AP_START"); IGNORE_COLUMN_SET.add("AP_STOP"); IGNORE_COLUMN_SET.add("AP_LENGTH"); IGNORE_COLUMN_SET.add("AP_LABEL"); for (int i = 1; i <= metaData.getColumnCount(); i++) { String value = ""; String columnName = metaData.getColumnName(i); if (IGNORE_COLUMN_SET.contains(columnName)) { if (feature != null) {} continue; } if (metaData.getColumnType(i) == java.sql.Types.CLOB) { CLOB clob = ((CLOB) ((OracleResultSet) resultSet) .getOracleObject(i)); if (clob != null) { value = clob.getSubString((long) 1, (int) clob.length()); } } else { value = resultSet.getString(i); } Property property = new Property(Q.stripAP(metaData .getColumnName(i)), value); if (propertyList == null && feature != null) { feature.addProperty(property); } else { propertyList.add(property); } } } // hard coded for now. move to db. // DATAHACK! private void buildCriterionDefaultMaps() { m_criterionDefaultValueMap = new HashMap(); m_criterionDefaultOperatorMap = new HashMap(); m_criterionDefaultValueMap.put(AP.BLAST_VIEW + "SCORE", "100.0"); m_criterionDefaultOperatorMap.put(AP.BLAST_VIEW + "SCORE", ">="); m_criterionDefaultValueMap.put(AP.BLAST_VIEW + "EXPECTED", "1.0E-20"); m_criterionDefaultOperatorMap.put(AP.BLAST_VIEW + "EXPECTED", "<="); } // * Data Munging Methods. // * SQL Generating Methods. private String generateGetPropertiesSql(Feature feature) { if (feature.getId() == null || feature.getId().equals("")) { // U.error("REINOS!!! " + feature.dump()); U.println("What the????"); return null; } if (((CalhounTrack) feature.getTrack()).getTrackType().getView() == null) { return "SELECT * FROM ap_feature WHERE ap_id = " + feature.getId(); } else { return "SELECT * FROM " + ((CalhounTrack) feature.getTrack()).getTrackType() .getView() + " WHERE ap_feature_id = " + feature.getId(); } } public static String getTrackCriteria(CalhounTrack t) { return getTrackCriteria(t, null); } public static String getTrackCriteria(CalhounTrack t, String prefix) { if (prefix == null) { prefix = ""; } else { prefix += "."; } return " AND " + prefix + "AP_ANALYSIS_EVENT_ID = " + t.getAnalysisEventId() + " AND " + prefix + "AP_ONTOLOGY_TERM_ID = " + t.getOntologyTerm().getId() + " AND " + prefix + " AP_SUBCLASS ='" + t.getSubclass() + "'"; } private String generateGetFeaturesSql(Segment segment, CalhounTrack track, Criterion[] criteria) { String trackSpecificCriteria = generateTrackSpecificCriteriaSql(track); String optionalCriteria = ""; // new StringBuffer(""); optionalCriteria = getCriteriaSql(criteria); String commonSql = " WHERE AP_SEQUENCE_ID = " + segment.getSequence().getId() + " AND AP_STOP >= ?" + " AND AP_START <= ?" + getTrackCriteria(track); StringBuffer orderByBuffer = new StringBuffer(); SortCriterion[] sortCriteria = track.getSortCriteria(); if (sortCriteria.length > 0) { orderByBuffer.append(" ORDER BY "); } for (int i = 0; i < sortCriteria.length; i++) { orderByBuffer.append("AP_" + sortCriteria[i].getKey()); if (!sortCriteria[i].isAscending()) { orderByBuffer.append(" DESC"); } if (i + 1 < sortCriteria.length) { orderByBuffer.append(", "); } } StringBuffer designerLabelFieldsBuffer = new StringBuffer(""); String[] designerLabelFields = track.getExtraDesignerLabelColumnNames(); if (designerLabelFields.length > 0) { designerLabelFieldsBuffer.append(","); } for (int i = 0; i < designerLabelFields.length; i++) { designerLabelFieldsBuffer.append("AP_" + designerLabelFields[i]); if (i + 1 < designerLabelFields.length) { designerLabelFieldsBuffer.append(", "); } } return track.getTrackType().getMinimalApFeatureSelect() + commonSql + trackSpecificCriteria + optionalCriteria + orderByBuffer; } public String generateTrackSpecificCriteriaSql(CalhounTrack track) { StringBuffer sql = new StringBuffer(""); Criterion[] criteria = track.getCriteria(); for (Criterion c : criteria) { if (!c.getValue().equals("")) { if (c instanceof DynamicPropertyCriterion) { DynamicPropertyCriterion dc = (DynamicPropertyCriterion) c; sql.append(dc.getSql()); } else if (c.getKey().equals("LENGTH")) { sql.append(" AND AP_STOP - AP_START " + c.getOperator() + " " + c.getQuotedValue() + " "); } else { sql.append(" AND " + c.toSql()); } } } return sql.toString(); } public String getUri(AlignmentTrack t) { return "calhoun://track/" + W.encode(t.getId()); } public RepeatCluster getRepeatCluster(Feature f){ String clusterId = f.getPropertyValue("CLUSTER_ID"); StringBuilder b = new StringBuilder(); RepeatCluster rc = null; String hql = "from RepeatCluster rc where rc.id = " + clusterId; Q.startStopWatch(hql); calhoun.util.DbSession s = CalhounConnectionManager.getInstance() .getDbSession(); List rows = s.find(hql); for (Object o : rows) { rc = (RepeatCluster) o; } Q.stopStopWatch(hql); return rc; } // ////////////////////////////////////////////////////////////////////////// // Transcript specific stuff. // ////////////////////////////////////////////////////////////////////////// /** * Get all supported curation flags. * * @return a CurationFlag[] value */ public CurationFlag[] getCurationFlags(String cellType) { String sql = "select ap_id, ap_curation_flag_group_name, " + " ap_curation_flag_name from ap_curation_flag_view "; if (cellType.equals("P")) { // hack for lucia... really nasty tackng on this 126 sql += " where ap_curation_flag_group_id = 10 or ap_id IN (126,129) "; // I.warn("FOUND P"); } else if (cellType.equals("E")) { sql += " where ap_curation_flag_group_id != 10 "; // I.warn("no p"); } List curationFlagList = new ArrayList(); try { Q.startStopWatch(sql); Statement statement = getConnection().createStatement(); ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()) { String group_name = resultSet.getString(2); String name = resultSet.getString(3); String label; // ah...hacky! Why do I feel like one day this is // going to confuse the hell out of someone? It's // a single space so it's invisible AND sorts // properly. if (name.equals(" ")) { label = group_name; } else { label = group_name + ": " + name; } curationFlagList.add(new CurationFlag(resultSet.getString(1), label)); } statement.close(); resultSet.close(); } catch (SQLException e) { I.error("Error getting curation flags. SQL:\n" + sql, e); } finally { Q.stopStopWatch(sql); } return (CurationFlag[]) curationFlagList.toArray(new CurationFlag[0]); } public TranscriptType[] getTranscriptTypes(String cellType) { String sql = "select ap_id,ap_transcript_type from ap_transcript_type where ap_cell_type = ? order by ap_transcript_type"; List transcriptTypeList = new ArrayList(); try { Q.startStopWatch(sql); PreparedStatement statement = getConnection().prepareStatement(sql); statement.setString(1, cellType); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { transcriptTypeList.add(new TranscriptType(resultSet .getString(1), resultSet.getString(2))); } statement.close(); resultSet.close(); } catch (SQLException e) { I.error("Error getting transcript types. SQL:\n" + sql, e); } finally { Q.stopStopWatch(sql); } return (TranscriptType[]) transcriptTypeList .toArray(new TranscriptType[0]); } public RetirementCode[] getRetirementCodes(String cellType) { String sql = "select ap_id,ap_name from ap_retirement_code where ap_cell_type = ? order by ap_sort_key"; List codeList = new ArrayList(); try { Q.startStopWatch(sql); PreparedStatement statement = getConnection().prepareStatement(sql); statement.setString(1, cellType); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { codeList.add(new RetirementCode(resultSet.getString(1), resultSet.getString(2))); } statement.close(); resultSet.close(); } catch (SQLException e) { I.error("Error getting retirement codes. SQL:\n" + sql, e); } finally { Q.stopStopWatch(sql); } return (RetirementCode[]) codeList.toArray(new RetirementCode[0]); } public void clearCache() { m_trackCache.clear(); m_virtualTrackIdsByTrackId.clear(); m_ontologyTermMap.clear(); } // ///////////////////////////////////////////////////////////////////////// // Data. // ///////////////////////////////////////////////////////////////////////// private Map m_ontologyTermMap = new HashMap(); private Map> m_virtualTrackIdsByTrackId = new HashMap>(); private Map m_criterionDefaultValueMap = new HashMap(); private Map m_criterionDefaultOperatorMap = new HashMap(); private Map m_columnPositionByName = new HashMap(); private Map> m_trackCache = new HashMap>(); private int m_maxOverlaps = 3; private Map m_trackTypeMap; private static CalhounTrackManager INSTANCE; }