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
20package javax.xml.parsers;
21
22import java.io.File;
23import java.io.IOException;
24import java.io.InputStream;
25import javax.xml.validation.Schema;
26import org.xml.sax.HandlerBase;
27import org.xml.sax.InputSource;
28import org.xml.sax.Parser;
29import org.xml.sax.SAXException;
30import org.xml.sax.SAXNotRecognizedException;
31import org.xml.sax.SAXNotSupportedException;
32import org.xml.sax.XMLReader;
33import 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 */
72public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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
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
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     */
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     */
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     */
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     */
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