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.Vector;
028
029import org.biojava.bio.BioException;
030import org.biojava.utils.ParseErrorEvent;
031import org.biojava.utils.ParseErrorListener;
032import org.biojava.utils.ParseErrorSource;
033
034/**
035 * Simple filter which handles attribute lines from a Genbank file
036 *
037 * @author Greg Cox
038 * @deprecated Use org.biojavax.bio.seq.io framework instead
039 */
040
041public class GenbankProcessor extends SequenceBuilderFilter
042implements ParseErrorSource
043{
044  public static final String PROPERTY_GENBANK_ACCESSIONS = "genbank_accessions";
045  private boolean mBadFeature = false;
046  private Vector mListeners = new Vector();
047  
048  /**
049  * Factory which wraps sequence builders in a GenbankProcessor
050  *
051  * @author Greg Cox
052  */
053  public static class Factory implements SequenceBuilderFactory, Serializable
054  {
055    private SequenceBuilderFactory delegateFactory;
056    
057    public Factory(SequenceBuilderFactory theDelegate)
058    {
059      delegateFactory = theDelegate;
060    }
061    
062    public SequenceBuilder makeSequenceBuilder()
063    {
064      return new GenbankProcessor(delegateFactory.makeSequenceBuilder());
065    }
066    
067    public SequenceBuilder makeSequenceBuilder(String theSource)
068    {
069      return new GenbankProcessor(delegateFactory.makeSequenceBuilder(), theSource);
070    }
071  }
072  
073  protected FeatureTableParser features;
074  private List accessions;
075
076  {
077    accessions = new ArrayList();
078  }
079  
080  public GenbankProcessor(SequenceBuilder theDelegate, String theSource)
081  {
082    super(theDelegate);
083    features = new FeatureTableParser(this, theSource);
084  }
085  
086  public GenbankProcessor(SequenceBuilder theDelegate)
087  {
088    super(theDelegate);
089    features = new FeatureTableParser(this, "GenBank");
090  }
091  
092  public void endSequence() throws ParseException
093  {
094    // Avoids leaving a null name and null URI if there is no
095    // accession number. If accession number is vital, failure of
096    // test of accessions.size() > 0 should throw a
097    // ParseException.
098    String uri = "";
099    if (accessions.size() > 0) {
100      uri = "urn:sequence/genbank:" + (String) accessions.get(0);
101      getDelegate().addSequenceProperty(PROPERTY_GENBANK_ACCESSIONS, accessions);
102    }
103    
104    getDelegate().setURI(uri);
105    getDelegate().endSequence();
106  }
107  
108  public void addSequenceProperty(Object key, Object value) throws ParseException
109  {
110    try
111    {
112      if(mBadFeature)
113      {
114        // If this feature is bad in some way, ignore it.
115        String featureLine = value.toString();
116        if((key.equals(GenbankFormat.FEATURE_FLAG)) && (featureLine.charAt(0) != ' '))
117        {
118          // If the offending feature is past, start reading data again
119          mBadFeature = false;
120          features.startFeature(featureLine.substring(0, 16).trim());
121          features.featureData(featureLine.substring(16));
122        }
123      }
124      else
125      {
126        if (features.inFeature() && !(key.equals(GenbankFormat.FEATURE_FLAG)))
127        {
128          features.endFeature();
129        }
130        
131        if(key.equals(GenbankFormat.FEATURE_FLAG))
132        {
133          String featureLine = value.toString();
134          if (featureLine.charAt(0) != ' ')
135          {
136            // This is a featuretype field
137            if (features.inFeature())
138            {
139              features.endFeature();
140            }
141            features.startFeature(featureLine.substring(0, 16).trim());
142          }
143          features.featureData(featureLine.substring(16));
144        }
145        else
146        {
147          getDelegate().addSequenceProperty(key, value);
148          if (key.equals(GenbankFormat.ACCESSION_TAG))
149          {
150            accessions.add(value);
151          }
152          else if (key.equals(GenbankFormat.LOCUS_TAG)) {
153            getDelegate().setName((String) value);
154            features.setSeqID((String) value);
155          }
156        }
157      }
158    }
159    catch (BioException ex)
160    {
161      // If an exception is thrown, notify the listeners and read past
162      // the offending feature
163      mBadFeature = true;
164      ParseErrorEvent offendingLineEvent = new ParseErrorEvent(this, "This line could not be parsed: " + value.toString());
165      this.notifyParseErrorEvent(offendingLineEvent);
166    }
167    catch (IndexOutOfBoundsException ex)
168    {
169      // This occurs when for some line min > max
170      mBadFeature = true;
171      ParseErrorEvent offendingLineEvent = new ParseErrorEvent(this, "From must be less than To: " + value.toString());
172      this.notifyParseErrorEvent(offendingLineEvent);
173    }
174  }
175  
176  /**
177  * Adds a parse error listener to the list of listeners if it isn't already
178  * included.
179  *
180  * @param theListener Listener to be added.
181  */
182  public synchronized void addParseErrorListener(
183  ParseErrorListener theListener)
184  {
185    if(mListeners.contains(theListener) == false)
186    {
187      mListeners.addElement(theListener);
188    }
189  }
190  
191  /**
192  * Removes a parse error listener from the list of listeners if it is
193  * included.
194  *
195  * @param theListener Listener to be removed.
196  */
197  public synchronized void removeParseErrorListener(
198  ParseErrorListener theListener)
199  {
200    if(mListeners.contains(theListener) == true)
201    {
202      mListeners.removeElement(theListener);
203    }
204  }
205  
206  // Protected methods
207  /**
208  * Passes the event on to all the listeners registered for ParseErrorEvents.
209  *
210  * @param theEvent The event to be handed to the listeners.
211  */
212  protected void notifyParseErrorEvent(ParseErrorEvent theEvent)
213  {
214    Vector listeners;
215    synchronized(this)
216    {
217      listeners = (Vector)mListeners.clone();
218    }
219    
220    for (int index = 0; index < listeners.size(); index++)
221    {
222      ParseErrorListener client = (ParseErrorListener)listeners.elementAt(index);
223      client.BadLineParsed(theEvent);
224    }
225  }
226}