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.io.IOException; 025import java.io.ObjectInputStream; 026import java.io.Serializable; 027import java.util.Iterator; 028import java.util.List; 029 030import org.biojava.bio.Annotation; 031import org.biojava.bio.BioError; 032import org.biojava.bio.BioException; 033import org.biojava.bio.OverlayAnnotation; 034import org.biojava.bio.seq.Feature; 035import org.biojava.bio.seq.FeatureFilter; 036import org.biojava.bio.seq.FeatureHolder; 037import org.biojava.bio.seq.FeatureRealizer; 038import org.biojava.bio.seq.MergeFeatureHolder; 039import org.biojava.bio.seq.RealizingFeatureHolder; 040import org.biojava.bio.seq.Sequence; 041import org.biojava.bio.seq.SimpleFeatureHolder; 042import org.biojava.bio.seq.projection.ProjectedFeatureHolder; 043import org.biojava.bio.seq.projection.ReparentContext; 044import org.biojava.bio.symbol.Alphabet; 045import org.biojava.bio.symbol.Edit; 046import org.biojava.bio.symbol.Location; 047import org.biojava.bio.symbol.Symbol; 048import org.biojava.bio.symbol.SymbolList; 049import org.biojava.utils.ChangeVetoException; 050import org.biojava.utils.Unchangeable; 051 052/** 053 * A view onto another Sequence object. This class allows new 054 * features and annotations to be overlaid onto an existing 055 * Sequence without modifying it. 056 * 057 * You will almost certainly want to be calling 058 * {@link org.biojava.bio.seq.SequenceTools#view(Sequence seq)} instead of instantiating this 059 * class directly. 060 * 061 * @author Thomas Down 062 * @author Matthew Pocock 063 */ 064 065public class ViewSequence 066 extends 067 Unchangeable 068 implements 069 Sequence, 070 RealizingFeatureHolder, 071 Serializable 072{ 073 private static final long serialVersionUID = 9866447; 074 /** 075 * Delegate Sequence. 076 */ 077 private Sequence seqDelegate; 078 079 /** 080 * FeatureHolder support 081 */ 082 private MergeFeatureHolder exposedFeatures; 083 private SimpleFeatureHolder addedFeatures; 084 085 /** 086 * IDs 087 */ 088 private String name; 089 private String urn; 090 091 /** 092 * Our annotation. 093 */ 094 private Annotation anno; 095 096 /** 097 * The FeatureRealizer we use. 098 */ 099 private transient FeatureRealizer featureRealizer; 100 101 private void readObject(ObjectInputStream s)throws IOException, ClassNotFoundException{ 102 s.defaultReadObject(); 103 this.featureRealizer = FeatureImpl.DEFAULT; 104 } 105 106 /** 107 * Construct a view onto an existing sequence and give it a new 108 * name. 109 * <p>The prefered method is SequenceTools.view(Sequence seq, String name) 110 */ 111 public ViewSequence(Sequence seq, String name) { 112 this.name = name; 113 114 seqDelegate = seq; 115 addedFeatures = new SimpleFeatureHolder(); 116 exposedFeatures = new MergeFeatureHolder(); 117 try { 118 exposedFeatures.addFeatureHolder(new ProjectedFeatureHolder( 119 new ReparentContext(this, seqDelegate))); 120 exposedFeatures.addFeatureHolder(addedFeatures); 121 } catch (ChangeVetoException cve) { 122 throw new BioError("Modification of hidden featureholder vetoed!", cve); 123 } 124 125 urn = seqDelegate.getURN(); 126 if (urn.indexOf('?') >= 0) 127 urn = urn + "&view=" + hashCode(); 128 else 129 urn = urn + "?view=" + hashCode(); 130 131 anno = new OverlayAnnotation(seqDelegate.getAnnotation()); 132 133 featureRealizer = FeatureImpl.DEFAULT; 134 } 135 136 /** 137 * Construct a view onto an existing sequence which takes on that 138 * sequence's name. 139 * <p>The prefered method is SequenceTools.view(Sequence seq) 140 */ 141 public ViewSequence(Sequence seq) { 142 this(seq, seq.getName()); 143 } 144 145 /** 146 * Construct a view onto a sequence, using a specific FeatureRealizer. 147 * 148 * <p>The prefered method is SequenceTools.view(Sequence seq, FeatureRealizer fr) 149 */ 150 public ViewSequence(Sequence seq, FeatureRealizer fr) { 151 this(seq); 152 this.featureRealizer = fr; 153 } 154 155 // 156 // We implement SymbolList by delegation 157 // 158 159 public Alphabet getAlphabet() { 160 return seqDelegate.getAlphabet(); 161 } 162 163 public Iterator iterator() { 164 return seqDelegate.iterator(); 165 } 166 167 public int length() { 168 return seqDelegate.length(); 169 } 170 171 public String seqString() { 172 return seqDelegate.seqString(); 173 } 174 175 public String subStr(int start, int end) { 176 return seqDelegate.subStr(start, end); 177 } 178 179 public SymbolList subList(int start, int end) { 180 return seqDelegate.subList(start, end); 181 } 182 183 public Symbol symbolAt(int indx) { 184 return seqDelegate.symbolAt(indx); 185 } 186 187 public List toList() { 188 return seqDelegate.toList(); 189 } 190 191 // 192 // ID methods -- we have our own. 193 // 194 195 public String getURN() { 196 return urn; 197 } 198 199 public String getName() { 200 return name; 201 } 202 203 // 204 // Basic FeatureHolder methods -- delegate to exposedFeatures 205 // 206 207 public int countFeatures() { 208 return exposedFeatures.countFeatures(); 209 } 210 211 public Iterator features() { 212 return exposedFeatures.features(); 213 } 214 215 public FeatureHolder filter(FeatureFilter fc, boolean recurse) { 216 return exposedFeatures.filter(fc, recurse); 217 } 218 219 public FeatureHolder filter(FeatureFilter fc) { 220 return exposedFeatures.filter(fc); 221 } 222 223 public FeatureFilter getSchema() { 224 return exposedFeatures.getSchema(); 225 } 226 227 // 228 // MutableFeatureHolder methods -- delegate to addedFeatures 229 // 230 231 /** 232 * Remove a feature from this sequence. <strong>NOTE:</strong> This 233 * method will only succeed for features which were added to this 234 * ViewSequence. Trying to remove a Feature from the underlying 235 * sequence will cause an IllegalArgumentException. I think this 236 * is the correct behaviour. 237 */ 238 239 public void removeFeature(Feature f) 240 throws ChangeVetoException 241 { 242 addedFeatures.removeFeature(f); 243 } 244 245 public boolean containsFeature(Feature f) { 246 return exposedFeatures.containsFeature(f); 247 } 248 249 // 250 // Get our annotation 251 // 252 253 public Annotation getAnnotation() { 254 return anno; 255 } 256 257 // 258 // Feature realization stuff 259 // 260 261 public Feature realizeFeature(FeatureHolder parent, Feature.Template template) 262 throws BioException 263 { 264 return featureRealizer.realizeFeature(this, parent, template); 265 } 266 267 public Feature createFeature(Feature.Template template) 268 throws BioException, ChangeVetoException 269 { 270 Location loc = template.location; 271 if(loc.getMin() < 1 || loc.getMax() > this.length()) { 272 throw new BioException("Failed to create a feature with a location " 273 + loc 274 + " outside the sequence: name '" 275 + getName() 276 + "', URN '" 277 + getURN() 278 + "' length " 279 + length()); 280 } 281 Feature f = realizeFeature(this, template); 282 addedFeatures.addFeature(f); 283 return f; 284 } 285 286 public FeatureHolder getAddedFeatures() { 287 return addedFeatures; 288 } 289 290 public void edit(Edit edit) throws ChangeVetoException { 291 throw new ChangeVetoException("ViewSequence is immutable"); 292 } 293}