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}