1 /*
2  * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package org.xml.sax.helpers;
27 
28 import java.io.IOException;
29 
30 import org.xml.sax.XMLReader;
31 import org.xml.sax.XMLFilter;
32 import org.xml.sax.InputSource;
33 import org.xml.sax.Locator;
34 import org.xml.sax.Attributes;
35 import org.xml.sax.EntityResolver;
36 import org.xml.sax.DTDHandler;
37 import org.xml.sax.ContentHandler;
38 import org.xml.sax.ErrorHandler;
39 import org.xml.sax.SAXException;
40 import org.xml.sax.SAXParseException;
41 import org.xml.sax.SAXNotSupportedException;
42 import org.xml.sax.SAXNotRecognizedException;
43 
44 
45 /**
46  * Base class for deriving an XML filter.
47  *
48  * <p>This class is designed to sit between an {@link org.xml.sax.XMLReader
49  * XMLReader} and the client application's event handlers.  By default, it
50  * does nothing but pass requests up to the reader and events
51  * on to the handlers unmodified, but subclasses can override
52  * specific methods to modify the event stream or the configuration
53  * requests as they pass through.</p>
54  *
55  * @since 1.4, SAX 2.0
56  * @author David Megginson
57  * @see org.xml.sax.XMLFilter
58  * @see org.xml.sax.XMLReader
59  * @see org.xml.sax.EntityResolver
60  * @see org.xml.sax.DTDHandler
61  * @see org.xml.sax.ContentHandler
62  * @see org.xml.sax.ErrorHandler
63  */
64 public class XMLFilterImpl
65     implements XMLFilter, EntityResolver, DTDHandler, ContentHandler, ErrorHandler
66 {
67 
68 
69     ////////////////////////////////////////////////////////////////////
70     // Constructors.
71     ////////////////////////////////////////////////////////////////////
72 
73 
74     /**
75      * Construct an empty XML filter, with no parent.
76      *
77      * <p>This filter will have no parent: you must assign a parent
78      * before you start a parse or do any configuration with
79      * setFeature or setProperty, unless you use this as a pure event
80      * consumer rather than as an {@link XMLReader}.</p>
81      *
82      * @see org.xml.sax.XMLReader#setFeature
83      * @see org.xml.sax.XMLReader#setProperty
84      * @see #setParent
85      */
XMLFilterImpl()86     public XMLFilterImpl ()
87     {
88         super();
89     }
90 
91 
92     /**
93      * Construct an XML filter with the specified parent.
94      *
95      * @param parent the specified parent
96      * @see #setParent
97      * @see #getParent
98      */
XMLFilterImpl(XMLReader parent)99     public XMLFilterImpl (XMLReader parent)
100     {
101         super();
102         setParent(parent);
103     }
104 
105 
106 
107     ////////////////////////////////////////////////////////////////////
108     // Implementation of org.xml.sax.XMLFilter.
109     ////////////////////////////////////////////////////////////////////
110 
111 
112     /**
113      * Set the parent reader.
114      *
115      * <p>This is the {@link org.xml.sax.XMLReader XMLReader} from which
116      * this filter will obtain its events and to which it will pass its
117      * configuration requests.  The parent may itself be another filter.</p>
118      *
119      * <p>If there is no parent reader set, any attempt to parse
120      * or to set or get a feature or property will fail.</p>
121      *
122      * @param parent The parent XML reader.
123      * @see #getParent
124      */
setParent(XMLReader parent)125     public void setParent (XMLReader parent)
126     {
127         this.parent = parent;
128     }
129 
130 
131     /**
132      * Get the parent reader.
133      *
134      * @return The parent XML reader, or null if none is set.
135      * @see #setParent
136      */
getParent()137     public XMLReader getParent ()
138     {
139         return parent;
140     }
141 
142 
143 
144     ////////////////////////////////////////////////////////////////////
145     // Implementation of org.xml.sax.XMLReader.
146     ////////////////////////////////////////////////////////////////////
147 
148 
149     /**
150      * Set the value of a feature.
151      *
152      * <p>This will always fail if the parent is null.</p>
153      *
154      * @param name The feature name.
155      * @param value The requested feature value.
156      * @throws org.xml.sax.SAXNotRecognizedException If the feature
157      *            value can't be assigned or retrieved from the parent.
158      * @throws org.xml.sax.SAXNotSupportedException When the
159      *            parent recognizes the feature name but
160      *            cannot set the requested value.
161      */
setFeature(String name, boolean value)162     public void setFeature (String name, boolean value)
163         throws SAXNotRecognizedException, SAXNotSupportedException
164     {
165         if (parent != null) {
166             parent.setFeature(name, value);
167         } else {
168             throw new SAXNotRecognizedException("Feature: " + name);
169         }
170     }
171 
172 
173     /**
174      * Look up the value of a feature.
175      *
176      * <p>This will always fail if the parent is null.</p>
177      *
178      * @param name The feature name.
179      * @return The current value of the feature.
180      * @throws org.xml.sax.SAXNotRecognizedException If the feature
181      *            value can't be assigned or retrieved from the parent.
182      * @throws org.xml.sax.SAXNotSupportedException When the
183      *            parent recognizes the feature name but
184      *            cannot determine its value at this time.
185      */
getFeature(String name)186     public boolean getFeature (String name)
187         throws SAXNotRecognizedException, SAXNotSupportedException
188     {
189         if (parent != null) {
190             return parent.getFeature(name);
191         } else {
192             throw new SAXNotRecognizedException("Feature: " + name);
193         }
194     }
195 
196 
197     /**
198      * Set the value of a property.
199      *
200      * <p>This will always fail if the parent is null.</p>
201      *
202      * @param name The property name.
203      * @param value The requested property value.
204      * @throws org.xml.sax.SAXNotRecognizedException If the property
205      *            value can't be assigned or retrieved from the parent.
206      * @throws org.xml.sax.SAXNotSupportedException When the
207      *            parent recognizes the property name but
208      *            cannot set the requested value.
209      */
setProperty(String name, Object value)210     public void setProperty (String name, Object value)
211         throws SAXNotRecognizedException, SAXNotSupportedException
212     {
213         if (parent != null) {
214             parent.setProperty(name, value);
215         } else {
216             throw new SAXNotRecognizedException("Property: " + name);
217         }
218     }
219 
220 
221     /**
222      * Look up the value of a property.
223      *
224      * @param name The property name.
225      * @return The current value of the property.
226      * @throws org.xml.sax.SAXNotRecognizedException If the property
227      *            value can't be assigned or retrieved from the parent.
228      * @throws org.xml.sax.SAXNotSupportedException When the
229      *            parent recognizes the property name but
230      *            cannot determine its value at this time.
231      */
getProperty(String name)232     public Object getProperty (String name)
233         throws SAXNotRecognizedException, SAXNotSupportedException
234     {
235         if (parent != null) {
236             return parent.getProperty(name);
237         } else {
238             throw new SAXNotRecognizedException("Property: " + name);
239         }
240     }
241 
242 
243     /**
244      * Set the entity resolver.
245      *
246      * @param resolver The new entity resolver.
247      */
setEntityResolver(EntityResolver resolver)248     public void setEntityResolver (EntityResolver resolver)
249     {
250         entityResolver = resolver;
251     }
252 
253 
254     /**
255      * Get the current entity resolver.
256      *
257      * @return The current entity resolver, or null if none was set.
258      */
getEntityResolver()259     public EntityResolver getEntityResolver ()
260     {
261         return entityResolver;
262     }
263 
264 
265     /**
266      * Set the DTD event handler.
267      *
268      * @param handler the new DTD handler
269      */
setDTDHandler(DTDHandler handler)270     public void setDTDHandler (DTDHandler handler)
271     {
272         dtdHandler = handler;
273     }
274 
275 
276     /**
277      * Get the current DTD event handler.
278      *
279      * @return The current DTD handler, or null if none was set.
280      */
getDTDHandler()281     public DTDHandler getDTDHandler ()
282     {
283         return dtdHandler;
284     }
285 
286 
287     /**
288      * Set the content event handler.
289      *
290      * @param handler the new content handler
291      */
setContentHandler(ContentHandler handler)292     public void setContentHandler (ContentHandler handler)
293     {
294         contentHandler = handler;
295     }
296 
297 
298     /**
299      * Get the content event handler.
300      *
301      * @return The current content handler, or null if none was set.
302      */
getContentHandler()303     public ContentHandler getContentHandler ()
304     {
305         return contentHandler;
306     }
307 
308 
309     /**
310      * Set the error event handler.
311      *
312      * @param handler the new error handler
313      */
setErrorHandler(ErrorHandler handler)314     public void setErrorHandler (ErrorHandler handler)
315     {
316         errorHandler = handler;
317     }
318 
319 
320     /**
321      * Get the current error event handler.
322      *
323      * @return The current error handler, or null if none was set.
324      */
getErrorHandler()325     public ErrorHandler getErrorHandler ()
326     {
327         return errorHandler;
328     }
329 
330 
331     /**
332      * Parse a document.
333      *
334      * @param input The input source for the document entity.
335      * @throws org.xml.sax.SAXException Any SAX exception, possibly
336      *            wrapping another exception.
337      * @throws java.io.IOException An IO exception from the parser,
338      *            possibly from a byte stream or character stream
339      *            supplied by the application.
340      */
parse(InputSource input)341     public void parse (InputSource input)
342         throws SAXException, IOException
343     {
344         setupParse();
345         parent.parse(input);
346     }
347 
348 
349     /**
350      * Parse a document.
351      *
352      * @param systemId The system identifier as a fully-qualified URI.
353      * @throws org.xml.sax.SAXException Any SAX exception, possibly
354      *            wrapping another exception.
355      * @throws java.io.IOException An IO exception from the parser,
356      *            possibly from a byte stream or character stream
357      *            supplied by the application.
358      */
parse(String systemId)359     public void parse (String systemId)
360         throws SAXException, IOException
361     {
362         parse(new InputSource(systemId));
363     }
364 
365 
366 
367     ////////////////////////////////////////////////////////////////////
368     // Implementation of org.xml.sax.EntityResolver.
369     ////////////////////////////////////////////////////////////////////
370 
371 
372     /**
373      * Filter an external entity resolution.
374      *
375      * @param publicId The entity's public identifier, or null.
376      * @param systemId The entity's system identifier.
377      * @return A new InputSource or null for the default.
378      * @throws org.xml.sax.SAXException The client may throw
379      *            an exception during processing.
380      * @throws java.io.IOException The client may throw an
381      *            I/O-related exception while obtaining the
382      *            new InputSource.
383      */
resolveEntity(String publicId, String systemId)384     public InputSource resolveEntity (String publicId, String systemId)
385         throws SAXException, IOException
386     {
387         if (entityResolver != null) {
388             return entityResolver.resolveEntity(publicId, systemId);
389         } else {
390             return null;
391         }
392     }
393 
394 
395 
396     ////////////////////////////////////////////////////////////////////
397     // Implementation of org.xml.sax.DTDHandler.
398     ////////////////////////////////////////////////////////////////////
399 
400 
401     /**
402      * Filter a notation declaration event.
403      *
404      * @param name The notation name.
405      * @param publicId The notation's public identifier, or null.
406      * @param systemId The notation's system identifier, or null.
407      * @throws org.xml.sax.SAXException The client may throw
408      *            an exception during processing.
409      */
notationDecl(String name, String publicId, String systemId)410     public void notationDecl (String name, String publicId, String systemId)
411         throws SAXException
412     {
413         if (dtdHandler != null) {
414             dtdHandler.notationDecl(name, publicId, systemId);
415         }
416     }
417 
418 
419     /**
420      * Filter an unparsed entity declaration event.
421      *
422      * @param name The entity name.
423      * @param publicId The entity's public identifier, or null.
424      * @param systemId The entity's system identifier, or null.
425      * @param notationName The name of the associated notation.
426      * @throws org.xml.sax.SAXException The client may throw
427      *            an exception during processing.
428      */
unparsedEntityDecl(String name, String publicId, String systemId, String notationName)429     public void unparsedEntityDecl (String name, String publicId,
430                                     String systemId, String notationName)
431         throws SAXException
432     {
433         if (dtdHandler != null) {
434             dtdHandler.unparsedEntityDecl(name, publicId, systemId,
435                                           notationName);
436         }
437     }
438 
439 
440 
441     ////////////////////////////////////////////////////////////////////
442     // Implementation of org.xml.sax.ContentHandler.
443     ////////////////////////////////////////////////////////////////////
444 
445 
446     /**
447      * Filter a new document locator event.
448      *
449      * @param locator The document locator.
450      */
setDocumentLocator(Locator locator)451     public void setDocumentLocator (Locator locator)
452     {
453         this.locator = locator;
454         if (contentHandler != null) {
455             contentHandler.setDocumentLocator(locator);
456         }
457     }
458 
459 
460     /**
461      * Filter a start document event.
462      *
463      * @throws org.xml.sax.SAXException The client may throw
464      *            an exception during processing.
465      */
startDocument()466     public void startDocument ()
467         throws SAXException
468     {
469         if (contentHandler != null) {
470             contentHandler.startDocument();
471         }
472     }
473 
474 
475     /**
476      * Filter an end document event.
477      *
478      * @throws org.xml.sax.SAXException The client may throw
479      *            an exception during processing.
480      */
endDocument()481     public void endDocument ()
482         throws SAXException
483     {
484         if (contentHandler != null) {
485             contentHandler.endDocument();
486         }
487     }
488 
489 
490     /**
491      * Filter a start Namespace prefix mapping event.
492      *
493      * @param prefix The Namespace prefix.
494      * @param uri The Namespace URI.
495      * @throws org.xml.sax.SAXException The client may throw
496      *            an exception during processing.
497      */
startPrefixMapping(String prefix, String uri)498     public void startPrefixMapping (String prefix, String uri)
499         throws SAXException
500     {
501         if (contentHandler != null) {
502             contentHandler.startPrefixMapping(prefix, uri);
503         }
504     }
505 
506 
507     /**
508      * Filter an end Namespace prefix mapping event.
509      *
510      * @param prefix The Namespace prefix.
511      * @throws org.xml.sax.SAXException The client may throw
512      *            an exception during processing.
513      */
endPrefixMapping(String prefix)514     public void endPrefixMapping (String prefix)
515         throws SAXException
516     {
517         if (contentHandler != null) {
518             contentHandler.endPrefixMapping(prefix);
519         }
520     }
521 
522 
523     /**
524      * Filter a start element event.
525      *
526      * @param uri The element's Namespace URI, or the empty string.
527      * @param localName The element's local name, or the empty string.
528      * @param qName The element's qualified (prefixed) name, or the empty
529      *        string.
530      * @param atts The element's attributes.
531      * @throws org.xml.sax.SAXException The client may throw
532      *            an exception during processing.
533      */
startElement(String uri, String localName, String qName, Attributes atts)534     public void startElement (String uri, String localName, String qName,
535                               Attributes atts)
536         throws SAXException
537     {
538         if (contentHandler != null) {
539             contentHandler.startElement(uri, localName, qName, atts);
540         }
541     }
542 
543 
544     /**
545      * Filter an end element event.
546      *
547      * @param uri The element's Namespace URI, or the empty string.
548      * @param localName The element's local name, or the empty string.
549      * @param qName The element's qualified (prefixed) name, or the empty
550      *        string.
551      * @throws org.xml.sax.SAXException The client may throw
552      *            an exception during processing.
553      */
endElement(String uri, String localName, String qName)554     public void endElement (String uri, String localName, String qName)
555         throws SAXException
556     {
557         if (contentHandler != null) {
558             contentHandler.endElement(uri, localName, qName);
559         }
560     }
561 
562 
563     /**
564      * Filter a character data event.
565      *
566      * @param ch An array of characters.
567      * @param start The starting position in the array.
568      * @param length The number of characters to use from the array.
569      * @throws org.xml.sax.SAXException The client may throw
570      *            an exception during processing.
571      */
characters(char ch[], int start, int length)572     public void characters (char ch[], int start, int length)
573         throws SAXException
574     {
575         if (contentHandler != null) {
576             contentHandler.characters(ch, start, length);
577         }
578     }
579 
580 
581     /**
582      * Filter an ignorable whitespace event.
583      *
584      * @param ch An array of characters.
585      * @param start The starting position in the array.
586      * @param length The number of characters to use from the array.
587      * @throws org.xml.sax.SAXException The client may throw
588      *            an exception during processing.
589      */
ignorableWhitespace(char ch[], int start, int length)590     public void ignorableWhitespace (char ch[], int start, int length)
591         throws SAXException
592     {
593         if (contentHandler != null) {
594             contentHandler.ignorableWhitespace(ch, start, length);
595         }
596     }
597 
598 
599     /**
600      * Filter a processing instruction event.
601      *
602      * @param target The processing instruction target.
603      * @param data The text following the target.
604      * @throws org.xml.sax.SAXException The client may throw
605      *            an exception during processing.
606      */
processingInstruction(String target, String data)607     public void processingInstruction (String target, String data)
608         throws SAXException
609     {
610         if (contentHandler != null) {
611             contentHandler.processingInstruction(target, data);
612         }
613     }
614 
615 
616     /**
617      * Filter a skipped entity event.
618      *
619      * @param name The name of the skipped entity.
620      * @throws org.xml.sax.SAXException The client may throw
621      *            an exception during processing.
622      */
skippedEntity(String name)623     public void skippedEntity (String name)
624         throws SAXException
625     {
626         if (contentHandler != null) {
627             contentHandler.skippedEntity(name);
628         }
629     }
630 
631 
632 
633     ////////////////////////////////////////////////////////////////////
634     // Implementation of org.xml.sax.ErrorHandler.
635     ////////////////////////////////////////////////////////////////////
636 
637 
638     /**
639      * Filter a warning event.
640      *
641      * @param e The warning as an exception.
642      * @throws org.xml.sax.SAXException The client may throw
643      *            an exception during processing.
644      */
warning(SAXParseException e)645     public void warning (SAXParseException e)
646         throws SAXException
647     {
648         if (errorHandler != null) {
649             errorHandler.warning(e);
650         }
651     }
652 
653 
654     /**
655      * Filter an error event.
656      *
657      * @param e The error as an exception.
658      * @throws org.xml.sax.SAXException The client may throw
659      *            an exception during processing.
660      */
error(SAXParseException e)661     public void error (SAXParseException e)
662         throws SAXException
663     {
664         if (errorHandler != null) {
665             errorHandler.error(e);
666         }
667     }
668 
669 
670     /**
671      * Filter a fatal error event.
672      *
673      * @param e The error as an exception.
674      * @throws org.xml.sax.SAXException The client may throw
675      *            an exception during processing.
676      */
fatalError(SAXParseException e)677     public void fatalError (SAXParseException e)
678         throws SAXException
679     {
680         if (errorHandler != null) {
681             errorHandler.fatalError(e);
682         }
683     }
684 
685 
686 
687     ////////////////////////////////////////////////////////////////////
688     // Internal methods.
689     ////////////////////////////////////////////////////////////////////
690 
691 
692     /**
693      * Set up before a parse.
694      *
695      * <p>Before every parse, check whether the parent is
696      * non-null, and re-register the filter for all of the
697      * events.</p>
698      */
setupParse()699     private void setupParse ()
700     {
701         if (parent == null) {
702             throw new NullPointerException("No parent for filter");
703         }
704         parent.setEntityResolver(this);
705         parent.setDTDHandler(this);
706         parent.setContentHandler(this);
707         parent.setErrorHandler(this);
708     }
709 
710 
711 
712     ////////////////////////////////////////////////////////////////////
713     // Internal state.
714     ////////////////////////////////////////////////////////////////////
715 
716     private XMLReader parent = null;
717     private Locator locator = null;
718     private EntityResolver entityResolver = null;
719     private DTDHandler dtdHandler = null;
720     private ContentHandler contentHandler = null;
721     private ErrorHandler errorHandler = null;
722 
723 }
724 
725 // end of XMLFilterImpl.java
726