1
// XMLReaderFactory.java - factory for creating a new reader.
2
// http://www.saxproject.org
3
// Written by David Megginson
4
// and by David Brownell
5
// NO WARRANTY! This class is in the Public Domain.
6
// $Id: XMLReaderFactory.java 226251 2005-06-21 19:19:22Z mrglavas $
8
package org.xml.sax.helpers;
9
import java.io.BufferedReader;
10
import java.io.IOException;
11
import java.io.InputStream;
12
import java.io.InputStreamReader;
13
import org.xml.sax.XMLReader;
14
import org.xml.sax.SAXException;
18
* Factory for creating an XML reader.
21
* <em>This module, both source code and documentation, is in the
22
* Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
23
* See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
24
* for further information.
27
* <p>This class contains static methods for creating an XML reader
28
* from an explicit class name, or based on runtime defaults:</p>
32
* XMLReader myReader = XMLReaderFactory.createXMLReader();
33
* } catch (SAXException e) {
34
* System.err.println(e.getMessage());
38
* <p><strong>Note to Distributions bundled with parsers:</strong>
39
* You should modify the implementation of the no-arguments
40
* <em>createXMLReader</em> to handle cases where the external
41
* configuration mechanisms aren't set up. That method should do its
42
* best to return a parser when one is in the class path, even when
43
* nothing bound its class name to <code>org.xml.sax.driver</code> so
44
* those configuration mechanisms would see it.</p>
47
* @author David Megginson, David Brownell
48
* @version 2.0.1 (sax2r2)
50
final public class XMLReaderFactory
53
* Private constructor.
55
* <p>This constructor prevents the class from being instantiated.</p>
57
private XMLReaderFactory ()
61
private static final String property = "org.xml.sax.driver";
64
* Default columns per line.
66
private static final int DEFAULT_LINE_LENGTH = 80;
69
* Attempt to create an XMLReader from system defaults.
70
* In environments which can support it, the name of the XMLReader
71
* class is determined by trying each these options in order, and
72
* using the first one which succeeds:</p> <ul>
74
* <li>If the system property <code>org.xml.sax.driver</code>
75
* has a value, that is used as an XMLReader class name. </li>
77
* <li>The JAR "Services API" is used to look for a class name
78
* in the <em>META-INF/services/org.xml.sax.driver</em> file in
79
* jarfiles available to the runtime.</li>
81
* <li> SAX parser distributions are strongly encouraged to provide
82
* a default XMLReader class name that will take effect only when
83
* previous options (on this list) are not successful.</li>
85
* <li>Finally, if {@link ParserFactory#makeParser()} can
86
* return a system default SAX1 parser, that parser is wrapped in
87
* a {@link ParserAdapter}. (This is a migration aid for SAX1
88
* environments, where the <code>org.xml.sax.parser</code> system
89
* property will often be usable.) </li>
93
* <p> In environments such as small embedded systems, which can not
94
* support that flexibility, other mechanisms to determine the default
97
* <p>Note that many Java environments allow system properties to be
98
* initialized on a command line. This means that <em>in most cases</em>
99
* setting a good value for that property ensures that calls to this
100
* method will succeed, except when security policies intervene.
101
* This will also maximize application portability to older SAX
102
* environments, with less robust implementations of this method.
105
* @return A new XMLReader.
106
* @exception org.xml.sax.SAXException If no default XMLReader class
107
* can be identified and instantiated.
108
* @see #createXMLReader(java.lang.String)
110
public static XMLReader createXMLReader ()
113
String className = null;
114
SecuritySupport ss = SecuritySupport.getInstance();
115
ClassLoader loader = NewInstance.getClassLoader ();
117
// 1. try the JVM-instance-wide system property
118
try { className = ss.getSystemProperty (property); }
119
catch (Exception e) { /* normally fails for applets */ }
121
// 2. if that fails, try META-INF/services/
122
if (className == null) {
123
String service = "META-INF/services/" + property;
125
InputStream is = null;
127
// First try the Context ClassLoader
128
ClassLoader cl = ss.getContextClassLoader();
130
is = ss.getResourceAsStream(cl, service);
132
// If no provider found then try the current ClassLoader
134
cl = XMLReaderFactory.class.getClassLoader();
135
is = ss.getResourceAsStream(cl, service);
138
// No Context ClassLoader or JDK 1.1 so try the current
140
cl = XMLReaderFactory.class.getClassLoader();
141
is = ss.getResourceAsStream(cl, service);
146
// Read the service provider name in UTF-8 as specified in
147
// the jar spec. Unfortunately this fails in Microsoft
148
// VJ++, which does not implement the UTF-8
149
// encoding. Theoretically, we should simply let it fail in
150
// that case, since the JVM is obviously broken if it
151
// doesn't support such a basic standard. But since there
152
// are still some users attempting to use VJ++ for
153
// development, we have dropped in a fallback which makes a
154
// second attempt using the platform's default encoding. In
155
// VJ++ this is apparently ASCII, which is a subset of
156
// UTF-8... and since the strings we'll be reading here are
157
// also primarily limited to the 7-bit ASCII range (at
158
// least, in English versions), this should work well
159
// enough to keep us on the air until we're ready to
160
// officially decommit from VJ++. [Edited comment from
164
rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH);
165
} catch (java.io.UnsupportedEncodingException e) {
166
rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH);
170
// XXX Does not handle all possible input as specified by the
171
// Jar Service Provider specification
172
className = rd.readLine();
174
catch (Exception x) {
179
// try to close the reader.
182
// Ignore the exception.
183
catch (IOException exc) {}
188
// 3. Distro-specific fallback
189
if (className == null) {
190
// BEGIN DISTRIBUTION-SPECIFIC
193
// className = "com.example.sax.XmlReader";
194
// or a $JAVA_HOME/jre/lib/*properties setting...
195
className = "org.apache.xerces.parsers.SAXParser";
197
// END DISTRIBUTION-SPECIFIC
200
// do we know the XMLReader implementation class yet?
201
if (className != null)
202
return loadClass (loader, className);
204
// 4. panic -- adapt any SAX1 parser
206
return new ParserAdapter (ParserFactory.makeParser ());
207
} catch (Exception e) {
208
throw new SAXException ("Can't create default XMLReader; "
209
+ "is system property org.xml.sax.driver set?");
215
* Attempt to create an XML reader from a class name.
217
* <p>Given a class name, this method attempts to load
218
* and instantiate the class as an XML reader.</p>
220
* <p>Note that this method will not be usable in environments where
221
* the caller (perhaps an applet) is not permitted to load classes
224
* @return A new XML reader.
225
* @exception org.xml.sax.SAXException If the class cannot be
226
* loaded, instantiated, and cast to XMLReader.
227
* @see #createXMLReader()
229
public static XMLReader createXMLReader (String className)
232
return loadClass (NewInstance.getClassLoader (), className);
235
private static XMLReader loadClass (ClassLoader loader, String className)
239
return (XMLReader) NewInstance.newInstance (loader, className);
240
} catch (ClassNotFoundException e1) {
241
throw new SAXException("SAX2 driver class " + className +
243
} catch (IllegalAccessException e2) {
244
throw new SAXException("SAX2 driver class " + className +
245
" found but cannot be loaded", e2);
246
} catch (InstantiationException e3) {
247
throw new SAXException("SAX2 driver class " + className +
248
" loaded but cannot be instantiated (no empty public constructor?)",
250
} catch (ClassCastException e4) {
251
throw new SAXException("SAX2 driver class " + className +
252
" does not implement XMLReader", e4);