View Javadoc

1   package net.sf.tomp.xtcl.filter;
2   
3   import org.xml.sax.Attributes;
4   import org.xml.sax.ContentHandler;
5   import org.xml.sax.DTDHandler;
6   import org.xml.sax.EntityResolver;
7   import org.xml.sax.ErrorHandler;
8   import org.xml.sax.InputSource;
9   import org.xml.sax.Locator;
10  import org.xml.sax.SAXException;
11  import org.xml.sax.SAXNotRecognizedException;
12  import org.xml.sax.SAXNotSupportedException;
13  import org.xml.sax.SAXParseException;
14  import org.xml.sax.XMLFilter;
15  import org.xml.sax.XMLReader;
16  import org.xml.sax.ext.LexicalHandler;
17  
18  import java.io.IOException;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  import java.util.Properties;
23  
24  /***
25   * DOCUMENT ME!
26   * 
27   * @author tomp
28   */
29  public class DynamicMultiFilterImpl extends XTFilterImpl implements
30          DynamicMultiFilter {
31      ////////////////////////////////////////////////////////////////////
32      // Internal state.
33      ////////////////////////////////////////////////////////////////////
34  
35      /*** DOCUMENT ME! */
36      protected List filters;
37  
38      /*** DOCUMENT ME! */
39      protected XMLFilter firstFilter = null;
40  
41      /*** DOCUMENT ME! */
42      protected XMLFilter lastFilter = null;
43  
44      /*** DOCUMENT ME! */
45      protected boolean isContentHandler;
46  
47      /*** DOCUMENT ME! */
48      protected boolean isDTDHandler;
49  
50      /*** DOCUMENT ME! */
51      protected boolean isErrorHandler;
52  
53      /*** DOCUMENT ME! */
54      protected boolean isLexicalHandler;
55  
56      /*** DOCUMENT ME! */
57      protected boolean isEntityResolver;
58  
59      /*** DOCUMENT ME! */
60      protected HasOutputProperties outputPropertiesListener = null;
61  
62      ////////////////////////////////////////////////////////////////////
63      // Constructors.
64      ////////////////////////////////////////////////////////////////////
65      public DynamicMultiFilterImpl() {
66          super();
67          filters = new ArrayList();
68  
69          //setFilter(f);
70      }
71  
72      /***
73       * Creates a new DynamicMultiFilterImpl object.
74       * 
75       * @param parent DOCUMENT ME!
76       */
77      public DynamicMultiFilterImpl(XMLReader parent) {
78          this();
79          setParent(parent);
80      }
81  
82      ////////////////////////////////////////////////////////////////////
83      // Implementation of org.xml.sax.XMLFilter.
84      ////////////////////////////////////////////////////////////////////
85      public void setParent(XMLReader parent) {
86          super.setParent(parent);
87  
88          //System.out.println(" ***DynamicMultiFilter:"+this+"
89          // setParent="+parent+"... ");
90          if (firstFilter != null) {
91              connectHandlers(parent, firstFilter);
92  
93              //firstFilter.setParent(parent);
94              //System.out.println("... also to firstFilter="+firstFilter);
95          }
96      }
97  
98      ////////////////////////////////////////////////////////////////////
99      // Implementation of org.xml.sax.XMLReader.
100     ////////////////////////////////////////////////////////////////////
101     public void setFeature(String name, boolean value)
102             throws SAXNotRecognizedException, SAXNotSupportedException {
103         // FIXME: setFeature to all filters or the 1st only?
104         if (firstFilter != null) {
105             firstFilter.setFeature(name, value);
106         }
107 
108         super.setFeature(name, value);
109     }
110 
111     /***
112      * DOCUMENT ME!
113      * 
114      * @param name DOCUMENT ME!
115      * @return DOCUMENT ME!
116      * @throws SAXNotRecognizedException DOCUMENT ME!
117      * @throws SAXNotSupportedException DOCUMENT ME!
118      */
119     public boolean getFeature(String name) throws SAXNotRecognizedException,
120             SAXNotSupportedException {
121         // FIXME: the same problem
122         if (firstFilter != null) {
123             return firstFilter.getFeature(name);
124         } else {
125             return super.getFeature(name);
126         }
127     }
128 
129     /*
130      * public void setProperty (String name, Object value) throws
131      * SAXNotRecognizedException, SAXNotSupportedException { if(firstFilter !=
132      * null) firstFilter.setProperty(name, value); super.setProperty(name,
133      * value); }
134      */
135 
136     /***
137      * Look up the value of a property.
138      * 
139      * @param name The property name.
140      * @return The current value of the property.
141      * @exception SAXNotRecognizedException If the property value can't be
142      *                assigned or retrieved from the parent.
143      * @exception SAXNotSupportedException When the parent recognizes the
144      *                property name but cannot determine its value at this time.
145      */
146     public Object getProperty(String name) throws SAXNotRecognizedException,
147             SAXNotSupportedException {
148         if (firstFilter != null) {
149             return firstFilter.getProperty(name);
150         } else {
151             return super.getProperty(name);
152         }
153     }
154 
155     /***
156      * Set the entity resolver.
157      * 
158      * @param resolver The new entity resolver.
159      */
160     public void setEntityResolver(EntityResolver resolver) {
161         // FIXME: to all???
162         if (firstFilter != null) {
163             firstFilter.setEntityResolver(resolver);
164         }
165 
166         super.setEntityResolver(resolver);
167     }
168 
169     /***
170      * Get the current entity resolver.
171      * 
172      * @return The current entity resolver, or null if none was set.
173      */
174     public EntityResolver getEntityResolver() {
175         if (firstFilter != null) {
176             return firstFilter.getEntityResolver();
177         } else {
178             return super.getEntityResolver();
179         }
180     }
181 
182     /***
183      * Set the DTD event handler.
184      * 
185      * @param handler The new DTD handler.
186      */
187     public void setDTDHandler(DTDHandler handler) {
188         if (lastFilter != null) {
189             lastFilter.setDTDHandler(handler);
190         }
191 
192         super.setDTDHandler(handler);
193     }
194 
195     /***
196      * Get the current DTD event handler.
197      * 
198      * @return The current DTD handler, or null if none was set.
199      */
200     public DTDHandler getDTDHandler() {
201         if (lastFilter != null) {
202             return lastFilter.getDTDHandler();
203         } else {
204             return super.getDTDHandler();
205         }
206     }
207 
208     /***
209      * Set the content event handler.
210      * 
211      * @param handler The new content handler.
212      */
213     public void setContentHandler(ContentHandler handler) {
214         //System.out.println(""+this+".setContentHandler="+handler);
215         if (lastFilter != null) {
216             lastFilter.setContentHandler(handler);
217         }
218 
219         super.setContentHandler(handler);
220     }
221 
222     /***
223      * Get the content event handler.
224      * 
225      * @return The current content handler, or null if none was set.
226      */
227     public ContentHandler getContentHandler() {
228         //System.out.println(""+this+".getContentHandler=>"+contentHandler);
229         if (lastFilter != null) {
230             return lastFilter.getContentHandler();
231         } else {
232             return super.getContentHandler();
233         }
234     }
235 
236     /***
237      * Set the error event handler.
238      * 
239      * @param handler The new error handler.
240      */
241     public void setErrorHandler(ErrorHandler handler) {
242         if (lastFilter != null) {
243             lastFilter.setErrorHandler(handler);
244         }
245 
246         super.setErrorHandler(handler);
247     }
248 
249     /***
250      * Get the current error event handler.
251      * 
252      * @return The current error handler, or null if none was set.
253      */
254     public ErrorHandler getErrorHandler() {
255         if (lastFilter != null) {
256             return lastFilter.getErrorHandler();
257         } else {
258             return super.getErrorHandler();
259         }
260     }
261 
262     /***
263      * Parse a document.
264      * 
265      * @param input The input source for the document entity.
266      * @exception SAXException Any SAX exception, possibly wrapping another
267      *                exception.
268      * @exception IOException An IO exception from the parser, possibly from a
269      *                byte stream or character stream supplied by the
270      *                application.
271      */
272     public void parse(InputSource input) throws SAXException, IOException {
273         if (lastFilter != null) {
274             lastFilter.parse(input);
275         } else {
276             super.parse(input);
277         }
278     }
279 
280     ////////////////////////////////////////////////////////////////////
281     // Implementation of org.xml.sax.EntityResolver.
282     ////////////////////////////////////////////////////////////////////
283 
284     /***
285      * Filter an external entity resolution.
286      * 
287      * @param publicId The entity's public identifier, or null.
288      * @param systemId The entity's system identifier.
289      * @return A new InputSource or null for the default.
290      * @exception SAXException The client may throw an exception during
291      *                processing.
292      * @exception IOException The client may throw an I/O-related exception
293      *                while obtaining the new InputSource.
294      */
295     public InputSource resolveEntity(String publicId, String systemId)
296             throws SAXException, IOException {
297         // FIXME ??? firstFilter or last or what?
298         if ((firstFilter != null) && isEntityResolver) {
299             return ((EntityResolver) firstFilter).resolveEntity(publicId,
300                     systemId);
301         } else {
302             return super.resolveEntity(publicId, systemId);
303         }
304     }
305 
306     ////////////////////////////////////////////////////////////////////
307     // Implementation of org.xml.sax.DTDHandler.
308     ////////////////////////////////////////////////////////////////////
309 
310     /***
311      * Filter a notation declaration event.
312      * 
313      * @param name The notation name.
314      * @param publicId The notation's public identifier, or null.
315      * @param systemId The notation's system identifier, or null.
316      * @exception SAXException The client may throw an exception during
317      *                processing.
318      */
319     public void notationDecl(String name, String publicId, String systemId)
320             throws SAXException {
321         if (firstFilter != null) {
322             if (isDTDHandler) {
323                 ((DTDHandler) firstFilter).notationDecl(name, publicId,
324                         systemId);
325             } else {
326                 super.notationDecl(name, publicId, systemId);
327             }
328         }
329     }
330 
331     /***
332      * Filter an unparsed entity declaration event.
333      * 
334      * @param name The entity name.
335      * @param publicId The entity's public identifier, or null.
336      * @param systemId The entity's system identifier, or null.
337      * @param notationName The name of the associated notation.
338      * @exception SAXException The client may throw an exception during
339      *                processing.
340      */
341     public void unparsedEntityDecl(String name, String publicId,
342             String systemId, String notationName) throws SAXException {
343         if (firstFilter != null) {
344             if (isDTDHandler) {
345                 ((DTDHandler) firstFilter).unparsedEntityDecl(name, publicId,
346                         systemId, notationName);
347             }
348         } else {
349             super.unparsedEntityDecl(name, publicId, systemId, notationName);
350         }
351     }
352 
353     ////////////////////////////////////////////////////////////////////
354     // Implementation of org.xml.sax.ContentHandler.
355     ////////////////////////////////////////////////////////////////////
356 
357     /***
358      * Filter a new document locator event.
359      * 
360      * @param locator The document locator.
361      */
362     public void setDocumentLocator(Locator locator) {
363         if (firstFilter != null) {
364             if (isContentHandler) {
365                 ((ContentHandler) firstFilter).setDocumentLocator(locator);
366             }
367         }
368 
369         super.setDocumentLocator(locator);
370     }
371 
372     /***
373      * Filter a start document event.
374      * 
375      * @exception SAXException The client may throw an exception during
376      *                processing.
377      */
378     public void startDocument() throws SAXException {
379         //System.out.println(""+this+".startDocument");
380         if (firstFilter != null) {
381             if (isContentHandler) {
382                 ((ContentHandler) firstFilter).startDocument();
383             }
384         } else {
385             super.startDocument();
386         }
387 
388         if (outputPropertiesListener != null) {
389             outputPropertiesListener.setOutputProperties(getOutputProperties());
390         }
391     }
392 
393     /***
394      * Filter an end document event.
395      * 
396      * @exception SAXException The client may throw an exception during
397      *                processing.
398      */
399     public void endDocument() throws SAXException {
400         //System.out.println("---DynamicFilter "+this+".endDocument,
401         // firstFilter="+firstFilter);
402         if (firstFilter != null) {
403             //System.out.println("---firstFilter has
404             // contenthandler="+firstFilter.getContentHandler());
405             if (isContentHandler) {
406                 ((ContentHandler) firstFilter).endDocument();
407             }
408         } else {
409             super.endDocument();
410         }
411     }
412 
413     /***
414      * Filter a start Namespace prefix mapping event.
415      * 
416      * @param prefix The Namespace prefix.
417      * @param uri The Namespace URI.
418      * @exception SAXException The client may throw an exception during
419      *                processing.
420      */
421     public void startPrefixMapping(String prefix, String uri)
422             throws SAXException {
423         if (firstFilter != null) {
424             if (isContentHandler) {
425                 ((ContentHandler) firstFilter).startPrefixMapping(prefix, uri);
426             }
427         } else {
428             super.startPrefixMapping(prefix, uri);
429         }
430     }
431 
432     /***
433      * Filter an end Namespace prefix mapping event.
434      * 
435      * @param prefix The Namespace prefix.
436      * @exception SAXException The client may throw an exception during
437      *                processing.
438      */
439     public void endPrefixMapping(String prefix) throws SAXException {
440         if (firstFilter != null) {
441             if (isContentHandler) {
442                 ((ContentHandler) firstFilter).endPrefixMapping(prefix);
443             }
444         } else {
445             super.endPrefixMapping(prefix);
446         }
447     }
448 
449     /***
450      * Filter a start element event.
451      * 
452      * @param uri The element's Namespace URI, or the empty string.
453      * @param localName The element's local name, or the empty string.
454      * @param qName The element's qualified (prefixed) name, or the empty
455      *            string.
456      * @param atts The element's attributes.
457      * @exception SAXException The client may throw an exception during
458      *                processing.
459      */
460     public void startElement(String uri, String localName, String qName,
461             Attributes atts) throws SAXException {
462         if (firstFilter != null) {
463             if (isContentHandler) {
464                 ((ContentHandler) firstFilter).startElement(uri, localName,
465                         qName, atts);
466             }
467         } else {
468             super.startElement(uri, localName, qName, atts);
469         }
470     }
471 
472     /***
473      * Filter an end element event.
474      * 
475      * @param uri The element's Namespace URI, or the empty string.
476      * @param localName The element's local name, or the empty string.
477      * @param qName The element's qualified (prefixed) name, or the empty
478      *            string.
479      * @exception SAXException The client may throw an exception during
480      *                processing.
481      */
482     public void endElement(String uri, String localName, String qName)
483             throws SAXException {
484         if (firstFilter != null) {
485             if (isContentHandler) {
486                 ((ContentHandler) firstFilter)
487                         .endElement(uri, localName, qName);
488             }
489         } else {
490             super.endElement(uri, localName, qName);
491         }
492     }
493 
494     /***
495      * Filter a character data event.
496      * 
497      * @param ch An array of characters.
498      * @param start The starting position in the array.
499      * @param length The number of characters to use from the array.
500      * @exception SAXException The client may throw an exception during
501      *                processing.
502      */
503     public void characters(char[] ch, int start, int length)
504             throws SAXException {
505         if (firstFilter != null) {
506             if (isContentHandler) {
507                 ((ContentHandler) firstFilter).characters(ch, start, length);
508             }
509         } else {
510             super.characters(ch, start, length);
511         }
512     }
513 
514     /***
515      * Filter an ignorable whitespace event.
516      * 
517      * @param ch An array of characters.
518      * @param start The starting position in the array.
519      * @param length The number of characters to use from the array.
520      * @exception SAXException The client may throw an exception during
521      *                processing.
522      */
523     public void ignorableWhitespace(char[] ch, int start, int length)
524             throws SAXException {
525         if (firstFilter != null) {
526             if (isContentHandler) {
527                 ((ContentHandler) firstFilter).ignorableWhitespace(ch, start,
528                         length);
529             }
530         } else {
531             super.ignorableWhitespace(ch, start, length);
532         }
533     }
534 
535     /***
536      * Filter a processing instruction event.
537      * 
538      * @param target The processing instruction target.
539      * @param data The text following the target.
540      * @exception SAXException The client may throw an exception during
541      *                processing.
542      */
543     public void processingInstruction(String target, String data)
544             throws SAXException {
545         if (firstFilter != null) {
546             if (isContentHandler) {
547                 ((ContentHandler) firstFilter).processingInstruction(target,
548                         data);
549             }
550         } else {
551             super.processingInstruction(target, data);
552         }
553     }
554 
555     /***
556      * Filter a skipped entity event.
557      * 
558      * @param name The name of the skipped entity.
559      * @exception SAXException The client may throw an exception during
560      *                processing.
561      */
562     public void skippedEntity(String name) throws SAXException {
563         if (firstFilter != null) {
564             if (isContentHandler) {
565                 ((ContentHandler) firstFilter).skippedEntity(name);
566             }
567         } else {
568             super.skippedEntity(name);
569         }
570     }
571 
572     ////////////////////////////////////////////////////////////////////
573     // Implementation of org.xml.sax.ErrorHandler.
574     ////////////////////////////////////////////////////////////////////
575 
576     /***
577      * Filter a warning event.
578      * 
579      * @param e The warning as an exception.
580      * @exception SAXException The client may throw an exception during
581      *                processing.
582      */
583     public void warning(SAXParseException e) throws SAXException {
584         if (firstFilter != null) {
585             if (isErrorHandler) {
586                 ((ErrorHandler) firstFilter).warning(e);
587             }
588         } else {
589             super.warning(e);
590         }
591     }
592 
593     /***
594      * Filter an error event.
595      * 
596      * @param e The error as an exception.
597      * @exception SAXException The client may throw an exception during
598      *                processing.
599      */
600     public void error(SAXParseException e) throws SAXException {
601         if (firstFilter != null) {
602             if (isErrorHandler) {
603                 ((ErrorHandler) firstFilter).error(e);
604             }
605         } else {
606             super.error(e);
607         }
608     }
609 
610     /***
611      * Filter a fatal error event.
612      * 
613      * @param e The error as an exception.
614      * @exception SAXException The client may throw an exception during
615      *                processing.
616      */
617     public void fatalError(SAXParseException e) throws SAXException {
618         if (firstFilter != null) {
619             if (isErrorHandler) {
620                 ((ErrorHandler) firstFilter).fatalError(e);
621             }
622         } else {
623             super.fatalError(e);
624         }
625     }
626 
627     ////////////////////////////////////////////////////////////////////
628     // Implementation of the LexicalHandler.
629     ////////////////////////////////////////////////////////////////////
630 
631     /***
632      * Callback interface for SAX (part of LexicalHandler interface): not for
633      * application use
634      * 
635      * @param ch DOCUMENT ME!
636      * @param start DOCUMENT ME!
637      * @param length DOCUMENT ME!
638      * @throws SAXException DOCUMENT ME!
639      */
640     public void comment(char[] ch, int start, int length) throws SAXException {
641         if (firstFilter != null) {
642             if (isLexicalHandler) {
643                 ((LexicalHandler) firstFilter).comment(ch, start, length);
644             }
645         } else {
646             super.comment(ch, start, length);
647         }
648     }
649 
650     // No-op methods to satisfy lexical handler interface
651 
652     /***
653      * Register the start of the DTD. Comments in the DTD are skipped because
654      * they are not part of the XPath data model
655      * 
656      * @param name DOCUMENT ME!
657      * @param publicId DOCUMENT ME!
658      * @param systemId DOCUMENT ME!
659      * @throws SAXException DOCUMENT ME!
660      */
661     public void startDTD(String name, String publicId, String systemId)
662             throws SAXException {
663         if (firstFilter != null) {
664             if (isLexicalHandler) {
665                 ((LexicalHandler) firstFilter).startDTD(name, publicId,
666                         systemId);
667             }
668         } else {
669             super.startDTD(name, publicId, systemId);
670         }
671     }
672 
673     /***
674      * Register the end of the DTD. Comments in the DTD are skipped because they
675      * are not part of the XPath data model
676      * 
677      * @throws SAXException DOCUMENT ME!
678      */
679     public void endDTD() throws SAXException {
680         if (firstFilter != null) {
681             if (isLexicalHandler) {
682                 ((LexicalHandler) firstFilter).endDTD();
683             }
684         } else {
685             super.endDTD();
686         }
687     }
688 
689     /***
690      * DOCUMENT ME!
691      * 
692      * @param name DOCUMENT ME!
693      * @throws SAXException DOCUMENT ME!
694      */
695     public void startEntity(String name) throws SAXException {
696         if (firstFilter != null) {
697             if (isLexicalHandler) {
698                 ((LexicalHandler) firstFilter).startEntity(name);
699             }
700         } else {
701             super.startEntity(name);
702         }
703     }
704 
705     /***
706      * DOCUMENT ME!
707      * 
708      * @param name DOCUMENT ME!
709      * @throws SAXException DOCUMENT ME!
710      */
711     public void endEntity(String name) throws SAXException {
712         if (firstFilter != null) {
713             if (isLexicalHandler) {
714                 ((LexicalHandler) firstFilter).endEntity(name);
715             }
716         } else {
717             super.endEntity(name);
718         }
719     }
720 
721     /***
722      * DOCUMENT ME!
723      * 
724      * @throws SAXException DOCUMENT ME!
725      */
726     public void startCDATA() throws SAXException {
727         if (firstFilter != null) {
728             if (isLexicalHandler) {
729                 ((LexicalHandler) firstFilter).startCDATA();
730             }
731         } else {
732             super.startCDATA();
733         }
734     }
735 
736     /***
737      * DOCUMENT ME!
738      * 
739      * @throws SAXException DOCUMENT ME!
740      */
741     public void endCDATA() throws SAXException {
742         if (firstFilter != null) {
743             if (isLexicalHandler) {
744                 ((LexicalHandler) firstFilter).endCDATA();
745             }
746         } else {
747             super.endCDATA();
748         }
749     }
750 
751     ////////////////////////////////////////////////////////////////////
752     // Internal methods.
753     ////////////////////////////////////////////////////////////////////
754     public void setLexicalHandler(LexicalHandler handler) {
755         //System.out.println(""+this+".setContentHandler="+handler);
756         super.setLexicalHandler(handler);
757 
758         if ((lastFilter != null) && lastFilter instanceof LexicalHandler) {
759             try {
760                 //System.out.println(" *** DMF.setLexicalHandler to "+handler);
761                 lastFilter.setProperty(
762                         "http://xml.org/sax/properties/lexical-handler",
763                         handler);
764             } catch (SAXException se) {
765                 se.printStackTrace();
766             }
767         }
768     }
769 
770     /***
771      * DOCUMENT ME!
772      * 
773      * @param pos DOCUMENT ME!
774      * @param f DOCUMENT ME!
775      * @throws SAXException DOCUMENT ME!
776      * @throws UnsupportedOperationException DOCUMENT ME!
777      */
778     public void setFilter(int pos, XMLFilter f) throws SAXException {
779         // FIXME
780         throw new UnsupportedOperationException();
781     }
782 
783     /***
784      * DOCUMENT ME!
785      * 
786      * @param pos DOCUMENT ME!
787      * @param f DOCUMENT ME!
788      * @throws SAXException DOCUMENT ME!
789      */
790     public void addFilter(int pos, XMLFilter f) throws SAXException {
791         // FIXME
792         // use case 1: add(0, f)
793         if (pos == 0) {
794             XMLReader parent = getParent();
795 
796             if (parent != null) {
797                 connectHandlers(parent, f);
798             }
799 
800             if (0 == getFilterCount()) {
801                 // the one and only
802                 copyHandlers(this, f);
803                 lastFilter = f;
804             } else {
805                 // already has some filters...
806                 copyHandlers(firstFilter, f);
807                 connectHandlers(f, firstFilter);
808             }
809 
810             firstFilter = f;
811             determineHandlerInfo();
812 
813             // use case 2: add(last, f)
814         } else if (pos == getFilterCount()) {
815             // already has some filters...
816             copyHandlers(lastFilter, f);
817 
818             connectHandlers(lastFilter, f);
819 
820             lastFilter = f;
821 
822             // use case 3: add(n, f) - general case, # of filters > 1
823         } else {
824             XMLFilter next = getFilter(pos);
825             XMLReader parent = next.getParent();
826 
827             copyHandlers(parent, f);
828             connectHandlers(parent, f);
829         }
830 
831         filters.add(pos, f);
832     }
833 
834     /***
835      * DOCUMENT ME!
836      * 
837      * @param pos DOCUMENT ME!
838      * @throws SAXException DOCUMENT ME!
839      * @throws UnsupportedOperationException DOCUMENT ME!
840      */
841     public void removeFilter(int pos) throws SAXException {
842         // FIXME
843         throw new UnsupportedOperationException();
844     }
845 
846     /***
847      * DOCUMENT ME!
848      */
849     protected void determineHandlerInfo() {
850         isContentHandler = firstFilter instanceof ContentHandler;
851         isDTDHandler = firstFilter instanceof DTDHandler;
852         isErrorHandler = firstFilter instanceof ErrorHandler;
853         isLexicalHandler = firstFilter instanceof LexicalHandler;
854         isEntityResolver = firstFilter instanceof EntityResolver;
855     }
856 
857     /***
858      * DOCUMENT ME!
859      * 
860      * @param parent DOCUMENT ME!
861      * @param f DOCUMENT ME!
862      */
863     protected static void connectHandlers(XMLReader parent, XMLFilter f) {
864         // route messages from parent to f
865         //System.out.println(parent+" *** SETS HANDLERS to "+f);
866         if (f instanceof EntityResolver) {
867             parent.setEntityResolver((EntityResolver) f);
868         }
869 
870         if (f instanceof DTDHandler) {
871             parent.setDTDHandler((DTDHandler) f);
872         }
873 
874         if (f instanceof ContentHandler) {
875             parent.setContentHandler((ContentHandler) f);
876         }
877 
878         if (f instanceof ErrorHandler) {
879             parent.setErrorHandler((ErrorHandler) f);
880         }
881 
882         try {
883             if (f instanceof LexicalHandler) {
884                 //System.out.println(parent+" *** SETS LexicalHandler to "+f);
885                 parent.setProperty(
886                         "http://xml.org/sax/properties/lexical-handler", f);
887             }
888         } catch (SAXException se) {
889             se.printStackTrace();
890         }
891 
892         // connect f to parent
893         f.setParent(parent);
894     }
895 
896     /***
897      * DOCUMENT ME!
898      * 
899      * @param from DOCUMENT ME!
900      * @param to DOCUMENT ME!
901      */
902     protected static void copyHandlers(XMLReader from, XMLReader to) {
903         // route messages from last filter to further handlers
904         //System.out.println(f+" *** SETS DTD HANDLER to "+getDTDHandler());
905         ContentHandler ch = from.getContentHandler();
906 
907         if (ch != null) {
908             to.setContentHandler(ch);
909         }
910 
911         DTDHandler dh = from.getDTDHandler();
912 
913         if (dh != null) {
914             to.setDTDHandler(dh);
915         }
916 
917         EntityResolver er = from.getEntityResolver();
918 
919         if (er != null) {
920             to.setEntityResolver(er);
921         }
922 
923         ErrorHandler eh = from.getErrorHandler();
924 
925         if (eh != null) {
926             to.setErrorHandler(eh);
927         }
928 
929         try {
930             Object lh = from
931                     .getProperty("http://xml.org/sax/properties/lexical-handler");
932 
933             if (lh != null) {
934                 to.setProperty("http://xml.org/sax/properties/lexical-handler",
935                         lh);
936             }
937         } catch (SAXException se) {
938             //se.printStackTrace();
939         }
940     }
941 
942     /***
943      * DOCUMENT ME!
944      * 
945      * @param pos DOCUMENT ME!
946      * @return DOCUMENT ME!
947      */
948     public XMLFilter getFilter(int pos) {
949         return (XMLFilter) filters.get(pos);
950     }
951 
952     /***
953      * DOCUMENT ME!
954      * 
955      * @return DOCUMENT ME!
956      */
957     public Properties getOutputProperties() {
958         //System.out.println(this+" +++++++++++++ getOutputProperties from
959         // lastFilter=" + lastFilter);
960         if (lastFilter instanceof HasOutputProperties) {
961             return ((HasOutputProperties) lastFilter).getOutputProperties();
962         }
963 
964         return null;
965     }
966 
967     /***
968      * DOCUMENT ME!
969      * 
970      * @param p DOCUMENT ME!
971      * @throws UnsupportedOperationException DOCUMENT ME!
972      */
973     public void setOutputProperties(Properties p) {
974         throw new UnsupportedOperationException(
975                 "Cannot setOutputProperties on " + this);
976     }
977 
978     /***
979      * DOCUMENT ME!
980      * 
981      * @param l DOCUMENT ME!
982      */
983     public void setOutputPropertiesListener(HasOutputProperties l) {
984         outputPropertiesListener = l;
985     }
986 
987     /***
988      * DOCUMENT ME!
989      * 
990      * @return DOCUMENT ME!
991      */
992     public int getFilterCount() {
993         return filters.size();
994     }
995 }
996 
997 /*
998  * The contents of this file are subject to the Mozilla Public License Version
999  * 1.1 (the "License"); you may not use this file except in compliance with the
1000  * License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
1001  * Software distributed under the License is distributed on an "AS IS" basis,
1002  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
1003  * the specific language governing rights and limitations under the License. The
1004  * Original Code is: all this file. The Initial Developer of the Original Code
1005  * is: Tomas Pitner, Masaryk University in Brno, Czech Republic. Contributor(s):
1006  */