/* 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 calhoun.db.*; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import calhoun.bean.AbstractEntity; import calhoun.gebo.api.AbstractFiledTrackManager; import calhoun.gebo.api.FiledSequenceManager; import calhoun.gebo.api.FiledTrack; import calhoun.gebo.model.CompoundFeature; import calhoun.gebo.model.Criterion; import calhoun.gebo.model.FatSubFeature; import calhoun.gebo.model.Feature; import calhoun.gebo.model.FeatureTrack; import calhoun.gebo.model.Helpful; import calhoun.gebo.model.Property; import calhoun.gebo.model.Segment; import calhoun.gebo.model.SegmentUtils; import calhoun.gebo.model.Sequence; import calhoun.gebo.model.SimpleSegment; import calhoun.gebo.model.Strand; import calhoun.gebo.model.SubFeature; import calhoun.gebo.util.Informer; import calhoun.gebo.util.S; import calhoun.util.FileSession; import calhoun.util.PropertyMap; import calhoun.util.FileSession.FeatureTypeName; /** */ public class CalhounXMLTrackManager extends AbstractFiledTrackManager implements Helpful, FiledSequenceManager { private static final Informer I = new Informer(CalhounXMLTrackManager.class); // ///////////////////////////////////////////////////////////////////////// // Constructors. // ///////////////////////////////////////////////////////////////////////// /** * @param id * @param label */ protected CalhounXMLTrackManager() { super("CalhounXML", "CalhounXML"); m_fileSession = new FileSession("production"); } // ////////////////////////////////////////////////////////////////////////// // Static Factory Methods. // ////////////////////////////////////////////////////////////////////////// public static CalhounXMLTrackManager getInstance() { if (INSTANCE == null) { INSTANCE = new CalhounXMLTrackManager(); } return INSTANCE; } // ///////////////////////////////////////////////////////////////////////// // Helpful Interface. // ///////////////////////////////////////////////////////////////////////// public String getHelpId() { return "calhoun_xml"; } public String getHelpLabel() { return "Calhoun XML Files"; } // ///////////////////////////////////////////////////////////////////////// // AbstractFileBasedTrackManager Interface. // ///////////////////////////////////////////////////////////////////////// public Feature[] getFeatures(Segment segment, FeatureTrack track) { if (track.isVisible()) { File file = ((FiledTrack) track).getFile(); AddBeanFeature closure = null; try { closure = new AddBeanFeature(segment, track); iterateXmlFile(file, closure); if (closure.getErrorBuffer().length() > 0) { I .error("The following errors were generated while trying to read features in track " + track + "\nFile: " + file + "\n" + closure.getErrorBuffer()); } return CompoundFeature.getMatching((Feature[]) closure .getFeatureList().toArray(new Feature[0]), track, segment); } catch (Throwable t) { I .error( "Error loading calhoun xml track file." + "\nSetting visible to false so you don't keep getting this message.", file, t); } } return new Feature[0]; } public FiledTrack getTrack(Sequence sequence, File file) { FiledTrack track = super.getTracks(sequence, file)[0]; if (track.getCriteria().length < 7) { List criteriaList = new ArrayList(Arrays .asList(track.getCriteria())); criteriaList.add(new Criterion(this.getId() + "." + track.getId(), "SCORE", "", Criterion.FLOAT)); criteriaList.add(new Criterion(this.getId() + "." + track.getId(), "EXPECTED", "", Criterion.FLOAT)); criteriaList.add(new Criterion(this.getId() + "." + track.getId(), "QUERY_START", "", Criterion.INT)); criteriaList.add(new Criterion(this.getId() + "." + track.getId(), "QUERY_STOP", "", Criterion.INT)); criteriaList.add(new Criterion(this.getId() + "." + track.getId(), "SUBJECT_START", "", Criterion.INT)); criteriaList.add(new Criterion(this.getId() + "." + track.getId(), "SUBJECT_STOP", "", Criterion.INT)); criteriaList.add(new Criterion(this.getId() + "." + track.getId(), "METHOD", "", Criterion.STRING)); criteriaList.add(new Criterion(this.getId() + "." + track.getId(), "QUERY_SEQ_ID", "", Criterion.STRING)); criteriaList.add(new Criterion(this.getId() + "." + track.getId(), "SUBJECT_SEQ_ID", "", Criterion.STRING)); track.setCriteria((Criterion[]) criteriaList .toArray(new Criterion[0])); } return track; } public FeatureTrack[] getTracks(Sequence sequence) { registerFileSessionTracks(sequence); return super.getTracks(sequence); // return new Track[0]; } public String[] getExtensions() { return new String[] { "xml" }; } public String[] getMimeTypes() { return new String[] { "calhounxml", "text/calhounxml" }; } public String getDescription() { return "Calhoun XML Files"; } private void registerFileSessionTracks(Sequence sequence) { if (sequence.getSequenceManager() instanceof CalhounSequenceManager) { try { I.time("calhounFileSession.getTracks()"); List featureTypeNamelist = getFileSession() .getFeatureTypesWithLabels( sequence.getPrimarySequenceGroup().getId(), sequence.getId()); for (Iterator it = featureTypeNamelist.iterator(); it.hasNext();) { FeatureTypeName ftn = (FeatureTypeName) it.next(); File file = new File(getFileSession() .getPath( sequence.getPrimarySequenceGroup().getId(), sequence.getId(), ftn.featureLabel, ftn.featureName)); registerTrackFile(file, sequence, false); if (ftn.featureLabel != null) { // I.warn("ftn featureLabel: " + ftn.featureLabel); // I.warn("ftn featureName: " + ftn.featureName); // I.warn("ftn file:" + file); FeatureTrack[] tracks = getTracks(file); for (int i = 0; i < tracks.length; i++) { // I.warn("Examining track: " + // tracks[i].getLabel()); if (!tracks[i].getLabel().startsWith( ftn.featureLabel)) { tracks[i].setLabel(ftn.featureLabel + ": " + tracks[i].getLabel()); // I.warn("setting featureLabel: " + // tracks[i].getLabel()); } } } } I.time("calhounFileSession.getTracks()"); } catch (Throwable t) { I.error("Error getting FileBase tracks for sequence " + sequence.getId(), t); } } } public FileSession getFileSession() { return m_fileSession; } // ////////////////////////////////////////////////////////////////////////// // SequenceManager Interface. // ////////////////////////////////////////////////////////////////////////// public Property[] getProperties(Sequence sequence) { return CalhounSequenceManager.getInstance().getProperties(sequence); } public String getRaw(Segment segment) { return CalhounSequenceManager.getInstance().getRaw(segment); } public int getPreferredCacheSize() { return CalhounSequenceManager.getInstance().getPreferredCacheSize(); } // ////////////////////////////////////////////////////////////////////////// // FiledSequenceManager Interface. // ////////////////////////////////////////////////////////////////////////// public Sequence[] loadSequenceFile(File file) { return SegmentUtils.getSequences(loadSegmentFile(file)); } // ////////////////////////////////////////////////////////////////////////// // CalhounXMLTrackManager Interface. // ////////////////////////////////////////////////////////////////////////// public Segment[] loadSegmentFile(File file) { try { I.time("loadSegmentFile"); Map segmentMap = new HashMap(); Closure closure = new AddBeanSegment(file, segmentMap); iterateXmlFile(file, closure); I.time("loadSegmentFile"); return SegmentUtils.collapse((Segment[]) segmentMap.values() .toArray(new Segment[0])); } catch (Throwable t) { I .error( "This does not appear to be a properly formatted calhoun xml file. ", file, t); } return null; } // ////////////////////////////////////////////////////////////////////////// // Private Methods. // ////////////////////////////////////////////////////////////////////////// interface Closure { public void exec(calhoun.bean.Feature beanFeature); } class AddBeanSegment implements Closure { File file; Map segmentMap; public AddBeanSegment(File file, Map segmentMap) { this.file = file; this.segmentMap = segmentMap; } public void exec(calhoun.bean.Feature beanFeature) { String sequenceId = beanFeature.getSequence().getId(); if (!segmentMap.containsKey(sequenceId)) { Sequence sequence = CalhounSequenceManager.getInstance() .getSequence(sequenceId); segmentMap.put(sequenceId, new SimpleSegment(sequence, beanFeature.getStart(), beanFeature.getStop())); registerTrackFile(file, sequence); // Track track = getTrack(sequence, file); } else { Segment segment = (Segment) segmentMap.get(sequenceId); // DD - Increase the range to cover the whole sequence. // if (beanOverlapsSegment(beanFeature, segment)) { if (beanFeature.getStart() < segment.getStart()) { segment.setStart(beanFeature.getStart()); } if (beanFeature.getStop() > segment.getStop()) { segment.setStop(beanFeature.getStop()); } // } } } } class AddBeanFeature implements Closure { Sequence sequence; Segment segment; FeatureTrack track; List featureList = new ArrayList(); StringBuffer errorBuffer = new StringBuffer(); int count = 0; Map parentById = new HashMap(); public List getFeatureList() { return featureList; } public StringBuffer getErrorBuffer() { return errorBuffer; } public AddBeanFeature(Segment segment, FeatureTrack track) { this.segment = segment; this.track = track; sequence = segment.getSequence(); } public void exec(calhoun.bean.Feature beanFeature) { int count = 0; if (beanFeature.getSequence() == null) { I.warn("NULL CONTIG"); } if (beanFeature.getSequence().getId().equals(sequence.getId())) { if (beanOverlapsSegment(beanFeature, segment)) { // try { Feature feature = null; if (isBeanGene(beanFeature)) { for (Iterator tit = beanFeature.getChildren() .iterator(); tit.hasNext();) { Feature transcript = beanToArgoFeature(sequence, track, (calhoun.bean.Feature) tit.next()); transcript.setGeneId(beanFeature.getId()); featureList.add(feature = transcript); count++; } } else { featureList.add(feature = beanToArgoFeature(sequence, track, beanFeature)); count++; } if (feature.hasProperty("ERRORS")) { errorBuffer.append(feature.getPropertyValue("ERRORS")); } } } } } private boolean isBeanGene(calhoun.bean.Feature beanFeature) { return beanFeature.getChildren().size() > 0 && ((calhoun.bean.Feature) beanFeature.getChildren().iterator() .next()).getChildren().size() > 0; } private Feature beanToArgoFeature(Sequence sequence, FeatureTrack track, calhoun.bean.Feature beanFeature) { Feature feature = new CompoundFeature(sequence, S.orString(beanFeature .getName(), "Unnamed"), beanFeature.getId(), beanFeature .getStart(), beanFeature.getStop(), track, beanFeature .getStrand().isPlus() ? Strand.PLUS : Strand.MINUS, false, false, 0); StringBuffer errorBuffer = new StringBuffer(); attachProperties(beanFeature, feature, errorBuffer); attachSubFeatures(beanFeature, feature, errorBuffer); if (errorBuffer.length() > 0) { // I.warn("setting errors property"); feature.setProperty("ERRORS", errorBuffer.toString()); } return feature; } private void attachSubFeatures(calhoun.bean.Feature beanParent, Feature parent, StringBuffer errorBuffer) { StringBuffer locationBuffer = new StringBuffer(); Collection beanChildren = beanParent.getChildren(); if (beanChildren.size() == 0) { return; } SubFeature[] children = new SubFeature[beanChildren.size()]; int i = 0; int beforeStart = parent.getStart(); int beforeStop = parent.getStop(); for (Iterator it = beanChildren.iterator(); it.hasNext();) { calhoun.bean.Feature beanChild = (calhoun.bean.Feature) it.next(); children[i] = new FatSubFeature(parent, beanChild.getStart(), beanChild.getStop()); attachProperties(beanChild, children[i], errorBuffer); i++; } parent.setSubFeatures(children); if (parent.getStart() != beforeStart || parent.getStop() != beforeStop) { I .error("Data error: parent boundaries not equal to children boundaries.\n" + "Parent boundaries: " + beforeStart + "-" + beforeStop + "\nBoundaries of Children: " + parent.getStart() + "-" + parent.getStop()); } } private void attachProperties(calhoun.bean.Feature beanFeature, Feature feature, StringBuffer errorBuffer) { try { PropertyMap props = beanFeature.definingProperties(); Property[] ret = new Property[props.keySet().size()]; Iterator it = props.getFlattenedProperties().entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String key = (String) entry.getKey(); Object value = entry.getValue(); if (value instanceof AbstractEntity) { feature.setProperty(key, ((AbstractEntity) value).getId()); } else if (value instanceof calhoun.bean.Feature) { feature.setProperty(key, ((calhoun.bean.Feature) value) .getId()); } else { feature.setProperty(key, value == null ? "" : value .toString()); } } } catch (Throwable t) { // I.warn("ERROR B: " + t); t.printStackTrace(); errorBuffer.append(t + "\n"); } } private boolean beanOverlapsSegment(calhoun.bean.Feature beanFeature, Segment segment) { return (beanFeature.getStop() >= segment.getStart() && beanFeature .getStart() <= segment.getStop()); } private void iterateXmlFile(File file, Closure closure) { Iterator it = FileSession.getFileFeatureIterator(file, CalhounConnectionManager.getInstance().getDbSession()); // new XmlArrayListIterator(file.toString(), // CalhounConnectionManager.getInstance().getDbSession()); iterateXmlFile(it, closure); } private void iterateXmlFile(Iterator it, Closure closure) { while (it.hasNext()) { Object object = it.next(); if (object instanceof calhoun.bean.Feature) { calhoun.bean.Feature beanFeature = (calhoun.bean.Feature) object; closure.exec(beanFeature); } else if (object instanceof Collection) { Collection c = (Collection) object; iterateXmlFile(c.iterator(), closure); } else if (object instanceof calhoun.bean.SyntenicAnchor) { calhoun.bean.SyntenicAnchor anchor = (calhoun.bean.SyntenicAnchor) object; closure.exec(anchor.getFirstAnchor()); closure.exec(anchor.getSecondAnchor()); } else { // I.warn("OOOPS! This is a: " + object.getClass()); } } } // ////////////////////////////////////////////////////////////////////////// // Data. // ////////////////////////////////////////////////////////////////////////// private FileSession m_fileSession; private static CalhounXMLTrackManager INSTANCE; }