1 /*
   2  * Copyright (c) 2000, 2015, 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 javax.xml.parsers;
  27 
  28 import java.io.File;
  29 import java.io.IOException;
  30 import java.io.InputStream;
  31 
  32 import javax.xml.validation.Schema;
  33 
  34 import org.xml.sax.HandlerBase;
  35 import org.xml.sax.InputSource;
  36 import org.xml.sax.Parser;
  37 import org.xml.sax.SAXException;
  38 import org.xml.sax.SAXNotRecognizedException;
  39 import org.xml.sax.SAXNotSupportedException;
  40 import org.xml.sax.XMLReader;
  41 import org.xml.sax.helpers.DefaultHandler;
  42 
  43 
  44 /**
  45  * Defines the API that wraps an {@link org.xml.sax.XMLReader}
  46  * implementation class. In JAXP 1.0, this class wrapped the
  47  * {@link org.xml.sax.Parser} interface, however this interface was
  48  * replaced by the {@link org.xml.sax.XMLReader}. For ease
  49  * of transition, this class continues to support the same name
  50  * and interface as well as supporting new methods.
  51  *
  52  * An instance of this class can be obtained from the
  53  * {@link javax.xml.parsers.SAXParserFactory#newSAXParser()} method.
  54  * Once an instance of this class is obtained, XML can be parsed from
  55  * a variety of input sources. These input sources are InputStreams,
  56  * Files, URLs, and SAX InputSources.<p>
  57  *
  58  * This static method creates a new factory instance based
  59  * on a system property setting or uses the platform default
  60  * if no property has been defined.<p>
  61  *
  62  * The system property that controls which Factory implementation
  63  * to create is named <code>&quot;javax.xml.parsers.SAXParserFactory&quot;</code>.
  64  * This property names a class that is a concrete subclass of this
  65  * abstract class. If no property is defined, a platform default
  66  * will be used.</p>
  67  *
  68  * As the content is parsed by the underlying parser, methods of the
  69  * given {@link org.xml.sax.HandlerBase} or the
  70  * {@link org.xml.sax.helpers.DefaultHandler} are called.<p>
  71  *
  72  * Implementors of this class which wrap an underlying implementation
  73  * can consider using the {@link org.xml.sax.helpers.ParserAdapter}
  74  * class to initially adapt their SAX1 implementation to work under
  75  * this revised class.
  76  *
  77  * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
  78  * @since 1.4
  79  */
  80 public abstract class SAXParser {
  81 
  82     /**
  83      * <p>Protected constructor to prevent instantiation.
  84      * Use {@link javax.xml.parsers.SAXParserFactory#newSAXParser()}.</p>
  85      */
  86     protected SAXParser () {
  87 
  88     }
  89 
  90         /**
  91          * <p>Reset this <code>SAXParser</code> to its original configuration.</p>
  92          *
  93          * <p><code>SAXParser</code> is reset to the same state as when it was created with
  94          * {@link SAXParserFactory#newSAXParser()}.
  95          * <code>reset()</code> is designed to allow the reuse of existing <code>SAXParser</code>s
  96          * thus saving resources associated with the creation of new <code>SAXParser</code>s.</p>
  97          *
  98          * <p>The reset <code>SAXParser</code> is not guaranteed to have the same {@link Schema}
  99          * <code>Object</code>, e.g. {@link Object#equals(Object obj)}.  It is guaranteed to have a functionally equal
 100          * <code>Schema</code>.</p>
 101      *
 102      * @throws UnsupportedOperationException When Implementations do not
 103      *   override this method
 104          *
 105          * @since 1.5
 106          */
 107         public void reset() {
 108 
 109                 // implementors should override this method
 110                 throw new UnsupportedOperationException(
 111                         "This SAXParser, \"" + this.getClass().getName() + "\", does not support the reset functionality."
 112                         + "  Specification \"" + this.getClass().getPackage().getSpecificationTitle() + "\""
 113                         + " version \"" + this.getClass().getPackage().getSpecificationVersion() + "\""
 114                         );
 115         }
 116 
 117     /**
 118      * <p>Parse the content of the given {@link java.io.InputStream}
 119      * instance as XML using the specified {@link org.xml.sax.HandlerBase}.
 120      * <i> Use of the DefaultHandler version of this method is recommended as
 121      * the HandlerBase class has been deprecated in SAX 2.0</i>.</p>
 122      *
 123      * @param is InputStream containing the content to be parsed.
 124      * @param hb The SAX HandlerBase to use.
 125      *
 126      * @throws IllegalArgumentException If the given InputStream is null.
 127      * @throws SAXException If parse produces a SAX error.
 128      * @throws IOException If an IO error occurs interacting with the
 129      *   <code>InputStream</code>.
 130      *
 131      * @see org.xml.sax.DocumentHandler
 132      */
 133     public void parse(InputStream is, HandlerBase hb)
 134         throws SAXException, IOException {
 135         if (is == null) {
 136             throw new IllegalArgumentException("InputStream cannot be null");
 137         }
 138 
 139         InputSource input = new InputSource(is);
 140         this.parse(input, hb);
 141     }
 142 
 143     /**
 144      * <p>Parse the content of the given {@link java.io.InputStream}
 145      * instance as XML using the specified {@link org.xml.sax.HandlerBase}.
 146      * <i> Use of the DefaultHandler version of this method is recommended as
 147      * the HandlerBase class has been deprecated in SAX 2.0</i>.</p>
 148      *
 149      * @param is InputStream containing the content to be parsed.
 150      * @param hb The SAX HandlerBase to use.
 151      * @param systemId The systemId which is needed for resolving relative URIs.
 152      *
 153      * @throws IllegalArgumentException If the given <code>InputStream</code> is
 154      *   <code>null</code>.
 155      * @throws IOException If any IO error occurs interacting with the
 156      *   <code>InputStream</code>.
 157      * @throws SAXException If any SAX errors occur during processing.
 158      *
 159      * @see org.xml.sax.DocumentHandler version of this method instead.
 160      */
 161     public void parse(
 162         InputStream is,
 163         HandlerBase hb,
 164         String systemId)
 165         throws SAXException, IOException {
 166         if (is == null) {
 167             throw new IllegalArgumentException("InputStream cannot be null");
 168         }
 169 
 170         InputSource input = new InputSource(is);
 171         input.setSystemId(systemId);
 172         this.parse(input, hb);
 173     }
 174 
 175     /**
 176      * Parse the content of the given {@link java.io.InputStream}
 177      * instance as XML using the specified
 178      * {@link org.xml.sax.helpers.DefaultHandler}.
 179      *
 180      * @param is InputStream containing the content to be parsed.
 181      * @param dh The SAX DefaultHandler to use.
 182      *
 183      * @throws IllegalArgumentException If the given InputStream is null.
 184      * @throws IOException If any IO errors occur.
 185      * @throws SAXException If any SAX errors occur during processing.
 186      *
 187      * @see org.xml.sax.DocumentHandler
 188      */
 189     public void parse(InputStream is, DefaultHandler dh)
 190         throws SAXException, IOException {
 191         if (is == null) {
 192             throw new IllegalArgumentException("InputStream cannot be null");
 193         }
 194 
 195         InputSource input = new InputSource(is);
 196         this.parse(input, dh);
 197     }
 198 
 199     /**
 200      * Parse the content of the given {@link java.io.InputStream}
 201      * instance as XML using the specified
 202      * {@link org.xml.sax.helpers.DefaultHandler}.
 203      *
 204      * @param is InputStream containing the content to be parsed.
 205      * @param dh The SAX DefaultHandler to use.
 206      * @param systemId The systemId which is needed for resolving relative URIs.
 207      *
 208      * @throws IllegalArgumentException If the given InputStream is null.
 209      * @throws IOException If any IO errors occur.
 210      * @throws SAXException If any SAX errors occur during processing.
 211      *
 212      * @see org.xml.sax.DocumentHandler version of this method instead.
 213      */
 214     public void parse(
 215         InputStream is,
 216         DefaultHandler dh,
 217         String systemId)
 218         throws SAXException, IOException {
 219         if (is == null) {
 220             throw new IllegalArgumentException("InputStream cannot be null");
 221         }
 222 
 223         InputSource input = new InputSource(is);
 224         input.setSystemId(systemId);
 225         this.parse(input, dh);
 226     }
 227 
 228     /**
 229      * Parse the content described by the giving Uniform Resource
 230      * Identifier (URI) as XML using the specified
 231      * {@link org.xml.sax.HandlerBase}.
 232      * <i> Use of the DefaultHandler version of this method is recommended as
 233      * the <code>HandlerBase</code> class has been deprecated in SAX 2.0</i>
 234      *
 235      * @param uri The location of the content to be parsed.
 236      * @param hb The SAX HandlerBase to use.
 237      *
 238      * @throws IllegalArgumentException If the uri is null.
 239      * @throws IOException If any IO errors occur.
 240      * @throws SAXException If any SAX errors occur during processing.
 241      *
 242      * @see org.xml.sax.DocumentHandler
 243      */
 244     public void parse(String uri, HandlerBase hb)
 245         throws SAXException, IOException {
 246         if (uri == null) {
 247             throw new IllegalArgumentException("uri cannot be null");
 248         }
 249 
 250         InputSource input = new InputSource(uri);
 251         this.parse(input, hb);
 252     }
 253 
 254     /**
 255      * Parse the content described by the giving Uniform Resource
 256      * Identifier (URI) as XML using the specified
 257      * {@link org.xml.sax.helpers.DefaultHandler}.
 258      *
 259      * @param uri The location of the content to be parsed.
 260      * @param dh The SAX DefaultHandler to use.
 261      *
 262      * @throws IllegalArgumentException If the uri is null.
 263      * @throws IOException If any IO errors occur.
 264      * @throws SAXException If any SAX errors occur during processing.
 265      *
 266      * @see org.xml.sax.DocumentHandler
 267      */
 268     public void parse(String uri, DefaultHandler dh)
 269         throws SAXException, IOException {
 270         if (uri == null) {
 271             throw new IllegalArgumentException("uri cannot be null");
 272         }
 273 
 274         InputSource input = new InputSource(uri);
 275         this.parse(input, dh);
 276     }
 277 
 278     /**
 279      * Parse the content of the file specified as XML using the
 280      * specified {@link org.xml.sax.HandlerBase}.
 281      * <i> Use of the DefaultHandler version of this method is recommended as
 282      * the HandlerBase class has been deprecated in SAX 2.0</i>
 283      *
 284      * @param f The file containing the XML to parse
 285      * @param hb The SAX HandlerBase to use.
 286      *
 287      * @throws IllegalArgumentException If the File object is null.
 288      * @throws IOException If any IO errors occur.
 289      * @throws SAXException If any SAX errors occur during processing.
 290      *
 291      * @see org.xml.sax.DocumentHandler
 292      */
 293     public void parse(File f, HandlerBase hb)
 294         throws SAXException, IOException {
 295         if (f == null) {
 296             throw new IllegalArgumentException("File cannot be null");
 297         }
 298 
 299         //convert file to appropriate URI, f.toURI().toASCIIString()
 300         //converts the URI to string as per rule specified in
 301         //RFC 2396,
 302         InputSource input = new InputSource(f.toURI().toASCIIString());
 303         this.parse(input, hb);
 304     }
 305 
 306     /**
 307      * Parse the content of the file specified as XML using the
 308      * specified {@link org.xml.sax.helpers.DefaultHandler}.
 309      *
 310      * @param f The file containing the XML to parse
 311      * @param dh The SAX DefaultHandler to use.
 312      *
 313      * @throws IllegalArgumentException If the File object is null.
 314      * @throws IOException If any IO errors occur.
 315      * @throws SAXException If any SAX errors occur during processing.
 316      *
 317      * @see org.xml.sax.DocumentHandler
 318      */
 319     public void parse(File f, DefaultHandler dh)
 320         throws SAXException, IOException {
 321         if (f == null) {
 322             throw new IllegalArgumentException("File cannot be null");
 323         }
 324 
 325         //convert file to appropriate URI, f.toURI().toASCIIString()
 326         //converts the URI to string as per rule specified in
 327         //RFC 2396,
 328         InputSource input = new InputSource(f.toURI().toASCIIString());
 329         this.parse(input, dh);
 330     }
 331 
 332     /**
 333      * Parse the content given {@link org.xml.sax.InputSource}
 334      * as XML using the specified
 335      * {@link org.xml.sax.HandlerBase}.
 336      * <i> Use of the DefaultHandler version of this method is recommended as
 337      * the HandlerBase class has been deprecated in SAX 2.0</i>
 338      *
 339      * @param is The InputSource containing the content to be parsed.
 340      * @param hb The SAX HandlerBase to use.
 341      *
 342      * @throws IllegalArgumentException If the <code>InputSource</code> object
 343      *   is <code>null</code>.
 344      * @throws IOException If any IO errors occur.
 345      * @throws SAXException If any SAX errors occur during processing.
 346      *
 347      * @see org.xml.sax.DocumentHandler
 348      */
 349     public void parse(InputSource is, HandlerBase hb)
 350         throws SAXException, IOException {
 351         if (is == null) {
 352             throw new IllegalArgumentException("InputSource cannot be null");
 353         }
 354 
 355         Parser parser = this.getParser();
 356         if (hb != null) {
 357             parser.setDocumentHandler(hb);
 358             parser.setEntityResolver(hb);
 359             parser.setErrorHandler(hb);
 360             parser.setDTDHandler(hb);
 361         }
 362         parser.parse(is);
 363     }
 364 
 365     /**
 366      * Parse the content given {@link org.xml.sax.InputSource}
 367      * as XML using the specified
 368      * {@link org.xml.sax.helpers.DefaultHandler}.
 369      *
 370      * @param is The InputSource containing the content to be parsed.
 371      * @param dh The SAX DefaultHandler to use.
 372      *
 373      * @throws IllegalArgumentException If the <code>InputSource</code> object
 374      *   is <code>null</code>.
 375      * @throws IOException If any IO errors occur.
 376      * @throws SAXException If any SAX errors occur during processing.
 377      *
 378      * @see org.xml.sax.DocumentHandler
 379      */
 380     public void parse(InputSource is, DefaultHandler dh)
 381         throws SAXException, IOException {
 382         if (is == null) {
 383             throw new IllegalArgumentException("InputSource cannot be null");
 384         }
 385 
 386         XMLReader reader = this.getXMLReader();
 387         if (dh != null) {
 388             reader.setContentHandler(dh);
 389             reader.setEntityResolver(dh);
 390             reader.setErrorHandler(dh);
 391             reader.setDTDHandler(dh);
 392         }
 393         reader.parse(is);
 394     }
 395 
 396     /**
 397      * Returns the SAX parser that is encapsulated by the
 398      * implementation of this class.
 399      *
 400      * @return The SAX parser that is encapsulated by the
 401      *         implementation of this class.
 402      *
 403      * @throws SAXException If any SAX errors occur during processing.
 404      */
 405     public abstract org.xml.sax.Parser getParser() throws SAXException;
 406 
 407     /**
 408      * Returns the {@link org.xml.sax.XMLReader} that is encapsulated by the
 409      * implementation of this class.
 410      *
 411      * @return The XMLReader that is encapsulated by the
 412      *         implementation of this class.
 413      *
 414      * @throws SAXException If any SAX errors occur during processing.
 415      */
 416 
 417     public abstract org.xml.sax.XMLReader getXMLReader() throws SAXException;
 418 
 419     /**
 420      * Indicates whether or not this parser is configured to
 421      * understand namespaces.
 422      *
 423      * @return true if this parser is configured to
 424      *         understand namespaces; false otherwise.
 425      */
 426 
 427     public abstract boolean isNamespaceAware();
 428 
 429     /**
 430      * Indicates whether or not this parser is configured to
 431      * validate XML documents.
 432      *
 433      * @return true if this parser is configured to
 434      *         validate XML documents; false otherwise.
 435      */
 436 
 437     public abstract boolean isValidating();
 438 
 439     /**
 440      * <p>Sets the particular property in the underlying implementation of
 441      * {@link org.xml.sax.XMLReader}.
 442      * A list of the core features and properties can be found at
 443      * <a href="http://sax.sourceforge.net/?selected=get-set">
 444      * http://sax.sourceforge.net/?selected=get-set</a>.</p>
 445      * <p>
 446      * All implementations that implement JAXP 1.5 or newer are required to
 447      * support the {@link javax.xml.XMLConstants#ACCESS_EXTERNAL_DTD} and
 448      * {@link javax.xml.XMLConstants#ACCESS_EXTERNAL_SCHEMA} properties.
 449      * </p>
 450      * <ul>
 451      *   <li>
 452      *      <p>
 453      *      Setting the {@link javax.xml.XMLConstants#ACCESS_EXTERNAL_DTD} property
 454      *      restricts the access to external DTDs, external Entity References to
 455      *      the protocols specified by the property.  If access is denied during parsing
 456      *      due to the restriction of this property, {@link org.xml.sax.SAXException}
 457      *      will be thrown by the parse methods defined by {@link javax.xml.parsers.SAXParser}.
 458      *      </p>
 459      *      <p>
 460      *      Setting the {@link javax.xml.XMLConstants#ACCESS_EXTERNAL_SCHEMA} property
 461      *      restricts the access to external Schema set by the schemaLocation attribute to
 462      *      the protocols specified by the property.  If access is denied during parsing
 463      *      due to the restriction of this property, {@link org.xml.sax.SAXException}
 464      *      will be thrown by the parse methods defined by the {@link javax.xml.parsers.SAXParser}.
 465      *      </p>
 466      *   </li>
 467      * </ul>
 468      *
 469      * @param name The name of the property to be set.
 470      * @param value The value of the property to be set.
 471      *
 472      * @throws SAXNotRecognizedException When the underlying XMLReader does
 473      *   not recognize the property name.
 474      * @throws SAXNotSupportedException When the underlying XMLReader
 475      *  recognizes the property name but doesn't support the property.
 476      *
 477      * @see org.xml.sax.XMLReader#setProperty
 478      */
 479     public abstract void setProperty(String name, Object value)
 480         throws SAXNotRecognizedException, SAXNotSupportedException;
 481 
 482     /**
 483      * <p>Returns the particular property requested for in the underlying
 484      * implementation of {@link org.xml.sax.XMLReader}.</p>
 485      *
 486      * @param name The name of the property to be retrieved.
 487      * @return Value of the requested property.
 488      *
 489      * @throws SAXNotRecognizedException When the underlying XMLReader does
 490      *    not recognize the property name.
 491      * @throws SAXNotSupportedException When the underlying XMLReader
 492      *  recognizes the property name but doesn't support the property.
 493      *
 494      * @see org.xml.sax.XMLReader#getProperty
 495      */
 496     public abstract Object getProperty(String name)
 497         throws SAXNotRecognizedException, SAXNotSupportedException;
 498 
 499     /** <p>Get current state of canonicalization.</p>
 500      *
 501      * @return current state canonicalization control
 502      */
 503     /*
 504     public boolean getCanonicalization() {
 505         return canonicalState;
 506     }
 507     */
 508 
 509     /** <p>Get a reference to the the {@link Schema} being used by
 510      * the XML processor.</p>
 511      *
 512      * <p>If no schema is being used, <code>null</code> is returned.</p>
 513      *
 514      * @return {@link Schema} being used or <code>null</code>
 515      *  if none in use
 516      *
 517      * @throws UnsupportedOperationException When implementation does not
 518      *   override this method
 519      *
 520      * @since 1.5
 521      */
 522     public Schema getSchema() {
 523         throw new UnsupportedOperationException(
 524             "This parser does not support specification \""
 525             + this.getClass().getPackage().getSpecificationTitle()
 526             + "\" version \""
 527             + this.getClass().getPackage().getSpecificationVersion()
 528             + "\""
 529             );
 530     }
 531 
 532     /**
 533      * <p>Get the XInclude processing mode for this parser.</p>
 534      *
 535      * @return
 536      *      the return value of
 537      *      the {@link SAXParserFactory#isXIncludeAware()}
 538      *      when this parser was created from factory.
 539      *
 540      * @throws UnsupportedOperationException When implementation does not
 541      *   override this method
 542      *
 543      * @since 1.5
 544      *
 545      * @see SAXParserFactory#setXIncludeAware(boolean)
 546      */
 547     public boolean isXIncludeAware() {
 548         throw new UnsupportedOperationException(
 549             "This parser does not support specification \""
 550             + this.getClass().getPackage().getSpecificationTitle()
 551             + "\" version \""
 552             + this.getClass().getPackage().getSpecificationVersion()
 553             + "\""
 554             );
 555     }
 556 
 557 
 558     /**
 559      * Stops the parsing process.
 560      * <p>
 561      * This method can be called anywhere from any event method of a SAX
 562      * handler. Once called, it does not terminate the parsing process
 563      * immediately. Instead, it will continue finishing and returning the
 564      * current event, and marking the state before it stops parsing. The
 565      * parsing state is maintained after the process is stopped.
 566      * <p>
 567      * The event from which the method is called is considered parsed. In case
 568      * the parsing process is subsequently resumed, it will start at the next
 569      * event.
 570      *
 571      * @implSpec
 572      * The method in the {@code javax.xml.parsers} API does nothing and returns
 573      * false by default. Implementations that implement this method may choose
 574      * to continue to a state for possible resumption of the operation. It is
 575      * recommended that the current event be returned before terminating
 576      * the parsing process.
 577      * <p>
 578      * The method shall return true once it has notified the parser to stop
 579      * parsing.
 580      *
 581      * @return true if the parsing process can be stopped, false otherwise
 582      */
 583     public boolean stop() {
 584         return false;
 585     }
 586 
 587     /**
 588      * Resumes the parsing process that has been stopped by the {@link #stop()}
 589      * method. The method will simply return if parsing is not stopped.
 590      *
 591      * @implSpec
 592      * The method in the {@code javax.xml.parsers} API does nothing and returns
 593      * false by default. Implementations that implement this method shall
 594      * check the state to determine whether the parsing process can be resumed.
 595      * It shall return true after it restarted the parsing regardless of what
 596      * may happen in the rest of the parsing process, that is, the return value
 597      * only indicates that the parsing can be and has been resumed.
 598      *
 599      * @return true if the parsing process is resumed successfully, false
 600      * otherwise
 601      */
 602     public boolean resume() {
 603         return false;
 604     }
 605 }