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.io;
023
024import java.io.Serializable;
025import java.util.ArrayList;
026import java.util.List;
027import java.util.StringTokenizer;
028import java.util.Vector;
029
030import org.biojava.bio.BioException;
031import org.biojava.utils.ParseErrorEvent;
032import org.biojava.utils.ParseErrorListener;
033import org.biojava.utils.ParseErrorSource;
034
035/**
036 * Simple filter which handles attribute lines from an Swissprot entry.
037 * Skeleton implementation, please add more functionality.
038 *
039 * <p>
040 * <strong>FIXME:</strong> Note that this is currently rather incomplete,
041 * and doesn't handle any of the header information sensibly except for
042 * ID and AC.
043 * </p>
044 *
045 * @author Thomas Down
046 * @author Matthew Pocock
047 * @author Greg Cox
048 * @since 1.1
049 * @deprecated Use org.biojavax.bio.seq.io framework instead
050 */
051
052public class SwissprotProcessor
053        extends
054                SequenceBuilderFilter
055        implements
056                ParseErrorSource
057{
058        public static final String PROPERTY_SWISSPROT_ACCESSIONS = "swissprot.accessions";
059        public static final String PROPERTY_SWISSPROT_COMMENT = "swissprot.comment";
060    public static final String PROPERTY_SWISSPROT_FEATUREATTRIBUTE = "swissprot.featureattribute";
061
062        private boolean mBadFeature = false;
063        private Vector mListeners = new Vector();
064
065        /**
066         * Factory which wraps SequenceBuilders in a SwissprotProcessor
067         *
068         * @author Thomas Down
069         */
070
071        public static class Factory implements SequenceBuilderFactory, Serializable
072        {
073                private SequenceBuilderFactory delegateFactory;
074
075                public Factory(SequenceBuilderFactory delegateFactory)
076                {
077                        this.delegateFactory = delegateFactory;
078                }
079
080                public SequenceBuilder makeSequenceBuilder()
081                {
082                        return new SwissprotProcessor(delegateFactory.makeSequenceBuilder());
083                }
084
085                public SequenceBuilder makeSequenceBuilder(String theSource)
086                {
087                        return new SwissprotProcessor(delegateFactory.makeSequenceBuilder(), theSource);
088                }
089        }
090
091        private SwissprotFeatureTableParser features;
092        private List accessions;
093        {
094                accessions = new ArrayList();
095        }
096
097        /**
098         * Constructor that sets the source of the feature to theSource.
099         *
100         * @param delegate The sequecence builder to be used in constructing the
101         * sequence
102         * @param theSource The source of the features.  e.g. "SWISS-PROT", "TrEMBL"
103         */
104        public SwissprotProcessor(SequenceBuilder delegate, String theSource)
105        {
106                super(delegate);
107                features = new SwissprotFeatureTableParser(this, theSource);
108        }
109
110        public SwissprotProcessor(SequenceBuilder delegate)
111        {
112                super(delegate);
113                features = new SwissprotFeatureTableParser(this, "SWISSPROT");
114        }
115
116        public void endSequence() throws ParseException
117        {
118                if (accessions.size() > 0)
119                {
120                        String id = (String) accessions.get(0);
121                        getDelegate().setName(id);
122                        getDelegate().setURI("urn:sequence/swissprot:" + id);
123                        getDelegate().addSequenceProperty(PROPERTY_SWISSPROT_ACCESSIONS, accessions);
124                        accessions = new ArrayList();
125                }
126
127                getDelegate().endSequence();
128        }
129
130        public void addSequenceProperty(Object key, Object value) throws ParseException
131        {
132                try
133                {
134                        if(mBadFeature)
135                        {
136                                // If this feature is bad in some way, ignore it.
137                                String featureLine = value.toString();
138                                if((key.equals("FT")) && (featureLine.charAt(0) != ' '))
139                                {
140                                        // If the offending feature is past, start reading data again
141                                        mBadFeature = false;
142                                        features.startFeature(featureLine.substring(0, 8).trim());
143                                        features.featureData(featureLine.substring(9));
144                                }
145                        }
146                        else
147                        {
148                        // Tidy up any end-of-block jobbies
149                                if (features.inFeature() && !key.equals("FT"))
150                                {
151                                        features.endFeature();
152                                }
153
154                                if (key.equals("FT"))
155                                {
156                                        String featureLine = value.toString();
157                                        if (featureLine.charAt(0) != ' ')
158                                        {
159                                                // This is a featuretype field
160                                                if (features.inFeature())
161                                                {
162                                                        features.endFeature();
163                                                }
164
165                                        features.startFeature(featureLine.substring(0, 8).trim());
166                                        }
167                                        features.featureData(featureLine.substring(9));
168                                }
169                                else
170                                {
171                                        getDelegate().addSequenceProperty(key, value);
172
173                                        if (key.equals("AC"))
174                                        {
175                                                String acc= value.toString();
176                                                StringTokenizer toke = new StringTokenizer(acc, "; ");
177                                                while (toke.hasMoreTokens())
178                                                {
179                                                        accessions.add(toke.nextToken());
180                                                }
181                                        }
182                                }
183                        }
184                }
185                catch (BioException ex)
186                {
187                        // If an exception is thrown, read past the offending feature
188                        mBadFeature = true;
189                        ParseErrorEvent offendingLineEvent = new ParseErrorEvent(this, "This line could not be parsed: " + value.toString());
190                        this.notifyParseErrorEvent(offendingLineEvent);
191            }
192            catch (IndexOutOfBoundsException ex)
193            {
194                // This occurs when for some line min > max
195                mBadFeature = true;
196                ParseErrorEvent offendingLineEvent = new ParseErrorEvent(this, "From must be less than To: " + value.toString());
197                        this.notifyParseErrorEvent(offendingLineEvent);
198            }
199        }
200
201        /**
202         * Adds a parse error listener to the list of listeners if it isn't already
203         * included.
204         *
205         * @param theListener Listener to be added.
206         */
207        public synchronized void addParseErrorListener(
208                        ParseErrorListener theListener)
209        {
210                if(mListeners.contains(theListener) == false)
211                {
212                        mListeners.addElement(theListener);
213                }
214        }
215
216        /**
217         * Removes a parse error listener from the list of listeners if it is
218         * included.
219         *
220         * @param theListener Listener to be removed.
221         */
222        public synchronized void removeParseErrorListener(
223                        ParseErrorListener theListener)
224        {
225                if(mListeners.contains(theListener) == true)
226                {
227                        mListeners.removeElement(theListener);
228                }
229        }
230
231        // Protected methods
232        /**
233         * Passes the event on to all the listeners registered for ParseErrorEvents.
234         *
235         * @param theEvent The event to be handed to the listeners.
236         */
237        protected void notifyParseErrorEvent(ParseErrorEvent theEvent)
238        {
239                Vector listeners;
240                synchronized(this)
241                {
242                        listeners = (Vector)mListeners.clone();
243                }
244
245                for (int index = 0; index < listeners.size(); index++)
246                {
247                        ParseErrorListener client = (ParseErrorListener)listeners.elementAt(index);
248                        client.BadLineParsed(theEvent);
249                }
250        }
251}