001: // XMLReaderFactory.java - factory for creating a new reader.
002: // http://www.saxproject.org
003: // Written by David Megginson
004: // and by David Brownell
005: // NO WARRANTY! This class is in the Public Domain.
006: // $Id: XMLReaderFactory.java,v 1.9 2002/02/01 20:06:20 db Exp $
007:
008: package org.xml.sax.helpers;
009:
010: import java.io.BufferedReader;
011: import java.io.InputStream;
012: import java.io.InputStreamReader;
013: import org.xml.sax.XMLReader;
014: import org.xml.sax.SAXException;
015:
016: /**
017: * Factory for creating an XML reader.
018: *
019: * <blockquote>
020: * <em>This module, both source code and documentation, is in the
021: * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
022: * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
023: * for further information.
024: * </blockquote>
025: *
026: * <p>This class contains static methods for creating an XML reader
027: * from an explicit class name, or based on runtime defaults:</p>
028: *
029: * <pre>
030: * try {
031: * XMLReader myReader = XMLReaderFactory.createXMLReader();
032: * } catch (SAXException e) {
033: * System.err.println(e.getMessage());
034: * }
035: * </pre>
036: *
037: * <p><strong>Note to Distributions bundled with parsers:</strong>
038: * You should modify the implementation of the no-arguments
039: * <em>createXMLReader</em> to handle cases where the external
040: * configuration mechanisms aren't set up. That method should do its
041: * best to return a parser when one is in the class path, even when
042: * nothing bound its class name to <code>org.xml.sax.driver</code> so
043: * those configuration mechanisms would see it.</p>
044: *
045: * @since SAX 2.0
046: * @author David Megginson, David Brownell
047: * @version 2.0.1 (sax2r2)
048: */
049: final public class XMLReaderFactory {
050: /**
051: * Private constructor.
052: *
053: * <p>This constructor prevents the class from being instantiated.</p>
054: */
055: private XMLReaderFactory() {
056: }
057:
058: private static final String property = "org.xml.sax.driver";
059:
060: /**
061: * Attempt to create an XMLReader from system defaults.
062: * In environments which can support it, the name of the XMLReader
063: * class is determined by trying each these options in order, and
064: * using the first one which succeeds:</p> <ul>
065: *
066: * <li>If the system property <code>org.xml.sax.driver</code>
067: * has a value, that is used as an XMLReader class name. </li>
068: *
069: * <li>The JAR "Services API" is used to look for a class name
070: * in the <em>META-INF/services/org.xml.sax.driver</em> file in
071: * jarfiles available to the runtime.</li>
072: *
073: * <li> SAX parser distributions are strongly encouraged to provide
074: * a default XMLReader class name that will take effect only when
075: * previous options (on this list) are not successful.</li>
076: *
077: * <li>Finally, if {@link ParserFactory#makeParser()} can
078: * return a system default SAX1 parser, that parser is wrapped in
079: * a {@link ParserAdapter}. (This is a migration aid for SAX1
080: * environments, where the <code>org.xml.sax.parser</code> system
081: * property will often be usable.) </li>
082: *
083: * </ul>
084: *
085: * <p> In environments such as small embedded systems, which can not
086: * support that flexibility, other mechanisms to determine the default
087: * may be used. </p>
088: *
089: * <p>Note that many Java environments allow system properties to be
090: * initialized on a command line. This means that <em>in most cases</em>
091: * setting a good value for that property ensures that calls to this
092: * method will succeed, except when security policies intervene.
093: * This will also maximize application portability to older SAX
094: * environments, with less robust implementations of this method.
095: * </p>
096: *
097: * @return A new XMLReader.
098: * @exception org.xml.sax.SAXException If no default XMLReader class
099: * can be identified and instantiated.
100: * @see #createXMLReader(java.lang.String)
101: */
102: public static XMLReader createXMLReader() throws SAXException {
103: String className = null;
104: ClassLoader loader = NewInstance.getClassLoader();
105:
106: // 1. try the JVM-instance-wide system property
107: try {
108: className = System.getProperty(property);
109: } catch (Exception e) { /* normally fails for applets */
110: }
111:
112: // 2. if that fails, try META-INF/services/
113: if (className == null) {
114: try {
115: String service = "META-INF/services/" + property;
116: InputStream in;
117: BufferedReader reader;
118:
119: if (loader == null)
120: in = ClassLoader.getSystemResourceAsStream(service);
121: else
122: in = loader.getResourceAsStream(service);
123:
124: if (in != null) {
125: reader = new BufferedReader(new InputStreamReader(
126: in, "UTF8"));
127: className = reader.readLine();
128: in.close();
129: }
130: } catch (Exception e) {
131: }
132: }
133:
134: // 3. Distro-specific fallback
135: if (className == null) {
136: // BEGIN DISTRIBUTION-SPECIFIC
137:
138: // use the non-validating one
139: className = "gnu.xml.aelfred2.SAXDriver";
140:
141: // END DISTRIBUTION-SPECIFIC
142: }
143:
144: // do we know the XMLReader implementation class yet?
145: if (className != null)
146: return loadClass(loader, className);
147:
148: // 4. panic -- adapt any SAX1 parser
149: try {
150: return new ParserAdapter(ParserFactory.makeParser());
151: } catch (Exception e) {
152: throw new SAXException("Can't create default XMLReader; "
153: + "is system property org.xml.sax.driver set?");
154: }
155: }
156:
157: /**
158: * Attempt to create an XML reader from a class name.
159: *
160: * <p>Given a class name, this method attempts to load
161: * and instantiate the class as an XML reader.</p>
162: *
163: * <p>Note that this method will not be usable in environments where
164: * the caller (perhaps an applet) is not permitted to load classes
165: * dynamically.</p>
166: *
167: * @return A new XML reader.
168: * @exception org.xml.sax.SAXException If the class cannot be
169: * loaded, instantiated, and cast to XMLReader.
170: * @see #createXMLReader()
171: */
172: public static XMLReader createXMLReader(String className)
173: throws SAXException {
174: return loadClass(NewInstance.getClassLoader(), className);
175: }
176:
177: private static XMLReader loadClass(ClassLoader loader,
178: String className) throws SAXException {
179: try {
180: return (XMLReader) NewInstance.newInstance(loader,
181: className);
182: } catch (ClassNotFoundException e1) {
183: throw new SAXException("SAX2 driver class " + className
184: + " not found", e1);
185: } catch (IllegalAccessException e2) {
186: throw new SAXException("SAX2 driver class " + className
187: + " found but cannot be loaded", e2);
188: } catch (InstantiationException e3) {
189: throw new SAXException(
190: "SAX2 driver class "
191: + className
192: + " loaded but cannot be instantiated (no empty public constructor?)",
193: e3);
194: } catch (ClassCastException e4) {
195: throw new SAXException("SAX2 driver class " + className
196: + " does not implement XMLReader", e4);
197: }
198: }
199: }
|