|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package javax.xml.validation; |
|
|
|
import com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory; |
|
import java.io.File; |
|
import java.lang.reflect.InvocationTargetException; |
|
import java.lang.reflect.Method; |
|
import java.lang.reflect.Modifier; |
|
import java.security.AccessControlContext; |
|
import java.security.AccessController; |
|
import java.security.PrivilegedAction; |
|
import java.util.Properties; |
|
import java.util.ServiceConfigurationError; |
|
import java.util.ServiceLoader; |
|
import java.util.function.Supplier; |
|
import jdk.xml.internal.SecuritySupport; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
class SchemaFactoryFinder { |
|
|
|
|
|
private static boolean debug = false; |
|
|
|
private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal"; |
|
|
|
|
|
*/ |
|
private static final Properties cacheProps = new Properties(); |
|
|
|
|
|
|
|
*/ |
|
private static volatile boolean firstTime = true; |
|
|
|
static { |
|
|
|
try { |
|
debug = SecuritySupport.getSystemProperty("jaxp.debug") != null; |
|
} catch (Exception unused) { |
|
debug = false; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static void debugPrintln(Supplier<String> msgGen) { |
|
if (debug) { |
|
System.err.println("JAXP: " + msgGen.get()); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private final ClassLoader classLoader; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public SchemaFactoryFinder(ClassLoader loader) { |
|
this.classLoader = loader; |
|
if( debug ) { |
|
debugDisplayClassLoader(); |
|
} |
|
} |
|
|
|
private void debugDisplayClassLoader() { |
|
try { |
|
if( classLoader == SecuritySupport.getContextClassLoader() ) { |
|
debugPrintln(()->"using thread context class loader ("+classLoader+") for search"); |
|
return; |
|
} |
|
} catch( Throwable unused ) { |
|
// getContextClassLoader() undefined in JDK1.1 |
|
} |
|
|
|
if( classLoader==ClassLoader.getSystemClassLoader() ) { |
|
debugPrintln(()->"using system class loader ("+classLoader+") for search"); |
|
return; |
|
} |
|
|
|
debugPrintln(()->"using class loader ("+classLoader+") for search"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public SchemaFactory newFactory(String schemaLanguage) { |
|
if(schemaLanguage==null) { |
|
throw new NullPointerException(); |
|
} |
|
SchemaFactory f = _newFactory(schemaLanguage); |
|
if (f != null) { |
|
debugPrintln(()->"factory '" + f.getClass().getName() + "' was found for " + schemaLanguage); |
|
} else { |
|
debugPrintln(()->"unable to find a factory for " + schemaLanguage); |
|
} |
|
return f; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private SchemaFactory _newFactory(String schemaLanguage) { |
|
SchemaFactory sf; |
|
|
|
String propertyName = SERVICE_CLASS.getName() + ":" + schemaLanguage; |
|
|
|
|
|
try { |
|
debugPrintln(()->"Looking up system property '"+propertyName+"'" ); |
|
String r = SecuritySupport.getSystemProperty(propertyName); |
|
if(r!=null) { |
|
debugPrintln(()->"The value is '"+r+"'"); |
|
sf = createInstance(r); |
|
if(sf!=null) return sf; |
|
} else |
|
debugPrintln(()->"The property is undefined."); |
|
} catch( Throwable t ) { |
|
if( debug ) { |
|
debugPrintln(()->"failed to look up system property '"+propertyName+"'" ); |
|
t.printStackTrace(); |
|
} |
|
} |
|
|
|
String javah = SecuritySupport.getSystemProperty( "java.home" ); |
|
String configFile = javah + File.separator + |
|
"conf" + File.separator + "jaxp.properties"; |
|
|
|
|
|
|
|
try { |
|
if(firstTime){ |
|
synchronized(cacheProps){ |
|
if(firstTime){ |
|
File f=new File( configFile ); |
|
firstTime = false; |
|
if(SecuritySupport.doesFileExist(f)){ |
|
debugPrintln(()->"Read properties file " + f); |
|
cacheProps.load(SecuritySupport.getFileInputStream(f)); |
|
} |
|
} |
|
} |
|
} |
|
final String factoryClassName = cacheProps.getProperty(propertyName); |
|
debugPrintln(()->"found " + factoryClassName + " in $java.home/conf/jaxp.properties"); |
|
|
|
if (factoryClassName != null) { |
|
sf = createInstance(factoryClassName); |
|
if(sf != null){ |
|
return sf; |
|
} |
|
} |
|
} catch (Exception ex) { |
|
if (debug) { |
|
ex.printStackTrace(); |
|
} |
|
} |
|
|
|
|
|
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; |
|
} |
|
|
|
|
|
if(schemaLanguage.equals("http://www.w3.org/2001/XMLSchema")) { |
|
debugPrintln(()->"attempting to use the platform default XML Schema validator"); |
|
return new XMLSchemaFactory(); |
|
} |
|
|
|
debugPrintln(()->"all things were tried, but none was found. bailing out."); |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@SuppressWarnings("removal") |
|
private Class<?> createClass(String className) { |
|
Class<?> clazz; |
|
|
|
boolean internal = false; |
|
if (System.getSecurityManager() != null) { |
|
if (className != null && className.startsWith(DEFAULT_PACKAGE)) { |
|
internal = true; |
|
} |
|
} |
|
|
|
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; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
SchemaFactory createInstance(String className) { |
|
SchemaFactory schemaFactory = null; |
|
|
|
debugPrintln(()->"createInstance(" + className + ")"); |
|
|
|
|
|
Class<?> clazz = createClass(className); |
|
if (clazz == null) { |
|
debugPrintln(()->"failed to getClass(" + className + ")"); |
|
return null; |
|
} |
|
debugPrintln(()->"loaded " + className + " from " + which(clazz)); |
|
|
|
|
|
try { |
|
if (!SchemaFactory.class.isAssignableFrom(clazz)) { |
|
throw new ClassCastException(clazz.getName() |
|
+ " cannot be cast to " + SchemaFactory.class); |
|
} |
|
schemaFactory = (SchemaFactory) clazz.getConstructor().newInstance(); |
|
} catch (ClassCastException | IllegalAccessException | IllegalArgumentException | |
|
InstantiationException | InvocationTargetException | NoSuchMethodException | |
|
SecurityException ex) { |
|
debugPrintln(()->"could not instantiate " + clazz.getName()); |
|
if (debug) { |
|
ex.printStackTrace(); |
|
} |
|
return null; |
|
} |
|
|
|
return schemaFactory; |
|
} |
|
|
|
|
|
@SuppressWarnings("removal") |
|
private boolean isSchemaLanguageSupportedBy(final SchemaFactory factory, |
|
final String schemaLanguage, |
|
AccessControlContext acc) { |
|
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { |
|
public Boolean run() { |
|
return factory.isSchemaLanguageSupported(schemaLanguage); |
|
} |
|
}, acc); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@SuppressWarnings("removal") |
|
private SchemaFactory findServiceProvider(final String schemaLanguage) { |
|
assert schemaLanguage != null; |
|
|
|
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 |
|
|
|
if (isSchemaLanguageSupportedBy(factory, schemaLanguage, acc)) { |
|
return factory; |
|
} |
|
} |
|
return null; |
|
} |
|
}); |
|
} catch (ServiceConfigurationError error) { |
|
throw new SchemaFactoryConfigurationError( |
|
"Provider for " + SERVICE_CLASS + " cannot be created", error); |
|
} |
|
} |
|
|
|
private static final Class<SchemaFactory> SERVICE_CLASS = SchemaFactory.class; |
|
|
|
|
|
|
|
private static String which( Class<?> clazz ) { |
|
return SecuritySupport.getClassSource(clazz); |
|
} |
|
} |