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.filterxml; 023 024import java.util.ArrayList; 025import java.util.HashMap; 026import java.util.Iterator; 027import java.util.List; 028import java.util.Map; 029 030import org.biojava.bio.seq.FeatureFilter; 031import org.biojava.bio.seq.FramedFeature; 032import org.biojava.bio.seq.StrandedFeature; 033import org.biojava.bio.symbol.Location; 034import org.biojava.bio.symbol.LocationTools; 035import org.biojava.bio.symbol.RangeLocation; 036import org.biojava.utils.ClassTools; 037import org.biojava.utils.stax.DelegationManager; 038import org.biojava.utils.stax.StAXContentHandler; 039import org.biojava.utils.stax.StAXContentHandlerBase; 040import org.biojava.utils.stax.StringElementHandlerBase; 041import org.xml.sax.Attributes; 042import org.xml.sax.SAXException; 043 044/** 045 * Factory producing content handlers for parsing FilterXML elements. 046 * 047 * <p> 048 * An XMLFilterHandler object is a collection of individual StAX handlers for parsing FilterXML 049 * documents. It uses XMLAnnotationTypeHandler to parse <code>byAnnotationType</code> elements. 050 * To handle an individual XML filter, you should call the getStAXContentHandler method 051 * <p> 052 * 053 * <p><strong>Example:</strong></p> 054 * <pre> 055 * // Setup 056 * XMLFilterHandler filterHandler = new XMLFilterHandler(); 057 * Reader xmlFile = new FileReader("featurefilter.xml"); 058 * 059 * // Create an XML parser 060 * SAXParserFactory spf = SAXParserFactory.newInstance(); 061 * spf.setNamespaceAware(true); 062 * XMLReader parser = spf.newSAXParser().getXMLReader(); 063 * 064 * // Create a new handler for this document 065 * XMLFilterHandler.FilterHandler handler = filterHandler.getStAXContentHandler(); 066 * parser.setContentHandler(new SAX2StAXAdaptor(handler)); 067 * 068 * // Parse the file and retrieve the FeatureFilter 069 * parser.parse(new InputSource(xmlFile)); 070 * FeatureFilter filter = handler.getFeatureFilter(); 071 * </pre> 072 * 073 * 074 * @author Thomas Down 075 * @since 1.3 076 */ 077 078public class XMLFilterHandler { 079 Map handlerFactories = new HashMap(); 080 081 /** 082 * StAXContentHandler for a particular type of FeatureFilter. Implement 083 * this interface to add parsing support for new types of FeatureFilter. 084 * 085 * @author Thomas Down 086 */ 087 088 public static interface FilterHandler extends StAXContentHandler { 089 public FeatureFilter getFeatureFilter() throws SAXException; 090 } 091 092 /** 093 * Factory of StAXContentHandlers for a particular type of FeatureFilter. Implement 094 * this interface to add parsing support for new types of FeatureFilter. 095 * 096 * @author Thomas Down 097 */ 098 099 public static interface FilterHandlerFactory { 100 public FilterHandler makeHandler(String nsURI, 101 String localName, 102 XMLFilterHandler config) 103 throws SAXException; 104 } 105 106 /** 107 * Register a factory used to create handlers for the specified tag name 108 */ 109 110 public void registerHandlerFactory(String nsURI, String localName, FilterHandlerFactory factory) { 111 handlerFactories.put(new QName(nsURI, localName), factory); 112 } 113 114 /** 115 * Retrieve a <code>FilterHandler</code> for the specified tag name. 116 */ 117 118 public FilterHandler getHandler(String nsURI, String localName) 119 throws SAXException 120 { 121 FilterHandlerFactory factory = (FilterHandlerFactory) handlerFactories.get(new QName(nsURI, localName)); 122 if (factory != null) { 123 return factory.makeHandler(nsURI, localName, this); 124 } else { 125 throw new SAXException("No handler for " + nsURI + ":" + localName); 126 } 127 } 128 129 /** 130 * Construct a new XMLFilterHandler which can parse the builtin types of <code>FeatureFilter</code>. 131 */ 132 133 public XMLFilterHandler() { 134 registerHandlerFactory( 135 XMLFilterWriter.XML_FILTER_NS, 136 "byType", 137 new CDATAHandlerFactory() { 138 protected FeatureFilter stringToFilter(String s) { 139 return new FeatureFilter.ByType(s); 140 } 141 } 142 ); 143 registerHandlerFactory( 144 XMLFilterWriter.XML_FILTER_NS, 145 "bySource", 146 new CDATAHandlerFactory() { 147 protected FeatureFilter stringToFilter(String s) { 148 return new FeatureFilter.BySource(s); 149 } 150 } 151 ); 152 registerHandlerFactory( 153 XMLFilterWriter.XML_FILTER_NS, 154 "byClass", 155 new CDATAHandlerFactory() { 156 protected FeatureFilter stringToFilter(String s) 157 throws SAXException 158 { 159 try { 160 return new FeatureFilter.ByClass(ClassTools.getClassLoader(this).loadClass(s)); 161 } catch (Exception ex) { 162 throw new SAXException("Couldn't load class " + s); 163 } 164 } 165 } 166 ); 167 registerHandlerFactory( 168 XMLFilterWriter.XML_FILTER_NS, 169 "byStrand", 170 new CDATAHandlerFactory() { 171 protected FeatureFilter stringToFilter(String s) 172 throws SAXException 173 { 174 s = s.trim(); 175 StrandedFeature.Strand strand = StrandedFeature.UNKNOWN; 176 if ("POSITIVE".equalsIgnoreCase(s)) { 177 strand = StrandedFeature.POSITIVE; 178 } else if ("NEGATIVE".equalsIgnoreCase(s)) { 179 strand = StrandedFeature.NEGATIVE; 180 } 181 return new FeatureFilter.StrandFilter(strand); 182 } 183 } 184 ); 185 registerHandlerFactory( 186 XMLFilterWriter.XML_FILTER_NS, 187 "byFrame", 188 new CDATAHandlerFactory() { 189 protected FeatureFilter stringToFilter(String s) 190 throws SAXException 191 { 192 int frameNum = Integer.parseInt(s.trim()); 193 switch (frameNum) { 194 case 0: 195 return new FeatureFilter.FrameFilter(FramedFeature.FRAME_0); 196 case 1: 197 return new FeatureFilter.FrameFilter(FramedFeature.FRAME_1); 198 case 2: 199 return new FeatureFilter.FrameFilter(FramedFeature.FRAME_2); 200 } 201 throw new SAXException("Invalid frame: " + frameNum); 202 } 203 } 204 ); 205 registerHandlerFactory( 206 XMLFilterWriter.XML_FILTER_NS, 207 "all", 208 new CDATAHandlerFactory() { 209 protected FeatureFilter stringToFilter(String s) { 210 return FeatureFilter.all; 211 } 212 } 213 ); 214 registerHandlerFactory( 215 XMLFilterWriter.XML_FILTER_NS, 216 "none", 217 new CDATAHandlerFactory() { 218 protected FeatureFilter stringToFilter(String s) { 219 return FeatureFilter.none; 220 } 221 } 222 ); 223 registerHandlerFactory( 224 XMLFilterWriter.XML_FILTER_NS, 225 "isTopLevel", 226 new CDATAHandlerFactory() { 227 protected FeatureFilter stringToFilter(String s) { 228 return FeatureFilter.top_level; 229 } 230 } 231 ); 232 registerHandlerFactory( 233 XMLFilterWriter.XML_FILTER_NS, 234 "isLeaf", 235 new CDATAHandlerFactory() { 236 protected FeatureFilter stringToFilter(String s) { 237 return FeatureFilter.leaf; 238 } 239 } 240 ); 241 registerHandlerFactory( 242 XMLFilterWriter.XML_FILTER_NS, 243 "bySequenceName", 244 new CDATAHandlerFactory() { 245 protected FeatureFilter stringToFilter(String s) { 246 return new FeatureFilter.BySequenceName(s); 247 } 248 } 249 ); 250 registerHandlerFactory( 251 XMLFilterWriter.XML_FILTER_NS, 252 "byComponentName", 253 new CDATAHandlerFactory() { 254 protected FeatureFilter stringToFilter(String s) { 255 return new FeatureFilter.ByComponentName(s); 256 } 257 } 258 ); 259 registerHandlerFactory( 260 XMLFilterWriter.XML_FILTER_NS, 261 "not", 262 new SingleFilterHandlerFactory() { 263 protected FeatureFilter filterToFilter(FeatureFilter ff) { 264 return new FeatureFilter.Not(ff); 265 } 266 } 267 ); 268 registerHandlerFactory( 269 XMLFilterWriter.XML_FILTER_NS, 270 "byParent", 271 new SingleFilterHandlerFactory() { 272 protected FeatureFilter filterToFilter(FeatureFilter ff) { 273 return new FeatureFilter.ByParent(ff); 274 } 275 } 276 ); 277 registerHandlerFactory( 278 XMLFilterWriter.XML_FILTER_NS, 279 "byAncestor", 280 new SingleFilterHandlerFactory() { 281 protected FeatureFilter filterToFilter(FeatureFilter ff) { 282 return new FeatureFilter.ByAncestor(ff); 283 } 284 } 285 ); 286 registerHandlerFactory( 287 XMLFilterWriter.XML_FILTER_NS, 288 "byChild", 289 new SingleFilterHandlerFactory() { 290 protected FeatureFilter filterToFilter(FeatureFilter ff) { 291 return new FeatureFilter.ByChild(ff); 292 } 293 } 294 ); 295 registerHandlerFactory( 296 XMLFilterWriter.XML_FILTER_NS, 297 "byDescendant", 298 new SingleFilterHandlerFactory() { 299 protected FeatureFilter filterToFilter(FeatureFilter ff) { 300 return new FeatureFilter.ByDescendant(ff); 301 } 302 } 303 ); 304 registerHandlerFactory( 305 XMLFilterWriter.XML_FILTER_NS, 306 "onlyChildren", 307 new SingleFilterHandlerFactory() { 308 protected FeatureFilter filterToFilter(FeatureFilter ff) { 309 return new FeatureFilter.OnlyChildren(ff); 310 } 311 } 312 ); 313 registerHandlerFactory( 314 XMLFilterWriter.XML_FILTER_NS, 315 "onlyDescendants", 316 new SingleFilterHandlerFactory() { 317 protected FeatureFilter filterToFilter(FeatureFilter ff) { 318 return new FeatureFilter.OnlyDescendants(ff); 319 } 320 } 321 ); 322 registerHandlerFactory( 323 XMLFilterWriter.XML_FILTER_NS, 324 "and", 325 new FiltersHandlerFactory() { 326 protected FeatureFilter filtersToFilter(List l) { 327 FeatureFilter ff; 328 Iterator i = l.iterator(); 329 ff = (FeatureFilter) i.next(); 330 while (i.hasNext()) { 331 ff = new FeatureFilter.And(ff, (FeatureFilter) i.next()); 332 } 333 return ff; 334 } 335 } 336 ); 337 registerHandlerFactory( 338 XMLFilterWriter.XML_FILTER_NS, 339 "or", 340 new FiltersHandlerFactory() { 341 protected FeatureFilter filtersToFilter(List l) { 342 FeatureFilter ff; 343 Iterator i = l.iterator(); 344 ff = (FeatureFilter) i.next(); 345 while (i.hasNext()) { 346 ff = new FeatureFilter.Or(ff, (FeatureFilter) i.next()); 347 } 348 return ff; 349 } 350 } 351 ); 352 registerHandlerFactory( 353 XMLFilterWriter.XML_FILTER_NS, 354 "overlapsLocation", 355 new LocationHandlerFactory() { 356 protected FeatureFilter locationToFilter(Location loc) { 357 return new FeatureFilter.OverlapsLocation(loc); 358 } 359 } 360 ); 361 registerHandlerFactory( 362 XMLFilterWriter.XML_FILTER_NS, 363 "containedByLocation", 364 new LocationHandlerFactory() { 365 protected FeatureFilter locationToFilter(Location loc) { 366 return new FeatureFilter.ContainedByLocation(loc); 367 } 368 } 369 ); 370 registerHandlerFactory( 371 XMLFilterWriter.XML_FILTER_NS, 372 "shadowOverlapsLocation", 373 new LocationHandlerFactory() { 374 protected FeatureFilter locationToFilter(Location loc) { 375 return new FeatureFilter.ShadowOverlapsLocation(loc); 376 } 377 } 378 ); 379 registerHandlerFactory( 380 XMLFilterWriter.XML_FILTER_NS, 381 "shadowContainedByLocation", 382 new LocationHandlerFactory() { 383 protected FeatureFilter locationToFilter(Location loc) { 384 return new FeatureFilter.ShadowContainedByLocation(loc); 385 } 386 } 387 ); 388 registerHandlerFactory( 389 XMLFilterWriter.XML_FILTER_NS, 390 "byAnnotationType", 391 new AnnotationTypeHandlerFactory() 392 ); 393 } 394 395 private abstract static class SingleFilterHandlerFactory extends FiltersHandlerFactory { 396 protected abstract FeatureFilter filterToFilter(FeatureFilter ff) throws SAXException; 397 protected final FeatureFilter filtersToFilter(List filters) 398 throws SAXException 399 { 400 if (filters.size() != 1) { 401 throw new SAXException("Expected 1 child filter but got " + filters.size()); 402 } 403 return filterToFilter((FeatureFilter) filters.get(0)); 404 } 405 } 406 407 private abstract static class FiltersHandlerFactory implements FilterHandlerFactory { 408 private class FiltersHandler extends StAXContentHandlerBase implements FilterHandler { 409 private XMLFilterHandler config; 410 private List filterChildren = new ArrayList(); 411 private int depth = 0; 412 413 public FiltersHandler(XMLFilterHandler config) { 414 super(); 415 this.config = config; 416 } 417 418 public void startElement(String nsURI, 419 String localName, 420 String qName, 421 Attributes attrs, 422 DelegationManager dm) 423 throws SAXException 424 { 425 if (depth == 1) { 426 FilterHandler childHandler = config.getHandler(nsURI, localName); 427 dm.delegate(childHandler); 428 } 429 ++depth; 430 } 431 432 public void endElement(String nsURI, 433 String localName, 434 String qName, 435 StAXContentHandler delegate) 436 throws SAXException 437 { 438 if (delegate instanceof FilterHandler) { 439 filterChildren.add(((FilterHandler) delegate).getFeatureFilter()); 440 } 441 --depth; 442 } 443 444 public FeatureFilter getFeatureFilter() 445 throws SAXException 446 { 447 return filtersToFilter(filterChildren); 448 } 449 } 450 451 protected abstract FeatureFilter filtersToFilter(List filters) throws SAXException; 452 453 public FilterHandler makeHandler(String nsURI, String localName, XMLFilterHandler config) { 454 return new FiltersHandler(config); 455 } 456 } 457 458 private abstract static class LocationHandlerFactory implements FilterHandlerFactory { 459 private class LocationHandler extends StAXContentHandlerBase implements FilterHandler { 460 private List spans = new ArrayList(); 461 462 public void startElement(String nsURI, 463 String localName, 464 String qName, 465 Attributes attrs, 466 DelegationManager dm) 467 throws SAXException 468 { 469 if ("span".equals(localName)) { 470 int start = Integer.parseInt(attrs.getValue("start")); 471 int stop = Integer.parseInt(attrs.getValue("stop")); 472 spans.add(new RangeLocation(start, stop)); 473 } 474 } 475 476 public FeatureFilter getFeatureFilter() 477 throws SAXException 478 { 479 return locationToFilter(LocationTools.union(spans)); 480 } 481 } 482 483 protected abstract FeatureFilter locationToFilter(Location loc) throws SAXException; 484 485 public FilterHandler makeHandler(String nsURI, String localName, XMLFilterHandler config) { 486 return new LocationHandler(); 487 } 488 } 489 490 private abstract static class CDATAHandlerFactory implements FilterHandlerFactory { 491 private class CDATAHandler extends StringElementHandlerBase implements FilterHandler { 492 private FeatureFilter ourFilter; 493 494 public FeatureFilter getFeatureFilter() { 495 return ourFilter; 496 } 497 498 protected void setStringValue(String s) 499 throws SAXException 500 { 501 ourFilter = stringToFilter(s); 502 } 503 } 504 505 protected abstract FeatureFilter stringToFilter(String s) throws SAXException; 506 507 public FilterHandler makeHandler(String nsURI, String localName, XMLFilterHandler config) { 508 return new CDATAHandler(); 509 } 510 } 511 512 private static class AnnotationTypeHandlerFactory implements FilterHandlerFactory { 513 private class AnnotationTypeHandler extends StAXContentHandlerBase implements FilterHandler { 514 private int depth = 0; 515 private FeatureFilter filter; 516 517 public void startElement(String nsURI, 518 String localName, 519 String qName, 520 Attributes attrs, 521 DelegationManager dm) 522 throws SAXException 523 { 524 if (depth == 1) { 525 dm.delegate(new XMLAnnotationTypeHandler()); 526 } 527 ++depth; 528 } 529 530 public void endElement(String nsURI, 531 String localName, 532 String qName, 533 StAXContentHandler delegate) 534 throws SAXException 535 { 536 if (delegate instanceof XMLAnnotationTypeHandler) { 537 filter = new FeatureFilter.ByAnnotationType(((XMLAnnotationTypeHandler) delegate).getAnnotationType()); 538 } 539 --depth; 540 } 541 542 public FeatureFilter getFeatureFilter() { 543 return filter; 544 } 545 } 546 547 public FilterHandler makeHandler(String nsURI, String localName, XMLFilterHandler config) { 548 return new AnnotationTypeHandler(); 549 } 550 } 551 552 private class AnyFilterHandler extends StAXContentHandlerBase implements FilterHandler { 553 private FeatureFilter filter; 554 555 public FeatureFilter getFeatureFilter() { 556 return filter; 557 } 558 559 public void startElement(String nsURI, 560 String localName, 561 String qName, 562 Attributes attrs, 563 DelegationManager dm) 564 throws SAXException 565 { 566 FilterHandler h = getHandler(nsURI, localName); 567 dm.delegate(h); 568 } 569 570 public void endElement(String nsURI, 571 String localName, 572 String qName, 573 StAXContentHandler delegate) 574 throws SAXException 575 { 576 filter = ((FilterHandler) delegate).getFeatureFilter(); 577 } 578 } 579 580 /** 581 * Return a StAXContentHandler which can deal with any FilterXML construct known to this class. 582 */ 583 584 public FilterHandler getStAXContentHandler() { 585 return new AnyFilterHandler(); 586 } 587}