001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021 022package org.biojava.bio.seq.impl; 023 024import java.util.Iterator; 025 026import org.biojava.bio.Annotation; 027import org.biojava.bio.BioError; 028import org.biojava.bio.BioException; 029import org.biojava.bio.seq.DNATools; 030import org.biojava.bio.seq.Feature; 031import org.biojava.bio.seq.FeatureFilter; 032import org.biojava.bio.seq.FeatureHolder; 033import org.biojava.bio.seq.Sequence; 034import org.biojava.bio.seq.SequenceTools; 035import org.biojava.bio.seq.projection.ProjectedFeatureHolder; 036import org.biojava.bio.seq.projection.Projection; 037import org.biojava.bio.seq.projection.TranslateFlipContext; 038import org.biojava.bio.symbol.Edit; 039import org.biojava.bio.symbol.IllegalAlphabetException; 040import org.biojava.bio.symbol.SimpleSymbolList; 041import org.biojava.bio.symbol.SymbolList; 042import org.biojava.utils.ChangeVetoException; 043 044/** 045 * A reverse complement view onto <code>Sequence</code> interface. 046 * <p> 047 * All features of the underlying sequence are reflected onto the RevCompSequence using a ProjectedFeatureHolder</p> 048 * calling createFeature() on a RevCompSequence creates a feature on the underlying 049 * sequence. Non-Stranded features will return the reverse compemented view of the sequence 050 * when getSymbols() is called that is to say if you get what you expect as if your RevCompSequence 051 * was a regular Sequence. 052 * 053 * @author David Waring 054 * @author Thomas Down 055 */ 056public class RevCompSequence 057 extends SimpleSequence 058{ 059 private ProjectedFeatureHolder pfh; 060 protected Sequence origSeq; 061 062 063 /** 064 * URN, Name and Annotation are copied as is from the original Sequence, unless you use the 065 * the other contructor that sets these. 066 */ 067 068 public RevCompSequence(Sequence seq) 069 throws IllegalAlphabetException 070 { 071 this(seq,seq.getURN(),seq.getName(),seq.getAnnotation()); 072 } 073 074 075 public RevCompSequence(Sequence seq, String urn, String name, Annotation annotation)throws IllegalAlphabetException { 076 super(DNATools.reverseComplement(seq),urn,name,annotation); 077 pfh = new ProjectedFeatureHolder(new TranslateFlipContext(this,seq,seq.length()+1,true)); 078 origSeq = seq; 079 } 080 081 082 // SymbolList stuff 083 /** 084 * edit() will try to edit the underlying Sequence. So if it is editable this will be too 085 * <p>Since I have not seen and editable Sequence I have not tested this </p> 086 * 087 */ 088 public void edit(Edit e)throws ChangeVetoException,IndexOutOfBoundsException{ 089 int pos = (this.length() - (e.pos + e.length)) + 2; 090 Edit newE = null; 091 try { 092 newE = new Edit (pos,e.length,DNATools.reverseComplement(e.replacement)); 093 origSeq.edit(newE); 094 }catch (IllegalAlphabetException iae){ 095 throw new BioError("Error while editing RevCompSequence " + iae.getMessage()); 096 } 097 098 } 099 100 // Sequence stuff 101 public Iterator features(){ 102 return pfh.features(); 103 } 104 105 public int countFeatures(){ 106 return pfh.countFeatures(); 107 } 108 109 public FeatureHolder filter(FeatureFilter ff) { 110 return pfh.filter(ff); 111 } 112 113 public FeatureHolder filter(FeatureFilter ff, boolean recurse) { 114 return pfh.filter(ff, recurse); 115 } 116 117 /** 118 * containsFeature() will return true if this seq contains the feature in question, or 119 * if if the original (non reverse complement) sequence contains the feature; 120 */ 121 122 public boolean containsFeature(Feature f) { 123 return pfh.containsFeature(f) || origSeq.containsFeature(f); 124 } 125 126 public void removeFeature(Feature f) 127 throws ChangeVetoException, BioException { 128 pfh.removeFeature(f); 129 } 130 131 /** 132 * createFeature() will call createFeature() on the underlying Sequence. 133 * returns the feature as it will be projected onto the reverse complement sequence 134 * not the actual feature that was created. 135 * 136 */ 137 public Feature createFeature(Feature.Template ft) throws ChangeVetoException,BioException{ 138 return pfh.getContext().createFeature(ft); 139 } 140 141 /** 142 * getFeatureFromOriginal() Since you can not create a feature on a projectedFeature at this time, I am 143 * including this method so that you can get the corresponding feature from the original sequence. 144 * (which is not projected) and do something with that such as createFeature(). 145 */ 146 147 public Feature getFeatureFromOriginal(Feature f){ 148 return ((Projection) f).getViewedFeature(); 149 } 150 151 /** 152 * clone() should make a complete copy of the Sequence with all features (and children) and return 153 * a SimpleSequence that is unconnected from the original sequence. 154 */ 155 156 public Object clone(){ 157 SymbolList sl = new SimpleSymbolList(this); 158 Sequence newSeq = new SimpleSequence(sl,this.getURN(),this.getName(),this.getAnnotation()); 159 try{ 160 SequenceTools.addAllFeatures(newSeq, this); 161 } catch ( BioException e){ 162 throw new BioError( "Error while cloning RevCompSequenece: " + e.getMessage()); 163 } catch (ChangeVetoException cve) { 164 throw new BioError("Couldn't modify newly created SimpleSequence", cve); 165 } 166 167 return newSeq; 168 169 } 170}