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:
parent
b10f2efea3
commit
9a94591b8e
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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. 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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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() );
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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() );
|
||||
|
Loading…
Reference in New Issue
Block a user