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}