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