1 /*
   2  * Copyright (c) 2000, 2019, 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      * @see #setParent
  96      * @see #getParent
  97      */
  98     public XMLFilterImpl (XMLReader parent)
  99     {
 100         super();
 101         setParent(parent);
 102     }
 103 
 104 
 105 
 106     ////////////////////////////////////////////////////////////////////
 107     // Implementation of org.xml.sax.XMLFilter.
 108     ////////////////////////////////////////////////////////////////////
 109 
 110 
 111     /**
 112      * Set the parent reader.
 113      *
 114      * <p>This is the {@link org.xml.sax.XMLReader XMLReader} from which
 115      * this filter will obtain its events and to which it will pass its
 116      * configuration requests.  The parent may itself be another filter.</p>
 117      *
 118      * <p>If there is no parent reader set, any attempt to parse
 119      * or to set or get a feature or property will fail.</p>
 120      *
 121      * @param parent The parent XML reader.
 122      * @see #getParent
 123      */
 124     public void setParent (XMLReader parent)
 125     {
 126         this.parent = parent;
 127     }
 128 
 129 
 130     /**
 131      * Get the parent reader.
 132      *
 133      * @return The parent XML reader, or null if none is set.
 134      * @see #setParent
 135      */
 136     public XMLReader getParent ()
 137     {
 138         return parent;
 139     }
 140 
 141 
 142 
 143     ////////////////////////////////////////////////////////////////////
 144     // Implementation of org.xml.sax.XMLReader.
 145     ////////////////////////////////////////////////////////////////////
 146 
 147 
 148     /**
 149      * Set the value of a feature.
 150      *
 151      * <p>This will always fail if the parent is null.</p>
 152      *
 153      * @param name The feature name.
 154      * @param value The requested feature value.
 155      * @exception org.xml.sax.SAXNotRecognizedException If the feature
 156      *            value can't be assigned or retrieved from the parent.
 157      * @exception org.xml.sax.SAXNotSupportedException When the
 158      *            parent recognizes the feature name but
 159      *            cannot set the requested value.
 160      */
 161     public void setFeature (String name, boolean value)
 162         throws SAXNotRecognizedException, SAXNotSupportedException
 163     {
 164         if (parent != null) {
 165             parent.setFeature(name, value);
 166         } else {
 167             throw new SAXNotRecognizedException("Feature: " + name);
 168         }
 169     }
 170 
 171 
 172     /**
 173      * Look up the value of a feature.
 174      *
 175      * <p>This will always fail if the parent is null.</p>
 176      *
 177      * @param name The feature name.
 178      * @return The current value of the feature.
 179      * @exception org.xml.sax.SAXNotRecognizedException If the feature
 180      *            value can't be assigned or retrieved from the parent.
 181      * @exception org.xml.sax.SAXNotSupportedException When the
 182      *            parent recognizes the feature name but
 183      *            cannot determine its value at this time.
 184      */
 185     public boolean getFeature (String name)
 186         throws SAXNotRecognizedException, SAXNotSupportedException
 187     {
 188         if (parent != null) {
 189             return parent.getFeature(name);
 190         } else {
 191             throw new SAXNotRecognizedException("Feature: " + name);
 192         }
 193     }
 194 
 195 
 196     /**
 197      * Set the value of a property.
 198      *
 199      * <p>This will always fail if the parent is null.</p>
 200      *
 201      * @param name The property name.
 202      * @param value The requested property value.
 203      * @exception org.xml.sax.SAXNotRecognizedException If the property
 204      *            value can't be assigned or retrieved from the parent.
 205      * @exception org.xml.sax.SAXNotSupportedException When the
 206      *            parent recognizes the property name but
 207      *            cannot set the requested value.
 208      */
 209     public void setProperty (String name, Object value)
 210         throws SAXNotRecognizedException, SAXNotSupportedException
 211     {
 212         if (parent != null) {
 213             parent.setProperty(name, value);
 214         } else {
 215             throw new SAXNotRecognizedException("Property: " + name);
 216         }
 217     }
 218 
 219 
 220     /**
 221      * Look up the value of a property.
 222      *
 223      * @param name The property name.
 224      * @return The current value of the property.
 225      * @exception org.xml.sax.SAXNotRecognizedException If the property
 226      *            value can't be assigned or retrieved from the parent.
 227      * @exception org.xml.sax.SAXNotSupportedException When the
 228      *            parent recognizes the property name but
 229      *            cannot determine its value at this time.
 230      */
 231     public Object getProperty (String name)
 232         throws SAXNotRecognizedException, SAXNotSupportedException
 233     {
 234         if (parent != null) {
 235             return parent.getProperty(name);
 236         } else {
 237             throw new SAXNotRecognizedException("Property: " + name);
 238         }
 239     }
 240 
 241 
 242     /**
 243      * Set the entity resolver.
 244      *
 245      * @param resolver The new entity resolver.
 246      */
 247     public void setEntityResolver (EntityResolver resolver)
 248     {
 249         entityResolver = resolver;
 250     }
 251 
 252 
 253     /**
 254      * Get the current entity resolver.
 255      *
 256      * @return The current entity resolver, or null if none was set.
 257      */
 258     public EntityResolver getEntityResolver ()
 259     {
 260         return entityResolver;
 261     }
 262 
 263 
 264     /**
 265      * Set the DTD event handler.
 266      *
 267      * @param handler the new DTD handler
 268      */
 269     public void setDTDHandler (DTDHandler handler)
 270     {
 271         dtdHandler = handler;
 272     }
 273 
 274 
 275     /**
 276      * Get the current DTD event handler.
 277      *
 278      * @return The current DTD handler, or null if none was set.
 279      */
 280     public DTDHandler getDTDHandler ()
 281     {
 282         return dtdHandler;
 283     }
 284 
 285 
 286     /**
 287      * Set the content event handler.
 288      *
 289      * @param handler the new content handler
 290      */
 291     public void setContentHandler (ContentHandler handler)
 292     {
 293         contentHandler = handler;
 294     }
 295 
 296 
 297     /**
 298      * Get the content event handler.
 299      *
 300      * @return The current content handler, or null if none was set.
 301      */
 302     public ContentHandler getContentHandler ()
 303     {
 304         return contentHandler;
 305     }
 306 
 307 
 308     /**
 309      * Set the error event handler.
 310      *
 311      * @param handler the new error handler
 312      */
 313     public void setErrorHandler (ErrorHandler handler)
 314     {
 315         errorHandler = handler;
 316     }
 317 
 318 
 319     /**
 320      * Get the current error event handler.
 321      *
 322      * @return The current error handler, or null if none was set.
 323      */
 324     public ErrorHandler getErrorHandler ()
 325     {
 326         return errorHandler;
 327     }
 328 
 329 
 330     /**
 331      * Parse a document.
 332      *
 333      * @param input The input source for the document entity.
 334      * @exception org.xml.sax.SAXException Any SAX exception, possibly
 335      *            wrapping another exception.
 336      * @exception java.io.IOException An IO exception from the parser,
 337      *            possibly from a byte stream or character stream
 338      *            supplied by the application.
 339      */
 340     public void parse (InputSource input)
 341         throws SAXException, IOException
 342     {
 343         setupParse();
 344         parent.parse(input);
 345     }
 346 
 347 
 348     /**
 349      * Parse a document.
 350      *
 351      * @param systemId The system identifier as a fully-qualified URI.
 352      * @exception org.xml.sax.SAXException Any SAX exception, possibly
 353      *            wrapping another exception.
 354      * @exception java.io.IOException An IO exception from the parser,
 355      *            possibly from a byte stream or character stream
 356      *            supplied by the application.
 357      */
 358     public void parse (String systemId)
 359         throws SAXException, IOException
 360     {
 361         parse(new InputSource(systemId));
 362     }
 363 
 364 
 365 
 366     ////////////////////////////////////////////////////////////////////
 367     // Implementation of org.xml.sax.EntityResolver.
 368     ////////////////////////////////////////////////////////////////////
 369 
 370 
 371     /**
 372      * Filter an external entity resolution.
 373      *
 374      * @param publicId The entity's public identifier, or null.
 375      * @param systemId The entity's system identifier.
 376      * @return A new InputSource or null for the default.
 377      * @exception org.xml.sax.SAXException The client may throw
 378      *            an exception during processing.
 379      * @exception java.io.IOException The client may throw an
 380      *            I/O-related exception while obtaining the
 381      *            new InputSource.
 382      */
 383     public InputSource resolveEntity (String publicId, String systemId)
 384         throws SAXException, IOException
 385     {
 386         if (entityResolver != null) {
 387             return entityResolver.resolveEntity(publicId, systemId);
 388         } else {
 389             return null;
 390         }
 391     }
 392 
 393 
 394 
 395     ////////////////////////////////////////////////////////////////////
 396     // Implementation of org.xml.sax.DTDHandler.
 397     ////////////////////////////////////////////////////////////////////
 398 
 399 
 400     /**
 401      * Filter a notation declaration event.
 402      *
 403      * @param name The notation name.
 404      * @param publicId The notation's public identifier, or null.
 405      * @param systemId The notation's system identifier, or null.
 406      * @exception org.xml.sax.SAXException The client may throw
 407      *            an exception during processing.
 408      */
 409     public void notationDecl (String name, String publicId, String systemId)
 410         throws SAXException
 411     {
 412         if (dtdHandler != null) {
 413             dtdHandler.notationDecl(name, publicId, systemId);
 414         }
 415     }
 416 
 417 
 418     /**
 419      * Filter an unparsed entity declaration event.
 420      *
 421      * @param name The entity name.
 422      * @param publicId The entity's public identifier, or null.
 423      * @param systemId The entity's system identifier, or null.
 424      * @param notationName The name of the associated notation.
 425      * @exception org.xml.sax.SAXException The client may throw
 426      *            an exception during processing.
 427      */
 428     public void unparsedEntityDecl (String name, String publicId,
 429                                     String systemId, String notationName)
 430         throws SAXException
 431     {
 432         if (dtdHandler != null) {
 433             dtdHandler.unparsedEntityDecl(name, publicId, systemId,
 434                                           notationName);
 435         }
 436     }
 437 
 438 
 439 
 440     ////////////////////////////////////////////////////////////////////
 441     // Implementation of org.xml.sax.ContentHandler.
 442     ////////////////////////////////////////////////////////////////////
 443 
 444 
 445     /**
 446      * Filter a new document locator event.
 447      *
 448      * @param locator The document locator.
 449      */
 450     public void setDocumentLocator (Locator locator)
 451     {
 452         this.locator = locator;
 453         if (contentHandler != null) {
 454             contentHandler.setDocumentLocator(locator);
 455         }
 456     }
 457 
 458 
 459     /**
 460      * Filter a start document event.
 461      *
 462      * @exception org.xml.sax.SAXException The client may throw
 463      *            an exception during processing.
 464      */
 465     public void startDocument ()
 466         throws SAXException
 467     {
 468         if (contentHandler != null) {
 469             contentHandler.startDocument();
 470         }
 471     }
 472 
 473 
 474     /**
 475      * Filter an end document event.
 476      *
 477      * @exception org.xml.sax.SAXException The client may throw
 478      *            an exception during processing.
 479      */
 480     public void endDocument ()
 481         throws SAXException
 482     {
 483         if (contentHandler != null) {
 484             contentHandler.endDocument();
 485         }
 486     }
 487 
 488 
 489     /**
 490      * Filter a start Namespace prefix mapping event.
 491      *
 492      * @param prefix The Namespace prefix.
 493      * @param uri The Namespace URI.
 494      * @exception org.xml.sax.SAXException The client may throw
 495      *            an exception during processing.
 496      */
 497     public void startPrefixMapping (String prefix, String uri)
 498         throws SAXException
 499     {
 500         if (contentHandler != null) {
 501             contentHandler.startPrefixMapping(prefix, uri);
 502         }
 503     }
 504 
 505 
 506     /**
 507      * Filter an end Namespace prefix mapping event.
 508      *
 509      * @param prefix The Namespace prefix.
 510      * @exception org.xml.sax.SAXException The client may throw
 511      *            an exception during processing.
 512      */
 513     public void endPrefixMapping (String prefix)
 514         throws SAXException
 515     {
 516         if (contentHandler != null) {
 517             contentHandler.endPrefixMapping(prefix);
 518         }
 519     }
 520 
 521 
 522     /**
 523      * Filter a start element event.
 524      *
 525      * @param uri The element's Namespace URI, or the empty string.
 526      * @param localName The element's local name, or the empty string.
 527      * @param qName The element's qualified (prefixed) name, or the empty
 528      *        string.
 529      * @param atts The element's attributes.
 530      * @exception org.xml.sax.SAXException The client may throw
 531      *            an exception during processing.
 532      */
 533     public void startElement (String uri, String localName, String qName,
 534                               Attributes atts)
 535         throws SAXException
 536     {
 537         if (contentHandler != null) {
 538             contentHandler.startElement(uri, localName, qName, atts);
 539         }
 540     }
 541 
 542 
 543     /**
 544      * Filter an end element event.
 545      *
 546      * @param uri The element's Namespace URI, or the empty string.
 547      * @param localName The element's local name, or the empty string.
 548      * @param qName The element's qualified (prefixed) name, or the empty
 549      *        string.
 550      * @exception org.xml.sax.SAXException The client may throw
 551      *            an exception during processing.
 552      */
 553     public void endElement (String uri, String localName, String qName)
 554         throws SAXException
 555     {
 556         if (contentHandler != null) {
 557             contentHandler.endElement(uri, localName, qName);
 558         }
 559     }
 560 
 561 
 562     /**
 563      * Filter a character data event.
 564      *
 565      * @param ch An array of characters.
 566      * @param start The starting position in the array.
 567      * @param length The number of characters to use from the array.
 568      * @exception org.xml.sax.SAXException The client may throw
 569      *            an exception during processing.
 570      */
 571     public void characters (char ch[], int start, int length)
 572         throws SAXException
 573     {
 574         if (contentHandler != null) {
 575             contentHandler.characters(ch, start, length);
 576         }
 577     }
 578 
 579 
 580     /**
 581      * Filter an ignorable whitespace event.
 582      *
 583      * @param ch An array of characters.
 584      * @param start The starting position in the array.
 585      * @param length The number of characters to use from the array.
 586      * @exception org.xml.sax.SAXException The client may throw
 587      *            an exception during processing.
 588      */
 589     public void ignorableWhitespace (char ch[], int start, int length)
 590         throws SAXException
 591     {
 592         if (contentHandler != null) {
 593             contentHandler.ignorableWhitespace(ch, start, length);
 594         }
 595     }
 596 
 597 
 598     /**
 599      * Filter a processing instruction event.
 600      *
 601      * @param target The processing instruction target.
 602      * @param data The text following the target.
 603      * @exception org.xml.sax.SAXException The client may throw
 604      *            an exception during processing.
 605      */
 606     public void processingInstruction (String target, String data)
 607         throws SAXException
 608     {
 609         if (contentHandler != null) {
 610             contentHandler.processingInstruction(target, data);
 611         }
 612     }
 613 
 614 
 615     /**
 616      * Filter a skipped entity event.
 617      *
 618      * @param name The name of the skipped entity.
 619      * @exception org.xml.sax.SAXException The client may throw
 620      *            an exception during processing.
 621      */
 622     public void skippedEntity (String name)
 623         throws SAXException
 624     {
 625         if (contentHandler != null) {
 626             contentHandler.skippedEntity(name);
 627         }
 628     }
 629 
 630 
 631 
 632     ////////////////////////////////////////////////////////////////////
 633     // Implementation of org.xml.sax.ErrorHandler.
 634     ////////////////////////////////////////////////////////////////////
 635 
 636 
 637     /**
 638      * Filter a warning event.
 639      *
 640      * @param e The warning as an exception.
 641      * @exception org.xml.sax.SAXException The client may throw
 642      *            an exception during processing.
 643      */
 644     public void warning (SAXParseException e)
 645         throws SAXException
 646     {
 647         if (errorHandler != null) {
 648             errorHandler.warning(e);
 649         }
 650     }
 651 
 652 
 653     /**
 654      * Filter an error event.
 655      *
 656      * @param e The error as an exception.
 657      * @exception org.xml.sax.SAXException The client may throw
 658      *            an exception during processing.
 659      */
 660     public void error (SAXParseException e)
 661         throws SAXException
 662     {
 663         if (errorHandler != null) {
 664             errorHandler.error(e);
 665         }
 666     }
 667 
 668 
 669     /**
 670      * Filter a fatal error event.
 671      *
 672      * @param e The error as an exception.
 673      * @exception org.xml.sax.SAXException The client may throw
 674      *            an exception during processing.
 675      */
 676     public void fatalError (SAXParseException e)
 677         throws SAXException
 678     {
 679         if (errorHandler != null) {
 680             errorHandler.fatalError(e);
 681         }
 682     }
 683 
 684 
 685 
 686     ////////////////////////////////////////////////////////////////////
 687     // Internal methods.
 688     ////////////////////////////////////////////////////////////////////
 689 
 690 
 691     /**
 692      * Set up before a parse.
 693      *
 694      * <p>Before every parse, check whether the parent is
 695      * non-null, and re-register the filter for all of the
 696      * events.</p>
 697      */
 698     private void setupParse ()
 699     {
 700         if (parent == null) {
 701             throw new NullPointerException("No parent for filter");
 702         }
 703         parent.setEntityResolver(this);
 704         parent.setDTDHandler(this);
 705         parent.setContentHandler(this);
 706         parent.setErrorHandler(this);
 707     }
 708 
 709 
 710 
 711     ////////////////////////////////////////////////////////////////////
 712     // Internal state.
 713     ////////////////////////////////////////////////////////////////////
 714 
 715     private XMLReader parent = null;
 716     private Locator locator = null;
 717     private EntityResolver entityResolver = null;
 718     private DTDHandler dtdHandler = null;
 719     private ContentHandler contentHandler = null;
 720     private ErrorHandler errorHandler = null;
 721 
 722 }
 723 
 724 // end of XMLFilterImpl.java