src/javax/xml/xpath/XPathFactoryFinder.java
Print this page
@@ -23,51 +23,48 @@
* questions.
*/
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.Method;
import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
+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)}.
*
* @author <a href="Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
* @version $Revision: 1.7 $, $Date: 2010-11-01 04:36:14 $
* @since 1.5
*/
class XPathFactoryFinder {
- private static SecuritySupport ss = new SecuritySupport() ;
- /** debug support code. */
+ private static final String DEFAULT_IMPL_NAME = "com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl";
+ private static SecuritySupport ss = new SecuritySupport();
+ /**
+ * debug support code.
+ */
private static boolean debug = false;
+
static {
// Use try/catch block to support applets
try {
debug = ss.getSystemProperty("jaxp.debug") != null;
} catch (Exception _) {
debug = false;
}
}
-
/**
* <p>Cache properties for performance.</p>
*/
private static Properties cacheProps = new Properties();
-
/**
* <p>First time requires initialization overhead.</p>
*/
private volatile static boolean firstTime = true;
@@ -79,66 +76,65 @@
private static void debugPrintln(String msg) {
if (debug) {
System.err.println("JAXP: " + msg);
}
}
-
/**
- * <p><code>ClassLoader</code> to use to find <code>XPathFactory</code>.</p>
+ * <p><code>ClassLoader</code> to use to find
+ * <code>XPathFactory</code>.</p>
*/
private final ClassLoader classLoader;
/**
- * <p>Constructor that specifies <code>ClassLoader</code> to use
- * to find <code>XPathFactory</code>.</p>
- *
- * @param loader
- * to be used to load resource, {@link XPathFactory}, and
- * {@link SchemaFactoryLoader} implementations during
- * the resolution process.
- * If this parameter is null, the default system class loader
- * will be used.
+ * <p>Constructor that specifies
+ * <code>ClassLoader</code> to use to find
+ * <code>XPathFactory</code>.</p>
+ *
+ * @param loader to be used to load resource, {@link XPathFactory}, and
+ * {@link SchemaFactoryLoader} implementations during the resolution
+ * process. If this parameter is null, the default system class loader will
+ * be used.
*/
public XPathFactoryFinder(ClassLoader loader) {
this.classLoader = loader;
- if( debug ) {
+ if (debug) {
debugDisplayClassLoader();
}
}
private void debugDisplayClassLoader() {
try {
- if( classLoader == ss.getContextClassLoader() ) {
- debugPrintln("using thread context class loader ("+classLoader+") for search");
+ if (classLoader == ss.getContextClassLoader()) {
+ debugPrintln("using thread context class loader (" + classLoader + ") for search");
return;
}
- } catch( Throwable _ ) {
+ } catch (Throwable _) {
; // getContextClassLoader() undefined in JDK1.1
}
- if( classLoader==ClassLoader.getSystemClassLoader() ) {
- debugPrintln("using system class loader ("+classLoader+") for search");
+ if (classLoader == ClassLoader.getSystemClassLoader()) {
+ debugPrintln("using system class loader (" + classLoader + ") for search");
return;
}
- debugPrintln("using class loader ("+classLoader+") for search");
+ debugPrintln("using class loader (" + classLoader + ") for search");
}
/**
- * <p>Creates a new {@link XPathFactory} object for the specified
- * schema language.</p>
+ * <p>Creates a new {@link XPathFactory} object for the specified schema
+ * language.</p>
*
- * @param uri
- * Identifies the underlying object model.
+ * @param uri Identifies the underlying object model.
*
* @return <code>null</code> if the callee fails to create one.
*
- * @throws NullPointerException
- * If the parameter is null.
+ * @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);
} else {
debugPrintln("unable to find a factory for " + uri);
@@ -151,46 +147,49 @@
*
* @param uri identifies the object model.
*
* @return {@link XPathFactory} for the given object model.
*/
- private XPathFactory _newFactory(String uri) {
+ private XPathFactory _newFactory(String uri) throws XPathFactoryConfigurationException {
XPathFactory xpathFactory;
String propertyName = SERVICE_CLASS.getName() + ":" + uri;
// system property look up
try {
- debugPrintln("Looking up system property '"+propertyName+"'" );
+ debugPrintln("Looking up system property '" + propertyName + "'");
String r = ss.getSystemProperty(propertyName);
- if(r!=null) {
- debugPrintln("The value is '"+r+"'");
+ if (r != null) {
+ debugPrintln("The value is '" + r + "'");
xpathFactory = createInstance(r, true);
- if(xpathFactory != null) return xpathFactory;
- } else
+ if (xpathFactory != null) {
+ return xpathFactory;
+ }
+ } else {
debugPrintln("The property is undefined.");
- } catch( Throwable t ) {
- if( debug ) {
- debugPrintln("failed to look up system property '"+propertyName+"'" );
+ }
+ } catch (Throwable t) {
+ if (debug) {
+ debugPrintln("failed to look up system property '" + propertyName + "'");
t.printStackTrace();
}
}
- String javah = ss.getSystemProperty( "java.home" );
- String configFile = javah + File.separator +
- "lib" + File.separator + "jaxp.properties";
+ String javah = ss.getSystemProperty("java.home");
+ String configFile = javah + File.separator
+ + "lib" + File.separator + "jaxp.properties";
- String factoryClassName = null ;
+ String factoryClassName = null;
// try to read from $java.home/lib/jaxp.properties
try {
- if(firstTime){
- synchronized(cacheProps){
- if(firstTime){
- File f=new File( configFile );
+ if (firstTime) {
+ synchronized (cacheProps) {
+ if (firstTime) {
+ File f = new File(configFile);
firstTime = false;
- if(ss.doesFileExist(f)){
+ if (ss.doesFileExist(f)) {
debugPrintln("Read properties file " + f);
cacheProps.load(ss.getFileInputStream(f));
}
}
}
@@ -198,50 +197,38 @@
factoryClassName = cacheProps.getProperty(propertyName);
debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
if (factoryClassName != null) {
xpathFactory = createInstance(factoryClassName, true);
- if(xpathFactory != null){
+ if (xpathFactory != null) {
return xpathFactory;
}
}
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
}
}
- // 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));
+ // try finding a service provider
+ xpathFactory = findServiceProvider(uri, DEFAULT_IMPL_NAME);
if (xpathFactory != null) {
return xpathFactory;
}
- } catch(IOException e) {
- if( debug ) {
- debugPrintln("failed to read "+resource);
- e.printStackTrace();
- }
- }
- }
// platform default
- if(uri.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) {
+ if (uri.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) {
debugPrintln("attempting to use the platform default W3C DOM XPath lib");
- return createInstance("com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", true);
+ return createInstance(DEFAULT_IMPL_NAME, true);
}
debugPrintln("all things were tried, but none was found. bailing out.");
return null;
}
- /** <p>Create class using appropriate ClassLoader.</p>
+ /**
+ * <p>Create class using appropriate ClassLoader.</p>
*
* @param className Name of class to create.
* @return Created class or <code>null</code>.
*/
private Class createClass(String className) {
@@ -253,30 +240,31 @@
clazz = classLoader.loadClass(className);
} else {
clazz = Class.forName(className);
}
} catch (Throwable t) {
- if(debug) t.printStackTrace();
+ if (debug) {
+ t.printStackTrace();
+ }
return null;
}
return clazz;
}
/**
* <p>Creates an instance of the specified and returns it.</p>
*
- * @param className
- * fully qualified class name to be instanciated.
+ * @param className fully qualified class name to be instanciated.
*
- * @return null
- * if it fails. Error messages will be printed by this method.
+ * @return null if it fails. Error messages will be printed by this method.
*/
- XPathFactory createInstance( String className ) {
- return createInstance( className, false );
+ XPathFactory createInstance(String className) {
+ return createInstance(className, false);
}
- XPathFactory createInstance( String className, boolean useServicesMechanism ) {
+
+ XPathFactory createInstance(String className, boolean useServicesMechanism) {
XPathFactory xPathFactory = null;
debugPrintln("createInstance(" + className + ")");
// get Class from className
@@ -315,214 +303,95 @@
return null;
}
return xPathFactory;
}
+
/**
- * Try to construct using newXPathFactoryNoServiceLoader
- * method if available.
+ * Try to construct using newXPathFactoryNoServiceLoader method if
+ * available.
*/
private static Object newInstanceNoServiceLoader(
- Class<?> providerClass
- ) {
+ Class<?> providerClass) {
// Retain maximum compatibility if no security manager.
if (System.getSecurityManager() == null) {
return null;
}
try {
Method creationMethod =
providerClass.getDeclaredMethod(
- "newXPathFactoryNoServiceLoader"
- );
+ "newXPathFactoryNoServiceLoader");
return creationMethod.invoke(null, null);
} catch (NoSuchMethodException exc) {
return null;
} catch (Exception exc) {
return null;
}
}
- /**
- * <p>Look up a value in a property file.</p>
+ /*
+ * Try to find a provider using Service Loader
*
- * <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>.
+ * @return instance of provider class if found or null
*/
- 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
+ private XPathFactory findServiceProvider(final String objectModel, final String fallbackClassName)
+ throws XPathFactoryConfigurationException {
try {
- xPathFactory = (XPathFactory) clazz.newInstance();
- } catch (ClassCastException classCastExcpetion) {
- xPathFactory = null;
- continue;
- } catch (InstantiationException instantiationException) {
- xPathFactory = null;
- continue;
- } catch (IllegalAccessException illegalAccessException) {
- xPathFactory = null;
- continue;
+ return (XPathFactory) AccessController.doPrivileged(new PrivilegedAction() {
+ public XPathFactory run() {
+ XPathFactory defaultProvider = null;
+ for (XPathFactory factory : ServiceLoader.load(XPathFactory.class)) {
+ if (factory.getClass().getName().equals(fallbackClassName)) {
+ defaultProvider = factory;
+ } else {
+ if (isObjectModelSupported(factory, objectModel)) {
+ return factory;
}
-
- // 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;
+ if (defaultProvider != null) {
+ return defaultProvider;
}
-
- // clean up
- configFile.close();
-
- // return new instance of XPathFactory or null
- return xPathFactory;
+ 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();
+ });
+ } catch (ServiceConfigurationError e) {
+ throw new XPathFactoryConfigurationException((Exception) e.getCause());
}
-
- protected abstract Object value();
}
/**
- * Looks up a value in a property file
- * while producing all sorts of debug messages.
+ * <p>Test if the specified schemas are supported by the provider.</p>
*
- * @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");
- return null;
- }
- }
-
- /**
- * Returns an {@link Iterator} that enumerates all
- * the META-INF/services files that we care.
+ * @param schemaFactory a Schema factory provider.
+ * @param schemaLanguage Schema Language to support.
+ *
+ * @return <code>true</code> if the Schema Language is supported by the
+ * provider.
*/
- 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 ));
- }
- };
- } else {
+ private static boolean isObjectModelSupported(XPathFactory xPathFactory, String objectModel) {
+ final Class[] stringClassArray = {"".getClass()};
+ final Object[] objectModelObjectArray = {objectModel};
+ final String isObjectModelSupportedMethod = "isObjectModelSupported";
+ // does this Class support desired Schema?
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();
+ Method isObjectModelSupported = xPathFactory.getClass().getMethod(isObjectModelSupportedMethod, stringClassArray);
+ Boolean supported = (Boolean) isObjectModelSupported.invoke(xPathFactory, objectModelObjectArray);
+ if (supported.booleanValue()) {
+ return true;
}
-
- public boolean hasNext() {
- return e.hasMoreElements();
+ } catch (NoSuchMethodException noSuchMethodException) {
+ } catch (IllegalAccessException illegalAccessException) {
+ } catch (InvocationTargetException invocationTargetException) {
}
- 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
+ return false;
}
- }
- }
-
private static final Class SERVICE_CLASS = XPathFactory.class;
- private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName();
-
-
- private static String which( Class clazz ) {
- return which( clazz.getName(), clazz.getClassLoader() );
+ private static String which(Class clazz) {
+ return which(clazz.getName(), clazz.getClassLoader());
}
/**
* <p>Search the specified classloader for the given classname.</p>
*
@@ -533,11 +402,13 @@
*/
private static String which(String classname, ClassLoader loader) {
String classnameAsResource = classname.replace('.', '/') + ".class";
- if( loader==null ) loader = ClassLoader.getSystemClassLoader();
+ if (loader == null) {
+ loader = ClassLoader.getSystemClassLoader();
+ }
//URL it = loader.getResource(classnameAsResource);
URL it = ss.getResourceAsURL(loader, classnameAsResource);
if (it != null) {
return it.toString();