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