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 */
021package org.biojava.bio.seq.io.agave;
022import java.util.ArrayList;
023import java.util.List;
024import java.util.ListIterator;
025
026import org.biojava.bio.seq.io.ParseException;
027import org.biojava.bio.seq.io.SeqIOListener;
028import org.biojava.utils.ChangeVetoException;
029import org.xml.sax.Attributes;
030import org.xml.sax.SAXException;
031
032/**
033 * StAX handler shamelessly ripped off from Thomas Down's
034 * XFFFeatureSetHandler.
035 *
036 * <strong>NOTE</strong> This class is not thread-safe -- it
037 * must only be used for one parse at any time.
038 *
039 * This class is the basis for classes that do not create
040 * a new feature but modify an existing feature.
041 *
042 * It is not compulsory for property handlers to subclass
043 * this class but those that don't but wish to use the
044 * handler stack facility need to use the StaxFeatureHandler's
045 * push and pop methods.
046 *
047 * @author copied from Thomas Down
048 * @author copied from David Huen
049 *
050 * @author Hanning Ni   Doubletwist Inc
051 */
052public class StAXPropertyHandler extends StAXContentHandlerBase
053{
054  private String myLocalName;
055  private boolean hasCallback = false;
056  private boolean inElement = false;
057  private boolean setOnceFired = false;
058
059  // class variables
060  protected SeqIOListener featureListener;
061  private List handlers;
062  protected StAXFeatureHandler staxenv;
063  private int baseLevel = 0;
064
065  // there should be a factory method here to make this class
066
067  // constructor
068  // because every StAXPropertyHandler was ultimately
069  // invoked from a StAXFeatureHandler via delegation
070  // the staxenv will point at the StAXFeatureHandler
071  // at the base of the current chain of StAXPropertyHandler,
072  // which is not necessarily the first root element
073  // StAXFeatureHandler.
074  StAXPropertyHandler(StAXFeatureHandler staxenv) {
075    // cache environmnet
076    this.staxenv = staxenv;
077    handlers = new ArrayList();
078  }
079
080/**
081 * Sets the element name that the class responds to.
082 */
083  public void setHandlerCharacteristics(String localName, boolean hasCallback)
084  {
085    if (!setOnceFired) {
086      myLocalName = localName;
087      this.hasCallback = hasCallback;
088      setOnceFired = true;
089    }
090  }
091
092
093/**
094 * get iterator for current stack starting at the position
095 * below mine.
096 */
097  protected ListIterator getHandlerStackIterator()
098      throws ParseException {
099    if (baseLevel >= 1)
100      return staxenv.getHandlerStackIterator(baseLevel-1);
101    else
102      throw new ParseException("getHandlerStackIterator while at bottom of stack.");
103  }
104
105  // Class to implement bindings
106  class Binding {
107    final ElementRecognizer recognizer;
108    final StAXHandlerFactory handlerFactory;
109    Binding(ElementRecognizer er, StAXHandlerFactory hf)
110    {
111      recognizer = er;
112      handlerFactory = hf;
113    }
114  }
115
116  // method to add a handler
117  // we do not distinguish whither it is a feature or property
118  // handler.  The factory method creates the right type subclassed
119  // from the correct type of handler
120  protected void addHandler(
121                   ElementRecognizer rec,
122                   StAXHandlerFactory handler)
123  {
124    handlers.add(new Binding(rec, handler));
125  }
126
127  protected void setProperty(String name, String value)
128  {
129     if(  staxenv.featureTemplate == null ||  staxenv.featureTemplate.annotation == null )
130         return  ;
131     if ( value != null) {
132         try {
133         staxenv.featureTemplate.annotation.setProperty( name, value);
134         featureListener.addFeatureProperty( name, value ) ;
135         }
136         catch (ChangeVetoException cae) {
137              System.err.println("GAMEAnnotationHandler: veto exception caught.");
138         }
139         catch (ParseException cae) {
140              System.err.println("parse exception in addfeatureProperty() .");
141         }
142     }
143  }
144/**
145 * Element-specific handler.
146 * Subclass this to do something useful!
147 */
148  public void startElementHandler(
149                String nsURI,
150                String localName,
151                String qName,
152                Attributes attrs)
153         throws SAXException
154  {
155  }
156
157/**
158 * Override this to do any processing required but call this
159 * prior to returning.  Delegation occurs here!
160 *
161 */
162  public void startElement(
163                String nsURI,
164                String localName,
165                String qName,
166                Attributes attrs,
167                DelegationManager dm)
168         throws SAXException
169  {
170      // if (!(myLocalName.equals(localName)) ) {
171       if( dm.getRecursive() )
172         for (int i = handlers.size() - 1; i >= 0; --i) {
173             Binding b = (Binding) handlers.get(i);
174             if (b.recognizer.filterStartElement(nsURI, localName, qName, attrs)) {
175                 dm.delegate(b.handlerFactory.getHandler(staxenv));
176                 return;
177             }
178        }
179    //}
180    // is this for me?
181    if (!(myLocalName.equals(localName)) ) return;
182
183    if (!inElement) {
184      // save current stack position just in case I want to search downwards.
185      baseLevel = staxenv.getLevel();
186
187      if (hasCallback) staxenv.push(this);
188
189      inElement = true;
190    }
191
192    if (inElement) startElementHandler(nsURI, localName, qName, attrs);
193  }
194
195/**
196 * Element specific exit handler
197 * Subclass to do anything useful.
198 */
199  public void endElementHandler(
200                String nsURI,
201                String localName,
202                String qName,
203                StAXContentHandler handler)
204              throws SAXException
205  {
206  }
207
208  public void endElement(
209                String nsURI,
210                String localName,
211                String qName,
212                StAXContentHandler handler)
213              throws SAXException
214  {
215    // is this mine?
216    if (!(myLocalName.equals(localName)) ) return;
217
218    // do the necessary before exit
219    if (inElement) {
220      // element specific handling
221      endElementHandler(nsURI, localName, qName, handler);
222
223      if (hasCallback)
224        if (setOnceFired) {
225          staxenv.pop();
226          setOnceFired = false;
227        }
228
229      inElement = false;
230    }
231  }
232}