001/**
002
003 *                    BioJava development code
004
005 *
006
007 * This code may be freely distributed and modified under the
008
009 * terms of the GNU Lesser General Public Licence.  This should
010
011 * be distributed with the code.  If you do not have a copy,
012
013 * see:
014
015 *
016
017 *      http://www.gnu.org/copyleft/lesser.html
018
019 *
020
021 * Copyright for this code is held jointly by the individual
022
023 * authors.  These should be listed in @author doc comments.
024
025 *
026
027 * For more information on the BioJava project and its aims,
028
029 * or to join the biojava-l mailing list, visit the home page
030
031 * at:
032
033 *
034
035 *      http://www.biojava.org/
036
037 *
038
039 */
040
041package org.biojava.bio.seq.io.agave;
042
043import java.util.ArrayList;
044import java.util.Iterator;
045import java.util.List;
046import java.util.ListIterator;
047
048import org.biojava.bio.Annotation;
049import org.biojava.bio.BioException;
050import org.biojava.bio.SimpleAnnotation;
051import org.biojava.bio.seq.Feature;
052import org.biojava.bio.seq.Sequence;
053import org.biojava.bio.seq.StrandedFeature;
054import org.biojava.bio.seq.io.ParseException;
055import org.biojava.bio.seq.io.SeqIOListener;
056import org.biojava.bio.symbol.Location;
057import org.biojava.utils.ChangeVetoException;
058import org.xml.sax.Attributes;
059import org.xml.sax.SAXException;
060
061
062
063/**
064
065 * StAX handler shamelessly ripped off from Thomas Down's
066
067 * XFFFeatureSetHandler.  It was modified for greater
068
069 * generality.
070
071 *
072
073 * <strong>NOTE</strong> This class is not thread-safe -- it
074
075 * must only be used for one parse at any time.
076
077 * <p>
078
079 * Because AGAVE has nested feature and each feature must attached to
080
081 * some parent feature-holder in biojava, which means we need to generate parents first,
082
083 * so we have to keep the tree structure of features in memory, which is really bad.
084
085 * anyway, we still saved a lot of memory compared with DOM tree . Hanning Ni)
086
087 
088
089 * @author copied from Thomas Down
090
091 * @author copied from David Huen
092
093 * @author Hanning Ni   Doubletwist Inc
094
095 *
096
097 */
098
099public class StAXFeatureHandler extends StAXContentHandlerBase
100
101{
102
103  // class variables
104
105  private boolean setOnceFired = false;
106
107  protected String myLocalName;
108
109  private boolean hasCallback = false;
110
111  private List handlers;
112
113  private boolean startFired=false;
114
115  private boolean endFired=false;
116
117  private boolean inFeature=false;  // have we been here before?
118
119
120
121  // class variables for use by nested elements
122
123  protected Feature.Template featureTemplate;
124
125  protected StAXFeatureHandler staxenv ;
126
127  protected SeqIOListener featureListener;
128
129  protected int startLoc;
130
131  protected int endLoc;  // needed because some XML don't give start and stops as attributes.
132
133/**
134
135 * this is the stack of handler objects for the current feature.
136
137  * The base value is the FeatureHandler itself.
138
139  * your feature and property handlers place and remove themselves
140
141  * from this stack.
142
143  *
144
145  * the purpose of all this is to implement context sensitivty for
146
147  * property handlers translucently.  Property handlers can pop the
148
149  * stack for other handlers that implement interfaces that process
150
151  * that element.  This way the context code is within the object that
152
153  * defines that context rather than in a child property handler.
154
155  */
156
157  protected List callbackStack;
158
159  protected int stackLevel;
160
161
162
163  //store all the sub features,  should be a tree structure with the root is
164
165  //top level seqeuence
166
167  protected List subFeatures ;
168
169
170
171  protected  SimpleAnnotation annot = new SimpleAnnotation();
172
173
174
175  StAXFeatureHandler(StAXFeatureHandler staxenv) {
176
177       // cache environmnet
178
179       this.staxenv = staxenv;
180
181       handlers = new ArrayList();
182
183       callbackStack = new ArrayList();
184
185       subFeatures = new ArrayList(1) ;
186
187  }
188
189
190
191  StAXFeatureHandler() {
192
193    handlers = new ArrayList();
194
195    callbackStack = new ArrayList();
196
197    subFeatures = new ArrayList(1) ;
198
199  }
200
201
202
203  // there should be a factory method here to make this class
204
205
206
207/**
208
209 * Sets the element name that the class responds to.
210
211 */
212
213  public void setHandlerCharacteristics(String localName, boolean hasCallback) {
214
215    if (!setOnceFired) {
216
217      myLocalName = localName;
218
219      this.hasCallback = hasCallback;
220
221      setOnceFired = true;
222
223    }
224
225  }
226
227
228
229  public void setFeatureListener(SeqIOListener siol) {
230
231    featureListener = siol;
232
233  }
234
235
236
237  // Class to implement bindings
238
239  class Binding {
240
241    final ElementRecognizer recognizer;
242
243    final StAXHandlerFactory handlerFactory;
244
245    Binding(ElementRecognizer er, StAXHandlerFactory hf)
246
247    {
248
249      recognizer = er;
250
251      handlerFactory = hf;
252
253    }
254
255  }
256
257
258
259  // method to add a handler
260
261  // we do not distinguish whither it is a feature or property
262
263  // handler.  The factory method creates the right type subclassed
264
265  // from the correct type of handler
266
267  protected void addHandler(
268
269                   ElementRecognizer rec,
270
271                   StAXHandlerFactory handler)
272
273  {
274
275    handlers.add(new Binding(rec, handler));
276
277  }
278
279
280
281/**
282
283 *  generates a very basic Template for the feature with
284
285 *  SmallAnnotation in the annotation field.
286
287 *  <p>
288
289 *  Override if you wish a more specialised Template.
290
291 */
292
293  protected Feature.Template createTemplate() {
294
295    // create Gene Template for this
296
297    StrandedFeature.Template st = new StrandedFeature.Template();
298
299
300
301    // assume feature set to describe a transcript
302
303    st.source = myLocalName;
304
305    st.type = myLocalName;
306
307    st.strand = StrandedFeature.UNKNOWN;
308
309    // set up annotation bundle
310
311    st.annotation = annot ;
312
313    st.location = Location.empty;
314
315    if( staxenv != null )
316
317        staxenv. subFeatures .add( this ) ;
318
319
320
321    return st;
322
323  }
324
325
326
327  /**
328
329   * recursively attach children features to parent
330
331   */
332
333  protected void realizeSubFeatures(Feature feature)
334
335  {
336
337    try{
338
339      Iterator it = subFeatures.iterator() ;
340
341      while( it.hasNext() )
342
343      {
344
345          StAXFeatureHandler handler =  (StAXFeatureHandler)it.next()  ;
346
347          if( handler instanceof SequenceHandler ) //already handled
348
349              continue ;
350
351            Feature f =  feature.createFeature ( handler.featureTemplate ) ;
352
353          handler.realizeSubFeatures( f ) ;
354
355      }
356
357     }catch(BioException e){  e.printStackTrace();}
358
359     catch(ChangeVetoException e){ e.printStackTrace();}
360
361  }
362
363
364
365  protected void addFeatureToSequence(Sequence seq) throws Exception
366
367  {
368
369      Iterator it = subFeatures.iterator() ;
370
371      while( it.hasNext() )
372
373      {
374
375          StAXFeatureHandler handler =  (StAXFeatureHandler)it.next()  ;
376
377          Feature f =  seq.createFeature ( handler.featureTemplate ) ;
378
379          handler.realizeSubFeatures( f ) ;
380
381      }
382
383  }
384
385/**
386
387 * return current stack level.  Remember that the
388
389 * stack level is incremented/decremented AFTER
390
391 * the push()/pop() calls and superclass
392
393 * startElement()/StopElement calls.
394
395 */
396
397  protected int getLevel() {
398
399    return stackLevel;
400
401  }
402
403
404
405/**
406
407 * return iterator to callbackStack
408
409 */
410
411  protected ListIterator getHandlerStackIterator(int level) {
412
413    return callbackStack.listIterator(level);
414
415  }
416
417
418
419/**
420
421 * Push StAXContentHandler object onto stack
422
423 */
424
425  protected void push(StAXContentHandler handler) {
426
427    // push handler
428
429    callbackStack.add(handler);
430
431
432
433    // increment pointer
434
435    stackLevel++;
436
437  }
438
439
440
441/**
442
443 * pop a StAXContentHandler off the stack.
444
445 */
446
447  protected void pop() {
448
449    // decrement pointer
450
451    stackLevel--;
452
453
454
455    // pop handler
456
457    callbackStack.remove(stackLevel);
458
459  }
460
461
462
463/**
464
465 * Return current feature listener
466
467 */
468
469  public SeqIOListener getFeatureListener() {
470
471    return featureListener;
472
473  }
474
475
476
477/**
478
479 *  Fire the startFeature event.
480
481 */
482
483  private void fireStartFeature()
484
485    throws ParseException
486
487  {
488
489    if (startFired)
490
491      throw new ParseException("startFeature event has already been fired");
492
493
494
495    if (featureTemplate == null)
496
497      featureTemplate = createTemplate();
498
499
500
501    if (featureTemplate.annotation == null)
502
503      featureTemplate.annotation = Annotation.EMPTY_ANNOTATION;
504
505
506
507    featureListener.startFeature(featureTemplate);
508
509    startFired = true;
510
511  }
512
513
514
515/**
516
517 * Fire the endFeature event.
518
519 */
520
521  private void fireEndFeature()
522
523    throws ParseException
524
525  {
526
527    if (!startFired)
528
529      throw new ParseException("startFeature has not yet been fired!");
530
531
532
533    if (endFired)
534
535      throw new ParseException("endFeature event has already been fired!");
536
537    featureListener.endFeature();
538
539    endFired = true;
540
541  }
542
543
544
545  protected void setProperty(String name, String value, boolean forFeature)
546
547  {
548
549      if ( value != null) {
550
551         try {
552
553           annot.setProperty( name, value);
554
555           if( forFeature )
556
557               featureListener.addFeatureProperty(name, value);
558
559           else
560
561               featureListener.addSequenceProperty(name, value);
562
563         }
564
565         catch (ChangeVetoException cae) {
566
567                 System.err.println(" veto exception caught.");
568
569         }
570
571         catch (ParseException cae) {
572
573                 System.err.println("parse exception in addProperty() .");
574
575         }
576
577     }
578
579  }
580
581/**
582
583 * Element-specific handler.
584
585 * Subclass this to do something useful!
586
587 */
588
589  public void startElementHandler(
590
591                String nsURI,
592
593                String localName,
594
595                String qName,
596
597                Attributes attrs)
598
599         throws SAXException
600
601  {
602
603  }
604
605
606
607
608
609/**
610
611 * Handles basic entry processing for all feature handlers.
612
613 */
614
615  public void startElement(
616
617                String nsURI,
618
619                String localName,
620
621                String qName,
622
623                Attributes attrs,
624
625                DelegationManager dm)
626
627         throws SAXException
628
629  {
630
631     // sanity check
632
633    if (!setOnceFired)
634
635      throw new SAXException("StAXFeaturehandler not initialised before use!");
636
637
638
639    // find out if this element is really for me.
640
641    // perform delegation
642
643  //  if (!(myLocalName.equals(localName)) ) {
644
645     if( dm.getRecursive() )
646
647        for (int i = handlers.size() - 1; i >= 0; --i) {
648
649            Binding b = (Binding) handlers.get(i);
650
651            if (b.recognizer.filterStartElement(nsURI, localName, qName, attrs)) {
652
653             dm.delegate(b.handlerFactory.getHandler(this));
654
655            return;
656
657            }
658
659        }
660
661  //  }
662
663    // I don't have a delegate for it but it might be a stray...
664
665    if (!(myLocalName.equals(localName)) ) {
666
667      //this one's not for me!
668
669      return;
670
671    }
672
673
674
675    // this one's mine.
676
677    // initialise if this is the first time thru'
678
679    if (!inFeature) {
680
681      inFeature = true;
682
683
684
685      if (hasCallback) {
686
687        if (stackLevel == 0) push(this);
688
689      }
690
691
692
693      // indicate start of feature to listener
694
695      try {
696
697        if (!startFired) fireStartFeature();
698
699      }
700
701      catch (ParseException pe) {
702
703        throw new SAXException("ParseException thrown in user code");
704
705      }
706
707    }
708
709
710
711    // call the element specific handler now.
712
713    startElementHandler(nsURI, localName, qName, attrs);
714
715
716
717  }
718
719
720
721/**
722
723 * Element specific exit handler
724
725 * Subclass to do anything useful.
726
727 */
728
729  public void endElementHandler(
730
731                String nsURI,
732
733                String localName,
734
735                String qName,
736
737                StAXContentHandler handler)
738
739              throws SAXException
740
741  {
742
743  }
744
745
746
747/**
748
749 * Handles basic exit processing.
750
751 */
752
753  public void endElement(
754
755                String nsURI,
756
757                String localName,
758
759                String qName,
760
761                StAXContentHandler handler)
762
763              throws SAXException
764
765  {
766
767    // is this a return after delegation or really mine?
768
769    if (!(myLocalName.equals(localName)) )
770
771       return;
772
773
774
775    // last chance to clear up before exiting
776
777    //endElementHandler(nsURI, localName, qName, handler);
778
779
780
781    // it's mine, get prepared to leave.
782
783    if (hasCallback) pop();
784
785
786
787    // is it time to go beddy-byes?
788
789    if (stackLevel == 0) {
790
791      // we need to cope with zero-sized elements
792
793      try {
794
795        if (!startFired) fireStartFeature();
796
797        if (!endFired) fireEndFeature();
798
799      }
800
801      catch (ParseException pe) {
802
803          throw new SAXException("ParseException thrown in user code");
804
805      }
806
807    }
808
809    endElementHandler(nsURI, localName, qName, handler);
810
811  }
812
813}
814