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}