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