1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 // $Id: SAXParser.java 584483 2007-10-14 02:54:48Z mrglavas $
19 
20 package javax.xml.parsers;
21 
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import javax.xml.validation.Schema;
26 import org.xml.sax.HandlerBase;
27 import org.xml.sax.InputSource;
28 import org.xml.sax.Parser;
29 import org.xml.sax.SAXException;
30 import org.xml.sax.SAXNotRecognizedException;
31 import org.xml.sax.SAXNotSupportedException;
32 import org.xml.sax.XMLReader;
33 import org.xml.sax.helpers.DefaultHandler;
34 
35 
36 /**
37  * Defines the API that wraps an {@link org.xml.sax.XMLReader}
38  * implementation class. In JAXP 1.0, this class wrapped the
39  * {@link org.xml.sax.Parser} interface, however this interface was
40  * replaced by the {@link org.xml.sax.XMLReader}. For ease
41  * of transition, this class continues to support the same name
42  * and interface as well as supporting new methods.
43  *
44  * An instance of this class can be obtained from the
45  * {@link javax.xml.parsers.SAXParserFactory#newSAXParser()} method.
46  * Once an instance of this class is obtained, XML can be parsed from
47  * a variety of input sources. These input sources are InputStreams,
48  * Files, URLs, and SAX InputSources.<p>
49  *
50  * This static method creates a new factory instance based
51  * on a system property setting or uses the platform default
52  * if no property has been defined.<p>
53  *
54  * The system property that controls which Factory implementation
55  * to create is named <code>&quot;javax.xml.parsers.SAXParserFactory&quot;</code>.
56  * This property names a class that is a concrete subclass of this
57  * abstract class. If no property is defined, a platform default
58  * will be used.</p>
59  *
60  * As the content is parsed by the underlying parser, methods of the
61  * given {@link org.xml.sax.HandlerBase} or the
62  * {@link org.xml.sax.helpers.DefaultHandler} are called.<p>
63  *
64  * Implementations of this class which wrap an underlying implementation
65  * can consider using the {@link org.xml.sax.helpers.ParserAdapter}
66  * class to initially adapt their SAX1 implementation to work under
67  * this revised class.
68  *
69  * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
70  * @version $Revision: 584483 $, $Date: 2007-10-13 19:54:48 -0700 (Sat, 13 Oct 2007) $
71  */
72 public abstract class SAXParser {
73 
74     private static final boolean DEBUG = false;
75 
76     /**
77      * <p>Protected constructor to prevent instantiation.
78      * Use {@link javax.xml.parsers.SAXParserFactory#newSAXParser()}.</p>
79      */
SAXParser()80     protected SAXParser () {
81 
82     }
83 
84     /**
85      * <p>Reset this <code>SAXParser</code> to its original configuration.</p>
86      *
87      * <p><code>SAXParser</code> is reset to the same state as when it was created with
88      * {@link SAXParserFactory#newSAXParser()}.
89      * <code>reset()</code> is designed to allow the reuse of existing <code>SAXParser</code>s
90      * thus saving resources associated with the creation of new <code>SAXParser</code>s.</p>
91      *
92      * <p>The reset <code>SAXParser</code> is not guaranteed to have the same {@link Schema}
93      * <code>Object</code>, e.g. {@link Object#equals(Object obj)}.  It is guaranteed to have a functionally equal
94      * <code>Schema</code>.</p>
95      *
96      * @since 1.5
97      */
reset()98     public void reset() {
99 
100         // implementors should override this method
101         throw new UnsupportedOperationException(
102             "This SAXParser, \"" + this.getClass().getName() + "\", does not support the reset functionality."
103             + "  Specification \"" + this.getClass().getPackage().getSpecificationTitle() + "\""
104             + " version \"" + this.getClass().getPackage().getSpecificationVersion() + "\""
105             );
106     }
107 
108     /**
109      * <p>Parse the content of the given {@link java.io.InputStream}
110      * instance as XML using the specified {@link org.xml.sax.HandlerBase}.
111      * <i> Use of the DefaultHandler version of this method is recommended as
112      * the HandlerBase class has been deprecated in SAX 2.0</i>.</p>
113      *
114      * @param is InputStream containing the content to be parsed.
115      * @param hb The SAX HandlerBase to use.
116      *
117      * @throws IllegalArgumentException If the given InputStream is null.
118      * @throws SAXException If parse produces a SAX error.
119      * @throws IOException If an IO error occurs interacting with the
120      *   <code>InputStream</code>.
121      *
122      * @see org.xml.sax.DocumentHandler
123      */
parse(InputStream is, HandlerBase hb)124     public void parse(InputStream is, HandlerBase hb)
125         throws SAXException, IOException {
126         if (is == null) {
127             throw new IllegalArgumentException("InputStream cannot be null");
128         }
129 
130         InputSource input = new InputSource(is);
131         this.parse(input, hb);
132     }
133 
134     /**
135      * <p>Parse the content of the given {@link java.io.InputStream}
136      * instance as XML using the specified {@link org.xml.sax.HandlerBase}.
137      * <i> Use of the DefaultHandler version of this method is recommended as
138      * the HandlerBase class has been deprecated in SAX 2.0</i>.</p>
139      *
140      * @param is InputStream containing the content to be parsed.
141      * @param hb The SAX HandlerBase to use.
142      * @param systemId The systemId which is needed for resolving relative URIs.
143      *
144      * @throws IllegalArgumentException If the given <code>InputStream</code> is
145      *   <code>null</code>.
146      * @throws IOException If any IO error occurs interacting with the
147      *   <code>InputStream</code>.
148      * @throws SAXException If any SAX errors occur during processing.
149      *
150      * @see org.xml.sax.DocumentHandler version of this method instead.
151      */
parse( InputStream is, HandlerBase hb, String systemId)152     public void parse(
153         InputStream is,
154         HandlerBase hb,
155         String systemId)
156         throws SAXException, IOException {
157         if (is == null) {
158             throw new IllegalArgumentException("InputStream cannot be null");
159         }
160 
161         InputSource input = new InputSource(is);
162         input.setSystemId(systemId);
163         this.parse(input, hb);
164     }
165 
166     /**
167      * Parse the content of the given {@link java.io.InputStream}
168      * instance as XML using the specified
169      * {@link org.xml.sax.helpers.DefaultHandler}.
170      *
171      * @param is InputStream containing the content to be parsed.
172      * @param dh The SAX DefaultHandler to use.
173      *
174      * @throws IllegalArgumentException If the given InputStream is null.
175      * @throws IOException If any IO errors occur.
176      * @throws SAXException If any SAX errors occur during processing.
177      *
178      * @see org.xml.sax.DocumentHandler
179      */
parse(InputStream is, DefaultHandler dh)180     public void parse(InputStream is, DefaultHandler dh)
181         throws SAXException, IOException {
182         if (is == null) {
183             throw new IllegalArgumentException("InputStream cannot be null");
184         }
185 
186         InputSource input = new InputSource(is);
187         this.parse(input, dh);
188     }
189 
190     /**
191      * Parse the content of the given {@link java.io.InputStream}
192      * instance as XML using the specified
193      * {@link org.xml.sax.helpers.DefaultHandler}.
194      *
195      * @param is InputStream containing the content to be parsed.
196      * @param dh The SAX DefaultHandler to use.
197      * @param systemId The systemId which is needed for resolving relative URIs.
198      *
199      * @throws IllegalArgumentException If the given InputStream is null.
200      * @throws IOException If any IO errors occur.
201      * @throws SAXException If any SAX errors occur during processing.
202      *
203      * @see org.xml.sax.DocumentHandler version of this method instead.
204      */
parse( InputStream is, DefaultHandler dh, String systemId)205     public void parse(
206         InputStream is,
207         DefaultHandler dh,
208         String systemId)
209         throws SAXException, IOException {
210         if (is == null) {
211             throw new IllegalArgumentException("InputStream cannot be null");
212         }
213 
214         InputSource input = new InputSource(is);
215         input.setSystemId(systemId);
216         this.parse(input, dh);
217     }
218 
219     /**
220      * Parse the content described by the giving Uniform Resource
221      * Identifier (URI) as XML using the specified
222      * {@link org.xml.sax.HandlerBase}.
223      * <i> Use of the DefaultHandler version of this method is recommended as
224      * the <code>HandlerBase</code> class has been deprecated in SAX 2.0</i>
225      *
226      * @param uri The location of the content to be parsed.
227      * @param hb The SAX HandlerBase to use.
228      *
229      * @throws IllegalArgumentException If the uri is null.
230      * @throws IOException If any IO errors occur.
231      * @throws SAXException If any SAX errors occur during processing.
232      *
233      * @see org.xml.sax.DocumentHandler
234      */
parse(String uri, HandlerBase hb)235     public void parse(String uri, HandlerBase hb)
236         throws SAXException, IOException {
237         if (uri == null) {
238             throw new IllegalArgumentException("uri cannot be null");
239         }
240 
241         InputSource input = new InputSource(uri);
242         this.parse(input, hb);
243     }
244 
245     /**
246      * Parse the content described by the giving Uniform Resource
247      * Identifier (URI) as XML using the specified
248      * {@link org.xml.sax.helpers.DefaultHandler}.
249      *
250      * @param uri The location of the content to be parsed.
251      * @param dh The SAX DefaultHandler to use.
252      *
253      * @throws IllegalArgumentException If the uri is null.
254      * @throws IOException If any IO errors occur.
255      * @throws SAXException If any SAX errors occur during processing.
256      *
257      * @see org.xml.sax.DocumentHandler
258      */
parse(String uri, DefaultHandler dh)259     public void parse(String uri, DefaultHandler dh)
260         throws SAXException, IOException {
261         if (uri == null) {
262             throw new IllegalArgumentException("uri cannot be null");
263         }
264 
265         InputSource input = new InputSource(uri);
266         this.parse(input, dh);
267     }
268 
269     /**
270      * Parse the content of the file specified as XML using the
271      * specified {@link org.xml.sax.HandlerBase}.
272      * <i> Use of the DefaultHandler version of this method is recommended as
273      * the HandlerBase class has been deprecated in SAX 2.0</i>
274      *
275      * @param f The file containing the XML to parse
276      * @param hb The SAX HandlerBase to use.
277      *
278      * @throws IllegalArgumentException If the File object is null.
279      * @throws IOException If any IO errors occur.
280      * @throws SAXException If any SAX errors occur during processing.
281      *
282      * @see org.xml.sax.DocumentHandler
283      */
parse(File f, HandlerBase hb)284     public void parse(File f, HandlerBase hb)
285         throws SAXException, IOException {
286         if (f == null) {
287             throw new IllegalArgumentException("File cannot be null");
288         }
289 
290         String escapedURI = FilePathToURI.filepath2URI(f.getAbsolutePath());
291 
292         if (DEBUG) {
293             System.out.println("Escaped URI = " + escapedURI);
294         }
295 
296         InputSource input = new InputSource(escapedURI);
297         this.parse(input, hb);
298     }
299 
300     /**
301      * Parse the content of the file specified as XML using the
302      * specified {@link org.xml.sax.helpers.DefaultHandler}.
303      *
304      * @param f The file containing the XML to parse
305      * @param dh The SAX DefaultHandler to use.
306      *
307      * @throws IllegalArgumentException If the File object is null.
308      * @throws IOException If any IO errors occur.
309      * @throws SAXException If any SAX errors occur during processing.
310      *
311      * @see org.xml.sax.DocumentHandler
312      */
parse(File f, DefaultHandler dh)313     public void parse(File f, DefaultHandler dh)
314         throws SAXException, IOException {
315         if (f == null) {
316             throw new IllegalArgumentException("File cannot be null");
317         }
318 
319         String escapedURI = FilePathToURI.filepath2URI(f.getAbsolutePath());
320 
321         if (DEBUG) {
322             System.out.println("Escaped URI = " + escapedURI);
323         }
324 
325         InputSource input = new InputSource(escapedURI);
326         this.parse(input, dh);
327     }
328 
329     /**
330      * Parse the content given {@link org.xml.sax.InputSource}
331      * as XML using the specified
332      * {@link org.xml.sax.HandlerBase}.
333      * <i> Use of the DefaultHandler version of this method is recommended as
334      * the HandlerBase class has been deprecated in SAX 2.0</i>
335      *
336      * @param is The InputSource containing the content to be parsed.
337      * @param hb The SAX HandlerBase to use.
338      *
339      * @throws IllegalArgumentException If the <code>InputSource</code> object
340      *   is <code>null</code>.
341      * @throws IOException If any IO errors occur.
342      * @throws SAXException If any SAX errors occur during processing.
343      *
344      * @see org.xml.sax.DocumentHandler
345      */
parse(InputSource is, HandlerBase hb)346     public void parse(InputSource is, HandlerBase hb)
347         throws SAXException, IOException {
348         if (is == null) {
349             throw new IllegalArgumentException("InputSource cannot be null");
350         }
351 
352         Parser parser = this.getParser();
353         if (hb != null) {
354             parser.setDocumentHandler(hb);
355             parser.setEntityResolver(hb);
356             parser.setErrorHandler(hb);
357             parser.setDTDHandler(hb);
358         }
359         parser.parse(is);
360     }
361 
362     /**
363      * Parse the content given {@link org.xml.sax.InputSource}
364      * as XML using the specified
365      * {@link org.xml.sax.helpers.DefaultHandler}.
366      *
367      * @param is The InputSource containing the content to be parsed.
368      * @param dh The SAX DefaultHandler to use.
369      *
370      * @throws IllegalArgumentException If the <code>InputSource</code> object
371      *   is <code>null</code>.
372      * @throws IOException If any IO errors occur.
373      * @throws SAXException If any SAX errors occur during processing.
374      *
375      * @see org.xml.sax.DocumentHandler
376      */
parse(InputSource is, DefaultHandler dh)377     public void parse(InputSource is, DefaultHandler dh)
378         throws SAXException, IOException {
379         if (is == null) {
380             throw new IllegalArgumentException("InputSource cannot be null");
381         }
382 
383         XMLReader reader = this.getXMLReader();
384         if (dh != null) {
385             reader.setContentHandler(dh);
386             reader.setEntityResolver(dh);
387             reader.setErrorHandler(dh);
388             reader.setDTDHandler(dh);
389         }
390         reader.parse(is);
391     }
392 
393     /**
394      * Returns the SAX parser that is encapsulated by the
395      * implementation of this class.
396      *
397      * @return The SAX parser that is encapsulated by the
398      *         implementation of this class.
399      *
400      * @throws SAXException If any SAX errors occur during processing.
401      */
getParser()402     public abstract org.xml.sax.Parser getParser() throws SAXException;
403 
404     /**
405      * Returns the {@link org.xml.sax.XMLReader} that is encapsulated by the
406      * implementation of this class.
407      *
408      * @return The XMLReader that is encapsulated by the
409      *         implementation of this class.
410      *
411      * @throws SAXException If any SAX errors occur during processing.
412      */
413 
getXMLReader()414     public abstract org.xml.sax.XMLReader getXMLReader() throws SAXException;
415 
416     /**
417      * Indicates whether or not this parser is configured to
418      * understand namespaces.
419      *
420      * @return true if this parser is configured to
421      *         understand namespaces; false otherwise.
422      */
423 
isNamespaceAware()424     public abstract boolean isNamespaceAware();
425 
426     /**
427      * Indicates whether or not this parser is configured to
428      * validate XML documents.
429      *
430      * @return true if this parser is configured to
431      *         validate XML documents; false otherwise.
432      */
433 
isValidating()434     public abstract boolean isValidating();
435 
436     /**
437      * <p>Sets the particular property in the underlying implementation of
438      * {@link org.xml.sax.XMLReader}.
439      * A list of the core features and properties can be found at
440      * <a href="http://sax.sourceforge.net/?selected=get-set">
441      * http://sax.sourceforge.net/?selected=get-set</a>.</p>
442      *
443      * @param name The name of the property to be set.
444      * @param value The value of the property to be set.
445      *
446      * @throws SAXNotRecognizedException When the underlying XMLReader does
447      *   not recognize the property name.
448      * @throws SAXNotSupportedException When the underlying XMLReader
449      *  recognizes the property name but doesn't support the property.
450      *
451      * @see org.xml.sax.XMLReader#setProperty
452      */
setProperty(String name, Object value)453     public abstract void setProperty(String name, Object value)
454         throws SAXNotRecognizedException, SAXNotSupportedException;
455 
456     /**
457      * <p>Returns the particular property requested for in the underlying
458      * implementation of {@link org.xml.sax.XMLReader}.</p>
459      *
460      * @param name The name of the property to be retrieved.
461      * @return Value of the requested property.
462      *
463      * @throws SAXNotRecognizedException When the underlying XMLReader does
464      *    not recognize the property name.
465      * @throws SAXNotSupportedException When the underlying XMLReader
466      *  recognizes the property name but doesn't support the property.
467      *
468      * @see org.xml.sax.XMLReader#getProperty
469      */
getProperty(String name)470     public abstract Object getProperty(String name)
471         throws SAXNotRecognizedException, SAXNotSupportedException;
472 
473     /** <p>Get a reference to the the {@link Schema} being used by
474      * the XML processor.</p>
475      *
476      * <p>If no schema is being used, <code>null</code> is returned.</p>
477      *
478      * @return {@link Schema} being used or <code>null</code>
479      *  if none in use
480      *
481      * @throws UnsupportedOperationException
482      *      For backward compatibility, when implementations for
483      *      earlier versions of JAXP is used, this exception will be
484      *      thrown.
485      *
486      * @since 1.5
487      */
getSchema()488     public Schema getSchema() {
489         throw new UnsupportedOperationException(
490             "This parser does not support specification \""
491             + this.getClass().getPackage().getSpecificationTitle()
492             + "\" version \""
493             + this.getClass().getPackage().getSpecificationVersion()
494             + "\""
495             );
496     }
497 
498     /**
499      * <p>Get the XInclude processing mode for this parser.</p>
500      *
501      * @return
502      *      the return value of
503      *      the {@link SAXParserFactory#isXIncludeAware()}
504      *      when this parser was created from factory.
505      *
506      * @throws UnsupportedOperationException
507      *      For backward compatibility, when implementations for
508      *      earlier versions of JAXP is used, this exception will be
509      *      thrown.
510      *
511      * @since 1.5
512      *
513      * @see SAXParserFactory#setXIncludeAware(boolean)
514      */
isXIncludeAware()515     public boolean isXIncludeAware() {
516         throw new UnsupportedOperationException(
517             "This parser does not support specification \""
518             + this.getClass().getPackage().getSpecificationTitle()
519             + "\" version \""
520             + this.getClass().getPackage().getSpecificationVersion()
521             + "\""
522             );
523     }
524 }
525