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      */
  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      */
  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      */
 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      */
 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      * @exception org.xml.sax.SAXNotRecognizedException If the feature
 157      *            value can't be assigned or retrieved from the parent.
 158      * @exception org.xml.sax.SAXNotSupportedException When the
 159      *            parent recognizes the feature name but
 160      *            cannot set the requested value.
 161      */
 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      * @exception org.xml.sax.SAXNotRecognizedException If the feature
 181      *            value can't be assigned or retrieved from the parent.
 182      * @exception org.xml.sax.SAXNotSupportedException When the
 183      *            parent recognizes the feature name but
 184      *            cannot determine its value at this time.
 185      */
 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      * @exception org.xml.sax.SAXNotRecognizedException If the property
 205      *            value can't be assigned or retrieved from the parent.
 206      * @exception org.xml.sax.SAXNotSupportedException When the
 207      *            parent recognizes the property name but
 208      *            cannot set the requested value.
 209      */
 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      * @exception org.xml.sax.SAXNotRecognizedException If the property
 227      *            value can't be assigned or retrieved from the parent.
 228      * @exception org.xml.sax.SAXNotSupportedException When the
 229      *            parent recognizes the property name but
 230      *            cannot determine its value at this time.
 231      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      * @exception org.xml.sax.SAXException Any SAX exception, possibly
 336      *            wrapping another exception.
 337      * @exception java.io.IOException An IO exception from the parser,
 338      *            possibly from a byte stream or character stream
 339      *            supplied by the application.
 340      */
 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      * @exception org.xml.sax.SAXException Any SAX exception, possibly
 354      *            wrapping another exception.
 355      * @exception java.io.IOException An IO exception from the parser,
 356      *            possibly from a byte stream or character stream
 357      *            supplied by the application.
 358      */
 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      * @exception org.xml.sax.SAXException The client may throw
 379      *            an exception during processing.
 380      * @exception java.io.IOException The client may throw an
 381      *            I/O-related exception while obtaining the
 382      *            new InputSource.
 383      */
 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      * @exception org.xml.sax.SAXException The client may throw
 408      *            an exception during processing.
 409      */
 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      * @exception org.xml.sax.SAXException The client may throw
 427      *            an exception during processing.
 428      */
 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      */
 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      * @exception org.xml.sax.SAXException The client may throw
 464      *            an exception during processing.
 465      */
 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      * @exception org.xml.sax.SAXException The client may throw
 479      *            an exception during processing.
 480      */
 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      * @exception org.xml.sax.SAXException The client may throw
 496      *            an exception during processing.
 497      */
 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      * @exception org.xml.sax.SAXException The client may throw
 512      *            an exception during processing.
 513      */
 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      * @exception org.xml.sax.SAXException The client may throw
 532      *            an exception during processing.
 533      */
 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      * @exception org.xml.sax.SAXException The client may throw
 552      *            an exception during processing.
 553      */
 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      * @exception org.xml.sax.SAXException The client may throw
 570      *            an exception during processing.
 571      */
 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      * @exception org.xml.sax.SAXException The client may throw
 588      *            an exception during processing.
 589      */
 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      * @exception org.xml.sax.SAXException The client may throw
 605      *            an exception during processing.
 606      */
 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      * @exception org.xml.sax.SAXException The client may throw
 621      *            an exception during processing.
 622      */
 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      * @exception org.xml.sax.SAXException The client may throw
 643      *            an exception during processing.
 644      */
 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      * @exception org.xml.sax.SAXException The client may throw
 659      *            an exception during processing.
 660      */
 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      * @exception org.xml.sax.SAXException The client may throw
 675      *            an exception during processing.
 676      */
 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      */
 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