Home | History | Annotate | Download | only in helpers
      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,v 1.10 2002/04/22 01:00:13 dbrownell Exp $
      7 
      8 package org.xml.sax.helpers;
      9 
     10 import java.io.BufferedReader;
     11 import java.io.InputStream;
     12 import java.io.InputStreamReader;
     13 import org.xml.sax.SAXException;
     14 import org.xml.sax.XMLReader;
     15 
     16 
     17 /**
     18  * Factory for creating an XML reader.
     19  *
     20  * <blockquote>
     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.
     25  * </blockquote>
     26  *
     27  * <p>This class contains static methods for creating an XML reader
     28  * from an explicit class name, or based on runtime defaults:</p>
     29  *
     30  * <pre>
     31  * try {
     32  *   XMLReader myReader = XMLReaderFactory.createXMLReader();
     33  * } catch (SAXException e) {
     34  *   System.err.println(e.getMessage());
     35  * }
     36  * </pre>
     37  *
     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>
     45  *
     46  * @since SAX 2.0
     47  * @author David Megginson, David Brownell
     48  * @version 2.0.1 (sax2r2)
     49  */
     50 final public class XMLReaderFactory
     51 {
     52     /**
     53      * Private constructor.
     54      *
     55      * <p>This constructor prevents the class from being instantiated.</p>
     56      */
     57     private XMLReaderFactory ()
     58     {
     59     }
     60 
     61     private static final String property = "org.xml.sax.driver";
     62 
     63     /**
     64      * Attempt to create an XMLReader from system defaults.
     65      * In environments which can support it, the name of the XMLReader
     66      * class is determined by trying each these options in order, and
     67      * using the first one which succeeds:</p> <ul>
     68      *
     69      * <li>If the system property <code>org.xml.sax.driver</code>
     70      * has a value, that is used as an XMLReader class name. </li>
     71      *
     72      * <li>The JAR "Services API" is used to look for a class name
     73      * in the <em>META-INF/services/org.xml.sax.driver</em> file in
     74      * jarfiles available to the runtime.</li>
     75      *
     76      * <li> SAX parser distributions are strongly encouraged to provide
     77      * a default XMLReader class name that will take effect only when
     78      * previous options (on this list) are not successful.</li>
     79      *
     80      * <li>Finally, if {@link ParserFactory#makeParser()} can
     81      * return a system default SAX1 parser, that parser is wrapped in
     82      * a {@link ParserAdapter}.  (This is a migration aid for SAX1
     83      * environments, where the <code>org.xml.sax.parser</code> system
     84      * property will often be usable.) </li>
     85      *
     86      * </ul>
     87      *
     88      * <p> In environments such as small embedded systems, which can not
     89      * support that flexibility, other mechanisms to determine the default
     90      * may be used. </p>
     91      *
     92      * <p>Note that many Java environments allow system properties to be
     93      * initialized on a command line.  This means that <em>in most cases</em>
     94      * setting a good value for that property ensures that calls to this
     95      * method will succeed, except when security policies intervene.
     96      * This will also maximize application portability to older SAX
     97      * environments, with less robust implementations of this method.
     98      * </p>
     99      *
    100      * @return A new XMLReader.
    101      * @exception org.xml.sax.SAXException If no default XMLReader class
    102      *            can be identified and instantiated.
    103      * @see #createXMLReader(java.lang.String)
    104      */
    105     public static XMLReader createXMLReader ()
    106     throws SAXException
    107     {
    108     String        className = null;
    109     ClassLoader    loader = NewInstance.getClassLoader ();
    110 
    111     // 1. try the JVM-instance-wide system property
    112     try { className = System.getProperty (property); }
    113     catch (RuntimeException e) { /* normally fails for applets */ }
    114 
    115     // 2. if that fails, try META-INF/services/
    116     if (className == null) {
    117         try {
    118         String        service = "META-INF/services/" + property;
    119         InputStream    in;
    120         BufferedReader    reader;
    121 
    122         if (loader == null)
    123             in = ClassLoader.getSystemResourceAsStream (service);
    124         else
    125             in = loader.getResourceAsStream (service);
    126 
    127         if (in != null) {
    128             reader = new BufferedReader (new InputStreamReader (in, "UTF8"));
    129             className = reader.readLine ();
    130             in.close ();
    131         }
    132         } catch (Exception e) {
    133         }
    134     }
    135 
    136     // 3. Distro-specific fallback
    137     if (className == null) {
    138 // BEGIN DISTRIBUTION-SPECIFIC
    139 
    140         // EXAMPLE:
    141         // className = "com.example.sax.XmlReader";
    142         // or a $JAVA_HOME/jre/lib/*properties setting...
    143 
    144 // END DISTRIBUTION-SPECIFIC
    145     }
    146 
    147     // do we know the XMLReader implementation class yet?
    148     if (className != null)
    149         return loadClass (loader, className);
    150 
    151     // 4. panic -- adapt any SAX1 parser
    152     try {
    153         return new ParserAdapter (ParserFactory.makeParser ());
    154     } catch (Exception e) {
    155         throw new SAXException ("Can't create default XMLReader; "
    156             + "is system property org.xml.sax.driver set?");
    157     }
    158     }
    159 
    160 
    161     /**
    162      * Attempt to create an XML reader from a class name.
    163      *
    164      * <p>Given a class name, this method attempts to load
    165      * and instantiate the class as an XML reader.</p>
    166      *
    167      * @param className the name of the class that should be instantiated.
    168      *
    169      * <p>Note that this method will not be usable in environments where
    170      * the caller (perhaps an applet) is not permitted to load classes
    171      * dynamically.</p>
    172      *
    173      * @return A new XML reader.
    174      * @exception org.xml.sax.SAXException If the class cannot be
    175      *            loaded, instantiated, and cast to XMLReader.
    176      * @see #createXMLReader()
    177      */
    178     public static XMLReader createXMLReader (String className)
    179     throws SAXException
    180     {
    181     return loadClass (NewInstance.getClassLoader (), className);
    182     }
    183 
    184     private static XMLReader loadClass (ClassLoader loader, String className)
    185     throws SAXException
    186     {
    187     try {
    188         return (XMLReader) NewInstance.newInstance (loader, className);
    189     } catch (ClassNotFoundException e1) {
    190         throw new SAXException("SAX2 driver class " + className +
    191                    " not found", e1);
    192     } catch (IllegalAccessException e2) {
    193         throw new SAXException("SAX2 driver class " + className +
    194                    " found but cannot be loaded", e2);
    195     } catch (InstantiationException e3) {
    196         throw new SAXException("SAX2 driver class " + className +
    197        " loaded but cannot be instantiated (no empty public constructor?)",
    198                    e3);
    199     } catch (ClassCastException e4) {
    200         throw new SAXException("SAX2 driver class " + className +
    201                    " does not implement XMLReader", e4);
    202     }
    203     }
    204 }
    205