View Javadoc
1 /* 2 * Copyright (c) 2003 3 * Information Desire GmbH 4 * All rights reserved. 5 */ 6 package com.infodesire.infobit.external.impl; 7 8 import com.infodesire.infobit.InfobitException; 9 10 import com.infodesire.infobit.external.ImportMessage; 11 12 import org.apache.commons.logging.Log; 13 import org.apache.commons.logging.LogFactory; 14 15 import org.xml.sax.Attributes; 16 import org.xml.sax.ContentHandler; 17 import org.xml.sax.InputSource; 18 import org.xml.sax.Locator; 19 import org.xml.sax.SAXException; 20 import org.xml.sax.SAXParseException; 21 import org.xml.sax.XMLReader; 22 23 import org.xml.sax.helpers.DefaultHandler; 24 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.io.OutputStream; 28 import java.io.Reader; 29 import java.io.Writer; 30 31 import java.net.URL; 32 33 import java.util.ArrayList; 34 import java.util.Calendar; 35 import java.util.Date; 36 import java.util.HashSet; 37 import java.util.List; 38 import java.util.Set; 39 40 import javax.xml.parsers.ParserConfigurationException; 41 import javax.xml.parsers.SAXParser; 42 import javax.xml.parsers.SAXParserFactory; 43 44 /*** 45 * Parses an external infobit representation into a graph of {@link BufferNode}s 46 * and {@link BufferEdge}s. Registers all infobits encountered to keep track of 47 * infobit cross references. 48 * 49 * @author peter2 50 * @created 1. September 2003 51 * @version $Revision: 1.23 $ 52 */ 53 class InfobitParser extends DefaultHandler { 54 55 private final static Log _log = LogFactory.getLog(InfobitParser.class); 56 57 /*** 58 * The collaborating semantic handler, used to keep track of infobit names 59 */ 60 private InfobitDictionary _dictionary; 61 62 /*** 63 * The collaborating diagnostics destination 64 */ 65 private ImportDiagnostics _diagnostics; 66 67 /*** 68 * Set of all buffered nodes. 69 */ 70 private List _bufferNodes = new ArrayList(); 71 72 /*** 73 * The stack of element handlers. 74 */ 75 private List _elementHandlers = new ArrayList(); 76 77 /*** 78 * Locator of the current parser, if applicable 79 */ 80 private Locator _locator; 81 82 /*** 83 * The location (line) of the most recent parse event. 84 */ 85 private int _currentLine; 86 87 /*** 88 * The location (row) of the most recent parse event. 89 */ 90 private int _currentColumn; 91 92 /*** 93 * The system ID of the the document entity 94 */ 95 private String _systemID; 96 97 98 /*** 99 * Initializes an instance from its collaboration environment. 100 * 101 * @param dict Description of Parameter 102 * @param diag Description of Parameter 103 */ 104 InfobitParser(ImportDiagnostics diag, InfobitDictionary dict) { 105 _diagnostics = diag; 106 _dictionary = dict; 107 } 108 109 110 111 //////////////////////////////////////////////////////////////////////// 112 // ContentHandler Implementation 113 //////////////////////////////////////////////////////////////////////// 114 115 /*** 116 * Accepts the current XML locator. 117 * 118 * @param loc The new DocumentLocator value 119 */ 120 public void setDocumentLocator(Locator loc) { 121 _locator = loc; 122 } 123 124 125 /*** 126 * Defined by the <code>ContentHandler</code> Interface. 127 * 128 * @param namespaceURI Description of Parameter 129 * @param localName Description of Parameter 130 * @param qName Description of Parameter 131 * @param atts Description of Parameter 132 * @exception SAXException Description of Exception 133 */ 134 public void startElement(String namespaceURI, 135 String localName, 136 String qName, 137 Attributes atts) 138 throws SAXException { 139 140 _log.trace("startElement: enter; localName: " + localName + 141 " qName: " + qName); 142 143 saveLocation(); 144 145 int n = _elementHandlers.size(); 146 if (n == 0) { 147 String m = "Failed assertion: empty handler stack"; 148 _log.fatal(m); 149 throw new RuntimeException(m); 150 } 151 152 ElementHandler tos = (ElementHandler) _elementHandlers.get(n - 1); 153 ElementHandler next = tos.start(qName); 154 if (next == null) { 155 String m = "unexpected element: " + qName; 156 error(m); 157 next = new ErrorHandler(); 158 } 159 160 if (!next.init(atts)) { 161 next = new ErrorHandler(); 162 } 163 164 _elementHandlers.add(next); 165 } 166 167 168 /*** 169 * DOCUMENT METHOD 170 * 171 * @param namespaceURI Description of Parameter 172 * @param localName Description of Parameter 173 * @param qName Description of Parameter 174 * @exception SAXException Description of Exception 175 */ 176 public void endElement(String namespaceURI, 177 String localName, 178 String qName) 179 throws SAXException { 180 181 _log.trace("endElement: enter: qName: " + qName); 182 saveLocation(); 183 184 int n = _elementHandlers.size(); 185 if (n < 2) { 186 String m = "Failed assertion: no element open"; 187 _log.error(m); 188 throw new RuntimeException(m); 189 } 190 191 boolean success = true; 192 ElementHandler closed = (ElementHandler) 193 _elementHandlers.remove(n - 1); 194 success = closed.complete(); 195 ElementHandler tos = (ElementHandler) _elementHandlers.get(n - 2); 196 success = success && tos.end(); 197 198 _log.trace("endElement: exit"); 199 } 200 201 202 /*** 203 * DOCUMENT METHOD 204 * 205 * @param ch Description of Parameter 206 * @param start Description of Parameter 207 * @param length Description of Parameter 208 * @exception SAXException Description of Exception 209 */ 210 public void characters(char[] ch, int start, int length) 211 throws SAXException { 212 213 int n = _elementHandlers.size(); 214 ElementHandler tos = (ElementHandler) _elementHandlers.get(n - 1); 215 tos.characters(ch, start, length); 216 } 217 218 219 //////////////////////////////////////////////////////////////////////// 220 // EntityResolver Implementation 221 //////////////////////////////////////////////////////////////////////// 222 223 /*** 224 * Reads entities of system IDs prefixed <q>http://www.infodesire/com/" from 225 * the classpath, accessing them by the path of the system ID. 226 * 227 * @param publicId Description of Parameter 228 * @param systemId Description of Parameter 229 * @return Description of the Returned Value 230 * @exception SAXException Description of Exception 231 * @exception IOException Description of Exception 232 */ 233 public InputSource resolveEntity(String publicId, 234 String systemId) 235 throws SAXException, IOException { 236 237 InputSource input = null; 238 URL si = new URL(systemId); 239 240 if (si.getHost().equals("www.infodesire.com")) { 241 String path = si.getPath(); 242 InputStream s = getClass().getResourceAsStream(path); 243 244 if (s != null) { 245 input = new InputSource(s); 246 input.setSystemId(path); 247 } 248 } 249 250 if (input == null) { 251 input = super.resolveEntity(publicId, systemId); 252 input.setSystemId(systemId); 253 } 254 255 return input; 256 } 257 258 259 /*** 260 * Gets all parsed buffer nodes. Valid after parsing. Nodes preserve the 261 * order of definition in the XML document, if possible. 262 * 263 * @return Callee-owned set of {@link BufferNode} 264 */ 265 List getBufferNodes() { 266 return _bufferNodes; 267 } 268 269 270 /*** 271 * Defines the collaborating semantics handler. 272 * 273 * @param dictionary The new Dictionary value 274 */ 275 void setDictionary(InfobitDictionary dictionary) { 276 _dictionary = dictionary; 277 } 278 279 280 /*** 281 * Defines the system ID of the root entity. 282 * 283 * @param s The new SystemID value 284 */ 285 void setSystemID(String s) { 286 _systemID = s; 287 } 288 289 290 /*** 291 * Converts the XML representation of exported infobits into an buffered 292 * graph. 293 * 294 * @param source Opened to read the XML document 295 * @exception InfobitException Description of Exception 296 */ 297 void buildTree(Reader source) throws InfobitException { 298 try { 299 RootDocHandler rootHandler = new RootDocHandler(); 300 _elementHandlers.clear(); 301 _elementHandlers.add(rootHandler); 302 303 SAXParserFactory fact = SAXParserFactory.newInstance(); 304 fact.setNamespaceAware(false); 305 fact.setValidating(true); 306 307 SAXParser parser = fact.newSAXParser(); 308 XMLReader reader = parser.getXMLReader(); 309 reader.setErrorHandler(this); 310 reader.setContentHandler(this); 311 reader.setDTDHandler(this); 312 reader.setEntityResolver(this); 313 314 InputSource input = new InputSource(source); 315 input.setSystemId(_systemID); 316 317 reader.parse(input); 318 319 } catch (SAXParseException e) { 320 // already handled by ErrorHandler implementation 321 } catch (SAXException e) { 322 String s = "generic import error parsing from _systemID"; 323 error(s, e); 324 } catch (IOException e) { 325 String s = "IO error parsing from " + _systemID; 326 error(s, e); 327 } catch (ParserConfigurationException e) { 328 _log.error(e); 329 throw new RuntimeException(e); 330 } 331 } 332 333 334 335 //////////////////////////////////////////////////////////////////////// 336 // ErrorHandler Implementation 337 //////////////////////////////////////////////////////////////////////// 338 339 //////////////////////////////////////////////////////////////////////// 340 // Implementation Private 341 //////////////////////////////////////////////////////////////////////// 342 343 /*** 344 * Saves the current parsing position, if available. 345 */ 346 private void saveLocation() { 347 if (_locator != null) { 348 _systemID = _locator.getSystemId(); 349 _currentLine = _locator.getLineNumber(); 350 _currentColumn = _locator.getColumnNumber(); 351 } 352 } 353 354 355 /*** 356 * Records an error condition, applicable to the {@link 357 * #saveLocation)current parsing condition. 358 * 359 * @param message Description of the error condition 360 */ 361 private void error(String message) { 362 error(message, null); 363 } 364 365 366 /*** 367 * Records an error condition, applicable to the {@link #saveLocation 368 * current parsing position}. 369 * 370 * @param message Error condition description 371 * @param cause Causing exception, or <code>null</code> if not applicable 372 */ 373 private void error(String message, Exception cause) { 374 375 String systemID = _systemID; 376 int line = _currentLine; 377 int col = _currentColumn; 378 379 if (systemID == null) { 380 systemID = "<unknown>"; 381 } 382 383 if (col == -1) { 384 col = 0; 385 } 386 387 if (line == -1) { 388 line = 0; 389 } 390 391 StringBuffer buf = new StringBuffer(message); 392 if (cause != null) { 393 buf.append(": "); 394 buf.append(cause.getMessage()); 395 } 396 String msg = buf.toString(); 397 398 ImportMessage m = 399 new ImportMessage(_systemID, line, col, msg); 400 _diagnostics.record(m); 401 402 if (cause != null) { 403 _log.error(msg, cause); 404 } 405 else { 406 _log.error(msg); 407 } 408 } 409 410 411 412 //////////////////////////////////////////////////////////////////////// 413 // Inner Classes 414 //////////////////////////////////////////////////////////////////////// 415 416 /*** 417 * Handles the document entity. 418 * 419 * @author peter2 420 * @created 1. September 2003 421 * @version $Revision: 1.23 $ 422 */ 423 class RootDocHandler extends ElementHandler { 424 425 /*** 426 * The handler of the document element 427 */ 428 private InfobitCollectionHandler _childHandler; 429 430 /*** 431 * The parsing result. List of parsed {@link InfobitNodes} 432 */ 433 private List _infobitNodes; 434 435 436 /*** 437 * DOCUMENT METHOD 438 * 439 * @param name Description of Parameter 440 * @return Description of the Returned Value 441 */ 442 ElementHandler start(String name) { 443 _childHandler = null; 444 ElementHandler eh = null; 445 446 if (name.equals("infobit-collection")) { 447 eh = _childHandler = new InfobitCollectionHandler(); 448 } 449 450 return eh; 451 } 452 453 454 /*** 455 * DOCUMENT METHOD 456 * 457 * @return Description of the Returned Value 458 */ 459 boolean end() { 460 _infobitNodes = _childHandler.getInfobitNodes(); 461 return true; 462 } 463 } 464 465 466 /*** 467 * Handles infobit-collection element 468 * 469 * @author peter2 470 * @created 1. September 2003 471 * @version $Revision: 1.23 $ 472 */ 473 class InfobitCollectionHandler extends ElementHandler { 474 475 /*** 476 * Parsed infobits. List of {@link InfobitBuffer}. 477 */ 478 private List _infobitNodes = new ArrayList(); 479 480 /*** 481 * The current child element handler 482 */ 483 private InfobitHandler _infobitHandler; 484 485 486 /*** 487 * Gets all infobits defined in the parsed element. 488 * 489 * @return List of {@link InfobitNode}s representing the infobits 490 * included as child elements in the parased element. 491 */ 492 List getInfobitNodes() { 493 return _infobitNodes; 494 } 495 496 497 /*** 498 * DOCUMENT METHOD 499 * 500 * @param name Description of Parameter 501 * @return Description of the Returned Value 502 */ 503 ElementHandler start(String name) { 504 _infobitHandler = null; 505 ElementHandler eh = null; 506 507 if (name.equals("coll-meta-info")) { 508 eh = new CollMetaInfoHandler(); 509 } 510 else if (name.equals("infobit")) { 511 eh = _infobitHandler = new InfobitHandler(); 512 } 513 514 return eh; 515 } 516 517 518 /*** 519 * DOCUMENT METHOD 520 * 521 * @return Description of the Returned Value 522 */ 523 boolean end() { 524 if (_infobitHandler != null) { 525 InfobitNode node = _infobitHandler.getInfobitNode(); 526 _infobitNodes.add(node); 527 } 528 529 return true; 530 } 531 532 } 533 534 535 /*** 536 * Handles coll-meta-info element. 537 * 538 * @author peter2 539 * @created 1. September 2003 540 * @version $Revision: 1.23 $ 541 */ 542 class CollMetaInfoHandler extends ElementHandler { 543 544 private DateHandler _dateHandler; 545 private PCDataBaseHandler _descHandler; 546 547 548 /*** 549 * DOCUMENT METHOD 550 * 551 * @param name Description of Parameter 552 * @return Description of the Returned Value 553 */ 554 ElementHandler start(String name) { 555 556 _dateHandler = null; 557 _descHandler = null; 558 ElementHandler eh = null; 559 560 if (name.equals("date")) { 561 eh = _dateHandler = new DateHandler(); 562 } 563 else if (name.equals("desc")) { 564 eh = _descHandler = new PCDataBaseHandler(); 565 } 566 567 return eh; 568 } 569 570 } 571 572 573 /*** 574 * Inner base class to handle parse events. 575 * 576 * @author peter2 577 * @created 1. September 2003 578 * @version $Revision: 1.23 $ 579 */ 580 private abstract class ElementHandler { 581 582 /*** 583 * Initializes the element handler before it receives {@link #start 584 * child element events}. The default implementation performs no 585 * operation. 586 * 587 * @param atts The attributes passed to the the current element 588 * @return The element has successfully been initialized 589 */ 590 boolean init(Attributes atts) { 591 return true; 592 } 593 594 595 /*** 596 * Called to handle start of element. Handles an element stack. This 597 * default implementation always returns an error. 598 * 599 * @param name (Local) name of the starting element 600 * @return The handler appropriate for the started elment, or 601 * <code>null<code> for an illegal child element 602 * 603 * 604 * 605 * 606 * 607 * 608 * 609 * 610 * 611 * 612 * 613 * 614 * 615 * 616 * 617 * 618 * 619 * 620 * 621 * 622 * 623 * 624 * 625 * 626 * 627 * 628 * 629 * 630 * 631 * 632 * 633 * 634 * 635 * 636 * 637 * 638 * 639 * 640 * 641 * 642 * 643 * 644 * 645 * 646 * 647 * 648 * 649 * 650 * 651 * 652 * 653 * 654 * 655 * 656 * 657 * 658 * 659 * 660 * 661 * 662 * 663 * 664 * 665 * 666 * 667 * 668 * 669 * 670 * 671 * 672 * 673 * 674 * 675 * 676 * 677 * 678 */ 679 ElementHandler start(String name) { 680 return null; 681 } 682 683 684 /*** 685 * Handles character data content. This default element signals an 686 * error. 687 * 688 * @param b Holds the characters to handle 689 * @param offset Index of the first byte to handle in <code>b</code> 690 * @param length Number of bytes to handle 691 * @return The data has successfully been processed 692 */ 693 boolean characters(char[] b, int offset, int length) { 694 695 _log.error(getClass().getName() + ": unexpected PCDATA"); 696 error("unexpected character data"); 697 return false; 698 } 699 700 701 /*** 702 * Called to handle end of element. This default implementation does 703 * nothing. 704 * 705 * @return The element has successfully been ended 706 * @exception SAXException Description of Exception 707 */ 708 boolean end() throws SAXException { 709 return true; 710 } 711 712 713 /*** 714 * Called after all content has been passed (by {@link #start start} or 715 * {@link #characters characters}). The default implementation performs 716 * no action. 717 * 718 * @return The element has successfully been completed. 719 */ 720 boolean complete() { 721 return true; 722 } 723 } 724 725 726 /*** 727 * Handles infobit element. 728 * 729 * @author peter2 730 * @created 1. September 2003 731 * @version $Revision: 1.23 $ 732 */ 733 private class InfobitHandler extends ElementHandler { 734 735 /*** 736 * Child content handler 737 */ 738 private VersionHandler _versionHandler; 739 740 private String _actualVersionName; 741 private ActualVersionNode _actualVersionNode; 742 private InfobitNode _infobitNode; 743 private ContentNode _previousVersionNode; 744 745 746 /*** 747 * Gets the represented infobit content. For use after element 748 * completion. 749 * 750 * @return The InfobitNode value 751 */ 752 InfobitNode getInfobitNode() { 753 return _infobitNode; 754 } 755 756 757 /*** 758 * DOCUMENT METHOD 759 * 760 * @param atts Description of Parameter 761 * @return Description of the Returned Value 762 */ 763 boolean init(Attributes atts) { 764 String name = atts.getValue("name"); 765 _actualVersionName = atts.getValue("actual-version-name"); 766 _infobitNode = new InfobitNode(); 767 _infobitNode.setName(name); 768 _infobitNode.setLocation(_systemID, _currentLine); 769 770 _bufferNodes.add(_infobitNode); 771 _dictionary.register(_infobitNode); 772 773 _previousVersionNode = null; 774 775 if (_actualVersionName != null) { 776 _actualVersionNode = new ActualVersionNode(); 777 _actualVersionNode.setInfobitNode(_infobitNode); 778 _actualVersionNode.setLocation(_systemID, _currentLine); 779 780 _bufferNodes.add(_actualVersionNode); 781 } 782 else { 783 _actualVersionNode = null; 784 } 785 786 return true; 787 } 788 789 790 /*** 791 * DOCUMENT METHOD 792 * 793 * @param name Description of Parameter 794 * @return Description of the Returned Value 795 */ 796 ElementHandler start(String name) { 797 ElementHandler eh = null; 798 799 if (name.equals("version")) { 800 eh = _versionHandler = new VersionHandler(); 801 } 802 803 return eh; 804 } 805 806 807 /*** 808 * DOCUMENT METHOD 809 * 810 * @return Description of the Returned Value 811 */ 812 boolean end() { 813 final String tag = getClass().getName() + ".end: "; 814 _log.trace(tag + "enter"); 815 816 if (_versionHandler != null) { 817 ContentNode contentNode = _versionHandler.getContentNode(); 818 819 _log.debug(tag + "setInfobitNode: _infobitNode null: " + 820 (_infobitNode == null) + "..."); 821 contentNode.setInfobitNode(_infobitNode); 822 _log.debug(tag + "...set"); 823 BufferEdge edge; 824 825 if (_previousVersionNode == null) { 826 edge = contentNode.addDependency(_infobitNode); 827 } 828 else { 829 edge = contentNode.addDependency(_previousVersionNode); 830 } 831 832 edge.setLocation(_systemID, _currentLine); 833 _previousVersionNode = contentNode; 834 835 if (_actualVersionNode != null && 836 _actualVersionName.equals(contentNode.getName())) { 837 838 _actualVersionNode.setActualVersionNode(contentNode); 839 BufferEdge e = 840 _actualVersionNode.addDependency(contentNode); 841 e.setLocation(_systemID, _currentLine); 842 } 843 } 844 845 return true; 846 } 847 848 } 849 850 851 /*** 852 * Handles version elements. 853 * 854 * @author peter2 855 * @created 1. September 2003 856 * @version $Revision: 1.23 $ 857 */ 858 private class VersionHandler extends ElementHandler { 859 860 /*** 861 * The parsed content 862 */ 863 private ContentNode _contentNode; 864 865 private DateHandler _dateHandler; 866 private ContentHandler _contentHandler; 867 868 private Date _date; 869 private String _name; 870 private String _author; 871 872 873 /*** 874 * Gets the imported version. 875 * 876 * @return The ContentNode value 877 */ 878 ContentNode getContentNode() { 879 return _contentNode; 880 } 881 882 883 /*** 884 * DOCUMENT METHOD 885 * 886 * @param atts Description of Parameter 887 * @return Description of the Returned Value 888 */ 889 boolean init(Attributes atts) { 890 _name = atts.getValue("name"); 891 _author = atts.getValue("author"); 892 893 return true; 894 } 895 896 897 /*** 898 * DOCUMENT METHOD 899 * 900 * @param name Description of Parameter 901 * @return Description of the Returned Value 902 */ 903 ElementHandler start(String name) { 904 ElementHandler eh = null; 905 _dateHandler = null; 906 _contentHandler = null; 907 908 if (name.equals("date")) { 909 eh = _dateHandler = new DateHandler(); 910 } 911 else if (name.equals("text-content")) { 912 eh = _contentHandler = new TextContentHandler(); 913 } 914 else if (name.equals("binary-content")) { 915 eh = _contentHandler = new BinaryContentHandler(); 916 } 917 else if (name.equals("template")) { 918 eh = _contentHandler = new TemplateHandler(); 919 } 920 else if (name.equals("script")) { 921 eh = _contentHandler = new ScriptHandler(); 922 } 923 924 return eh; 925 } 926 927 928 /*** 929 * DOCUMENT METHOD 930 * 931 * @return Description of the Returned Value 932 */ 933 boolean end() { 934 if (_dateHandler != null) { 935 _date = _dateHandler.getDate(); 936 } 937 else if (_contentHandler != null) { 938 _contentNode = _contentHandler.getContentNode(); 939 _contentNode.setDate(_date); 940 _contentNode.setAuthor(_author); 941 _contentNode.setName(_name); 942 } 943 944 return true; 945 } 946 947 } 948 949 950 /*** 951 * Handles genreic version content elements. 952 * 953 * @author peter2 954 * @created 1. September 2003 955 * @version $Revision: 1.23 $ 956 */ 957 private abstract class ContentHandler extends ElementHandler { 958 959 /*** 960 * Gets the parsed content version buffer node. 961 * 962 * @return The ContentNode value 963 */ 964 abstract ContentNode getContentNode(); 965 966 } 967 968 969 /*** 970 * Handles text-content nodes. 971 * 972 * @author peter2 973 * @created 1. September 2003 974 * @version $Revision: 1.23 $ 975 */ 976 private class TextContentHandler extends ContentHandler { 977 978 /*** 979 * Buffer representation of the parsed content 980 */ 981 private TextContentNode _textContentNode; 982 983 /*** 984 * Keyword assigned to the content. List of <code>String</code>. 985 */ 986 private List _keywords = new ArrayList(); 987 988 private Writer _textDestination; 989 990 private KeywordHandler _keywordHandler; 991 private PCDataBaseHandler _textHandler; 992 993 994 /*** 995 * Gets the parsed text content node. 996 * 997 * @return The parsed text content node 998 */ 999 ContentNode getContentNode() { 1000 return _textContentNode; 1001 } 1002 1003 1004 /*** 1005 * DOCUMENT METHOD 1006 * 1007 * @param atts Description of Parameter 1008 * @return Description of the Returned Value 1009 */ 1010 boolean init(Attributes atts) { 1011 _textContentNode = new TextContentNode(); 1012 _textContentNode.setLocation(_systemID, _currentLine); 1013 _bufferNodes.add(_textContentNode); 1014 1015 _keywords.clear(); 1016 1017 return true; 1018 } 1019 1020 1021 /*** 1022 * DOCUMENT METHOD 1023 * 1024 * @param name Description of Parameter 1025 * @return Description of the Returned Value 1026 */ 1027 ElementHandler start(String name) { 1028 ElementHandler eh = null; 1029 _keywordHandler = null; 1030 _textHandler = null; 1031 1032 if (name.equals("keyword")) { 1033 eh = _keywordHandler = new KeywordHandler(); 1034 } 1035 else if (name.equals("text")) { 1036 eh = _textHandler = new PCDataBaseHandler(); 1037 _textDestination = _textContentNode.getDestination(); 1038 _textHandler.setDestination(_textDestination); 1039 } 1040 1041 return eh; 1042 } 1043 1044 1045 /*** 1046 * DOCUMENT METHOD 1047 * 1048 * @return Description of the Returned Value 1049 */ 1050 boolean end() { 1051 boolean success = true; 1052 1053 try { 1054 if (_keywordHandler != null) { 1055 _keywords.add(_keywordHandler.getKeyword()); 1056 } 1057 else if (_textHandler != null) { 1058 _textDestination.close(); 1059 } 1060 } catch (IOException e) { 1061 error("Cannot complete PCDATA import", e); 1062 success = false; 1063 } 1064 1065 return success; 1066 } 1067 1068 } 1069 1070 1071 /*** 1072 * Handles binary-content element. 1073 * 1074 * @author peter2 1075 * @created 1. September 2003 1076 * @version $Revision: 1.23 $ 1077 */ 1078 private class BinaryContentHandler extends ContentHandler { 1079 1080 private List _keywords = new ArrayList(); 1081 private OutputStream _dataDestination; 1082 1083 private KeywordHandler _keywordHandler; 1084 private DataHandler _dataHandler; 1085 1086 private BinaryContentNode _binaryContentNode; 1087 1088 1089 /*** 1090 * Gets the parsed binary content node. 1091 * 1092 * @return The parsed text content node 1093 */ 1094 ContentNode getContentNode() { 1095 return _binaryContentNode; 1096 } 1097 1098 1099 /*** 1100 * DOCUMENT METHOD 1101 * 1102 * @param atts Description of Parameter 1103 * @return Description of the Returned Value 1104 */ 1105 boolean init(Attributes atts) { 1106 String mimeType = atts.getValue("mime-type"); 1107 _binaryContentNode = new BinaryContentNode(); 1108 _binaryContentNode.setMimeType(mimeType); 1109 _binaryContentNode.setLocation(_systemID, _currentLine); 1110 1111 _bufferNodes.add(_binaryContentNode); 1112 1113 return true; 1114 } 1115 1116 1117 /*** 1118 * DOCUMENT METHOD 1119 * 1120 * @param name Description of Parameter 1121 * @return Description of the Returned Value 1122 */ 1123 ElementHandler start(String name) { 1124 ElementHandler eh = null; 1125 _keywordHandler = null; 1126 _dataHandler = null; 1127 1128 if (name.equals("keyword")) { 1129 eh = _keywordHandler = new KeywordHandler(); 1130 } 1131 else if (name.equals("data")) { 1132 eh = _dataHandler = new DataHandler(); 1133 _dataDestination = _binaryContentNode.getDestination(); 1134 _dataHandler.setDestination(_dataDestination); 1135 } 1136 1137 return eh; 1138 } 1139 1140 1141 /*** 1142 * DOCUMENT METHOD 1143 * 1144 * @return Description of the Returned Value 1145 */ 1146 boolean end() { 1147 boolean success = true; 1148 1149 try { 1150 if (_keywordHandler != null) { 1151 _keywords.add(_keywordHandler.getKeyword()); 1152 } 1153 else if (_dataHandler != null) { 1154 _dataDestination.close(); 1155 } 1156 } catch (IOException e) { 1157 error("Cannot complete binary data import", e); 1158 success = false; 1159 } 1160 1161 return success; 1162 } 1163 1164 } 1165 1166 1167 /*** 1168 * Handles template elements. 1169 * 1170 * @author peter2 1171 * @created 1. September 2003 1172 * @version $Revision: 1.23 $ 1173 */ 1174 private class TemplateHandler extends ContentHandler { 1175 1176 /*** 1177 * Buffer representation of the parsed template 1178 */ 1179 private TemplateNode _templateNode; 1180 1181 /*** 1182 * Child content handler 1183 */ 1184 private PCDataBaseHandler _textHandler; 1185 1186 1187 /*** 1188 * Gets the parsed template node. 1189 * 1190 * @return The parsed text content node 1191 */ 1192 ContentNode getContentNode() { 1193 return _templateNode; 1194 } 1195 1196 1197 /*** 1198 * DOCUMENT METHOD 1199 * 1200 * @param atts Description of Parameter 1201 * @return Description of the Returned Value 1202 */ 1203 boolean init(Attributes atts) { 1204 _templateNode = new TemplateNode(); 1205 _templateNode.setLocation(_systemID, _currentLine); 1206 1207 _bufferNodes.add(_templateNode); 1208 1209 return true; 1210 } 1211 1212 1213 /*** 1214 * DOCUMENT METHOD 1215 * 1216 * @param name Description of Parameter 1217 * @return Description of the Returned Value 1218 */ 1219 ElementHandler start(String name) { 1220 ElementHandler eh = null; 1221 1222 if (name.equals("text")) { 1223 eh = _textHandler = new PCDataBaseHandler(); 1224 Writer dest = _templateNode.getDestination(); 1225 _textHandler.setDestination(dest); 1226 } 1227 1228 return eh; 1229 } 1230 } 1231 1232 1233 /*** 1234 * Handles script elements. 1235 * 1236 * @author peter2 1237 * @created 1. September 2003 1238 * @version $Revision: 1.23 $ 1239 */ 1240 private class ScriptHandler extends ContentHandler { 1241 1242 /*** 1243 * Buffer representation of the parsed script content 1244 */ 1245 private ScriptNode _scriptNode; 1246 1247 private List _keywords = new ArrayList(); 1248 1249 private KeywordHandler _keywordHandler; 1250 private LinkHandler _linkHandler; 1251 1252 1253 /*** 1254 * Gets the parsed script node. 1255 * 1256 * @return The parsed script node 1257 */ 1258 ContentNode getContentNode() { 1259 return _scriptNode; 1260 } 1261 1262 1263 /*** 1264 * DOCUMENT METHOD 1265 * 1266 * @param atts Description of Parameter 1267 * @return Description of the Returned Value 1268 */ 1269 boolean init(Attributes atts) { 1270 String templateName = atts.getValue("template-name"); 1271 _scriptNode = new ScriptNode(); 1272 _scriptNode.setLocation(_systemID, _currentLine); 1273 1274 InfobitNode template = _dictionary.lookup(templateName); 1275 _scriptNode.setTemplateNode(template); 1276 BufferEdge edge = _scriptNode.addDependency(template); 1277 edge.setLocation(_systemID, _currentLine); 1278 1279 _bufferNodes.add(_scriptNode); 1280 1281 return true; 1282 } 1283 1284 1285 /*** 1286 * DOCUMENT METHOD 1287 * 1288 * @param name Description of Parameter 1289 * @return Description of the Returned Value 1290 */ 1291 ElementHandler start(String name) { 1292 ElementHandler eh = null; 1293 _keywordHandler = null; 1294 _linkHandler = null; 1295 1296 if (name.equals("keyword")) { 1297 eh = _keywordHandler = new KeywordHandler(); 1298 } 1299 else if (name.equals("link")) { 1300 eh = _linkHandler = new LinkHandler(); 1301 } 1302 1303 return eh; 1304 } 1305 1306 1307 /*** 1308 * DOCUMENT METHOD 1309 * 1310 * @return Description of the Returned Value 1311 */ 1312 boolean end() { 1313 if (_keywordHandler != null) { 1314 _keywords.add(_keywordHandler.getKeyword()); 1315 } 1316 else if (_linkHandler != null) { 1317 String key = _linkHandler.getKey(); 1318 String valueName = _linkHandler.getValueName(); 1319 InfobitNode valueNode = _dictionary.lookup(valueName); 1320 _scriptNode.addLink(key, valueNode); 1321 BufferEdge edge = _scriptNode.addDependency(valueNode); 1322 edge.setLocation(_systemID, _currentColumn); 1323 } 1324 1325 return true; 1326 } 1327 1328 } 1329 1330 1331 /*** 1332 * Handles date elements. 1333 * 1334 * @author peter2 1335 * @created 1. September 2003 1336 * @version $Revision: 1.23 $ 1337 */ 1338 private class DateHandler extends ElementHandler { 1339 1340 Date _date; 1341 1342 1343 /*** 1344 * Gets the represented date. 1345 * 1346 * @return The Date value 1347 */ 1348 Date getDate() { 1349 return _date; 1350 } 1351 1352 1353 /*** 1354 * DOCUMENT METHOD 1355 * 1356 * @param atts Description of Parameter 1357 * @return Description of the Returned Value 1358 */ 1359 boolean init(Attributes atts) { 1360 boolean success = false; 1361 1362 try { 1363 int year = Integer.parseInt(atts.getValue("year")); 1364 int month = Integer.parseInt(atts.getValue("month")); 1365 int day = Integer.parseInt(atts.getValue("day")); 1366 1367 Calendar cal = Calendar.getInstance(); 1368 cal.clear(); 1369 cal.set(year, month - 1, day); 1370 1371 _date = cal.getTime(); 1372 success = true; 1373 } catch (NumberFormatException e) { 1374 error("Illegally formatted date attribute values: " + e); 1375 } catch (IllegalArgumentException e) { 1376 error("Illegal date attribute values: " + e); 1377 } 1378 1379 return success; 1380 } 1381 1382 } 1383 1384 1385 /*** 1386 * Handles PCDATA content. Replaces predefined GE references. 1387 * 1388 * @author peter2 1389 * @created 1. September 2003 1390 * @version $Revision: 1.23 $ 1391 */ 1392 private class PCDataBaseHandler extends ElementHandler { 1393 1394 /*** 1395 * Auxiliary instance used to decode 1396 */ 1397 private EntityReferenceDecoder _decoder = new EntityReferenceDecoder(); 1398 1399 1400 /*** 1401 * Defines the destination of the text content 1402 * 1403 * @param dest The new Destination value 1404 */ 1405 void setDestination(Writer dest) { 1406 _decoder.setDestination(dest); 1407 } 1408 1409 1410 /*** 1411 * DOCUMENT METHOD 1412 * 1413 * @param b Description of Parameter 1414 * @param offset Description of Parameter 1415 * @param length Description of Parameter 1416 * @return Description of the Returned Value 1417 */ 1418 boolean characters(char[] b, int offset, int length) { 1419 boolean success = false; 1420 1421 try { 1422 _decoder.decodeChunk(b, offset, length); 1423 success = true; 1424 } catch (IOException e) { 1425 error("Cannot read/store element content"); 1426 } 1427 1428 return success; 1429 } 1430 1431 1432 /*** 1433 * DOCUMENT METHOD 1434 * 1435 * @return Description of the Returned Value 1436 */ 1437 boolean complete() { 1438 boolean success = false; 1439 1440 try { 1441 _decoder.endOfText(); 1442 success = true; 1443 } catch (IOException e) { 1444 error("Cannot store text content"); 1445 } 1446 1447 return success; 1448 } 1449 } 1450 1451 1452 /*** 1453 * Handles keyword elements. 1454 * 1455 * @author peter2 1456 * @created 1. September 2003 1457 * @version $Revision: 1.23 $ 1458 */ 1459 private class KeywordHandler extends ElementHandler { 1460 1461 /*** 1462 * The <code>key</code> attribute value 1463 */ 1464 private String _key; 1465 1466 1467 /*** 1468 * Gets the provided keyword. 1469 * 1470 * @return The Keyword value 1471 */ 1472 String getKeyword() { 1473 return _key; 1474 } 1475 1476 1477 /*** 1478 * DOCUMENT METHOD 1479 * 1480 * @param atts Description of Parameter 1481 * @return Description of the Returned Value 1482 */ 1483 boolean init(Attributes atts) { 1484 _key = atts.getValue("key"); 1485 return true; 1486 } 1487 1488 } 1489 1490 1491 /*** 1492 * Handles data elements. 1493 * 1494 * @author peter2 1495 * @created 1. September 2003 1496 * @version $Revision: 1.23 $ 1497 */ 1498 private class DataHandler extends ElementHandler { 1499 1500 /*** 1501 * Destination where to send decoded data to 1502 */ 1503 private OutputStream _destination; 1504 1505 /*** 1506 * Decoder to use 1507 */ 1508 private Decoder _decoder; 1509 1510 1511 /*** 1512 * Defines the destination where to put the content to 1513 * 1514 * @param dest The new Destination value 1515 */ 1516 void setDestination(OutputStream dest) { 1517 _destination = dest; 1518 } 1519 1520 1521 /*** 1522 * DOCUMENT METHOD 1523 * 1524 * @param atts Description of Parameter 1525 * @return Description of the Returned Value 1526 */ 1527 boolean init(Attributes atts) { 1528 final String tag = getClass().getName() + ".init: "; 1529 _log.trace(tag + "enter"); 1530 1531 boolean success = false; 1532 1533 String encoding = atts.getValue("encoding"); 1534 String l = atts.getValue("content-length"); 1535 int contentLength = -1; 1536 1537 try { 1538 contentLength = Integer.parseInt(l); 1539 } catch (NumberFormatException e) { 1540 // null; 1541 } 1542 1543 if (!encoding.equalsIgnoreCase("base64")) { 1544 error("Unsupported encoding: " + encoding); 1545 } 1546 else if (contentLength < 0) { 1547 error("Illegal content length: " + l); 1548 } 1549 else { 1550 _decoder = new Base64Decoder(); 1551 _decoder.setDestination(_destination); 1552 _decoder.setContentLength(contentLength); 1553 success = true; 1554 } 1555 1556 _log.trace(tag + "exit: " + success); 1557 1558 return success; 1559 } 1560 1561 1562 /*** 1563 * DOCUMENT METHOD 1564 * 1565 * @param b Description of Parameter 1566 * @param offset Description of Parameter 1567 * @param length Description of Parameter 1568 * @return Description of the Returned Value 1569 */ 1570 boolean characters(char[] b, int offset, int length) { 1571 boolean success = false; 1572 1573 final String tag = getClass().getName() + ".characters: "; 1574 _log.trace(tag + "enter"); 1575 _log.debug(tag + "data: " + new String(b, offset, length)); 1576 1577 try { 1578 if (!_decoder.hasError()) { 1579 _decoder.decodeChunk(b, offset, length); 1580 success = !_decoder.hasError(); 1581 1582 if (!success) { 1583 error("Cannot decode data: " + 1584 _decoder.getErrorText()); 1585 } 1586 } 1587 1588 } catch (IOException e) { 1589 error("Cannot process encoded binary data", e); 1590 } catch (Exception e) { 1591 error("Generic error: ", e); 1592 } 1593 1594 _log.trace(tag + "exit: " + success); 1595 1596 return success; 1597 } 1598 1599 1600 /*** 1601 * DOCUMENT METHOD 1602 * 1603 * @return Description of the Returned Value 1604 * @exception SAXException Description of Exception 1605 */ 1606 boolean end() throws SAXException { 1607 boolean success = false; 1608 1609 final String tag = getClass().getName(); 1610 _log.trace(tag + "enter"); 1611 1612 try { 1613 if (!_decoder.hasError()) { 1614 _decoder.endOfData(); 1615 success = !_decoder.hasError(); 1616 1617 if (!success) { 1618 error("Cannot decode data: " + 1619 _decoder.getErrorText()); 1620 } 1621 } 1622 } catch (IOException e) { 1623 error("Cannot process encoded binary data", e); 1624 } 1625 1626 _log.trace(tag + "exit: " + success); 1627 1628 return success; 1629 } 1630 } 1631 1632 1633 /*** 1634 * Processes link elements. 1635 * 1636 * @author peter2 1637 * @created 1. September 2003 1638 * @version $Revision: 1.23 $ 1639 */ 1640 private class LinkHandler extends ElementHandler { 1641 1642 private String _key; 1643 private String _valueName; 1644 1645 1646 /*** 1647 * Gets the <code>key</code> attribute value. 1648 * 1649 * @return The Key value 1650 */ 1651 String getKey() { 1652 return _key; 1653 } 1654 1655 1656 /*** 1657 * Gets the <code>value-name</code> attribute value. 1658 * 1659 * @return The ValueName value 1660 */ 1661 String getValueName() { 1662 return _valueName; 1663 } 1664 1665 1666 /*** 1667 * DOCUMENT METHOD 1668 * 1669 * @param atts Description of Parameter 1670 * @return Description of the Returned Value 1671 */ 1672 boolean init(Attributes atts) { 1673 _key = atts.getValue("key"); 1674 _valueName = atts.getValue("value-name"); 1675 1676 return true; 1677 } 1678 1679 } 1680 1681 1682 /*** 1683 * Void element handler, to recover from errors. 1684 * 1685 * @author peter2 1686 * @created 2. September 2003 1687 * @version $Revision: 1.23 $ 1688 */ 1689 private class ErrorHandler extends ElementHandler { 1690 1691 /*** 1692 * Always returns an error handler. 1693 * 1694 * @param name Description of Parameter 1695 * @return Description of the Returned Value 1696 */ 1697 ElementHandler start(String name) { 1698 return new ErrorHandler(); 1699 } 1700 1701 1702 /*** 1703 * Ignores all characters. 1704 * 1705 * @param b Description of Parameter 1706 * @param offset Description of Parameter 1707 * @param length Description of Parameter 1708 * @return Description of the Returned Value 1709 */ 1710 boolean characters(char[] b, int offset, int length) { 1711 return true; 1712 } 1713 } 1714 1715 }

This page was automatically generated by Maven