--- old/src/javax/xml/parsers/DocumentBuilderFactory.java 2012-12-05 16:02:06.000000000 +0100 +++ new/src/javax/xml/parsers/DocumentBuilderFactory.java 2012-12-05 16:02:06.000000000 +0100 @@ -40,9 +40,6 @@ public abstract class DocumentBuilderFactory { - /** The default property name according to the JAXP spec */ - private static final String DEFAULT_PROPERTY_NAME = "javax.xml.parsers.DocumentBuilderFactory"; - private boolean validating = false; private boolean namespaceAware = false; private boolean whitespace = false; @@ -50,8 +47,6 @@ private boolean ignoreComments = false; private boolean coalescing = false; - private boolean canonicalState = false; - /** *

Protected constructor to prevent instantiation. * Use {@link #newInstance()}.

@@ -85,11 +80,16 @@ * of any property in jaxp.properties after it has been read for the first time. * *
  • - * Use the Services API (as detailed in the JAR specification), if - * available, to determine the classname. The Services API will look - * for a classname in the file - * META-INF/services/javax.xml.parsers.DocumentBuilderFactory - * in jars available to the runtime. + * Uses the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. If there are providers other than the + * implementation specific default located, then the first provider that is + * not the default is instantiated and returned; Otherwise the default + * implementation, if present, is returned. + *
    + * In case of {@link java.util.ServiceConfigurationError service + * configuration error} a {@link javax.xml.parsers.FactoryConfigurationError} + * will be thrown. *
  • *
  • * Platform default DocumentBuilderFactory instance. @@ -117,17 +117,11 @@ * available or cannot be instantiated. */ public static DocumentBuilderFactory newInstance() { - try { - return (DocumentBuilderFactory) FactoryFinder.find( + return FactoryFinder.find( /* The default property name according to the JAXP spec */ - "javax.xml.parsers.DocumentBuilderFactory", + DocumentBuilderFactory.class, // "javax.xml.parsers.DocumentBuilderFactory" /* The fallback implementation class name */ "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } - } /** @@ -165,13 +159,8 @@ * @since 1.6 */ public static DocumentBuilderFactory newInstance(String factoryClassName, ClassLoader classLoader){ - try { //do not fallback if given classloader can't find the class, throw exception return (DocumentBuilderFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } } /** @@ -391,75 +380,64 @@ public abstract Object getAttribute(String name) throws IllegalArgumentException; - /** - *

    Set a feature for this DocumentBuilderFactory and DocumentBuilders created by this factory.

    - * - *

    - * Feature names are fully qualified {@link java.net.URI}s. - * Implementations may define their own features. - * A {@link ParserConfigurationException} is thrown if this DocumentBuilderFactory or the - * DocumentBuilders it creates cannot support the feature. - * It is possible for a DocumentBuilderFactory to expose a feature value but be unable to change its state. - *

    - * - *

    - * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. - * When the feature is:

    - * - * - * @param name Feature name. - * @param value Is feature state true or false. - * - * @throws ParserConfigurationException if this DocumentBuilderFactory or the DocumentBuilders - * it creates cannot support this feature. + /** + *

    Set a feature for this DocumentBuilderFactory and DocumentBuilders created by this factory.

    + * + *

    + * Feature names are fully qualified {@link java.net.URI}s. + * Implementations may define their own features. + * A {@link ParserConfigurationException} is thrown if this DocumentBuilderFactory or the + * DocumentBuilders it creates cannot support the feature. + * It is possible for a DocumentBuilderFactory to expose a feature value but be unable to change its state. + *

    + * + *

    + * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. + * When the feature is:

    + * + * + * @param name Feature name. + * @param value Is feature state true or false. + * + * @throws ParserConfigurationException if this DocumentBuilderFactory or the DocumentBuilders + * it creates cannot support this feature. * @throws NullPointerException If the name parameter is null. - */ - public abstract void setFeature(String name, boolean value) - throws ParserConfigurationException; - - /** - *

    Get the state of the named feature.

    - * - *

    - * Feature names are fully qualified {@link java.net.URI}s. - * Implementations may define their own features. - * An {@link ParserConfigurationException} is thrown if this DocumentBuilderFactory or the - * DocumentBuilders it creates cannot support the feature. - * It is possible for an DocumentBuilderFactory to expose a feature value but be unable to change its state. - *

    - * - * @param name Feature name. - * - * @return State of the named feature. - * - * @throws ParserConfigurationException if this DocumentBuilderFactory - * or the DocumentBuilders it creates cannot support this feature. - */ - public abstract boolean getFeature(String name) - throws ParserConfigurationException; - - - /**

    Get current state of canonicalization.

    - * - * @return current state canonicalization control - */ - /* - public boolean getCanonicalization() { - return canonicalState; - } - */ + */ + public abstract void setFeature(String name, boolean value) + throws ParserConfigurationException; + + /** + *

    Get the state of the named feature.

    + * + *

    + * Feature names are fully qualified {@link java.net.URI}s. + * Implementations may define their own features. + * An {@link ParserConfigurationException} is thrown if this DocumentBuilderFactory or the + * DocumentBuilders it creates cannot support the feature. + * It is possible for an DocumentBuilderFactory to expose a feature value but be unable to change its state. + *

    + * + * @param name Feature name. + * + * @return State of the named feature. + * + * @throws ParserConfigurationException if this DocumentBuilderFactory + * or the DocumentBuilders it creates cannot support this feature. + */ + public abstract boolean getFeature(String name) + throws ParserConfigurationException; /** @@ -488,17 +466,6 @@ } - /*

    Set canonicalization control to true or - * false.

    - * - * @param state of canonicalization - */ - /* - public void setCanonicalization(boolean state) { - canonicalState = state; - } - */ - /** *

    Set the {@link Schema} to be used by parsers created * from this factory. --- old/src/javax/xml/parsers/FactoryFinder.java 2012-12-05 16:02:06.000000000 +0100 +++ new/src/javax/xml/parsers/FactoryFinder.java 2012-12-05 16:02:06.000000000 +0100 @@ -25,15 +25,16 @@ package javax.xml.parsers; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** - *

    Implements pluggable Datatypes.

    + *

    Implements pluggable Parsers.

    * *

    This class is duplicated for each JAXP subpackage so keep it in * sync. It is package private for secure class loading.

    @@ -51,7 +52,7 @@ /** * Cache for properties in java.home/lib/jaxp.properties */ - static Properties cacheProps = new Properties(); + private static final Properties cacheProps = new Properties(); /** * Flag indicating if properties from java.home/lib/jaxp.properties @@ -63,7 +64,7 @@ * Security support class use to check access control before * getting certain system resources. */ - static SecuritySupport ss = new SecuritySupport(); + private static final SecuritySupport ss = new SecuritySupport(); // Define system property "jaxp.debug" to get output static { @@ -96,7 +97,7 @@ * * Use bootstrap classLoader if cl = null and useBSClsLoader is true */ - static private Class getProviderClass(String className, ClassLoader cl, + static private Class getProviderClass(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { try { @@ -109,12 +110,12 @@ throw new ClassNotFoundException(); } else { - return cl.loadClass(className); + return Class.forName(className, true, cl); } } } else { - return cl.loadClass(className); + return Class.forName(className, true, cl); } } catch (ClassNotFoundException e1) { @@ -142,7 +143,7 @@ * a fallback if the class is not found using cl */ static Object newInstance(String className, ClassLoader cl, boolean doFallback) - throws ConfigurationError + throws FactoryConfigurationError { return newInstance(className, cl, doFallback, false); } @@ -164,10 +165,10 @@ * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. */ static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) - throws ConfigurationError + throws FactoryConfigurationError { try { - Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); Object instance = providerClass.newInstance(); if (debug) { // Extra check to avoid computing cl strings dPrint("created new instance of " + providerClass + @@ -176,13 +177,12 @@ return instance; } catch (ClassNotFoundException x) { - throw new ConfigurationError( - "Provider " + className + " not found", x); + throw new FactoryConfigurationError(x, + "Provider " + className + " not found"); } catch (Exception x) { - throw new ConfigurationError( - "Provider " + className + " could not be instantiated: " + x, - x); + throw new FactoryConfigurationError(x, + "Provider " + className + " could not be instantiated: " + x); } } @@ -191,16 +191,17 @@ * entry point. * @return Class object of factory, never null * - * @param factoryId Name of the factory to find, same as - * a property name + * @param type Base class / Service interface of the + * factory to find. * @param fallbackClassName Implementation class name, if nothing else * is found. Use null to mean no fallback. * * Package private so this code can be shared. */ - static Object find(String factoryId, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String fallbackClassName) + throws FactoryConfigurationError { + final String factoryId = type.getName(); dPrint("find factoryId =" + factoryId); // Use the system property first @@ -208,7 +209,7 @@ String systemProp = ss.getSystemProperty(factoryId); if (systemProp != null) { dPrint("found system property, value=" + systemProp); - return newInstance(systemProp, null, true); + return type.cast(newInstance(systemProp, null, true)); } } catch (SecurityException se) { @@ -236,7 +237,7 @@ if (factoryClassName != null) { dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); - return newInstance(factoryClassName, null, true); + return type.cast(newInstance(factoryClassName, null, true)); } } catch (Exception ex) { @@ -244,112 +245,59 @@ } // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); + T provider = findServiceProvider(type, fallbackClassName); if (provider != null) { return provider; } if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); + throw new FactoryConfigurationError( + "Provider for " + factoryId + " cannot be found"); } dPrint("loaded from fallback value: " + fallbackClassName); - return newInstance(fallbackClassName, null, true); + return type.cast(newInstance(fallbackClassName, null, true)); } /* - * Try to find provider using Jar Service Provider Mechanism + * Try to find provider using the ServiceLoader API * * @return instance of provider class if found or null */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError - { - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = ss.getContextClassLoader(); - boolean useBSClsLoader = false; - if (cl != null) { - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - } else { - // No Context ClassLoader, try the current ClassLoader - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - - if (is == null) { - // No provider found - return null; - } - - if (debug) { // Extra check to avoid computing cl strings - dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); - } - - BufferedReader rd; - try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } - catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName = null; + private static T findServiceProvider(Class type, final String defaultImplementationClassName) { try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - rd.close(); - } catch (IOException x) { - // No provider found - return null; - } - - if (factoryClassName != null && !"".equals(factoryClassName)) { - dPrint("found in resource, value=" + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false, useBSClsLoader); - } - - // No provider found - return null; - } - - static class ConfigurationError extends Error { - private Exception exception; - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } - - Exception getException() { - return exception; - } - /** - * use the exception chaining mechanism of JDK1.4 - */ - @Override - public Throwable getCause() { - return exception; + final ServiceLoader serviceLoader = ServiceLoader.load(type); + return AccessController.doPrivileged(new PrivilegedAction() { + public T run() { + T defaultProvider = null; + for (T provider : serviceLoader) { + if (provider.getClass().getName().equals(defaultImplementationClassName)) { + // This is the default implementation - we will return + // the first default provider encountered if no third + // party provider was found. + if (defaultProvider == null) { + defaultProvider = provider; + } + continue; + } + // We have found a non default provider: return it. + return provider; + } + return defaultProvider; + } + }); + } catch(ServiceConfigurationError e) { + // It is not possible to wrap an error directly in + // FactoryConfigurationError - so we need to wrap the + // ServiceConfigurationError in a RuntimeException. + // The alternative would be to modify the logic in + // FactoryConfigurationError to allow setting a + // Throwable as the cause, but that could cause + // compatibility issues down the road. + final RuntimeException x = new RuntimeException( + "Provider for " + type + " cannot be created", e); + final FactoryConfigurationError error = + new FactoryConfigurationError(x, x.getMessage()); + throw error; } } --- old/src/javax/xml/parsers/SAXParserFactory.java 2012-12-05 16:02:07.000000000 +0100 +++ new/src/javax/xml/parsers/SAXParserFactory.java 2012-12-05 16:02:07.000000000 +0100 @@ -26,7 +26,6 @@ package javax.xml.parsers; import javax.xml.validation.Schema; - import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; @@ -42,8 +41,6 @@ * */ public abstract class SAXParserFactory { - /** The default property name according to the JAXP spec */ - private static final String DEFAULT_PROPERTY_NAME = "javax.xml.parsers.SAXParserFactory"; /** *

    Should Parsers be validating?

    @@ -87,11 +84,16 @@ * of any property in jaxp.properties after it has been read for the first time. *
  • *
  • - * Use the Services API (as detailed in the JAR specification), if - * available, to determine the classname. The Services API will look - * for a classname in the file - * META-INF/services/javax.xml.parsers.SAXParserFactory - * in jars available to the runtime. + * Uses the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. If there are providers other than the + * implementation specific default located, then the first provider that is + * not the default is instantiated and returned; + * Otherwise the default implementation, if present, is returned. + *
    + * In case of {@link java.util.ServiceConfigurationError service + * configuration error} a {@link javax.xml.parsers.FactoryConfigurationError} + * will be thrown. *
  • *
  • * Platform default SAXParserFactory instance. @@ -109,7 +111,7 @@ * this method to print a lot of debug messages * to System.err about what it is doing and where it is looking at.

    * - *

    If you have problems loading {@link DocumentBuilder}s, try:

    + *

    If you have problems loading {@link SAXParser}s, try:

    *
          * java -Djaxp.debug=1 YourProgram ....
          * 
    @@ -122,16 +124,11 @@ */ public static SAXParserFactory newInstance() { - try { - return (SAXParserFactory) FactoryFinder.find( + return FactoryFinder.find( /* The default property name according to the JAXP spec */ - "javax.xml.parsers.SAXParserFactory", + SAXParserFactory.class, /* The fallback implementation class name */ "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } } /** @@ -169,13 +166,8 @@ * @since 1.6 */ public static SAXParserFactory newInstance(String factoryClassName, ClassLoader classLoader){ - try { //do not fallback if given classloader can't find the class, throw exception return (SAXParserFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } } /** @@ -266,22 +258,22 @@ * A list of the core features and properties can be found at * http://www.saxproject.org/

    * - *

    All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. - * When the feature is

    - * - * + *

    All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. + * When the feature is

    + * + * * @param name The name of the feature to be set. * @param value The value of the feature to be set. * @@ -320,17 +312,6 @@ SAXNotSupportedException; - - /*

    Get current state of canonicalization.

    - * - * @return current state canonicalization control - */ - /* - public boolean getCanonicalization() { - return canonicalState; - } - */ - /** * Gets the {@link Schema} object specified through * the {@link #setSchema(Schema schema)} method. @@ -357,17 +338,6 @@ ); } - /**

    Set canonicalization control to true or - * false.

    - * - * @param state of canonicalization - */ - /* - public void setCanonicalization(boolean state) { - canonicalState = state; - } - */ - /** *

    Set the {@link Schema} to be used by parsers created * from this factory.