8005954: JAXP Plugability Layer should use java.util.ServiceLoader

This fix replaces manual processing of files under META-INF/services in JAXP factories by calls to java.util.ServiceLoader.

Reviewed-by: alanb, joehw, mchung
This commit is contained in:
Daniel Fuchs 2013-04-17 15:23:19 +02:00
parent b10f2efea3
commit 9a94591b8e
16 changed files with 1829 additions and 2136 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,14 +26,12 @@
package javax.xml.datatype;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Iterator;
import java.util.Properties;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
/**
* <p>Implements pluggable Datatypes.</p>
@ -54,19 +52,19 @@ class FactoryFinder {
/**
* Cache for properties in java.home/lib/jaxp.properties
*/
static Properties cacheProps = new Properties();
private final static Properties cacheProps = new Properties();
/**
* Flag indicating if properties from java.home/lib/jaxp.properties
* have been cached.
*/
static volatile boolean firstTime = true;
private static volatile boolean firstTime = true;
/**
* Security support class use to check access control before
* getting certain system resources.
*/
static SecuritySupport ss = new SecuritySupport();
private final static SecuritySupport ss = new SecuritySupport();
// Define system property "jaxp.debug" to get output
static {
@ -99,31 +97,31 @@ class FactoryFinder {
*
* 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 {
if (cl == null) {
if (useBSClsLoader) {
return Class.forName(className, true, FactoryFinder.class.getClassLoader());
return Class.forName(className, false, FactoryFinder.class.getClassLoader());
} else {
cl = ss.getContextClassLoader();
if (cl == null) {
throw new ClassNotFoundException();
}
else {
return cl.loadClass(className);
return Class.forName(className, false, cl);
}
}
}
else {
return cl.loadClass(className);
return Class.forName(className, false, cl);
}
}
catch (ClassNotFoundException e1) {
if (doFallback) {
// Use current class loader - should always be bootstrap CL
return Class.forName(className, true, FactoryFinder.class.getClassLoader());
return Class.forName(className, false, FactoryFinder.class.getClassLoader());
}
else {
throw e1;
@ -135,6 +133,9 @@ class FactoryFinder {
* Create an instance of a class. Delegates to method
* <code>getProviderClass()</code> in order to load the class.
*
* @param type Base class / Service interface of the factory to
* instantiate.
*
* @param className Name of the concrete class corresponding to the
* service provider
*
@ -144,16 +145,19 @@ class FactoryFinder {
* @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
static <T> T newInstance(Class<T> type, String className, ClassLoader cl, boolean doFallback)
throws DatatypeConfigurationException
{
return newInstance(className, cl, doFallback, false);
return newInstance(type, className, cl, doFallback, false);
}
/**
* Create an instance of a class. Delegates to method
* <code>getProviderClass()</code> in order to load the class.
*
* @param type Base class / Service interface of the factory to
* instantiate.
*
* @param className Name of the concrete class corresponding to the
* service provider
*
@ -166,9 +170,12 @@ class FactoryFinder {
* @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
static <T> T newInstance(Class<T> type, String className, ClassLoader cl,
boolean doFallback, boolean useBSClsLoader)
throws DatatypeConfigurationException
{
assert type != null;
// make sure we have access to restricted packages
if (System.getSecurityManager() != null) {
if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
@ -178,20 +185,23 @@ class FactoryFinder {
}
try {
Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
if (!type.isAssignableFrom(providerClass)) {
throw new ClassCastException(className + " cannot be cast to " + type.getName());
}
Object instance = providerClass.newInstance();
if (debug) { // Extra check to avoid computing cl strings
dPrint("created new instance of " + providerClass +
" using ClassLoader: " + cl);
}
return instance;
return type.cast(instance);
}
catch (ClassNotFoundException x) {
throw new ConfigurationError(
throw new DatatypeConfigurationException(
"Provider " + className + " not found", x);
}
catch (Exception x) {
throw new ConfigurationError(
throw new DatatypeConfigurationException(
"Provider " + className + " could not be instantiated: " + x,
x);
}
@ -202,16 +212,17 @@ class FactoryFinder {
* 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> T find(Class<T> type, String fallbackClassName)
throws DatatypeConfigurationException
{
final String factoryId = type.getName();
dPrint("find factoryId =" + factoryId);
// Use the system property first
@ -219,7 +230,7 @@ class FactoryFinder {
String systemProp = ss.getSystemProperty(factoryId);
if (systemProp != null) {
dPrint("found system property, value=" + systemProp);
return newInstance(systemProp, null, true);
return newInstance(type, systemProp, null, true);
}
}
catch (SecurityException se) {
@ -228,7 +239,6 @@ class FactoryFinder {
// try to read from $java.home/lib/jaxp.properties
try {
String factoryClassName = null;
if (firstTime) {
synchronized (cacheProps) {
if (firstTime) {
@ -243,11 +253,11 @@ class FactoryFinder {
}
}
}
factoryClassName = cacheProps.getProperty(factoryId);
final String factoryClassName = cacheProps.getProperty(factoryId);
if (factoryClassName != null) {
dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
return newInstance(factoryClassName, null, true);
return newInstance(type, factoryClassName, null, true);
}
}
catch (Exception ex) {
@ -255,112 +265,46 @@ class FactoryFinder {
}
// Try Jar Service Provider Mechanism
Object provider = findJarServiceProvider(factoryId);
final T provider = findServiceProvider(type);
if (provider != null) {
return provider;
}
if (fallbackClassName == null) {
throw new ConfigurationError(
"Provider for " + factoryId + " cannot be found", null);
throw new DatatypeConfigurationException(
"Provider for " + factoryId + " cannot be found");
}
dPrint("loaded from fallback value: " + fallbackClassName);
return newInstance(fallbackClassName, null, true);
return newInstance(type, fallbackClassName, null, true);
}
/*
* Try to find provider using Jar Service Provider Mechanism
* Try to find provider using the ServiceLoader API
*
* @param type Base class / Service interface of the factory to find.
*
* @return instance of provider class if found or null
*/
private static Object findJarServiceProvider(String factoryId)
throws ConfigurationError
private static <T> T findServiceProvider(final Class<T> type)
throws DatatypeConfigurationException
{
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;
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<T>() {
public T run() {
final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
final Iterator<T> iterator = serviceLoader.iterator();
if (iterator.hasNext()) {
return iterator.next();
} else {
return null;
}
}
});
} catch(ServiceConfigurationError e) {
final DatatypeConfigurationException error =
new DatatypeConfigurationException(
"Provider for " + type + " cannot be found", e);
throw error;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -40,9 +40,6 @@ import javax.xml.validation.Schema;
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 @@ public abstract class DocumentBuilderFactory {
private boolean ignoreComments = false;
private boolean coalescing = false;
private boolean canonicalState = false;
/**
* <p>Protected constructor to prevent instantiation.
* Use {@link #newInstance()}.</p>
@ -85,14 +80,12 @@ public abstract class DocumentBuilderFactory {
* of any property in jaxp.properties after it has been read for the first time.
* </li>
* <li>
* 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
* <code>META-INF/services/javax.xml.parsers.DocumentBuilderFactory</code>
* 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.
* </li>
* <li>
* Platform default <code>DocumentBuilderFactory</code> instance.
* Otherwise, the system-default implementation is returned.
* </li>
* </ul>
*
@ -113,21 +106,16 @@ public abstract class DocumentBuilderFactory {
*
* @return New instance of a <code>DocumentBuilderFactory</code>
*
* @throws FactoryConfigurationError if the implementation is not
* available or cannot be instantiated.
* @throws FactoryConfigurationError in case of {@linkplain
* java.util.ServiceConfigurationError service configuration error} or if
* the implementation is not 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 +153,9 @@ public abstract class DocumentBuilderFactory {
* @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());
}
return FactoryFinder.newInstance(DocumentBuilderFactory.class,
factoryClassName, classLoader, false);
}
/**
@ -391,75 +375,64 @@ public abstract class DocumentBuilderFactory {
public abstract Object getAttribute(String name)
throws IllegalArgumentException;
/**
* <p>Set a feature for this <code>DocumentBuilderFactory</code> and <code>DocumentBuilder</code>s created by this factory.</p>
*
* <p>
* Feature names are fully qualified {@link java.net.URI}s.
* Implementations may define their own features.
* A {@link ParserConfigurationException} is thrown if this <code>DocumentBuilderFactory</code> or the
* <code>DocumentBuilder</code>s it creates cannot support the feature.
* It is possible for a <code>DocumentBuilderFactory</code> to expose a feature value but be unable to change its state.
* </p>
*
* <p>
* All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
* When the feature is:</p>
* <ul>
* <li>
* <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
* Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources.
* If XML processing is limited for security reasons, it will be reported via a call to the registered
* {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}.
* See {@link DocumentBuilder#setErrorHandler(org.xml.sax.ErrorHandler errorHandler)}.
* </li>
* <li>
* <code>false</code>: the implementation will processing XML according to the XML specifications without
* regard to possible implementation limits.
* </li>
* </ul>
*
* @param name Feature name.
* @param value Is feature state <code>true</code> or <code>false</code>.
*
* @throws ParserConfigurationException if this <code>DocumentBuilderFactory</code> or the <code>DocumentBuilder</code>s
* it creates cannot support this feature.
* @throws NullPointerException If the <code>name</code> parameter is null.
*/
public abstract void setFeature(String name, boolean value)
throws ParserConfigurationException;
/**
* <p>Get the state of the named feature.</p>
*
* <p>
* Feature names are fully qualified {@link java.net.URI}s.
* Implementations may define their own features.
* An {@link ParserConfigurationException} is thrown if this <code>DocumentBuilderFactory</code> or the
* <code>DocumentBuilder</code>s it creates cannot support the feature.
* It is possible for an <code>DocumentBuilderFactory</code> to expose a feature value but be unable to change its state.
* </p>
*
* @param name Feature name.
*
* @return State of the named feature.
*
* @throws ParserConfigurationException if this <code>DocumentBuilderFactory</code>
* or the <code>DocumentBuilder</code>s it creates cannot support this feature.
*/
public abstract boolean getFeature(String name)
throws ParserConfigurationException;
/** <p>Get current state of canonicalization.</p>
/**
* <p>Set a feature for this <code>DocumentBuilderFactory</code> and <code>DocumentBuilder</code>s created by this factory.</p>
*
* @return current state canonicalization control
* <p>
* Feature names are fully qualified {@link java.net.URI}s.
* Implementations may define their own features.
* A {@link ParserConfigurationException} is thrown if this <code>DocumentBuilderFactory</code> or the
* <code>DocumentBuilder</code>s it creates cannot support the feature.
* It is possible for a <code>DocumentBuilderFactory</code> to expose a feature value but be unable to change its state.
* </p>
*
* <p>
* All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
* When the feature is:</p>
* <ul>
* <li>
* <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
* Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources.
* If XML processing is limited for security reasons, it will be reported via a call to the registered
* {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}.
* See {@link DocumentBuilder#setErrorHandler(org.xml.sax.ErrorHandler errorHandler)}.
* </li>
* <li>
* <code>false</code>: the implementation will processing XML according to the XML specifications without
* regard to possible implementation limits.
* </li>
* </ul>
*
* @param name Feature name.
* @param value Is feature state <code>true</code> or <code>false</code>.
*
* @throws ParserConfigurationException if this <code>DocumentBuilderFactory</code> or the <code>DocumentBuilder</code>s
* it creates cannot support this feature.
* @throws NullPointerException If the <code>name</code> parameter is null.
*/
/*
public boolean getCanonicalization() {
return canonicalState;
}
*/
public abstract void setFeature(String name, boolean value)
throws ParserConfigurationException;
/**
* <p>Get the state of the named feature.</p>
*
* <p>
* Feature names are fully qualified {@link java.net.URI}s.
* Implementations may define their own features.
* An {@link ParserConfigurationException} is thrown if this <code>DocumentBuilderFactory</code> or the
* <code>DocumentBuilder</code>s it creates cannot support the feature.
* It is possible for an <code>DocumentBuilderFactory</code> to expose a feature value but be unable to change its state.
* </p>
*
* @param name Feature name.
*
* @return State of the named feature.
*
* @throws ParserConfigurationException if this <code>DocumentBuilderFactory</code>
* or the <code>DocumentBuilder</code>s it creates cannot support this feature.
*/
public abstract boolean getFeature(String name)
throws ParserConfigurationException;
/**
@ -488,17 +461,6 @@ public abstract class DocumentBuilderFactory {
}
/* <p>Set canonicalization control to <code>true</code> or
* </code>false</code>.</p>
*
* @param state of canonicalization
*/
/*
public void setCanonicalization(boolean state) {
canonicalState = state;
}
*/
/**
* <p>Set the {@link Schema} to be used by parsers created
* from this factory.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -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;
/**
* <p>Implements pluggable Datatypes.</p>
* <p>Implements pluggable Parsers.</p>
*
* <p>This class is duplicated for each JAXP subpackage so keep it in
* sync. It is package private for secure class loading.</p>
@ -51,7 +52,7 @@ class FactoryFinder {
/**
* 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 @@ class FactoryFinder {
* 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,31 +97,31 @@ class FactoryFinder {
*
* 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 {
if (cl == null) {
if (useBSClsLoader) {
return Class.forName(className, true, FactoryFinder.class.getClassLoader());
return Class.forName(className, false, FactoryFinder.class.getClassLoader());
} else {
cl = ss.getContextClassLoader();
if (cl == null) {
throw new ClassNotFoundException();
}
else {
return cl.loadClass(className);
return Class.forName(className, false, cl);
}
}
}
else {
return cl.loadClass(className);
return Class.forName(className, false, cl);
}
}
catch (ClassNotFoundException e1) {
if (doFallback) {
// Use current class loader - should always be bootstrap CL
return Class.forName(className, true, FactoryFinder.class.getClassLoader());
return Class.forName(className, false, FactoryFinder.class.getClassLoader());
}
else {
throw e1;
@ -132,6 +133,9 @@ class FactoryFinder {
* Create an instance of a class. Delegates to method
* <code>getProviderClass()</code> in order to load the class.
*
* @param type Base class / Service interface of the factory to
* instantiate.
*
* @param className Name of the concrete class corresponding to the
* service provider
*
@ -141,16 +145,20 @@ class FactoryFinder {
* @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
static <T> T newInstance(Class<T> type, String className, ClassLoader cl,
boolean doFallback)
throws FactoryConfigurationError
{
return newInstance(className, cl, doFallback, false);
return newInstance(type, className, cl, doFallback, false);
}
/**
* Create an instance of a class. Delegates to method
* <code>getProviderClass()</code> in order to load the class.
*
* @param type Base class / Service interface of the factory to
* instantiate.
*
* @param className Name of the concrete class corresponding to the
* service provider
*
@ -163,9 +171,11 @@ class FactoryFinder {
* @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
static <T> T newInstance(Class<T> type, String className, ClassLoader cl,
boolean doFallback, boolean useBSClsLoader)
throws FactoryConfigurationError
{
assert type != null;
// make sure we have access to restricted packages
if (System.getSecurityManager() != null) {
if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
@ -175,22 +185,24 @@ class FactoryFinder {
}
try {
Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
if (!type.isAssignableFrom(providerClass)) {
throw new ClassCastException(className + " cannot be cast to " + type.getName());
}
Object instance = providerClass.newInstance();
if (debug) { // Extra check to avoid computing cl strings
dPrint("created new instance of " + providerClass +
" using ClassLoader: " + cl);
}
return instance;
return type.cast(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);
}
}
@ -199,16 +211,17 @@ class FactoryFinder {
* 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> T find(Class<T> type, String fallbackClassName)
throws FactoryConfigurationError
{
final String factoryId = type.getName();
dPrint("find factoryId =" + factoryId);
// Use the system property first
@ -216,7 +229,7 @@ class FactoryFinder {
String systemProp = ss.getSystemProperty(factoryId);
if (systemProp != null) {
dPrint("found system property, value=" + systemProp);
return newInstance(systemProp, null, true);
return newInstance(type, systemProp, null, true);
}
}
catch (SecurityException se) {
@ -225,7 +238,6 @@ class FactoryFinder {
// try to read from $java.home/lib/jaxp.properties
try {
String factoryClassName = null;
if (firstTime) {
synchronized (cacheProps) {
if (firstTime) {
@ -240,11 +252,11 @@ class FactoryFinder {
}
}
}
factoryClassName = cacheProps.getProperty(factoryId);
final String factoryClassName = cacheProps.getProperty(factoryId);
if (factoryClassName != null) {
dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
return newInstance(factoryClassName, null, true);
return newInstance(type, factoryClassName, null, true);
}
}
catch (Exception ex) {
@ -252,112 +264,52 @@ class FactoryFinder {
}
// Try Jar Service Provider Mechanism
Object provider = findJarServiceProvider(factoryId);
T provider = findServiceProvider(type);
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 newInstance(type, fallbackClassName, null, true);
}
/*
* Try to find provider using Jar Service Provider Mechanism
* Try to find provider using the ServiceLoader API
*
* @param type Base class / Service interface of the factory to find.
*
* @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;
private static <T> T findServiceProvider(final Class<T> type) {
try {
rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
}
catch (java.io.UnsupportedEncodingException e) {
rd = new BufferedReader(new InputStreamReader(is));
}
String factoryClassName = null;
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<T>() {
public T run() {
final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
final Iterator<T> iterator = serviceLoader.iterator();
if (iterator.hasNext()) {
return iterator.next();
} else {
return null;
}
}
});
} 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;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -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 @@ import org.xml.sax.SAXNotSupportedException;
*
*/
public abstract class SAXParserFactory {
/** The default property name according to the JAXP spec */
private static final String DEFAULT_PROPERTY_NAME = "javax.xml.parsers.SAXParserFactory";
/**
* <p>Should Parsers be validating?</p>
@ -87,14 +84,12 @@ public abstract class SAXParserFactory {
* of any property in jaxp.properties after it has been read for the first time.
* </li>
* <li>
* 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
* <code>META-INF/services/javax.xml.parsers.SAXParserFactory</code>
* in jars available to the runtime.
* Use the service-provider loading facilities, defined by the
* {@link java.util.ServiceLoader} class, to attempt to locate and load an
* implementation of the service.
* </li>
* <li>
* Platform default <code>SAXParserFactory</code> instance.
* Otherwise the system-default implementation is returned.
* </li>
* </ul>
*
@ -109,7 +104,7 @@ public abstract class SAXParserFactory {
* this method to print a lot of debug messages
* to <code>System.err</code> about what it is doing and where it is looking at.</p>
*
* <p> If you have problems loading {@link DocumentBuilder}s, try:</p>
* <p> If you have problems loading {@link SAXParser}s, try:</p>
* <pre>
* java -Djaxp.debug=1 YourProgram ....
* </pre>
@ -117,21 +112,17 @@ public abstract class SAXParserFactory {
*
* @return A new instance of a SAXParserFactory.
*
* @throws FactoryConfigurationError if the implementation is
* not available or cannot be instantiated.
* @throws FactoryConfigurationError in case of {@linkplain
* java.util.ServiceConfigurationError service configuration error} or if
* the implementation is not available or cannot be instantiated.
*/
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 +160,9 @@ public abstract class SAXParserFactory {
* @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());
}
return FactoryFinder.newInstance(SAXParserFactory.class,
factoryClassName, classLoader, false);
}
/**
@ -266,22 +253,22 @@ public abstract class SAXParserFactory {
* A list of the core features and properties can be found at
* <a href="http://www.saxproject.org/">http://www.saxproject.org/</a></p>
*
* <p>All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
* When the feature is</p>
* <ul>
* <li>
* <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
* Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources.
* If XML processing is limited for security reasons, it will be reported via a call to the registered
* {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}.
* See {@link SAXParser} <code>parse</code> methods for handler specification.
* </li>
* <li>
* When the feature is <code>false</code>, the implementation will processing XML according to the XML specifications without
* regard to possible implementation limits.
* </li>
* </ul>
*
* <p>All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
* When the feature is</p>
* <ul>
* <li>
* <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
* Examples include entity expansion limits and XML Schema constructs that would consume large amounts of resources.
* If XML processing is limited for security reasons, it will be reported via a call to the registered
* {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}.
* See {@link SAXParser} <code>parse</code> methods for handler specification.
* </li>
* <li>
* When the feature is <code>false</code>, the implementation will processing XML according to the XML specifications without
* regard to possible implementation limits.
* </li>
* </ul>
*
* @param name The name of the feature to be set.
* @param value The value of the feature to be set.
*
@ -320,17 +307,6 @@ public abstract class SAXParserFactory {
SAXNotSupportedException;
/* <p>Get current state of canonicalization.</p>
*
* @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 +333,6 @@ public abstract class SAXParserFactory {
);
}
/** <p>Set canonicalization control to <code>true</code> or
* </code>false</code>.</p>
*
* @param state of canonicalization
*/
/*
public void setCanonicalization(boolean state) {
canonicalState = state;
}
*/
/**
* <p>Set the {@link Schema} to be used by parsers created
* from this factory.</p>
@ -400,7 +365,7 @@ public abstract class SAXParserFactory {
* Such configuration will cause a {@link SAXException}
* exception when those properties are set on a {@link SAXParser}.</p>
*
* <h4>Note for implmentors</h4>
* <h4>Note for implementors</h4>
* <p>
* A parser must be able to work with any {@link Schema}
* implementation. However, parsers and schemas are allowed

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,15 +25,16 @@
package javax.xml.stream;
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;
/**
* <p>Implements pluggable Datatypes.</p>
* <p>Implements pluggable streams.</p>
*
* <p>This class is duplicated for each JAXP subpackage so keep it in
* sync. It is package private for secure class loading.</p>
@ -52,19 +53,19 @@ class FactoryFinder {
/**
* Cache for properties in java.home/lib/jaxp.properties
*/
static Properties cacheProps = new Properties();
final private static Properties cacheProps = new Properties();
/**
* Flag indicating if properties from java.home/lib/jaxp.properties
* have been cached.
*/
static volatile boolean firstTime = true;
private static volatile boolean firstTime = true;
/**
* Security support class use to check access control before
* getting certain system resources.
*/
static SecuritySupport ss = new SecuritySupport();
final private static SecuritySupport ss = new SecuritySupport();
// Define system property "jaxp.debug" to get output
static {
@ -103,25 +104,25 @@ class FactoryFinder {
try {
if (cl == null) {
if (useBSClsLoader) {
return Class.forName(className, true, FactoryFinder.class.getClassLoader());
return Class.forName(className, false, FactoryFinder.class.getClassLoader());
} else {
cl = ss.getContextClassLoader();
if (cl == null) {
throw new ClassNotFoundException();
}
else {
return cl.loadClass(className);
return Class.forName(className, false, cl);
}
}
}
else {
return cl.loadClass(className);
return Class.forName(className, false, cl);
}
}
catch (ClassNotFoundException e1) {
if (doFallback) {
// Use current class loader - should always be bootstrap CL
return Class.forName(className, true, FactoryFinder.class.getClassLoader());
return Class.forName(className, false, FactoryFinder.class.getClassLoader());
}
else {
throw e1;
@ -133,6 +134,9 @@ class FactoryFinder {
* Create an instance of a class. Delegates to method
* <code>getProviderClass()</code> in order to load the class.
*
* @param type Base class / Service interface of the factory to
* instantiate.
*
* @param className Name of the concrete class corresponding to the
* service provider
*
@ -142,16 +146,19 @@ class FactoryFinder {
* @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
static <T> T newInstance(Class<T> type, String className, ClassLoader cl, boolean doFallback)
throws FactoryConfigurationError
{
return newInstance(className, cl, doFallback, false);
return newInstance(type, className, cl, doFallback, false);
}
/**
* Create an instance of a class. Delegates to method
* <code>getProviderClass()</code> in order to load the class.
*
* @param type Base class / Service interface of the factory to
* instantiate.
*
* @param className Name of the concrete class corresponding to the
* service provider
*
@ -164,9 +171,12 @@ class FactoryFinder {
* @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
static <T> T newInstance(Class<T> type, String className, ClassLoader cl,
boolean doFallback, boolean useBSClsLoader)
throws FactoryConfigurationError
{
assert type != null;
// make sure we have access to restricted packages
if (System.getSecurityManager() != null) {
if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
@ -176,20 +186,23 @@ class FactoryFinder {
}
try {
Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
if (!type.isAssignableFrom(providerClass)) {
throw new ClassCastException(className + " cannot be cast to " + type.getName());
}
Object instance = providerClass.newInstance();
if (debug) { // Extra check to avoid computing cl strings
dPrint("created new instance of " + providerClass +
" using ClassLoader: " + cl);
}
return instance;
return type.cast(instance);
}
catch (ClassNotFoundException x) {
throw new ConfigurationError(
throw new FactoryConfigurationError(
"Provider " + className + " not found", x);
}
catch (Exception x) {
throw new ConfigurationError(
throw new FactoryConfigurationError(
"Provider " + className + " could not be instantiated: " + x,
x);
}
@ -200,17 +213,18 @@ class FactoryFinder {
*
* @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> T find(Class<T> type, String fallbackClassName)
throws FactoryConfigurationError
{
return find(factoryId, null, fallbackClassName);
return find(type, type.getName(), null, fallbackClassName);
}
/**
@ -218,6 +232,9 @@ class FactoryFinder {
* entry point.
* @return Class object of factory, never null
*
* @param type Base class / Service interface of the
* factory to find.
*
* @param factoryId Name of the factory to find, same as
* a property name
*
@ -229,8 +246,8 @@ class FactoryFinder {
*
* Package private so this code can be shared.
*/
static Object find(String factoryId, ClassLoader cl, String fallbackClassName)
throws ConfigurationError
static <T> T find(Class<T> type, String factoryId, ClassLoader cl, String fallbackClassName)
throws FactoryConfigurationError
{
dPrint("find factoryId =" + factoryId);
@ -239,7 +256,9 @@ class FactoryFinder {
String systemProp = ss.getSystemProperty(factoryId);
if (systemProp != null) {
dPrint("found system property, value=" + systemProp);
return newInstance(systemProp, null, true);
// There's a bug here - because 'cl' is ignored.
// This will be handled separately.
return newInstance(type, systemProp, null, true);
}
}
catch (SecurityException se) {
@ -250,7 +269,6 @@ class FactoryFinder {
// $java.home/lib/jaxp.properties if former not present
String configFile = null;
try {
String factoryClassName = null;
if (firstTime) {
synchronized (cacheProps) {
if (firstTime) {
@ -269,130 +287,80 @@ class FactoryFinder {
if (ss.doesFileExist(f)) {
dPrint("Read properties file "+f);
cacheProps.load(ss.getFileInputStream(f));
}
}
}
}
}
}
}
factoryClassName = cacheProps.getProperty(factoryId);
final String factoryClassName = cacheProps.getProperty(factoryId);
if (factoryClassName != null) {
dPrint("found in " + configFile + " value=" + factoryClassName);
return newInstance(factoryClassName, null, true);
// There's a bug here - because 'cl' is ignored.
// This will be handled separately.
return newInstance(type, factoryClassName, null, true);
}
}
catch (Exception ex) {
if (debug) ex.printStackTrace();
}
// Try Jar Service Provider Mechanism
Object provider = findJarServiceProvider(factoryId);
if (provider != null) {
return provider;
if (type.getName().equals(factoryId)) {
// Try Jar Service Provider Mechanism
final T provider = findServiceProvider(type);
if (provider != null) {
return provider;
}
} else {
// We're in the case where a 'custom' factoryId was provided,
// and in every case where that happens, we expect that
// fallbackClassName will be null.
assert fallbackClassName == null;
}
if (fallbackClassName == null) {
throw new ConfigurationError(
throw new FactoryConfigurationError(
"Provider for " + factoryId + " cannot be found", null);
}
dPrint("loaded from fallback value: " + fallbackClassName);
return newInstance(fallbackClassName, cl, true);
return newInstance(type, fallbackClassName, cl, true);
}
/*
* Try to find provider using Jar Service Provider Mechanism
* Try to find provider using the ServiceLoader API
*
* @param type Base class / Service interface of the factory to find.
*
* @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;
private static <T> T findServiceProvider(final Class<T> type) {
try {
rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
}
catch (java.io.UnsupportedEncodingException e) {
rd = new BufferedReader(new InputStreamReader(is));
}
String factoryClassName = null;
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<T>() {
@Override
public T run() {
final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
final Iterator<T> iterator = serviceLoader.iterator();
if (iterator.hasNext()) {
return iterator.next();
} else {
return null;
}
}
});
} 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;
}
}
}

View File

@ -23,14 +23,14 @@
*/
/*
* Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
* Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved.
*/
package javax.xml.stream;
import javax.xml.stream.events.*;
import java.util.Iterator;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import java.util.Iterator;
import javax.xml.stream.events.*;
/**
* This interface defines a utility class for creating instances of
* XMLEvents
@ -54,48 +54,59 @@ public abstract class XMLEventFactory {
/**
* Create a new instance of the factory
* Creates a new instance of the factory in exactly the same manner as the
* {@link #newFactory()} method.
* @throws FactoryConfigurationError if an instance of this factory cannot be loaded
*/
public static XMLEventFactory newInstance()
throws FactoryConfigurationError
{
return (XMLEventFactory) FactoryFinder.find(
JAXPFACTORYID,
DEFAULIMPL);
return FactoryFinder.find(XMLEventFactory.class, DEFAULIMPL);
}
/**
* Create a new instance of the factory.
* <p>
* This static method creates a new factory instance.
* This method uses the following ordered lookup procedure to determine
* the XMLEventFactory implementation class to load:
* </p>
* <ul>
* <li>
* Use the javax.xml.stream.XMLEventFactory system property.
* </li>
* <li>
* Use the properties file "lib/stax.properties" in the JRE directory.
* This configuration file is in standard java.util.Properties format
* and contains the fully qualified name of the implementation class
* with the key being the system property defined above.
* 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.stream.XMLEventFactory in jars
* available to the runtime.
* Platform default XMLEventFactory instance.
*
* </li>
* <li>
* Use the service-provider loading facilities, defined by the
* {@link java.util.ServiceLoader} class, to attempt to locate and load an
* implementation of the service.
* </li>
* <li>
* Otherwise, the system-default implementation is returned.
* </li>
* </ul>
* <p>
* Once an application has obtained a reference to a XMLEventFactory it
* can use the factory to configure and obtain stream instances.
*
* </p>
* <p>
* Note that this is a new method that replaces the deprecated newInstance() method.
* No changes in behavior are defined by this replacement method relative to
* the deprecated method.
*
* @throws FactoryConfigurationError if an instance of this factory cannot be loaded
* </p>
* @throws FactoryConfigurationError in case of {@linkplain
* java.util.ServiceConfigurationError service configuration error} or if
* the implementation is not available or cannot be instantiated.
*/
public static XMLEventFactory newFactory()
throws FactoryConfigurationError
{
return (XMLEventFactory) FactoryFinder.find(
JAXPFACTORYID,
DEFAULIMPL);
return FactoryFinder.find(XMLEventFactory.class, DEFAULIMPL);
}
/**
@ -116,40 +127,59 @@ public abstract class XMLEventFactory {
public static XMLEventFactory newInstance(String factoryId,
ClassLoader classLoader)
throws FactoryConfigurationError {
try {
//do not fallback if given classloader can't find the class, throw exception
return (XMLEventFactory) FactoryFinder.find(factoryId, classLoader, null);
} catch (FactoryFinder.ConfigurationError e) {
throw new FactoryConfigurationError(e.getException(),
e.getMessage());
}
//do not fallback if given classloader can't find the class, throw exception
return FactoryFinder.find(XMLEventFactory.class, factoryId, classLoader, null);
}
/**
* Create a new instance of the factory.
* If the classLoader argument is null, then the ContextClassLoader is used.
* <p>
* This method uses the following ordered lookup procedure to determine
* the XMLEventFactory implementation class to load:
* </p>
* <ul>
* <li>
* Use the value of the system property identified by {@code factoryId}.
* </li>
* <li>
* Use the properties file "lib/stax.properties" in the JRE directory.
* This configuration file is in standard java.util.Properties format
* and contains the fully qualified name of the implementation class
* with the key being the given {@code factoryId}.
* </li>
* <li>
* If {@code factoryId} is "javax.xml.stream.XMLEventFactory",
* use the service-provider loading facilities, defined by the
* {@link java.util.ServiceLoader} class, to attempt to locate and load an
* implementation of the service.
* </li>
* <li>
* Otherwise, throws a {@link FactoryConfigurationError}.
* </li>
* </ul>
*
* <p>
* Note that this is a new method that replaces the deprecated
* newInstance(String factoryId, ClassLoader classLoader) method.
* {@link #newInstance(java.lang.String, java.lang.ClassLoader)
* newInstance(String factoryId, ClassLoader classLoader)} method.
* No changes in behavior are defined by this replacement method relative
* to the deprecated method.
* </p>
*
* @param factoryId Name of the factory to find, same as
* a property name
* @param classLoader classLoader to use
* @return the factory implementation
* @throws FactoryConfigurationError if an instance of this factory cannot be loaded
* @throws FactoryConfigurationError in case of {@linkplain
* java.util.ServiceConfigurationError service configuration error} or if
* the implementation is not available or cannot be instantiated.
*/
public static XMLEventFactory newFactory(String factoryId,
ClassLoader classLoader)
ClassLoader classLoader)
throws FactoryConfigurationError {
try {
//do not fallback if given classloader can't find the class, throw exception
return (XMLEventFactory) FactoryFinder.find(factoryId, classLoader, null);
} catch (FactoryFinder.ConfigurationError e) {
throw new FactoryConfigurationError(e.getException(),
e.getMessage());
}
//do not fallback if given classloader can't find the class, throw exception
return FactoryFinder.find(XMLEventFactory.class, factoryId, classLoader, null);
}
/**

View File

@ -23,13 +23,13 @@
*/
/*
* Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
* Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved.
*/
package javax.xml.stream;
import javax.xml.transform.Source;
import javax.xml.stream.util.XMLEventAllocator;
import javax.xml.transform.Source;
/**
* Defines an abstract implementation of a factory for getting streams.
@ -144,48 +144,59 @@ public abstract class XMLInputFactory {
protected XMLInputFactory(){}
/**
* Create a new instance of the factory.
* Creates a new instance of the factory in exactly the same manner as the
* {@link #newFactory()} method.
* @throws FactoryConfigurationError if an instance of this factory cannot be loaded
*/
public static XMLInputFactory newInstance()
throws FactoryConfigurationError
{
return (XMLInputFactory) FactoryFinder.find(
"javax.xml.stream.XMLInputFactory",
DEFAULIMPL);
return FactoryFinder.find(XMLInputFactory.class, DEFAULIMPL);
}
/**
* Create a new instance of the factory.
* <p>
* This static method creates a new factory instance.
* This method uses the following ordered lookup procedure to determine
* the XMLInputFactory implementation class to load:
* </p>
* <ul>
* <li>
* Use the javax.xml.stream.XMLInputFactory system property.
* </li>
* <li>
* Use the properties file "lib/stax.properties" in the JRE directory.
* This configuration file is in standard java.util.Properties format
* and contains the fully qualified name of the implementation class
* with the key being the system property defined above.
* 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.stream.XMLInputFactory in jars
* available to the runtime.
* Platform default XMLInputFactory instance.
*
* </li>
* <li>
* Use the service-provider loading facilities, defined by the
* {@link java.util.ServiceLoader} class, to attempt to locate and load an
* implementation of the service.
* </li>
* <li>
* Otherwise, the system-default implementation is returned.
* </li>
* </ul>
* <p>
* Once an application has obtained a reference to a XMLInputFactory it
* can use the factory to configure and obtain stream instances.
*
* </p>
* <p>
* Note that this is a new method that replaces the deprecated newInstance() method.
* No changes in behavior are defined by this replacement method relative to
* the deprecated method.
*
* @throws FactoryConfigurationError if an instance of this factory cannot be loaded
* </p>
* @throws FactoryConfigurationError in case of {@linkplain
* java.util.ServiceConfigurationError service configuration error} or if
* the implementation is not available or cannot be instantiated.
*/
public static XMLInputFactory newFactory()
throws FactoryConfigurationError
{
return (XMLInputFactory) FactoryFinder.find(
"javax.xml.stream.XMLInputFactory",
DEFAULIMPL);
return FactoryFinder.find(XMLInputFactory.class, DEFAULIMPL);
}
/**
@ -206,40 +217,60 @@ public abstract class XMLInputFactory {
public static XMLInputFactory newInstance(String factoryId,
ClassLoader classLoader)
throws FactoryConfigurationError {
try {
//do not fallback if given classloader can't find the class, throw exception
return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null);
} catch (FactoryFinder.ConfigurationError e) {
throw new FactoryConfigurationError(e.getException(),
e.getMessage());
}
//do not fallback if given classloader can't find the class, throw exception
return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null);
}
/**
* Create a new instance of the factory.
* If the classLoader argument is null, then the ContextClassLoader is used.
* <p>
* This method uses the following ordered lookup procedure to determine
* the XMLInputFactory implementation class to load:
* </p>
* <ul>
* <li>
* Use the value of the system property identified by {@code factoryId}.
* </li>
* <li>
* Use the properties file "lib/stax.properties" in the JRE directory.
* This configuration file is in standard java.util.Properties format
* and contains the fully qualified name of the implementation class
* with the key being the given {@code factoryId}.
* </li>
* <li>
* If {@code factoryId} is "javax.xml.stream.XMLInputFactory",
* use the service-provider loading facilities, defined by the
* {@link java.util.ServiceLoader} class, to attempt to locate and load an
* implementation of the service.
* </li>
* <li>
* Otherwise, throws a {@link FactoryConfigurationError}.
* </li>
* </ul>
*
* <p>
* Note that this is a new method that replaces the deprecated
* newInstance(String factoryId, ClassLoader classLoader) method.
* {@link #newInstance(java.lang.String, java.lang.ClassLoader)
* newInstance(String factoryId, ClassLoader classLoader)} method.
* No changes in behavior are defined by this replacement method relative
* to the deprecated method.
* </p>
*
* @param factoryId Name of the factory to find, same as
* a property name
* @param classLoader classLoader to use
* @return the factory implementation
* @throws FactoryConfigurationError in case of {@linkplain
* java.util.ServiceConfigurationError service configuration error} or if
* the implementation is not available or cannot be instantiated.
* @throws FactoryConfigurationError if an instance of this factory cannot be loaded
*/
public static XMLInputFactory newFactory(String factoryId,
ClassLoader classLoader)
throws FactoryConfigurationError {
try {
//do not fallback if given classloader can't find the class, throw exception
return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null);
} catch (FactoryFinder.ConfigurationError e) {
throw new FactoryConfigurationError(e.getException(),
e.getMessage());
}
//do not fallback if given classloader can't find the class, throw exception
return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null);
}
/**

View File

@ -23,7 +23,7 @@
*/
/*
* Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
* Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved.
*/
package javax.xml.stream;
@ -120,46 +120,58 @@ public abstract class XMLOutputFactory {
protected XMLOutputFactory(){}
/**
* Create a new instance of the factory.
* Creates a new instance of the factory in exactly the same manner as the
* {@link #newFactory()} method.
* @throws FactoryConfigurationError if an instance of this factory cannot be loaded
*/
public static XMLOutputFactory newInstance()
throws FactoryConfigurationError
{
return (XMLOutputFactory) FactoryFinder.find("javax.xml.stream.XMLOutputFactory",
DEFAULIMPL);
return FactoryFinder.find(XMLOutputFactory.class, DEFAULIMPL);
}
/**
* Create a new instance of the factory.
* <p>
* This static method creates a new factory instance. This method uses the
* following ordered lookup procedure to determine the XMLOutputFactory
* implementation class to load:
* </p>
* <ul>
* <li>
* Use the javax.xml.stream.XMLOutputFactory system property.
* </li>
* <li>
* Use the properties file "lib/stax.properties" in the JRE directory.
* This configuration file is in standard java.util.Properties format
* and contains the fully qualified name of the implementation class
* with the key being the system property defined above.
* 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.stream.XMLOutputFactory in jars
* available to the runtime.
* Platform default XMLOutputFactory instance.
*
* </li>
* <li>
* Use the service-provider loading facilities, defined by the
* {@link java.util.ServiceLoader} class, to attempt to locate and load an
* implementation of the service.
* </li>
* <li>
* Otherwise, the system-default implementation is returned.
* </li>
* <p>
* Once an application has obtained a reference to a XMLOutputFactory it
* can use the factory to configure and obtain stream instances.
*
* </p>
* <p>
* Note that this is a new method that replaces the deprecated newInstance() method.
* No changes in behavior are defined by this replacement method relative to the
* deprecated method.
*
* @throws FactoryConfigurationError if an instance of this factory cannot be loaded
* </p>
* @throws FactoryConfigurationError in case of {@linkplain
* java.util.ServiceConfigurationError service configuration error} or if
* the implementation is not available or cannot be instantiated.
*/
public static XMLOutputFactory newFactory()
throws FactoryConfigurationError
{
return (XMLOutputFactory) FactoryFinder.find("javax.xml.stream.XMLOutputFactory",
DEFAULIMPL);
return FactoryFinder.find(XMLOutputFactory.class, DEFAULIMPL);
}
/**
@ -179,42 +191,59 @@ public abstract class XMLOutputFactory {
public static XMLInputFactory newInstance(String factoryId,
ClassLoader classLoader)
throws FactoryConfigurationError {
try {
//do not fallback if given classloader can't find the class, throw exception
return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null);
} catch (FactoryFinder.ConfigurationError e) {
throw new FactoryConfigurationError(e.getException(),
e.getMessage());
}
//do not fallback if given classloader can't find the class, throw exception
return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null);
}
/**
* Create a new instance of the factory.
* If the classLoader argument is null, then the ContextClassLoader is used.
* <p>
* This method uses the following ordered lookup procedure to determine
* the XMLOutputFactory implementation class to load:
* </p>
* <ul>
* <li>
* Use the value of the system property identified by {@code factoryId}.
* </li>
* <li>
* Use the properties file "lib/stax.properties" in the JRE directory.
* This configuration file is in standard java.util.Properties format
* and contains the fully qualified name of the implementation class
* with the key being the given {@code factoryId}.
* </li>
* <li>
* If {@code factoryId} is "javax.xml.stream.XMLOutputFactory",
* use the service-provider loading facilities, defined by the
* {@link java.util.ServiceLoader} class, to attempt to locate and load an
* implementation of the service.
* </li>
* <li>
* Otherwise, throws a {@link FactoryConfigurationError}.
* </li>
* </ul>
*
* <p>
* Note that this is a new method that replaces the deprecated
* newInstance(String factoryId, ClassLoader classLoader) method.
*
* No changes in behavior are defined by this replacement method relative
* to the deprecated method.
*
* {@link #newInstance(java.lang.String, java.lang.ClassLoader)
* newInstance(String factoryId, ClassLoader classLoader)} method.
* No changes in behavior are defined by this replacement method relative
* to the deprecated method.
* </p>
*
* @param factoryId Name of the factory to find, same as
* a property name
* @param classLoader classLoader to use
* @return the factory implementation
* @throws FactoryConfigurationError if an instance of this factory cannot be loaded
* @throws FactoryConfigurationError in case of {@linkplain
* java.util.ServiceConfigurationError service configuration error} or if
* the implementation is not available or cannot be instantiated.
*/
public static XMLOutputFactory newFactory(String factoryId,
ClassLoader classLoader)
throws FactoryConfigurationError {
try {
//do not fallback if given classloader can't find the class, throw exception
return (XMLOutputFactory) FactoryFinder.find(factoryId, classLoader, null);
} catch (FactoryFinder.ConfigurationError e) {
throw new FactoryConfigurationError(e.getException(),
e.getMessage());
}
//do not fallback if given classloader can't find the class, throw exception
return FactoryFinder.find(XMLOutputFactory.class, factoryId, classLoader, null);
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,13 +25,15 @@
package javax.xml.transform;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Iterator;
import java.util.Properties;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
/**
* <p>Implements pluggable Datatypes.</p>
@ -53,7 +55,7 @@ class FactoryFinder {
/**
* Cache for properties in java.home/lib/jaxp.properties
*/
static Properties cacheProps = new Properties();
private final static Properties cacheProps = new Properties();
/**
* Flag indicating if properties from java.home/lib/jaxp.properties
@ -65,7 +67,7 @@ class FactoryFinder {
* Security support class use to check access control before
* getting certain system resources.
*/
static SecuritySupport ss = new SecuritySupport();
private final static SecuritySupport ss = new SecuritySupport();
// Define system property "jaxp.debug" to get output
static {
@ -98,31 +100,31 @@ class FactoryFinder {
*
* 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 {
if (cl == null) {
if (useBSClsLoader) {
return Class.forName(className, true, FactoryFinder.class.getClassLoader());
return Class.forName(className, false, FactoryFinder.class.getClassLoader());
} else {
cl = ss.getContextClassLoader();
if (cl == null) {
throw new ClassNotFoundException();
}
else {
return cl.loadClass(className);
return Class.forName(className, false, cl);
}
}
}
else {
return cl.loadClass(className);
return Class.forName(className, false, cl);
}
}
catch (ClassNotFoundException e1) {
if (doFallback) {
// Use current class loader - should always be bootstrap CL
return Class.forName(className, true, FactoryFinder.class.getClassLoader());
return Class.forName(className, false, FactoryFinder.class.getClassLoader());
}
else {
throw e1;
@ -134,24 +136,8 @@ class FactoryFinder {
* Create an instance of a class. Delegates to method
* <code>getProviderClass()</code> in order to load the class.
*
* @param className Name of the concrete class corresponding to the
* service provider
*
* @param cl <code>ClassLoader</code> used to load the factory class. If <code>null</code>
* current <code>Thread</code>'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
*/
static Object newInstance(String className, ClassLoader cl, boolean doFallback)
throws ConfigurationError
{
return newInstance(className, cl, doFallback, false, false);
}
/**
* Create an instance of a class. Delegates to method
* <code>getProviderClass()</code> in order to load the class.
* @param type Base class / Service interface of the factory to
* instantiate.
*
* @param className Name of the concrete class corresponding to the
* service provider
@ -162,14 +148,15 @@ class FactoryFinder {
* @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 useServicesMechanism True use services mechanism
*/
static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader, boolean useServicesMechanism)
throws ConfigurationError
static <T> T newInstance(Class<T> type, String className, ClassLoader cl,
boolean doFallback, boolean useServicesMechanism)
throws TransformerFactoryConfigurationError
{
assert type != null;
boolean useBSClsLoader = false;
// make sure we have access to restricted packages
if (System.getSecurityManager() != null) {
if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
@ -179,10 +166,13 @@ class FactoryFinder {
}
try {
Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
if (!type.isAssignableFrom(providerClass)) {
throw new ClassCastException(className + " cannot be cast to " + type.getName());
}
Object instance = null;
if (!useServicesMechanism) {
instance = newInstanceNoServiceLoader(providerClass);
instance = newInstanceNoServiceLoader(type, providerClass);
}
if (instance == null) {
instance = providerClass.newInstance();
@ -191,63 +181,87 @@ class FactoryFinder {
dPrint("created new instance of " + providerClass +
" using ClassLoader: " + cl);
}
return instance;
return type.cast(instance);
}
catch (ClassNotFoundException x) {
throw new ConfigurationError(
"Provider " + className + " not found", x);
throw new TransformerFactoryConfigurationError(x,
"Provider " + className + " not found");
}
catch (Exception x) {
throw new ConfigurationError(
"Provider " + className + " could not be instantiated: " + x,
x);
throw new TransformerFactoryConfigurationError(x,
"Provider " + className + " could not be instantiated: " + x);
}
}
/**
* Try to construct using newTransformerFactoryNoServiceLoader
* method if available.
*/
private static Object newInstanceNoServiceLoader(
Class<?> providerClass
) {
private static <T> T newInstanceNoServiceLoader(Class<T> type, Class<?> providerClass) {
// Retain maximum compatibility if no security manager.
if (System.getSecurityManager() == null) {
return null;
}
try {
Method creationMethod =
providerClass.getDeclaredMethod(
"newTransformerFactoryNoServiceLoader"
);
return creationMethod.invoke(null, (Object[])null);
} catch (NoSuchMethodException exc) {
return null;
} catch (Exception exc) {
final Method creationMethod =
providerClass.getDeclaredMethod(
"newTransformerFactoryNoServiceLoader"
);
final int modifiers = creationMethod.getModifiers();
// Do not call the method if it's not public static.
if (!Modifier.isPublic(modifiers) || !Modifier.isStatic(modifiers)) {
return null;
}
// Only call the method if it's declared to return an instance of
// TransformerFactory
final Class<?> returnType = creationMethod.getReturnType();
if (type.isAssignableFrom(returnType)) {
final Object result = creationMethod.invoke(null, (Object[])null);
return type.cast(result);
} else {
// This should not happen, as
// TransformerFactoryImpl.newTransformerFactoryNoServiceLoader is
// declared to return TransformerFactory.
throw new ClassCastException(returnType + " cannot be cast to " + type);
}
} catch (ClassCastException e) {
throw new TransformerFactoryConfigurationError(e, e.getMessage());
} catch (NoSuchMethodException exc) {
return null;
} catch (Exception exc) {
return null;
}
}
/**
* 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 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> T find(Class<T> type, String fallbackClassName)
throws TransformerFactoryConfigurationError
{
assert type != null;
final String factoryId = type.getName();
dPrint("find factoryId =" + factoryId);
// Use the system property first
try {
String systemProp = ss.getSystemProperty(factoryId);
if (systemProp != null) {
dPrint("found system property, value=" + systemProp);
return newInstance(systemProp, null, true, false, true);
return newInstance(type, systemProp, null, true, true);
}
}
catch (SecurityException se) {
@ -256,7 +270,6 @@ class FactoryFinder {
// try to read from $java.home/lib/jaxp.properties
try {
String factoryClassName = null;
if (firstTime) {
synchronized (cacheProps) {
if (firstTime) {
@ -271,11 +284,11 @@ class FactoryFinder {
}
}
}
factoryClassName = cacheProps.getProperty(factoryId);
final String factoryClassName = cacheProps.getProperty(factoryId);
if (factoryClassName != null) {
dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
return newInstance(factoryClassName, null, true, false, true);
return newInstance(type, factoryClassName, null, true, true);
}
}
catch (Exception ex) {
@ -283,113 +296,54 @@ class FactoryFinder {
}
// Try Jar Service Provider Mechanism
Object provider = findJarServiceProvider(factoryId);
T provider = findServiceProvider(type);
if (provider != null) {
return provider;
}
if (fallbackClassName == null) {
throw new ConfigurationError(
"Provider for " + factoryId + " cannot be found", null);
throw new TransformerFactoryConfigurationError(null,
"Provider for " + factoryId + " cannot be found");
}
dPrint("loaded from fallback value: " + fallbackClassName);
return newInstance(fallbackClassName, null, true, false, true);
return newInstance(type, fallbackClassName, null, true, true);
}
/*
* Try to find provider using Jar Service Provider Mechanism
* Try to find provider using the ServiceLoader.
*
* @param type Base class / Service interface of the factory to find.
*
* @return instance of provider class if found or null
*/
private static Object findJarServiceProvider(String factoryId)
throws ConfigurationError
private static <T> T findServiceProvider(final Class<T> type)
throws TransformerFactoryConfigurationError
{
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;
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, true);
}
// 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;
try {
return AccessController.doPrivileged(new PrivilegedAction<T>() {
public T run() {
final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
final Iterator<T> iterator = serviceLoader.iterator();
if (iterator.hasNext()) {
return iterator.next();
} else {
return null;
}
}
});
} 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 TransformerFactoryConfigurationError error =
new TransformerFactoryConfigurationError(x, x.getMessage());
throw error;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -52,8 +52,8 @@ public abstract class TransformerFactory {
/**
* <p>Obtain a new instance of a <code>TransformerFactory</code>.
* This static method creates a new factory instance
* This method uses the following ordered lookup procedure to determine
* This static method creates a new factory instance.</p>
* <p>This method uses the following ordered lookup procedure to determine
* the <code>TransformerFactory</code> implementation class to
* load:</p>
* <ul>
@ -67,7 +67,7 @@ public abstract class TransformerFactory {
* </code> format and contains the fully qualified name of the
* implementation class with the key being the system property defined
* above.
*
* <br>
* The jaxp.properties file is read only once by the JAXP implementation
* and it's values are then cached for future use. If the file does not exist
* when the first attempt is made to read from it, no further attempts are
@ -75,14 +75,12 @@ public abstract class TransformerFactory {
* of any property in jaxp.properties after it has been read for the first time.
* </li>
* <li>
* 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
* <code>META-INF/services/javax.xml.transform.TransformerFactory</code>
* in jars available to the runtime.
* Use the service-provider loading facilities, defined by the
* {@link java.util.ServiceLoader} class, to attempt to locate and load an
* implementation of the service.
* </li>
* <li>
* Platform default <code>TransformerFactory</code> instance.
* Otherwise, the system-default implementation is returned.
* </li>
* </ul>
*
@ -92,22 +90,18 @@ public abstract class TransformerFactory {
*
* @return new TransformerFactory instance, never null.
*
* @throws TransformerFactoryConfigurationError Thrown if the implementation
* is not available or cannot be instantiated.
* @throws TransformerFactoryConfigurationError Thrown in case of {@linkplain
* java.util.ServiceConfigurationError service configuration error} or if
* the implementation is not available or cannot be instantiated.
*/
public static TransformerFactory newInstance()
throws TransformerFactoryConfigurationError {
try {
return (TransformerFactory) FactoryFinder.find(
return FactoryFinder.find(
/* The default property name according to the JAXP spec */
"javax.xml.transform.TransformerFactory",
TransformerFactory.class,
/* The fallback implementation class name, XSLTC */
"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
} catch (FactoryFinder.ConfigurationError e) {
throw new TransformerFactoryConfigurationError(
e.getException(),
e.getMessage());
}
}
/**
@ -147,14 +141,10 @@ public abstract class TransformerFactory {
*/
public static TransformerFactory newInstance(String factoryClassName, ClassLoader classLoader)
throws TransformerFactoryConfigurationError{
try {
//do not fallback if given classloader can't find the class, throw exception
return (TransformerFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false);
} catch (FactoryFinder.ConfigurationError e) {
throw new TransformerFactoryConfigurationError(
e.getException(),
e.getMessage());
}
//do not fallback if given classloader can't find the class, throw exception
return FactoryFinder.newInstance(TransformerFactory.class,
factoryClassName, classLoader, false, false);
}
/**
* <p>Process the <code>Source</code> into a <code>Transformer</code>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,15 +27,14 @@ package javax.xml.validation;
import java.io.File;
import java.net.URL;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.SAXParseException;
/**
* Factory that creates {@link Schema} objects&#x2E; Entry-point to
@ -79,7 +78,7 @@ import org.xml.sax.SAXNotSupportedException;
* and has a significant effect on the parsing process, it is impossible
* to define the DTD validation as a process independent from parsing.
* For this reason, this specification does not define the semantics for
* the XML DTD. This doesn't prohibit implentors from implementing it
* the XML DTD. This doesn't prohibit implementors from implementing it
* in a way they see fit, but <em>users are warned that any DTD
* validation implemented on this interface necessarily deviate from
* the XML DTD semantics as defined in the XML 1.0</em>.
@ -147,14 +146,17 @@ public abstract class SchemaFactory {
* is looked for. If present, the value is processed just like above.
* </li>
* <li>
* <p>The class loader is asked for service provider provider-configuration files matching
* <code>javax.xml.validation.SchemaFactory</code> in the resource directory META-INF/services.
* See the JAR File Specification for file format and parsing rules.
* Each potential service provider is required to implement the method:</p>
* <pre>
* {@link #isSchemaLanguageSupported(String schemaLanguage)}
* </pre>
* The first service provider found in class loader order that supports the specified schema language is returned.
* Use the service-provider loading facilities, defined by the
* {@link java.util.ServiceLoader} class, to attempt to locate and load an
* implementation of the service.<br>
* Each potential service provider is required to implement the method
* {@link #isSchemaLanguageSupported(String schemaLanguage)}.
* <br>
* The first service provider found that supports the specified schema
* language is returned.
* <br>
* In case of {@link java.util.ServiceConfigurationError} a
* {@link SchemaFactoryConfigurationError} will be thrown.
* </li>
* <li>
* Platform default <code>SchemaFactory</code> is located
@ -186,10 +188,12 @@ public abstract class SchemaFactory {
* If no implementation of the schema language is available.
* @throws NullPointerException
* If the <code>schemaLanguage</code> parameter is null.
* @throws SchemaFactoryConfigurationError
* If a configuration error is encountered.
*
* @see #newInstance(String schemaLanguage, String factoryClassName, ClassLoader classLoader)
*/
public static final SchemaFactory newInstance(String schemaLanguage) {
public static SchemaFactory newInstance(String schemaLanguage) {
ClassLoader cl;
cl = ss.getContextClassLoader();
@ -275,19 +279,19 @@ public abstract class SchemaFactory {
}
/**
* <p>Is specified schema supported by this <code>SchemaFactory</code>?</p>
*
* @param schemaLanguage Specifies the schema language which the returned <code>SchemaFactory</code> will understand.
/**
* <p>Is specified schema supported by this <code>SchemaFactory</code>?</p>
*
* @param schemaLanguage Specifies the schema language which the returned <code>SchemaFactory</code> will understand.
* <code>schemaLanguage</code> must specify a <a href="#schemaLanguage">valid</a> schema language.
*
* @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>.
*
* @throws NullPointerException If <code>schemaLanguage</code> is <code>null</code>.
* @throws IllegalArgumentException If <code>schemaLanguage.length() == 0</code>
* or <code>schemaLanguage</code> does not specify a <a href="#schemaLanguage">valid</a> schema language.
*/
public abstract boolean isSchemaLanguageSupported(String schemaLanguage);
*
* @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>.
*
* @throws NullPointerException If <code>schemaLanguage</code> is <code>null</code>.
* @throws IllegalArgumentException If <code>schemaLanguage.length() == 0</code>
* or <code>schemaLanguage</code> does not specify a <a href="#schemaLanguage">valid</a> schema language.
*/
public abstract boolean isSchemaLanguageSupported(String schemaLanguage);
/**
* Look up the value of a feature flag.

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.xml.validation;
/**
* Thrown when a problem with configuration with the Schema Factories
* exists. This error will typically be thrown when the class of a
* schema factory specified in the system properties cannot be found
* or instantiated.
* @since 1.8
*/
public final class SchemaFactoryConfigurationError extends Error {
static final long serialVersionUID = 3531438703147750126L;
/**
* Create a new <code>SchemaFactoryConfigurationError</code> with no
* detail message.
*/
public SchemaFactoryConfigurationError() {
}
/**
* Create a new <code>SchemaFactoryConfigurationError</code> with
* the <code>String</code> specified as an error message.
*
* @param message The error message for the exception.
*/
public SchemaFactoryConfigurationError(String message) {
super(message);
}
/**
* Create a new <code>SchemaFactoryConfigurationError</code> with the
* given <code>Throwable</code> base cause.
*
* @param cause The exception or error to be encapsulated in a
* SchemaFactoryConfigurationError.
*/
public SchemaFactoryConfigurationError(Throwable cause) {
super(cause);
}
/**
* Create a new <code>SchemaFactoryConfigurationError</code> with the
* given <code>Throwable</code> base cause and detail message.
*
* @param cause The exception or error to be encapsulated in a
* SchemaFactoryConfigurationError.
* @param message The detail message.
*/
public SchemaFactoryConfigurationError(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,19 +25,16 @@
package javax.xml.validation;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Properties;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
/**
* Implementation of {@link SchemaFactory#newInstance(String)}.
@ -53,17 +50,17 @@ class SchemaFactoryFinder {
/**
*<p> Take care of restrictions imposed by java security model </p>
*/
private static SecuritySupport ss = new SecuritySupport();
private static final SecuritySupport ss = new SecuritySupport();
private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal";
/**
* <p>Cache properties for performance.</p>
*/
private static Properties cacheProps = new Properties();
private static final Properties cacheProps = new Properties();
/**
* <p>First time requires initialization overhead.</p>
*/
private static volatile boolean firstTime = true;
/**
* <p>First time requires initialization overhead.</p>
*/
private static volatile boolean firstTime = true;
static {
// Use try/catch block to support applets
@ -115,7 +112,7 @@ class SchemaFactoryFinder {
return;
}
} catch( Throwable unused ) {
; // getContextClassLoader() undefined in JDK1.1
// getContextClassLoader() undefined in JDK1.1
}
if( classLoader==ClassLoader.getSystemClassLoader() ) {
@ -138,9 +135,13 @@ class SchemaFactoryFinder {
*
* @throws NullPointerException
* If the <code>schemaLanguage</code> parameter is null.
* @throws SchemaFactoryConfigurationError
* If a configuration error is encountered.
*/
public SchemaFactory newFactory(String schemaLanguage) {
if(schemaLanguage==null) throw new NullPointerException();
if(schemaLanguage==null) {
throw new NullPointerException();
}
SchemaFactory f = _newFactory(schemaLanguage);
if (f != null) {
debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage);
@ -183,7 +184,6 @@ class SchemaFactoryFinder {
String configFile = javah + File.separator +
"lib" + File.separator + "jaxp.properties";
String factoryClassName = null ;
// try to read from $java.home/lib/jaxp.properties
try {
@ -199,7 +199,7 @@ class SchemaFactoryFinder {
}
}
}
factoryClassName = cacheProps.getProperty(propertyName);
final String factoryClassName = cacheProps.getProperty(propertyName);
debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
if (factoryClassName != null) {
@ -214,21 +214,15 @@ class SchemaFactoryFinder {
}
}
// try META-INF/services files
Iterator sitr = createServiceFileIterator();
while(sitr.hasNext()) {
URL resource = (URL)sitr.next();
debugPrintln("looking into " + resource);
try {
sf = loadFromService(schemaLanguage,resource.toExternalForm(),
ss.getURLInputStream(resource));
if(sf!=null) return sf;
} catch(IOException e) {
if( debug ) {
debugPrintln("failed to read "+resource);
e.printStackTrace();
}
}
// Try with ServiceLoader
final SchemaFactory factoryImpl = findServiceProvider(schemaLanguage);
// The following assertion should always be true.
// Uncomment it, recompile, and run with -ea in case of doubts:
// assert factoryImpl == null || factoryImpl.isSchemaLanguageSupported(schemaLanguage);
if (factoryImpl != null) {
return factoryImpl;
}
// platform default
@ -246,8 +240,8 @@ class SchemaFactoryFinder {
* @param className Name of class to create.
* @return Created class or <code>null</code>.
*/
private Class createClass(String className) {
Class clazz;
private Class<?> createClass(String className) {
Class<?> clazz;
// make sure we have access to restricted packages
boolean internal = false;
if (System.getSecurityManager() != null) {
@ -256,25 +250,27 @@ class SchemaFactoryFinder {
}
}
try {
if (classLoader != null && !internal) {
clazz = classLoader.loadClass(className);
} else {
clazz = Class.forName(className);
}
} catch (Throwable t) {
if(debug) t.printStackTrace();
return null;
try {
if (classLoader != null && !internal) {
clazz = Class.forName(className, false, classLoader);
} else {
clazz = Class.forName(className);
}
} catch (Throwable t) {
if(debug) {
t.printStackTrace();
}
return null;
}
return clazz;
return clazz;
}
/**
* <p>Creates an instance of the specified and returns it.</p>
*
* @param className
* fully qualified class name to be instanciated.
* fully qualified class name to be instantiated.
*
* @return null
* if it fails. Error messages will be printed by this method.
@ -289,7 +285,7 @@ class SchemaFactoryFinder {
debugPrintln("createInstance(" + className + ")");
// get Class from className
Class clazz = createClass(className);
Class<?> clazz = createClass(className);
if (clazz == null) {
debugPrintln("failed to getClass(" + className + ")");
return null;
@ -298,9 +294,13 @@ class SchemaFactoryFinder {
// instantiate Class as a SchemaFactory
try {
if (!useServicesMechanism) {
schemaFactory = (SchemaFactory) newInstanceNoServiceLoader(clazz);
}
if (!SchemaFactory.class.isAssignableFrom(clazz)) {
throw new ClassCastException(clazz.getName()
+ " cannot be cast to " + SchemaFactory.class);
}
if (!useServicesMechanism) {
schemaFactory = newInstanceNoServiceLoader(clazz);
}
if (schemaFactory == null) {
schemaFactory = (SchemaFactory) clazz.newInstance();
}
@ -326,11 +326,12 @@ class SchemaFactoryFinder {
return schemaFactory;
}
/**
* Try to construct using newTransformerFactoryNoServiceLoader
* Try to construct using newXMLSchemaFactoryNoServiceLoader
* method if available.
*/
private static Object newInstanceNoServiceLoader(
private static SchemaFactory newInstanceNoServiceLoader(
Class<?> providerClass
) {
// Retain maximum compatibility if no security manager.
@ -338,196 +339,87 @@ class SchemaFactoryFinder {
return null;
}
try {
Method creationMethod =
final Method creationMethod =
providerClass.getDeclaredMethod(
"newXMLSchemaFactoryNoServiceLoader"
);
return creationMethod.invoke(null, (Object[])null);
} catch (NoSuchMethodException exc) {
final int modifiers = creationMethod.getModifiers();
// Do not call the method if it's not public static.
if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
return null;
} catch (Exception exc) {
return null;
}
}
}
/** Iterator that lazily computes one value and returns it. */
private static abstract class SingleIterator implements Iterator {
private boolean seen = false;
public final void remove() { throw new UnsupportedOperationException(); }
public final boolean hasNext() { return !seen; }
public final Object next() {
if(seen) throw new NoSuchElementException();
seen = true;
return value();
}
protected abstract Object value();
}
/**
* Looks up a value in a property file
* while producing all sorts of debug messages.
*
* @return null
* if there was an error.
*/
private SchemaFactory loadFromProperty( String keyName, String resourceName, InputStream in )
throws IOException {
debugPrintln("Reading "+resourceName );
Properties props=new Properties();
props.load(in);
in.close();
String factoryClassName = props.getProperty(keyName);
if(factoryClassName != null){
debugPrintln("found "+keyName+" = " + factoryClassName);
return createInstance(factoryClassName);
} else {
debugPrintln(keyName+" is not in the property file");
// Only calls "newXMLSchemaFactoryNoServiceLoader" if it's
// declared to return an instance of SchemaFactory.
final Class<?> returnType = creationMethod.getReturnType();
if (SERVICE_CLASS.isAssignableFrom(returnType)) {
return SERVICE_CLASS.cast(creationMethod.invoke(null, (Object[])null));
} else {
// Should not happen since
// XMLSchemaFactory.newXMLSchemaFactoryNoServiceLoader is
// declared to return XMLSchemaFactory.
throw new ClassCastException(returnType
+ " cannot be cast to " + SERVICE_CLASS);
}
} catch(ClassCastException e) {
throw new SchemaFactoryConfigurationError(e.getMessage(), e);
} catch (NoSuchMethodException exc) {
return null;
} catch (Exception exc) {
return null;
}
}
/**
* <p>Look up a value in a property file.</p>
*
* <p>Set <code>debug</code> to <code>true</code> to trace property evaluation.</p>
*
* @param schemaLanguage Schema Language to support.
* @param inputName Name of <code>InputStream</code>.
* @param in <code>InputStream</code> of properties.
*
* @return <code>SchemaFactory</code> as determined by <code>keyName</code> value or <code>null</code> if there was an error.
*
* @throws IOException If IO error reading from <code>in</code>.
*/
private SchemaFactory loadFromService(
String schemaLanguage,
String inputName,
InputStream in)
throws IOException {
SchemaFactory schemaFactory = null;
final Class[] stringClassArray = {"".getClass()};
final Object[] schemaLanguageObjectArray = {schemaLanguage};
final String isSchemaLanguageSupportedMethod = "isSchemaLanguageSupported";
debugPrintln("Reading " + inputName);
// read from InputStream until a match is found
BufferedReader configFile = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = configFile.readLine()) != null) {
// '#' is comment char
int comment = line.indexOf("#");
switch (comment) {
case -1: break; // no comment
case 0: line = ""; break; // entire line is a comment
default: line = line.substring(0, comment); break; // trim comment
}
// trim whitespace
line = line.trim();
// any content left on line?
if (line.length() == 0) {
continue;
}
// line content is now the name of the class
Class clazz = createClass(line);
if (clazz == null) {
continue;
}
// create an instance of the Class
try {
schemaFactory = (SchemaFactory) clazz.newInstance();
} catch (ClassCastException classCastExcpetion) {
schemaFactory = null;
continue;
} catch (InstantiationException instantiationException) {
schemaFactory = null;
continue;
} catch (IllegalAccessException illegalAccessException) {
schemaFactory = null;
continue;
}
// does this Class support desired Schema?
try {
Method isSchemaLanguageSupported = clazz.getMethod(isSchemaLanguageSupportedMethod, stringClassArray);
Boolean supported = (Boolean) isSchemaLanguageSupported.invoke(schemaFactory, schemaLanguageObjectArray);
if (supported.booleanValue()) {
break;
}
} catch (NoSuchMethodException noSuchMethodException) {
} catch (IllegalAccessException illegalAccessException) {
} catch (InvocationTargetException invocationTargetException) {
}
schemaFactory = null;
// Call isSchemaLanguageSupported with initial context.
private boolean isSchemaLanguageSupportedBy(final SchemaFactory factory,
final String schemaLanguage,
AccessControlContext acc) {
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return factory.isSchemaLanguageSupported(schemaLanguage);
}
// clean up
configFile.close();
// return new instance of SchemaFactory or null
return schemaFactory;
}, acc);
}
/**
* Returns an {@link Iterator} that enumerates all
* the META-INF/services files that we care.
* Finds a service provider subclass of SchemaFactory that supports the
* given schema language using the ServiceLoader.
*
* @param schemaLanguage The schema language for which we seek a factory.
* @return A SchemaFactory supporting the specified schema language, or null
* if none is found.
* @throws SchemaFactoryConfigurationError if a configuration error is found.
*/
private Iterator createServiceFileIterator() {
if (classLoader == null) {
return new SingleIterator() {
protected Object value() {
ClassLoader classLoader = SchemaFactoryFinder.class.getClassLoader();
//return (ClassLoader.getSystemResource( SERVICE_ID ));
return ss.getResourceAsURL(classLoader, SERVICE_ID);
private SchemaFactory findServiceProvider(final String schemaLanguage) {
assert schemaLanguage != null;
// store current context.
final AccessControlContext acc = AccessController.getContext();
try {
return AccessController.doPrivileged(new PrivilegedAction<SchemaFactory>() {
public SchemaFactory run() {
final ServiceLoader<SchemaFactory> loader =
ServiceLoader.load(SERVICE_CLASS);
for (SchemaFactory factory : loader) {
// restore initial context to call
// factory.isSchemaLanguageSupported
if (isSchemaLanguageSupportedBy(factory, schemaLanguage, acc)) {
return factory;
}
}
return null; // no factory found.
}
};
} else {
try {
//final Enumeration e = classLoader.getResources(SERVICE_ID);
final Enumeration e = ss.getResources(classLoader, SERVICE_ID);
if(!e.hasMoreElements()) {
debugPrintln("no "+SERVICE_ID+" file was found");
}
// wrap it into an Iterator.
return new Iterator() {
public void remove() {
throw new UnsupportedOperationException();
}
public boolean hasNext() {
return e.hasMoreElements();
}
public Object next() {
return e.nextElement();
}
};
} catch (IOException e) {
debugPrintln("failed to enumerate resources "+SERVICE_ID);
if(debug) e.printStackTrace();
return new ArrayList().iterator(); // empty iterator
}
});
} catch (ServiceConfigurationError error) {
throw new SchemaFactoryConfigurationError(
"Provider for " + SERVICE_CLASS + " cannot be created", error);
}
}
private static final Class SERVICE_CLASS = SchemaFactory.class;
private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName();
private static final Class<SchemaFactory> SERVICE_CLASS = SchemaFactory.class;
private static String which( Class clazz ) {
private static String which( Class<?> clazz ) {
return which( clazz.getName(), clazz.getClassLoader() );
}

View File

@ -90,7 +90,7 @@ public abstract class XPathFactory {
* @throws RuntimeException When there is a failure in creating an
* <code>XPathFactory</code> for the default object model.
*/
public static final XPathFactory newInstance() {
public static XPathFactory newInstance() {
try {
return newInstance(DEFAULT_OBJECT_MODEL_URI);
@ -121,14 +121,17 @@ public abstract class XPathFactory {
* If present, the value is processed just like above.
* </li>
* <li>
* The class loader is asked for service provider provider-configuration files matching <code>javax.xml.xpath.XPathFactory</code>
* in the resource directory META-INF/services.
* See the JAR File Specification for file format and parsing rules.
* Each potential service provider is required to implement the method:
* <pre>
* {@link #isObjectModelSupported(String objectModel)}
* </pre>
* The first service provider found in class loader order that supports the specified object model is returned.
* Use the service-provider loading facilities, defined by the
* {@link java.util.ServiceLoader} class, to attempt to locate and load an
* implementation of the service.
* <br>
* Each potential service provider is required to implement the method
* {@link #isObjectModelSupported(String objectModel)}.
* The first service provider found that supports the specified object
* model is returned.
* <br>
* In case of {@link java.util.ServiceConfigurationError} an
* {@link XPathFactoryConfigurationException} will be thrown.
* </li>
* <li>
* Platform default <code>XPathFactory</code> is located in a platform specific way.
@ -152,43 +155,41 @@ public abstract class XPathFactory {
*
* @return Instance of an <code>XPathFactory</code>.
*
* @throws XPathFactoryConfigurationException If the specified object model is unavailable.
* @throws XPathFactoryConfigurationException If the specified object model
* is unavailable, or if there is a configuration error.
* @throws NullPointerException If <code>uri</code> is <code>null</code>.
* @throws IllegalArgumentException If <code>uri</code> is <code>null</code>
* @throws IllegalArgumentException If <code>uri</code> is <code>null</code>
* or <code>uri.length() == 0</code>.
*/
public static final XPathFactory newInstance(final String uri)
public static XPathFactory newInstance(final String uri)
throws XPathFactoryConfigurationException {
if (uri == null) {
throw new NullPointerException(
"XPathFactory#newInstance(String uri) cannot be called with uri == null"
);
throw new NullPointerException(
"XPathFactory#newInstance(String uri) cannot be called with uri == null");
}
if (uri.length() == 0) {
throw new IllegalArgumentException(
"XPathFactory#newInstance(String uri) cannot be called with uri == \"\""
);
}
if (uri.length() == 0) {
throw new IllegalArgumentException(
"XPathFactory#newInstance(String uri) cannot be called with uri == \"\"");
}
ClassLoader classLoader = ss.getContextClassLoader();
ClassLoader classLoader = ss.getContextClassLoader();
if (classLoader == null) {
//use the current class loader
classLoader = XPathFactory.class.getClassLoader();
}
XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).newFactory(uri);
XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).newFactory(uri);
if (xpathFactory == null) {
throw new XPathFactoryConfigurationException(
"No XPathFactory implementation found for the object model: "
+ uri
);
}
if (xpathFactory == null) {
throw new XPathFactoryConfigurationException(
"No XPathFactory implementation found for the object model: "
+ uri);
}
return xpathFactory;
return xpathFactory;
}
/**
@ -242,16 +243,14 @@ public abstract class XPathFactory {
ClassLoader cl = classLoader;
if (uri == null) {
throw new NullPointerException(
"XPathFactory#newInstance(String uri) cannot be called with uri == null"
);
throw new NullPointerException(
"XPathFactory#newInstance(String uri) cannot be called with uri == null");
}
if (uri.length() == 0) {
throw new IllegalArgumentException(
"XPathFactory#newInstance(String uri) cannot be called with uri == \"\""
);
}
if (uri.length() == 0) {
throw new IllegalArgumentException(
"XPathFactory#newInstance(String uri) cannot be called with uri == \"\"");
}
if (cl == null) {
cl = ss.getContextClassLoader();
@ -260,31 +259,32 @@ public abstract class XPathFactory {
XPathFactory f = new XPathFactoryFinder(cl).createInstance(factoryClassName);
if (f == null) {
throw new XPathFactoryConfigurationException(
"No XPathFactory implementation found for the object model: "
+ uri
);
throw new XPathFactoryConfigurationException(
"No XPathFactory implementation found for the object model: "
+ uri);
}
//if this factory supports the given schemalanguage return this factory else thrown exception
if(f.isObjectModelSupported(uri)){
if (f.isObjectModelSupported(uri)) {
return f;
}else{
throw new XPathFactoryConfigurationException("Factory " + factoryClassName + " doesn't support given " + uri + " object model");
} else {
throw new XPathFactoryConfigurationException("Factory "
+ factoryClassName + " doesn't support given " + uri
+ " object model");
}
}
/**
* <p>Is specified object model supported by this <code>XPathFactory</code>?</p>
*
* @param objectModel Specifies the object model which the returned <code>XPathFactory</code> will understand.
*
* @return <code>true</code> if <code>XPathFactory</code> supports <code>objectModel</code>, else <code>false</code>.
*
* @throws NullPointerException If <code>objectModel</code> is <code>null</code>.
* @throws IllegalArgumentException If <code>objectModel.length() == 0</code>.
*/
public abstract boolean isObjectModelSupported(String objectModel);
/**
* <p>Is specified object model supported by this <code>XPathFactory</code>?</p>
*
* @param objectModel Specifies the object model which the returned <code>XPathFactory</code> will understand.
*
* @return <code>true</code> if <code>XPathFactory</code> supports <code>objectModel</code>, else <code>false</code>.
*
* @throws NullPointerException If <code>objectModel</code> is <code>null</code>.
* @throws IllegalArgumentException If <code>objectModel.length() == 0</code>.
*/
public abstract boolean isObjectModelSupported(String objectModel);
/**
* <p>Set a feature for this <code>XPathFactory</code> and
@ -314,8 +314,8 @@ public abstract class XPathFactory {
* it creates cannot support this feature.
* @throws NullPointerException if <code>name</code> is <code>null</code>.
*/
public abstract void setFeature(String name, boolean value)
throws XPathFactoryConfigurationException;
public abstract void setFeature(String name, boolean value)
throws XPathFactoryConfigurationException;
/**
* <p>Get the state of the named feature.</p>
@ -339,8 +339,8 @@ public abstract class XPathFactory {
* it creates cannot support this feature.
* @throws NullPointerException if <code>name</code> is <code>null</code>.
*/
public abstract boolean getFeature(String name)
throws XPathFactoryConfigurationException;
public abstract boolean getFeature(String name)
throws XPathFactoryConfigurationException;
/**
* <p>Establish a default variable resolver.</p>
@ -359,19 +359,19 @@ public abstract class XPathFactory {
public abstract void setXPathVariableResolver(XPathVariableResolver resolver);
/**
* <p>Establish a default function resolver.</p>
*
* <p>Any <code>XPath</code> objects constructed from this factory will
* use the specified resolver by default.</p>
*
* <p>A <code>NullPointerException</code> is thrown if
* <code>resolver</code> is <code>null</code>.</p>
*
* @param resolver XPath function resolver.
*
* @throws NullPointerException If <code>resolver</code> is
* <code>null</code>.
*/
* <p>Establish a default function resolver.</p>
*
* <p>Any <code>XPath</code> objects constructed from this factory will
* use the specified resolver by default.</p>
*
* <p>A <code>NullPointerException</code> is thrown if
* <code>resolver</code> is <code>null</code>.</p>
*
* @param resolver XPath function resolver.
*
* @throws NullPointerException If <code>resolver</code> is
* <code>null</code>.
*/
public abstract void setXPathFunctionResolver(XPathFunctionResolver resolver);
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,20 +25,16 @@
package javax.xml.xpath;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Properties;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
/**
* Implementation of {@link XPathFactory#newInstance(String)}.
@ -50,7 +46,7 @@ import java.util.Properties;
class XPathFactoryFinder {
private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xpath.internal";
private static SecuritySupport ss = new SecuritySupport() ;
private static final SecuritySupport ss = new SecuritySupport() ;
/** debug support code. */
private static boolean debug = false;
static {
@ -65,12 +61,12 @@ class XPathFactoryFinder {
/**
* <p>Cache properties for performance.</p>
*/
private static Properties cacheProps = new Properties();
private static final Properties cacheProps = new Properties();
/**
* <p>First time requires initialization overhead.</p>
*/
private volatile static boolean firstTime = true;
/**
* <p>First time requires initialization overhead.</p>
*/
private volatile static boolean firstTime = true;
/**
* <p>Conditional debug printing.</p>
@ -93,9 +89,8 @@ class XPathFactoryFinder {
* to find <code>XPathFactory</code>.</p>
*
* @param loader
* to be used to load resource, {@link XPathFactory}, and
* {@link SchemaFactoryLoader} implementations during
* the resolution process.
* to be used to load resource and {@link XPathFactory}
* implementations during the resolution process.
* If this parameter is null, the default system class loader
* will be used.
*/
@ -113,7 +108,7 @@ class XPathFactoryFinder {
return;
}
} catch( Throwable unused ) {
; // getContextClassLoader() undefined in JDK1.1
// getContextClassLoader() undefined in JDK1.1
}
if( classLoader==ClassLoader.getSystemClassLoader() ) {
@ -126,7 +121,7 @@ class XPathFactoryFinder {
/**
* <p>Creates a new {@link XPathFactory} object for the specified
* schema language.</p>
* object model.</p>
*
* @param uri
* Identifies the underlying object model.
@ -136,8 +131,10 @@ class XPathFactoryFinder {
* @throws NullPointerException
* If the parameter is null.
*/
public XPathFactory newFactory(String uri) {
if(uri==null) throw new NullPointerException();
public XPathFactory newFactory(String uri) throws XPathFactoryConfigurationException {
if (uri == null) {
throw new NullPointerException();
}
XPathFactory f = _newFactory(uri);
if (f != null) {
debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri);
@ -154,8 +151,8 @@ class XPathFactoryFinder {
*
* @return {@link XPathFactory} for the given object model.
*/
private XPathFactory _newFactory(String uri) {
XPathFactory xpathFactory;
private XPathFactory _newFactory(String uri) throws XPathFactoryConfigurationException {
XPathFactory xpathFactory = null;
String propertyName = SERVICE_CLASS.getName() + ":" + uri;
@ -166,7 +163,9 @@ class XPathFactoryFinder {
if(r!=null) {
debugPrintln("The value is '"+r+"'");
xpathFactory = createInstance(r, true);
if(xpathFactory != null) return xpathFactory;
if (xpathFactory != null) {
return xpathFactory;
}
} else
debugPrintln("The property is undefined.");
} catch( Throwable t ) {
@ -180,8 +179,6 @@ class XPathFactoryFinder {
String configFile = javah + File.separator +
"lib" + File.separator + "jaxp.properties";
String factoryClassName = null ;
// try to read from $java.home/lib/jaxp.properties
try {
if(firstTime){
@ -196,7 +193,7 @@ class XPathFactoryFinder {
}
}
}
factoryClassName = cacheProps.getProperty(propertyName);
final String factoryClassName = cacheProps.getProperty(propertyName);
debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
if (factoryClassName != null) {
@ -211,23 +208,16 @@ class XPathFactoryFinder {
}
}
// try META-INF/services files
Iterator sitr = createServiceFileIterator();
while(sitr.hasNext()) {
URL resource = (URL)sitr.next();
debugPrintln("looking into " + resource);
try {
xpathFactory = loadFromService(uri, resource.toExternalForm(),
ss.getURLInputStream(resource));
if (xpathFactory != null) {
return xpathFactory;
}
} catch(IOException e) {
if( debug ) {
debugPrintln("failed to read "+resource);
e.printStackTrace();
}
}
// Try with ServiceLoader
assert xpathFactory == null;
xpathFactory = findServiceProvider(uri);
// The following assertion should always be true.
// Uncomment it, recompile, and run with -ea in case of doubts:
// assert xpathFactory == null || xpathFactory.isObjectModelSupported(uri);
if (xpathFactory != null) {
return xpathFactory;
}
// platform default
@ -245,8 +235,8 @@ class XPathFactoryFinder {
* @param className Name of class to create.
* @return Created class or <code>null</code>.
*/
private Class createClass(String className) {
Class clazz;
private Class<?> createClass(String className) {
Class clazz;
// make sure we have access to restricted packages
boolean internal = false;
if (System.getSecurityManager() != null) {
@ -258,47 +248,54 @@ class XPathFactoryFinder {
// use approprite ClassLoader
try {
if (classLoader != null && !internal) {
clazz = classLoader.loadClass(className);
clazz = Class.forName(className, false, classLoader);
} else {
clazz = Class.forName(className);
}
} catch (Throwable t) {
if(debug) t.printStackTrace();
return null;
if(debug) {
t.printStackTrace();
}
return null;
}
return clazz;
return clazz;
}
/**
* <p>Creates an instance of the specified and returns it.</p>
*
* @param className
* fully qualified class name to be instanciated.
* fully qualified class name to be instantiated.
*
* @return null
* if it fails. Error messages will be printed by this method.
*/
XPathFactory createInstance( String className ) {
XPathFactory createInstance( String className )
throws XPathFactoryConfigurationException
{
return createInstance( className, false );
}
XPathFactory createInstance( String className, boolean useServicesMechanism ) {
XPathFactory createInstance( String className, boolean useServicesMechanism )
throws XPathFactoryConfigurationException
{
XPathFactory xPathFactory = null;
debugPrintln("createInstance(" + className + ")");
// get Class from className
Class clazz = createClass(className);
Class<?> clazz = createClass(className);
if (clazz == null) {
debugPrintln("failed to getClass(" + className + ")");
return null;
debugPrintln("failed to getClass(" + className + ")");
return null;
}
debugPrintln("loaded " + className + " from " + which(clazz));
// instantiate Class as a XPathFactory
try {
if (!useServicesMechanism) {
xPathFactory = (XPathFactory) newInstanceNoServiceLoader(clazz);
xPathFactory = newInstanceNoServiceLoader(clazz);
}
if (xPathFactory == null) {
xPathFactory = (XPathFactory) clazz.newInstance();
@ -329,203 +326,94 @@ class XPathFactoryFinder {
* Try to construct using newXPathFactoryNoServiceLoader
* method if available.
*/
private static Object newInstanceNoServiceLoader(
private static XPathFactory newInstanceNoServiceLoader(
Class<?> providerClass
) {
) throws XPathFactoryConfigurationException {
// Retain maximum compatibility if no security manager.
if (System.getSecurityManager() == null) {
return null;
}
try {
Method creationMethod =
providerClass.getDeclaredMethod(
"newXPathFactoryNoServiceLoader"
);
return creationMethod.invoke(null, (Object[])null);
} catch (NoSuchMethodException exc) {
providerClass.getDeclaredMethod(
"newXPathFactoryNoServiceLoader"
);
final int modifiers = creationMethod.getModifiers();
// Do not call "newXPathFactoryNoServiceLoader" if it's
// not public static.
if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
return null;
} catch (Exception exc) {
return null;
}
}
/**
* <p>Look up a value in a property file.</p>
*
* <p>Set <code>debug</code> to <code>true</code> to trace property evaluation.</p>
*
* @param objectModel URI of object model to support.
* @param inputName Name of <code>InputStream</code>.
* @param in <code>InputStream</code> of properties.
*
* @return <code>XPathFactory</code> as determined by <code>keyName</code> value or <code>null</code> if there was an error.
*
* @throws IOException If IO error reading from <code>in</code>.
*/
private XPathFactory loadFromService(
String objectModel,
String inputName,
InputStream in)
throws IOException {
XPathFactory xPathFactory = null;
final Class[] stringClassArray = {"".getClass()};
final Object[] objectModelObjectArray = {objectModel};
final String isObjectModelSupportedMethod = "isObjectModelSupported";
debugPrintln("Reading " + inputName);
// read from InputStream until a match is found
BufferedReader configFile = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = configFile.readLine()) != null) {
// '#' is comment char
int comment = line.indexOf("#");
switch (comment) {
case -1: break; // no comment
case 0: line = ""; break; // entire line is a comment
default: line = line.substring(0, comment); break; // trim comment
}
// trim whitespace
line = line.trim();
// any content left on line?
if (line.length() == 0) {
continue;
}
// line content is now the name of the class
Class clazz = createClass(line);
if (clazz == null) {
continue;
}
// create an instance of the Class
try {
xPathFactory = (XPathFactory) clazz.newInstance();
} catch (ClassCastException classCastExcpetion) {
xPathFactory = null;
continue;
} catch (InstantiationException instantiationException) {
xPathFactory = null;
continue;
} catch (IllegalAccessException illegalAccessException) {
xPathFactory = null;
continue;
}
// does this Class support desired object model?
try {
Method isObjectModelSupported = clazz.getMethod(isObjectModelSupportedMethod, stringClassArray);
Boolean supported = (Boolean) isObjectModelSupported.invoke(xPathFactory, objectModelObjectArray);
if (supported.booleanValue()) {
break;
}
} catch (NoSuchMethodException noSuchMethodException) {
} catch (IllegalAccessException illegalAccessException) {
} catch (InvocationTargetException invocationTargetException) {
}
xPathFactory = null;
}
// clean up
configFile.close();
// return new instance of XPathFactory or null
return xPathFactory;
}
/** Iterator that lazily computes one value and returns it. */
private static abstract class SingleIterator implements Iterator {
private boolean seen = false;
public final void remove() { throw new UnsupportedOperationException(); }
public final boolean hasNext() { return !seen; }
public final Object next() {
if(seen) throw new NoSuchElementException();
seen = true;
return value();
}
protected abstract Object value();
}
/**
* Looks up a value in a property file
* while producing all sorts of debug messages.
*
* @return null
* if there was an error.
*/
private XPathFactory loadFromProperty( String keyName, String resourceName, InputStream in )
throws IOException {
debugPrintln("Reading "+resourceName );
Properties props = new Properties();
props.load(in);
in.close();
String factoryClassName = props.getProperty(keyName);
if(factoryClassName != null){
debugPrintln("found "+keyName+" = " + factoryClassName);
return createInstance(factoryClassName, true);
} else {
debugPrintln(keyName+" is not in the property file");
// Only calls "newXPathFactoryNoServiceLoader" if it's
// declared to return an instance of XPathFactory.
final Class<?> returnType = creationMethod.getReturnType();
if (SERVICE_CLASS.isAssignableFrom(returnType)) {
return SERVICE_CLASS.cast(creationMethod.invoke(null, (Object[])null));
} else {
// Should not happen since
// XPathFactoryImpl.newXPathFactoryNoServiceLoader is
// declared to return XPathFactory.
throw new ClassCastException(returnType
+ " cannot be cast to " + SERVICE_CLASS);
}
} catch (ClassCastException e) {
throw new XPathFactoryConfigurationException(e);
} catch (NoSuchMethodException exc) {
return null;
} catch (Exception exc) {
return null;
}
}
// Call isObjectModelSupportedBy with initial context.
private boolean isObjectModelSupportedBy(final XPathFactory factory,
final String objectModel,
AccessControlContext acc) {
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return factory.isObjectModelSupported(objectModel);
}
}, acc);
}
/**
* Returns an {@link Iterator} that enumerates all
* the META-INF/services files that we care.
* Finds a service provider subclass of XPathFactory that supports the
* given object model using the ServiceLoader.
*
* @param objectModel URI of object model to support.
* @return An XPathFactory supporting the specified object model, or null
* if none is found.
* @throws XPathFactoryConfigurationException if a configuration error is found.
*/
private Iterator createServiceFileIterator() {
if (classLoader == null) {
return new SingleIterator() {
protected Object value() {
ClassLoader classLoader = XPathFactoryFinder.class.getClassLoader();
return ss.getResourceAsURL(classLoader, SERVICE_ID);
//return (ClassLoader.getSystemResource( SERVICE_ID ));
private XPathFactory findServiceProvider(final String objectModel)
throws XPathFactoryConfigurationException {
assert objectModel != null;
// store current context.
final AccessControlContext acc = AccessController.getContext();
try {
return AccessController.doPrivileged(new PrivilegedAction<XPathFactory>() {
public XPathFactory run() {
final ServiceLoader<XPathFactory> loader =
ServiceLoader.load(SERVICE_CLASS);
for (XPathFactory factory : loader) {
// restore initial context to call
// factory.isObjectModelSupportedBy
if (isObjectModelSupportedBy(factory, objectModel, acc)) {
return factory;
}
}
return null; // no factory found.
}
};
} else {
try {
//final Enumeration e = classLoader.getResources(SERVICE_ID);
final Enumeration e = ss.getResources(classLoader, SERVICE_ID);
if(!e.hasMoreElements()) {
debugPrintln("no "+SERVICE_ID+" file was found");
}
// wrap it into an Iterator.
return new Iterator() {
public void remove() {
throw new UnsupportedOperationException();
}
public boolean hasNext() {
return e.hasMoreElements();
}
public Object next() {
return e.nextElement();
}
};
} catch (IOException e) {
debugPrintln("failed to enumerate resources "+SERVICE_ID);
if(debug) e.printStackTrace();
return new ArrayList().iterator(); // empty iterator
}
});
} catch (ServiceConfigurationError error) {
throw new XPathFactoryConfigurationException(error);
}
}
private static final Class SERVICE_CLASS = XPathFactory.class;
private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName();
private static final Class<XPathFactory> SERVICE_CLASS = XPathFactory.class;
private static String which( Class clazz ) {
return which( clazz.getName(), clazz.getClassLoader() );