--- old/src/javax/xml/parsers/FactoryFinder.java 2012-08-27 21:27:08.997876800 -0700 +++ new/src/javax/xml/parsers/FactoryFinder.java 2012-08-27 21:27:08.234563800 -0700 @@ -25,18 +25,18 @@ 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.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** *

Implements pluggable Datatypes.

* - *

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

+ *

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

* * @author Santiago.PericasGeertsen@sun.com * @author Huizhe.Wang@oracle.com @@ -47,21 +47,18 @@ * Internal debug flag. */ private static boolean debug = false; - /** * Cache for properties in java.home/lib/jaxp.properties */ static Properties cacheProps = new Properties(); - /** - * Flag indicating if properties from java.home/lib/jaxp.properties - * have been cached. + * Flag indicating if properties from java.home/lib/jaxp.properties have + * been cached. */ static volatile boolean firstTime = true; - /** - * Security support class use to check access control before - * getting certain system resources. + * Security support class use to check access control before getting certain + * system resources. */ static SecuritySupport ss = new SecuritySupport(); @@ -73,8 +70,7 @@ String val = ss.getSystemProperty("jaxp.debug"); // Allow simply setting the prop to turn on debug debug = val != null && !"false".equals(val); - } - catch (SecurityException se) { + } catch (SecurityException se) { debug = false; } } @@ -90,15 +86,14 @@ * and fall back is enabled, the current (i.e. bootstrap) class loader is * tried. * - * If the class loader supplied is null, first try using the - * context class loader followed by the current (i.e. bootstrap) class - * loader. + * If the class loader supplied is + * null, first try using the context class loader followed by + * the current (i.e. bootstrap) class loader. * * Use bootstrap classLoader if cl = null and useBSClsLoader is true */ static private Class getProviderClass(String className, ClassLoader cl, - boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException - { + boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { try { if (cl == null) { if (useBSClsLoader) { @@ -107,22 +102,18 @@ cl = ss.getContextClassLoader(); if (cl == null) { throw new ClassNotFoundException(); - } - else { + } else { return cl.loadClass(className); } } - } - else { + } else { return cl.loadClass(className); } - } - catch (ClassNotFoundException e1) { + } catch (ClassNotFoundException e1) { if (doFallback) { // Use current class loader - should always be bootstrap CL return Class.forName(className, true, FactoryFinder.class.getClassLoader()); - } - else { + } else { throw e1; } } @@ -132,18 +123,18 @@ * Create an instance of a class. Delegates to method * getProviderClass() in order to load the class. * - * @param className Name of the concrete class corresponding to the - * service provider + * @param className Name of the concrete class corresponding to the service + * provider * - * @param cl ClassLoader used to load the factory class. If null - * current Thread's context classLoader is used to load the factory class. + * @param cl ClassLoader used to load the factory class. + * If null current Thread's context classLoader is + * used to load the factory class. * - * @param doFallback True if the current ClassLoader should be tried as - * a fallback if the class is not found using cl + * @param doFallback True if the current ClassLoader should be tried as 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); } @@ -151,56 +142,54 @@ * Create an instance of a class. Delegates to method * getProviderClass() in order to load the class. * - * @param className Name of the concrete class corresponding to the - * service provider - * - * @param cl ClassLoader used to load the factory class. If null - * current Thread's context classLoader is used to load the factory class. + * @param className Name of the concrete class corresponding to the service + * provider * - * @param doFallback True if the current ClassLoader should be tried as - * a fallback if the class is not found using cl - * - * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter - * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. + * @param cl ClassLoader used to load the factory class. + * If null current Thread's context classLoader is + * used to load the factory class. + * + * @param doFallback True if the current ClassLoader should be tried as a + * fallback if the class is not found using cl + * + * @param useBSClsLoader True if cl=null actually meant bootstrap + * classLoader. This parameter 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); Object instance = providerClass.newInstance(); if (debug) { // Extra check to avoid computing cl strings - dPrint("created new instance of " + providerClass + - " using ClassLoader: " + cl); + dPrint("created new instance of " + providerClass + + " using ClassLoader: " + cl); } return instance; - } - catch (ClassNotFoundException x) { - throw new ConfigurationError( - "Provider " + className + " not found", x); - } - catch (Exception x) { - throw new ConfigurationError( - "Provider " + className + " could not be instantiated: " + x, - x); + } catch (ClassNotFoundException x) { + throw new FactoryConfigurationError(x, + "Provider " + className + " not found"); + } catch (Exception x) { + throw new FactoryConfigurationError(x, + "Provider " + className + " could not be instantiated: " + x); } } /** - * Finds the implementation Class object in the specified order. Main - * entry point. + * Finds the implementation Class object in the specified order. Main entry + * point. + * * @return Class object of factory, never null * - * @param factoryId Name of the factory to find, same as - * a property name - * @param fallbackClassName Implementation class name, if nothing else - * is found. Use null to mean no fallback. + * @param factoryId Name of the factory to find, same as a property name + * @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 Object find(Class factoryClass, String factoryId, String fallbackClassName) + throws FactoryConfigurationError { dPrint("find factoryId =" + factoryId); // Use the system property first @@ -210,9 +199,10 @@ dPrint("found system property, value=" + systemProp); return newInstance(systemProp, null, true); } - } - catch (SecurityException se) { - if (debug) se.printStackTrace(); + } catch (SecurityException se) { + if (debug) { + se.printStackTrace(); + } } // try to read from $java.home/lib/jaxp.properties @@ -221,12 +211,12 @@ if (firstTime) { synchronized (cacheProps) { if (firstTime) { - String configFile = ss.getSystemProperty("java.home") + File.separator + - "lib" + File.separator + "jaxp.properties"; + String configFile = ss.getSystemProperty("java.home") + File.separator + + "lib" + File.separator + "jaxp.properties"; File f = new File(configFile); firstTime = false; if (ss.doesFileExist(f)) { - dPrint("Read properties file "+f); + dPrint("Read properties file " + f); cacheProps.load(ss.getFileInputStream(f)); } } @@ -238,19 +228,25 @@ dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); return newInstance(factoryClassName, null, true); } - } - catch (Exception ex) { - if (debug) ex.printStackTrace(); + } catch (Exception ex) { + if (debug) { + ex.printStackTrace(); + } } - // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); - if (provider != null) { - return provider; + // Try service-provider loading facilities + try { + Object provider = findServiceProvider(factoryClass, fallbackClassName); + if (provider != null) { + return provider; + } + } catch (FactoryConfigurationError e) { + throw e; } + + // Last, check if fallback is requested 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); @@ -258,99 +254,31 @@ } /* - * Try to find provider using Jar Service Provider Mechanism + * Try to find a provider using Service Loader * * @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 Object findServiceProvider(final Class factoryClass, final String fallbackClassName) + throws FactoryConfigurationError { 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; + return AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + Object defaultProvider = null; + for (Object factory : ServiceLoader.load(factoryClass)) { + if (factory.getClass().getName().equals(fallbackClassName)) { + defaultProvider = factory; + } else { + return factory; + } + } + if (defaultProvider != null) { + return defaultProvider; + } + return null; + } + }); + } catch (ServiceConfigurationError e) { + throw new FactoryConfigurationError((Exception) e.getCause(), e.getMessage()); } } - }