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.Serializable;
025import java.util.Collections;
026import java.util.Iterator;
027import java.util.List;
028
029import org.biojava.bio.Annotation;
030import org.biojava.bio.BioException;
031import org.biojava.bio.SimpleAnnotation;
032import org.biojava.bio.seq.Feature;
033import org.biojava.bio.seq.FeatureFilter;
034import org.biojava.bio.seq.FeatureHolder;
035import org.biojava.bio.seq.FeatureRealizer;
036import org.biojava.bio.seq.RealizingFeatureHolder;
037import org.biojava.bio.seq.Sequence;
038import org.biojava.bio.seq.SimpleFeatureHolder;
039import org.biojava.bio.symbol.Alphabet;
040import org.biojava.bio.symbol.Edit;
041import org.biojava.bio.symbol.Symbol;
042import org.biojava.bio.symbol.SymbolList;
043import org.biojava.utils.AbstractChangeable;
044import org.biojava.utils.ChangeEvent;
045import org.biojava.utils.ChangeListener;
046import org.biojava.utils.ChangeSupport;
047import org.biojava.utils.ChangeType;
048import org.biojava.utils.ChangeVetoException;
049
050/**
051 * A basic implementation of the <code>Sequence</code> interface.
052 * <p>
053 * This class now implements all methods in the SymbolList interface by
054 * delegating to another SymbolList object. This avoids unnecessary copying, but
055 * means that any changes in the underlying SymbolList will be silently
056 * reflected in the SimpleSequence. In general, SimpleSequences should
057 * <em>only</em> be constructed from SymbolLists which are known to be
058 * immutable.
059 * </p>
060 * 
061 * <p>
062 * By default, features attached to a SimpleSequence are realized as simple
063 * in-memory implementations using <code>SimpleFeatureRealizer.DEFAULT</code>.
064 * If you need alternative feature realization behaviour, any
065 * <code>FeatureRealizer</code> implementation may be supplied at
066 * construction-time.
067 * </p>
068 * More functionality and better persistence to biosql is offered by
069 * {@link org.biojavax.bio.seq.SimpleRichSequence SimpleRichSequence}
070 * 
071 * @author Matthew Pocock
072 * @author Thomas Down
073 * @author Mark Schreiber
074 * @serial WARNING serialized versions of this class may not be compatable with
075 *         future versions of Biojava
076 */
077public class SimpleSequence extends AbstractChangeable implements Sequence,
078                RealizingFeatureHolder, Serializable {
079        //
080        // This section is for the SymbolList implementation-by-delegation
081        //
082
083        private class FeatureForwarder implements ChangeListener {
084                public void postChange(ChangeEvent cev) {
085                        ChangeSupport cs = getChangeSupport(cev.getType());
086                        synchronized (cs) {
087                                cs.firePostChangeEvent(cev);
088                        }
089                }
090
091                public void preChange(ChangeEvent cev) throws ChangeVetoException {
092                        ChangeSupport cs = getChangeSupport(cev.getType());
093                        synchronized (cs) {
094                                cs.firePreChangeEvent(cev);
095                        }
096                }
097        }
098        /**
099         * 
100         */
101        private static final long serialVersionUID = -8681680737943980721L;
102
103        private Annotation annotation;
104
105        private transient ChangeListener featureForwarder;
106
107        private SimpleFeatureHolder featureHolder;
108
109        private transient FeatureRealizer featureRealizer;
110
111        private String name;
112
113        /**
114         * Delegate SymbolList.
115         */
116
117        private SymbolList symList;
118
119        private String urn;
120
121        /**
122         * Create a SimpleSequence with the symbols and alphabet of sym, and the
123         * sequence properties listed.
124         * 
125         * @param sym
126         *            the SymbolList to wrap as a sequence
127         * @param urn
128         *            the URN
129         * @param name
130         *            the name - should be unique if practical
131         * @param annotation
132         *            the annotation object to use or null
133         */
134        public SimpleSequence(SymbolList sym, String urn, String name,
135                        Annotation annotation) {
136                symList = sym;
137
138                setURN(urn);
139                setName(name);
140                this.annotation = annotation;
141                this.featureRealizer = FeatureImpl.DEFAULT;
142        }
143
144        //
145        // Extra stuff which is unique to Sequences
146        //
147
148        /**
149         * Create a SimpleSequence using a specified FeatureRealizer.
150         * 
151         * @param sym
152         *            the SymbolList to wrap as a sequence
153         * @param urn
154         *            the URN
155         * @param name
156         *            the name - should be unique if practical
157         * @param annotation
158         *            the annotation object to use or null
159         * @param realizer
160         *            the FeatureRealizer implemetation to use when adding features
161         */
162        public SimpleSequence(SymbolList sym, String urn, String name,
163                        Annotation annotation, FeatureRealizer realizer) {
164                symList = sym;
165
166                setURN(urn);
167                setName(name);
168                this.annotation = annotation;
169                this.featureRealizer = realizer;
170        }
171        public boolean containsFeature(Feature f) {
172                if (featureHolderAllocated()) {
173                        return getFeatureHolder().containsFeature(f);
174                } else {
175                        return false;
176                }
177        }
178        public int countFeatures() {
179                if (featureHolderAllocated())
180                        return getFeatureHolder().countFeatures();
181                return 0;
182        }
183        public Feature createFeature(Feature.Template template)
184                        throws BioException, ChangeVetoException {
185                Feature f = realizeFeature(this, template);
186                SimpleFeatureHolder fh = this.getFeatureHolder();
187                synchronized (fh) {
188                        fh.addFeature(f);
189                }
190                return f;
191        }
192        /**
193         * Create a new feature in any FeatureHolder associated with this sequence.
194         * 
195         * @deprecated Please use new 1-arg createFeature instead.
196         */
197
198        public Feature createFeature(FeatureHolder fh, Feature.Template template)
199                        throws BioException, ChangeVetoException {
200                return fh.createFeature(template);
201        }
202
203        // private void readObject(ObjectInputStream s)throws IOException,
204        // ClassNotFoundException{
205        // s.defaultReadObject();
206        // this.featureRealizer = FeatureImpl.DEFAULT;
207        // }
208
209        public void edit(Edit edit) throws ChangeVetoException {
210                throw new ChangeVetoException("Can't edit the underlying SymbolList");
211        }
212
213        protected boolean featureHolderAllocated() {
214                return featureHolder != null;
215        }
216
217        public Iterator<Feature> features() {
218                if (featureHolderAllocated())
219                        return getFeatureHolder().features();
220                return Collections.EMPTY_LIST.iterator();
221        }
222
223        public FeatureHolder filter(FeatureFilter filter) {
224                return getFeatureHolder().filter(filter);
225        }
226
227        public FeatureHolder filter(FeatureFilter ff, boolean recurse) {
228                if (featureHolderAllocated()) {
229                        return getFeatureHolder().filter(ff, recurse);
230                }
231                return FeatureHolder.EMPTY_FEATURE_HOLDER;
232        }
233
234        public Alphabet getAlphabet() {
235                return symList.getAlphabet();
236        }
237
238        public Annotation getAnnotation() {
239                if (annotation == null)
240                        annotation = new SimpleAnnotation();
241                return annotation;
242        }
243
244        protected ChangeSupport getChangeSupport(ChangeType ct) {
245                ChangeSupport changeSupport = super.getChangeSupport(ct);
246
247                if (featureForwarder == null && featureHolder != null) {
248                        featureForwarder = new FeatureForwarder();
249                        featureHolder.addChangeListener(featureForwarder,
250                                        ChangeType.UNKNOWN);
251                }
252
253                return changeSupport;
254        }
255
256        protected SimpleFeatureHolder getFeatureHolder() {
257                if (featureHolder == null) {
258                        featureHolder = new SimpleFeatureHolder(FeatureFilter.top_level);
259                }
260                return featureHolder;
261        }
262
263        public String getName() {
264                return name;
265        }
266
267        public FeatureFilter getSchema() {
268                return getFeatureHolder().getSchema();
269        }
270
271        public String getURN() {
272                return urn;
273        }
274
275        public Iterator iterator() {
276                return symList.iterator();
277        }
278
279        public int length() {
280                return symList.length();
281        }
282
283        public Feature realizeFeature(FeatureHolder parent,
284                        Feature.Template template) throws BioException {
285                return featureRealizer.realizeFeature(this, parent, template);
286        }
287
288        /**
289         * Remove a feature attached to this sequence.
290         */
291
292        public void removeFeature(Feature f) throws ChangeVetoException,
293                        BioException {
294                getFeatureHolder().removeFeature(f);
295        }
296
297        public String seqString() {
298                return symList.seqString();
299        }
300
301        /**
302         *Assign a name to this sequence
303         */
304
305        public void setName(String name) {
306                this.name = name;
307        }
308
309        /**
310         *Provide the URN for this sequence
311         */
312
313        public void setURN(String urn) {
314                this.urn = urn;
315        }
316
317        public SymbolList subList(int start, int end) {
318                return symList.subList(start, end);
319        }
320
321        public String subStr(int start, int end) {
322                return symList.subStr(start, end);
323        }
324
325        //
326        // Changeable stuff
327        //
328
329        public Symbol symbolAt(int index) {
330                return symList.symbolAt(index);
331        }
332
333        public List toList() {
334                return symList.toList();
335        }
336
337        public String toString() {
338                return super.toString() + " name: " + getName();
339        }
340}