/* * BioJava development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public Licence. This should * be distributed with the code. If you do not have a copy, * see: * * http://www.gnu.org/copyleft/lesser.html * * Copyright for this code is held jointly by the individual * authors. These should be listed in @author doc comments. * * For more information on the BioJava project and its aims, * or to join the biojava-l mailing list, visit the home page * at: * * http://www.biojava.org/ * */ package org.biojava.bio.program.das; import java.util.Iterator; import java.util.NoSuchElementException; import org.biojava.bio.Annotation; import org.biojava.bio.BioError; import org.biojava.bio.BioException; import org.biojava.bio.BioRuntimeException; import org.biojava.bio.seq.ComponentFeature; import org.biojava.bio.seq.Feature; import org.biojava.bio.seq.FeatureFilter; import org.biojava.bio.seq.FeatureHolder; import org.biojava.bio.seq.FilterUtils; import org.biojava.bio.seq.Sequence; import org.biojava.bio.seq.StrandedFeature; import org.biojava.bio.seq.projection.ProjectedFeatureHolder; import org.biojava.bio.seq.projection.TranslateFlipContext; import org.biojava.bio.symbol.Location; import org.biojava.bio.symbol.SymbolList; import org.biojava.ontology.OntoTools; import org.biojava.ontology.Term; import org.biojava.utils.ChangeEvent; import org.biojava.utils.ChangeVetoException; import org.biojava.utils.Unchangeable; /** * Component feature mapping a DAS landmark sequence onto its parent. * * @author Thomas Down * @author Matthew Pocock */ class DASComponentFeature extends Unchangeable implements ComponentFeature { private final DASSequence parent; private FeatureHolder projectedFeatures; private final Location location; private final StrandedFeature.Strand strand; private final String type; private final String source; private final Annotation annotation; private String componentID; private DASSequence componentSequence; private Location componentLocation; private final FeatureFilter membershipFilter; public DASComponentFeature(DASSequence parent, ComponentFeature.Template temp) throws BioException { if (locationContent(temp.location) != locationContent(temp.componentLocation)) { throw new BioException("Component and container locations must contain an equal number of symbols."); } if (!temp.location.isContiguous() || !temp.componentLocation.isContiguous()) { throw new BioException("Can only include contiguous segments in an assembly"); } this.parent = parent; this.location = temp.location; this.componentLocation = temp.componentLocation; this.strand = temp.strand; this.type = temp.type; this.source = temp.source; this.annotation = temp.annotation; membershipFilter = new FeatureFilter.ContainedByLocation(this.location); if (temp.componentSequence != null) { componentSequence = (DASSequence) temp.componentSequence; componentID = componentSequence.getName(); } else { componentID = temp.componentSequenceName; if (componentID == null) { try { componentID = (String) temp.annotation.getProperty("sequence.id"); } catch (NoSuchElementException ex) { throw new BioRuntimeException("No sequence.id property"); } } } if (strand != StrandedFeature.NEGATIVE && strand != StrandedFeature.POSITIVE) { throw new BioException("Strand must be specified when creating a ComponentFeature"); } } private int locationContent(Location l) { if (l.isContiguous()) return l.getMax() - l.getMin() + 1; int content = 0; for (Iterator i = l.blockIterator(); i.hasNext(); ) { Location sl = (Location) i.next(); content += (sl.getMax() - sl.getMin() + 1); } return content; } public boolean isComponentResolvable() { return true; } public String getComponentSequenceName() { return componentID; } public StrandedFeature.Strand getStrand() { return strand; } public void setStrand(Strand strand) throws ChangeVetoException { throw new ChangeVetoException( new ChangeEvent(this, STRAND, strand, this.strand), "Can't change strand as it is immutable" ); } public Location getLocation() { return location; } public void setLocation(Location loc) throws ChangeVetoException { throw new ChangeVetoException( new ChangeEvent(this, LOCATION, loc, this.location), "Can't change location as it is immutable" ); } public FeatureHolder getParent() { return parent; } public Sequence getSequence() { return parent; } public String getSource() { return source; } public Term getSourceTerm() { return OntoTools.ANY; } public void setSource(String source) throws ChangeVetoException { throw new ChangeVetoException( new ChangeEvent(this, TYPE, source, this.source), "Can't change source as it is immutable" ); } public void setSourceTerm(Term source) throws ChangeVetoException { throw new ChangeVetoException( "Can't change source as it is immutable" ); } public String getType() { return type; } public Term getTypeTerm() { return OntoTools.ANY; } public void setType(String type) throws ChangeVetoException { throw new ChangeVetoException( new ChangeEvent(this, TYPE, type, this.type), "Can't change type as it is immutable" ); } public void setTypeTerm(Term type) throws ChangeVetoException { throw new ChangeVetoException( "Can't change type as it is immutable" ); } public Annotation getAnnotation() { return annotation; } public SymbolList getSymbols() { SymbolList syms = componentLocation.symbols(getComponentSequence()); // if (strand == StrandedFeature.NEGATIVE) { // try { // syms = DNATools.reverseComplement(syms); // } catch (IllegalAlphabetException ex) { // throw new BioRuntimeException(ex); // } // } return syms; } DASSequence getSequenceLazy() { return componentSequence; } public Sequence getComponentSequence() { return _getComponentSequence(); } private DASSequence _getComponentSequence() { if (componentSequence == null) { try { componentSequence = parent.getParentDB()._getSequence(componentID, parent.dataSourceURLs()); } catch (Exception ex) { throw new BioRuntimeException("Couldn't create child DAS sequence", ex); } } return componentSequence; } public Location getComponentLocation() { return componentLocation; } // protected FeatureHolder getProjectedFeatures() { // if (projectedFeatures == null) { // if (strand == StrandedFeature.NEGATIVE) { // int translation = location.getMax() + componentLocation.getMin(); // this.projectedFeatures = new ProjectedFeatureHolder(getComponentSequence(), this, translation, true); // } else if (strand == StrandedFeature.POSITIVE) { // int translation = location.getMin() - componentLocation.getMin(); // this.projectedFeatures = new ProjectedFeatureHolder(getComponentSequence(), this, translation, false); // } // } // return projectedFeatures; // } protected FeatureHolder getProjectedFeatures() { if (projectedFeatures == null) { int translation; boolean flip; if (strand == StrandedFeature.NEGATIVE) { translation = location.getMax() + componentLocation.getMin(); flip = true; } else if (strand == StrandedFeature.POSITIVE) { translation = location.getMin() - componentLocation.getMin(); flip = false; } else { throw new BioError("No strand -- erk!"); } projectedFeatures = new ProjectedFeatureHolder( new TranslateFlipContext( getComponentSequence(), this, translation, flip)); } return projectedFeatures; } public int countFeatures() { return getComponentSequence().countFeatures(); } public Iterator features() { // System.err.println("Going to iterate over DASComponentFeature: " + getComponentSequenceName()); return getProjectedFeatures().features(); } public boolean containsFeature(Feature f) { return getProjectedFeatures().containsFeature(f); } public FeatureHolder filter(FeatureFilter ff, boolean recurse) { // System.err.println("Filtering in DASComponentFEature:" + getComponentSequenceName()); if (FilterUtils.areDisjoint(ff, membershipFilter)) { // System.err.println("Wheeeee! Disjunction in DASComponentFeature"); return FeatureHolder.EMPTY_FEATURE_HOLDER; } return getProjectedFeatures().filter(ff, recurse); } public FeatureHolder filter(FeatureFilter ff) { if (FilterUtils.areDisjoint(ff, membershipFilter)) { return FeatureHolder.EMPTY_FEATURE_HOLDER; } return getProjectedFeatures().filter(ff); } public Feature createFeature(Feature.Template temp) throws BioException { throw new BioException("Can't create features in a ComponentFeature (yet?)"); } public void removeFeature(Feature f) { throw new UnsupportedOperationException("Can't remove features from a ComponentFeature."); } public Feature.Template makeTemplate() { ComponentFeature.Template temp = new ComponentFeature.Template(); temp.type = getType(); temp.source = getSource(); temp.location = getLocation(); temp.annotation = getAnnotation(); temp.strand = getStrand(); temp.componentLocation = getComponentLocation(); temp.componentSequenceName = componentID; // temp.componentSequence = getComponentSequence(); return temp; } public FeatureFilter getSchema() { return new FeatureFilter.ByParent(new FeatureFilter.ByFeature(this)); } }