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.HashSet; 027import java.util.Iterator; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031 032import org.biojava.bio.AnnotationType; 033import org.biojava.bio.BioError; 034import org.biojava.bio.CardinalityConstraint; 035import org.biojava.bio.CollectionConstraint; 036import org.biojava.bio.PropertyConstraint; 037import org.biojava.bio.symbol.Location; 038import org.biojava.bio.symbol.LocationTools; 039import org.biojava.bio.symbol.RangeLocation; 040import org.biojava.utils.ChangeVetoException; 041import org.biojava.utils.ClassTools; 042import org.biojava.utils.stax.DelegationManager; 043import org.biojava.utils.stax.StAXContentHandler; 044import org.biojava.utils.stax.StAXContentHandlerBase; 045import org.biojava.utils.stax.StringElementHandlerBase; 046import org.xml.sax.Attributes; 047import org.xml.sax.SAXException; 048 049/** 050 * StAX handler for parsing AnnotationTypes in FilterXML documents. Mainly 051 * used internally by XMLFilterHandler. 052 * 053 * @author Thomas Down 054 * @since 1.3 055 */ 056 057public class XMLAnnotationTypeHandler extends StAXContentHandlerBase { 058 private Map handlerFactories = new HashMap(); 059 private Map collectionHandlerFactories = new HashMap(); 060 private AnnotationType annotationType = new AnnotationType.Impl(); 061 private int depth = 0; 062 063 /** 064 * Return the AnnotationType built by this handler 065 */ 066 067 public AnnotationType getAnnotationType() { 068 return annotationType; 069 } 070 071 /** 072 * Handler for an individual <code>PropertyConstraint</code> in an AnnotationType. 073 * Implement this if you want to add support for additional types of 074 * PropertyConstraint. 075 */ 076 077 public static interface PropertyConstraintHandler extends StAXContentHandler { 078 public PropertyConstraint getPropertyConstraint() throws SAXException; 079 } 080 081 /** 082 * Handler Factory for a <code>PropertyConstraint</code> in an AnnotationType. 083 * Implement this if you want to add support for additional types of 084 * PropertyConstraint. 085 */ 086 087 public static interface PropertyConstraintHandlerFactory { 088 public PropertyConstraintHandler makeHandler(String nsURI, 089 String localName) 090 throws SAXException; 091 } 092 093 /** 094 * Handler for an individual <code>CollectionConstraint</code> in an AnnotationType. 095 * Implement this if you want to add support for additional types of 096 * CollectionConstraint. 097 */ 098 099 public static interface CollectionConstraintHandler extends StAXContentHandler { 100 public CollectionConstraint getCollectionConstraint() throws SAXException; 101 } 102 103 /** 104 * Handler Factory for a <code>CollectionConstraint</code> in an AnnotationType. 105 * Implement this if you want to add support for additional types of 106 * CollectionConstraint. 107 */ 108 109 public static interface CollectionConstraintHandlerFactory { 110 public CollectionConstraintHandler makeHandler(String nsURI, 111 String localName) 112 throws SAXException; 113 } 114 115 /** 116 * Register a factory used to create handlers for the specified tag in an 117 * XML AnnotationType 118 */ 119 120 public void registerPropertyHandlerFactory(String nsURI, String localName, PropertyConstraintHandlerFactory factory) { 121 handlerFactories.put(new QName(nsURI, localName), factory); 122 } 123 124 /** 125 * Register a factory used to create handlers for the specified tag in an 126 * XML AnnotationType 127 */ 128 129 public void registerCollectionHandlerFactory(String nsURI, String localName, CollectionConstraintHandlerFactory factory) { 130 collectionHandlerFactories.put(new QName(nsURI, localName), factory); 131 } 132 133 134 135 private PropertyConstraintHandler getHandler(String nsURI, String localName) 136 throws SAXException 137 { 138 PropertyConstraintHandlerFactory factory = (PropertyConstraintHandlerFactory) handlerFactories.get(new QName(nsURI, localName)); 139 if (factory != null) { 140 return factory.makeHandler(nsURI, localName); 141 } else { 142 throw new SAXException("Unrecognized element (property context) " + nsURI + ":" + localName); 143 } 144 } 145 146 private CollectionConstraintHandler getCollectionHandler(String nsURI, String localName) 147 throws SAXException 148 { 149 CollectionConstraintHandlerFactory factory = (CollectionConstraintHandlerFactory) collectionHandlerFactories.get(new QName(nsURI, localName)); 150 if (factory != null) { 151 return factory.makeHandler(nsURI, localName); 152 } else { 153 throw new SAXException("Unrecognized element (collection context) " + nsURI + ":" + localName); 154 } 155 } 156 157 /** 158 * Construct a new XMLAnnotationTypeHandler which can parse the builtin PropertyConstraints. 159 */ 160 161 public XMLAnnotationTypeHandler() { 162 registerPropertyHandlerFactory( 163 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 164 "any", 165 new CDATAHandlerFactory() { 166 protected PropertyConstraint stringToConstraint(String s) { 167 return PropertyConstraint.ANY; 168 } 169 } 170 ); 171 registerPropertyHandlerFactory( 172 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 173 "none", 174 new CDATAHandlerFactory() { 175 protected PropertyConstraint stringToConstraint(String s) { 176 return PropertyConstraint.NONE; 177 } 178 } 179 ); 180 registerPropertyHandlerFactory( 181 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 182 "value", 183 new CDATAHandlerFactory() { 184 protected PropertyConstraint stringToConstraint(String s) { 185 return new PropertyConstraint.ExactValue(s); 186 } 187 } 188 ); 189 registerPropertyHandlerFactory( 190 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 191 "byClass", 192 new CDATAHandlerFactory() { 193 protected PropertyConstraint stringToConstraint(String s) 194 throws SAXException 195 { 196 try { 197 return new PropertyConstraint.ByClass(ClassTools.getClassLoader(this).loadClass(s)); 198 } catch (Exception ex) { 199 throw new SAXException("Couldn't find class " + s); 200 } 201 } 202 } 203 ); 204 registerPropertyHandlerFactory( 205 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 206 "and", 207 new ConstraintsHandlerFactory() { 208 public PropertyConstraint constraintsToConstraint(List l) 209 throws SAXException 210 { 211 PropertyConstraint pc = PropertyConstraint.ANY; 212 Iterator i = l.iterator(); 213 pc = (PropertyConstraint) i.next(); 214 while (i.hasNext()) { 215 pc = new PropertyConstraint.And(pc, (PropertyConstraint) i.next()); 216 } 217 return pc; 218 } 219 } 220 ); 221 registerPropertyHandlerFactory( 222 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 223 "or", 224 new ConstraintsHandlerFactory() { 225 public PropertyConstraint constraintsToConstraint(List l) 226 throws SAXException 227 { 228 boolean notValue = false; 229 for (Iterator i = l.iterator(); i.hasNext(); ) { 230 if (! (i.next() instanceof PropertyConstraint.ExactValue)) { 231 notValue = true; 232 } 233 } 234 if (notValue) { 235 PropertyConstraint pc = PropertyConstraint.ANY; 236 Iterator i = l.iterator(); 237 pc = (PropertyConstraint) i.next(); 238 while (i.hasNext()) { 239 pc = new PropertyConstraint.Or(pc, (PropertyConstraint) i.next()); 240 } 241 return pc; 242 } else { 243 Set values = new HashSet(); 244 for (Iterator i = l.iterator(); i.hasNext(); ) { 245 values.add(((PropertyConstraint.ExactValue) i.next()).getValue()); 246 } 247 return new PropertyConstraint.Enumeration(values); 248 } 249 } 250 } 251 ); 252 registerPropertyHandlerFactory( 253 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 254 "byAnnotationType", 255 new ByAnnotationTypeHandlerFactory() 256 ); 257 258 259 registerCollectionHandlerFactory( 260 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 261 "any", 262 new CDATACollectionHandlerFactory() { 263 protected CollectionConstraint stringToConstraint(String s) { 264 return CollectionConstraint.ANY; 265 } 266 } 267 ); 268 registerCollectionHandlerFactory( 269 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 270 "none", 271 new CDATACollectionHandlerFactory() { 272 protected CollectionConstraint stringToConstraint(String s) { 273 return CollectionConstraint.NONE; 274 } 275 } 276 ); 277 registerCollectionHandlerFactory( 278 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 279 "empty", 280 new CDATACollectionHandlerFactory() { 281 protected CollectionConstraint stringToConstraint(String s) { 282 return CollectionConstraint.EMPTY; 283 } 284 } 285 ); 286 registerCollectionHandlerFactory( 287 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 288 "and", 289 new ConstraintsCollectionHandlerFactory() { 290 public CollectionConstraint constraintsToConstraint(List l) 291 throws SAXException 292 { 293 CollectionConstraint pc = CollectionConstraint.ANY; 294 Iterator i = l.iterator(); 295 pc = (CollectionConstraint) i.next(); 296 while (i.hasNext()) { 297 pc = new CollectionConstraint.And(pc, (CollectionConstraint) i.next()); 298 } 299 return pc; 300 } 301 } 302 ); 303 registerCollectionHandlerFactory( 304 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 305 "or", 306 new ConstraintsCollectionHandlerFactory() { 307 public CollectionConstraint constraintsToConstraint(List l) 308 throws SAXException 309 { 310 CollectionConstraint pc = CollectionConstraint.ANY; 311 Iterator i = l.iterator(); 312 pc = (CollectionConstraint) i.next(); 313 while (i.hasNext()) { 314 pc = new CollectionConstraint.Or(pc, (CollectionConstraint) i.next()); 315 } 316 return pc; 317 } 318 } 319 ); 320 registerCollectionHandlerFactory( 321 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 322 "allValuesIn", 323 new PropCardCollectionHandlerFactory() { 324 public CollectionConstraint constraintsToConstraint(Location card, PropertyConstraint pc) 325 throws SAXException 326 { 327 return new CollectionConstraint.AllValuesIn(pc, card); 328 } 329 } 330 ); 331 registerCollectionHandlerFactory( 332 XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, 333 "contains", 334 new PropCardCollectionHandlerFactory() { 335 public CollectionConstraint constraintsToConstraint(Location card, PropertyConstraint pc) 336 throws SAXException 337 { 338 return new CollectionConstraint.Contains(pc, card); 339 } 340 } 341 ); 342 } 343 344 public void startElement(String nsURI, 345 String localName, 346 String qName, 347 Attributes attrs, 348 DelegationManager dm) 349 throws SAXException 350 { 351 if (depth == 1) { 352 if (localName.equals("propertyDefault")) { 353 // System.err.println("Handling default constraints"); 354 dm.delegate(new PropertyHandler() { 355 protected void setConstraint(CollectionConstraint cc) 356 throws ChangeVetoException 357 { 358 annotationType.setDefaultConstraint(cc); 359 } 360 } ); 361 } else if (localName.equals("property")) { 362 final Object propName = attrs.getValue(XMLAnnotationTypeWriter.XML_ANNOTATIONTYPE_NS, "name"); 363 // System.err.println("Handling constraints on " + propName); 364 dm.delegate(new PropertyHandler() { 365 protected void setConstraint(CollectionConstraint cc) 366 throws ChangeVetoException 367 { 368 annotationType.setConstraint(propName, cc); 369 } 370 } ); 371 } else { 372 throw new SAXException("Unexpected element " + nsURI + ":" + localName); 373 } 374 } 375 ++depth; 376 } 377 378 public void endElement(String nsURI, 379 String localName, 380 String qName, 381 StAXContentHandler delegate) 382 throws SAXException 383 { 384 --depth; 385 } 386 387 private abstract class PropertyHandler extends StAXContentHandlerBase { 388 private CollectionConstraint cons; 389 private int depth = 0; 390 391 public void startElement(String nsURI, 392 String localName, 393 String qName, 394 Attributes attrs, 395 DelegationManager dm) 396 throws SAXException 397 { 398 if (depth == 1) { 399 dm.delegate(getCollectionHandler(nsURI, localName)); 400 } 401 402 ++depth; 403 } 404 405 public void endElement(String nsURI, 406 String localName, 407 String qName, 408 StAXContentHandler delegate) 409 throws SAXException 410 { 411 --depth; 412 413 /* 414 415 if (delegate instanceof CardinalityHandler) { 416 cardinality = ((CardinalityHandler) delegate).getCardinality(); 417 } else if (delegate instanceof PropertyConstraintHandler) { 418 cons = ((PropertyConstraintHandler) delegate).getPropertyConstraint(); 419 } 420 421 */ 422 if (delegate instanceof CollectionConstraintHandler) { 423 cons = ((CollectionConstraintHandler) delegate).getCollectionConstraint(); 424 } 425 } 426 427 public void endTree() { 428 try { 429 setConstraint(cons); 430 } catch (ChangeVetoException ex) { 431 throw new BioError("Assertion failed: couldn't modify AnnotationType", ex); 432 } 433 } 434 435 protected abstract void setConstraint(CollectionConstraint cc) throws ChangeVetoException; 436 } 437 438 private class CardinalityHandler extends StAXContentHandlerBase { 439 private List spans = new ArrayList(); 440 441 public void startElement(String nsURI, 442 String localName, 443 String qName, 444 Attributes attrs, 445 DelegationManager dm) 446 throws SAXException 447 { 448 // System.err.println("CardinalityHandler: " + localName); 449 if ("span".equals(localName)) { 450 int start = Integer.parseInt(attrs.getValue("start")); 451 String stops = attrs.getValue("stop"); 452 int stop; 453 if (stops.equals("infinity")) { 454 stop = Integer.MAX_VALUE; 455 } else { 456 stop = Integer.parseInt(stops); 457 } 458 spans.add(new RangeLocation(start, stop)); 459 } 460 } 461 462 public Location getCardinality() { 463 // System.err.println("GetCardinality"); 464 return LocationTools.union(spans); 465 } 466 } 467 468 private abstract class CDATAHandlerFactory implements PropertyConstraintHandlerFactory { 469 private class CDATAHandler extends StringElementHandlerBase implements PropertyConstraintHandler { 470 private PropertyConstraint cons; 471 472 public PropertyConstraint getPropertyConstraint() { 473 return cons; 474 } 475 476 protected void setStringValue(String s) 477 throws SAXException 478 { 479 cons = stringToConstraint(s); 480 // System.err.println("stringToConstraint returned " + cons); 481 } 482 } 483 484 protected abstract PropertyConstraint stringToConstraint(String s) throws SAXException; 485 486 public PropertyConstraintHandler makeHandler(String nsURI, String localName) { 487 // System.err.println("Making CDATAHandler for " + localName); 488 return new CDATAHandler(); 489 } 490 } 491 492 private abstract class ConstraintsHandlerFactory implements PropertyConstraintHandlerFactory { 493 private class ConstraintsHandler extends StAXContentHandlerBase implements PropertyConstraintHandler { 494 private List constraintChildren = new ArrayList(); 495 private int depth = 0; 496 497 public void startElement(String nsURI, 498 String localName, 499 String qName, 500 Attributes attrs, 501 DelegationManager dm) 502 throws SAXException 503 { 504 if (depth == 1) { 505 PropertyConstraintHandler childHandler = getHandler(nsURI, localName); 506 dm.delegate(childHandler); 507 } 508 ++depth; 509 } 510 511 public void endElement(String nsURI, 512 String localName, 513 String qName, 514 StAXContentHandler delegate) 515 throws SAXException 516 { 517 if (delegate instanceof PropertyConstraintHandler) { 518 constraintChildren.add(((PropertyConstraintHandler) delegate).getPropertyConstraint()); 519 } 520 --depth; 521 } 522 523 public PropertyConstraint getPropertyConstraint() 524 throws SAXException 525 { 526 return constraintsToConstraint(constraintChildren); 527 } 528 } 529 530 protected abstract PropertyConstraint constraintsToConstraint(List filters) throws SAXException; 531 532 public PropertyConstraintHandler makeHandler(String nsURI, String localName) { 533 return new ConstraintsHandler(); 534 } 535 } 536 537 private class ByAnnotationTypeHandlerFactory implements PropertyConstraintHandlerFactory { 538 private class ByAnnotationTypeHandler extends StAXContentHandlerBase implements PropertyConstraintHandler { 539 private int depth = 0; 540 private AnnotationType annoType; 541 542 public void startElement(String nsURI, 543 String localName, 544 String qName, 545 Attributes attrs, 546 DelegationManager dm) 547 throws SAXException 548 { 549 if (depth == 1) { 550 dm.delegate(new XMLAnnotationTypeHandler()); 551 } 552 ++depth; 553 } 554 555 public void endElement(String nsURI, 556 String localName, 557 String qName, 558 StAXContentHandler delegate) 559 throws SAXException 560 { 561 if (delegate instanceof XMLAnnotationTypeHandler) { 562 annoType = ((XMLAnnotationTypeHandler) delegate).getAnnotationType(); 563 } 564 --depth; 565 } 566 567 public PropertyConstraint getPropertyConstraint() 568 throws SAXException 569 { 570 return new PropertyConstraint.ByAnnotationType(annoType); 571 } 572 } 573 574 public PropertyConstraintHandler makeHandler(String nsURI, String localName) { 575 return new ByAnnotationTypeHandler(); 576 } 577 } 578 579 private abstract class CDATACollectionHandlerFactory implements CollectionConstraintHandlerFactory { 580 private class CDATAHandler extends StringElementHandlerBase implements CollectionConstraintHandler { 581 private CollectionConstraint cons; 582 583 public CollectionConstraint getCollectionConstraint() { 584 return cons; 585 } 586 587 protected void setStringValue(String s) 588 throws SAXException 589 { 590 cons = stringToConstraint(s); 591 // System.err.println("stringToConstraint returned " + cons); 592 } 593 } 594 595 protected abstract CollectionConstraint stringToConstraint(String s) throws SAXException; 596 597 public CollectionConstraintHandler makeHandler(String nsURI, String localName) { 598 // System.err.println("Making CDATAHandler for " + localName); 599 return new CDATAHandler(); 600 } 601 } 602 603 private abstract class ConstraintsCollectionHandlerFactory implements CollectionConstraintHandlerFactory { 604 private class ConstraintsHandler extends StAXContentHandlerBase implements CollectionConstraintHandler { 605 private List constraintChildren = new ArrayList(); 606 private int depth = 0; 607 608 public void startElement(String nsURI, 609 String localName, 610 String qName, 611 Attributes attrs, 612 DelegationManager dm) 613 throws SAXException 614 { 615 if (depth == 1) { 616 CollectionConstraintHandler childHandler = getCollectionHandler(nsURI, localName); 617 dm.delegate(childHandler); 618 } 619 ++depth; 620 } 621 622 public void endElement(String nsURI, 623 String localName, 624 String qName, 625 StAXContentHandler delegate) 626 throws SAXException 627 { 628 if (delegate instanceof CollectionConstraintHandler) { 629 constraintChildren.add(((CollectionConstraintHandler) delegate).getCollectionConstraint()); 630 } 631 --depth; 632 } 633 634 public CollectionConstraint getCollectionConstraint() 635 throws SAXException 636 { 637 return constraintsToConstraint(constraintChildren); 638 } 639 } 640 641 protected abstract CollectionConstraint constraintsToConstraint(List filters) throws SAXException; 642 643 public CollectionConstraintHandler makeHandler(String nsURI, String localName) { 644 return new ConstraintsHandler(); 645 } 646 } 647 648 private abstract class PropCardCollectionHandlerFactory implements CollectionConstraintHandlerFactory { 649 private class PropCardHandler extends StAXContentHandlerBase implements CollectionConstraintHandler { 650 private Location cardinality; 651 private PropertyConstraint pc; 652 private int depth = 0; 653 654 public void startElement(String nsURI, 655 String localName, 656 String qName, 657 Attributes attrs, 658 DelegationManager dm) 659 throws SAXException 660 { 661 if (depth == 1) { 662 if ("cardinalityAny".equals(localName)) { 663 cardinality = CardinalityConstraint.ANY; 664 } else if ("cardinalityZero".equals(localName)) { 665 cardinality = CardinalityConstraint.ZERO; 666 } else if ("cardinalityOne".equals(localName)) { 667 cardinality = CardinalityConstraint.ONE; 668 } else if ("cardinalityNone".equals(localName)) { 669 cardinality = CardinalityConstraint.NONE; 670 } else if ("cardinality".equals(localName)) { 671 dm.delegate(new CardinalityHandler()); 672 } else { 673 dm.delegate(getHandler(nsURI, localName)); 674 } 675 } 676 ++depth; 677 } 678 679 public void endElement(String nsURI, 680 String localName, 681 String qName, 682 StAXContentHandler delegate) 683 throws SAXException 684 { 685 if (delegate instanceof CardinalityHandler) { 686 cardinality = ((CardinalityHandler) delegate).getCardinality(); 687 } else if (delegate instanceof PropertyConstraintHandler) { 688 pc = ((PropertyConstraintHandler) delegate).getPropertyConstraint(); 689 } 690 --depth; 691 } 692 693 public CollectionConstraint getCollectionConstraint() 694 throws SAXException 695 { 696 return constraintsToConstraint(cardinality, pc); 697 } 698 } 699 700 protected abstract CollectionConstraint constraintsToConstraint(Location card, PropertyConstraint pc) throws SAXException; 701 702 public CollectionConstraintHandler makeHandler(String nsURI, String localName) { 703 return new PropCardHandler(); 704 } 705 } 706}