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.program.xff;
023
024import java.util.ArrayList;
025import java.util.List;
026
027import org.biojava.bio.Annotation;
028import org.biojava.bio.seq.io.SeqIOListener;
029import org.biojava.utils.stax.DelegationManager;
030import org.biojava.utils.stax.StAXContentHandler;
031import org.biojava.utils.stax.StAXContentHandlerBase;
032import org.xml.sax.Attributes;
033import org.xml.sax.SAXException;
034
035/**
036 * StAX handler which converts and stream of parse events for an XFF
037 * featureSet element into BioJava SeqIO events.
038 *
039 * <strong>NOTE</strong> This class is not thread-safe -- it
040 * must only be used for one parse at any time.
041 *
042 * @author Thomas Down
043 * @since 1.2
044 */
045
046public class XFFFeatureSetHandler extends StAXContentHandlerBase {
047  public final static String PROPERTY_XFF_ID = "org.biojava.bio.program.xff.id";
048
049  private List featureHandlers;
050  private List detailHandlers;
051  private SeqIOListener featureListener;
052  private Annotation mergeAnnotation;
053
054  {
055    featureHandlers = new ArrayList();
056    detailHandlers = new ArrayList();
057    mergeAnnotation = Annotation.EMPTY_ANNOTATION;
058  }
059
060  //
061  // Current parse status
062  //
063
064  /**
065   * Construct a new XFFFeatureSetHandler with the default set of handlers.
066   */
067
068  public XFFFeatureSetHandler() {
069    addFeatureHandler(ElementRecognizer.ALL, FeatureHandler.FEATURE_HANDLER_FACTORY);
070    addFeatureHandler(new ElementRecognizer.HasAttribute("strand"),
071                      StrandedFeatureHandler.STRANDEDFEATURE_HANDLER_FACTORY);
072
073    addDetailHandler(new ElementRecognizer.ByLocalName("prop"),
074                     PropDetailHandler.PROPDETAIL_HANDLER_FACTORY);
075  }
076
077  /**
078   * Set the object which receives startFeature/endFeature notifications.
079   */
080
081  public void setFeatureListener(SeqIOListener siol)
082  {
083    featureListener = siol;
084  }
085
086  /**
087   * Return the object which receives startFeature/endFeature notifications.
088   */
089
090  public SeqIOListener getFeatureListener() {
091    return featureListener;
092  }
093
094  public void setMergeAnnotation(Annotation ann)
095  {
096    this.mergeAnnotation = ann;
097  }
098
099  public Annotation getMergeAnnotation()
100  {
101    return this.mergeAnnotation;
102  }
103
104  /**
105   * Extend this FeatureSetHandler to delegate certain feature elements
106   * to the specified handler type.
107   *
108   * @param rec A selector for some sub-set of feature elements.
109   * @param handler A factory which returns StAX handlers for matching elements.
110   */
111
112  public void addFeatureHandler(ElementRecognizer rec,
113                                XFFPartHandlerFactory handler)
114  {
115    featureHandlers.add(new Binding(rec, handler));
116  }
117
118  /**
119   * Extend this FeatureSetHandler to delegate certain detail elements
120   * to the specified handler type.
121   *
122   * @param rec A selector for some sub-set of detail elements.
123   * @param handler A factory which returns StAX handlers for matching elements.
124   */
125
126  public void addDetailHandler(ElementRecognizer rec,
127                               XFFPartHandlerFactory handler)
128  {
129    detailHandlers.add(new Binding(rec, handler));
130  }
131
132  class Binding {
133    final ElementRecognizer recognizer;
134    final XFFPartHandlerFactory handlerFactory;
135
136    Binding(ElementRecognizer er,
137            XFFPartHandlerFactory hf)
138    {
139      recognizer = er;
140      handlerFactory = hf;
141    }
142
143    public String toString()
144    {
145      return "Binding[rec=" + recognizer + " fact=" + handlerFactory + "]";
146    }
147  }
148
149
150  public void startElement(String nsURI,
151                           String localName,
152                           String qName,
153                           Attributes attrs,
154                           DelegationManager dm)
155          throws SAXException
156  {
157    //System.err.println("Processing startElement(" + nsURI + ", " + localName + ", " + qName + ", " + pretify(attrs));
158    if (localName.equals("featureSet")) {
159      return;
160    }
161
162    for (int i = featureHandlers.size() - 1; i >= 0; --i) {
163      Binding b = (Binding) featureHandlers.get(i);
164      //System.err.println("Binding: " + b);
165      if (b.recognizer.filterStartElement(nsURI, localName, qName, attrs)) {
166        //System.err.println("Accepting binding");
167        dm.delegate(b.handlerFactory.getPartHandler(this));
168        return;
169      }
170    }
171
172    throw new SAXException("Couldn't handle element " + localName + " in namespace " + nsURI);
173  }
174
175  public void endElement(String nsURI,
176                         String localName,
177                         String qName,
178                         StAXContentHandler handler)
179  {
180    if (localName.equals("featureSet")) {
181    }
182  }
183
184  /**
185   * Return a handler for the XFF <code>details</code> element.
186   * This handler will, in turn, delegate to the specific detail
187   * handlers provided with <code>addDetailHandler</code>
188   */
189
190  public StAXContentHandlerBase getDetailsHandler() {
191    return new XFFDetailsHandler();
192  }
193
194  private class XFFDetailsHandler extends StAXContentHandlerBase {
195
196    public void startElement(String nsURI,
197                             String localName,
198                             String qName,
199                             Attributes attrs,
200                             DelegationManager dm)
201            throws SAXException
202    {
203      if (localName.equals("details")) {
204        return;
205      }
206
207      for (int i = detailHandlers.size() - 1; i >= 0; --i) {
208        Binding b = (Binding) detailHandlers.get(i);
209        if (b.recognizer.filterStartElement(nsURI, localName, qName, attrs)) {
210          dm.delegate(b.handlerFactory.getPartHandler(XFFFeatureSetHandler.this));
211          return;
212        }
213      }
214
215      // Unknown detail types get silently ignored.
216    }
217
218    public void endElement(String nsURI,
219                           String localName,
220                           String qName)
221    {
222      if (localName.equals("details")) {
223      }
224    }
225  }
226}