src/javax/xml/xpath/XPathFactoryFinder.java

Print this page
rev 406 : 8005954: JAXP Plugability Layer should use java.util.ServiceLoader
Summary: 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
   1 /*
   2  * Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.xml.xpath;
  27 
  28 import java.io.BufferedReader;
  29 import java.io.File;
  30 import java.io.FileInputStream;
  31 import java.io.IOException;
  32 import java.io.InputStream;
  33 import java.io.InputStreamReader;
  34 import java.lang.reflect.Method;
  35 import java.lang.reflect.InvocationTargetException;
  36 import java.net.URL;
  37 import java.util.ArrayList;
  38 import java.util.Enumeration;
  39 import java.util.Iterator;
  40 import java.util.NoSuchElementException;
  41 import java.util.Properties;


  42 
  43 /**
  44  * Implementation of {@link XPathFactory#newInstance(String)}.
  45  *
  46  * @author <a href="Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
  47  * @version $Revision: 1.7 $, $Date: 2010-11-01 04:36:14 $
  48  * @since 1.5
  49  */
  50 class XPathFactoryFinder  {
  51     private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xpath.internal";
  52 
  53     private static SecuritySupport ss = new SecuritySupport() ;
  54     /** debug support code. */
  55     private static boolean debug = false;
  56     static {
  57         // Use try/catch block to support applets
  58         try {
  59             debug = ss.getSystemProperty("jaxp.debug") != null;
  60         } catch (Exception unused) {
  61             debug = false;
  62         }
  63     }
  64 
  65     /**
  66      * <p>Cache properties for performance.</p>
  67      */
  68         private static Properties cacheProps = new Properties();
  69 
  70         /**
  71          * <p>First time requires initialization overhead.</p>
  72          */
  73         private volatile static boolean firstTime = true;
  74 
  75     /**
  76      * <p>Conditional debug printing.</p>
  77      *
  78      * @param msg to print
  79      */
  80     private static void debugPrintln(String msg) {
  81         if (debug) {
  82             System.err.println("JAXP: " + msg);
  83         }
  84     }
  85 
  86     /**
  87      * <p><code>ClassLoader</code> to use to find <code>XPathFactory</code>.</p>
  88      */
  89     private final ClassLoader classLoader;
  90 
  91     /**
  92      * <p>Constructor that specifies <code>ClassLoader</code> to use
  93      * to find <code>XPathFactory</code>.</p>
  94      *
  95      * @param loader
  96      *      to be used to load resource, {@link XPathFactory}, and
  97      *      {@link SchemaFactoryLoader} implementations during
  98      *      the resolution process.
  99      *      If this parameter is null, the default system class loader
 100      *      will be used.
 101      */
 102     public XPathFactoryFinder(ClassLoader loader) {
 103         this.classLoader = loader;
 104         if( debug ) {
 105             debugDisplayClassLoader();
 106         }
 107     }
 108 
 109     private void debugDisplayClassLoader() {
 110         try {
 111             if( classLoader == ss.getContextClassLoader() ) {
 112                 debugPrintln("using thread context class loader ("+classLoader+") for search");
 113                 return;
 114             }
 115         } catch( Throwable unused ) {
 116             ; // getContextClassLoader() undefined in JDK1.1
 117         }
 118 
 119         if( classLoader==ClassLoader.getSystemClassLoader() ) {
 120             debugPrintln("using system class loader ("+classLoader+") for search");
 121             return;
 122         }
 123 
 124         debugPrintln("using class loader ("+classLoader+") for search");
 125     }
 126 
 127     /**
 128      * <p>Creates a new {@link XPathFactory} object for the specified
 129      * schema language.</p>
 130      *
 131      * @param uri
 132      *       Identifies the underlying object model.
 133      *
 134      * @return <code>null</code> if the callee fails to create one.
 135      *
 136      * @throws NullPointerException
 137      *      If the parameter is null.
 138      */
 139     public XPathFactory newFactory(String uri) {
 140         if(uri==null)        throw new NullPointerException();


 141         XPathFactory f = _newFactory(uri);
 142         if (f != null) {
 143             debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri);
 144         } else {
 145             debugPrintln("unable to find a factory for " + uri);
 146         }
 147         return f;
 148     }
 149 
 150     /**
 151      * <p>Lookup a {@link XPathFactory} for the given object model.</p>
 152      *
 153      * @param uri identifies the object model.
 154      *
 155      * @return {@link XPathFactory} for the given object model.
 156      */
 157     private XPathFactory _newFactory(String uri) {
 158         XPathFactory xpathFactory;
 159 
 160         String propertyName = SERVICE_CLASS.getName() + ":" + uri;
 161 
 162         // system property look up
 163         try {
 164             debugPrintln("Looking up system property '"+propertyName+"'" );
 165             String r = ss.getSystemProperty(propertyName);
 166             if(r!=null) {
 167                 debugPrintln("The value is '"+r+"'");
 168                 xpathFactory = createInstance(r, true);
 169                 if(xpathFactory != null)    return xpathFactory;


 170             } else
 171                 debugPrintln("The property is undefined.");
 172         } catch( Throwable t ) {
 173             if( debug ) {
 174                 debugPrintln("failed to look up system property '"+propertyName+"'" );
 175                 t.printStackTrace();
 176             }
 177         }
 178 
 179         String javah = ss.getSystemProperty( "java.home" );
 180         String configFile = javah + File.separator +
 181         "lib" + File.separator + "jaxp.properties";
 182 
 183         String factoryClassName = null ;
 184 
 185         // try to read from $java.home/lib/jaxp.properties
 186         try {
 187             if(firstTime){
 188                 synchronized(cacheProps){
 189                     if(firstTime){
 190                         File f=new File( configFile );
 191                         firstTime = false;
 192                         if(ss.doesFileExist(f)){
 193                             debugPrintln("Read properties file " + f);
 194                             cacheProps.load(ss.getFileInputStream(f));
 195                         }
 196                     }
 197                 }
 198             }
 199             factoryClassName = cacheProps.getProperty(propertyName);
 200             debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
 201 
 202             if (factoryClassName != null) {
 203                 xpathFactory = createInstance(factoryClassName, true);
 204                 if(xpathFactory != null){
 205                     return xpathFactory;
 206                 }
 207             }
 208         } catch (Exception ex) {
 209             if (debug) {
 210                 ex.printStackTrace();
 211             }
 212         }
 213 
 214         // try META-INF/services files
 215         Iterator sitr = createServiceFileIterator();
 216         while(sitr.hasNext()) {
 217             URL resource = (URL)sitr.next();
 218             debugPrintln("looking into " + resource);
 219             try {
 220                 xpathFactory = loadFromService(uri, resource.toExternalForm(),
 221                                                 ss.getURLInputStream(resource));
 222                 if (xpathFactory != null) {
 223                     return xpathFactory;
 224                 }
 225             } catch(IOException e) {
 226                 if( debug ) {
 227                     debugPrintln("failed to read "+resource);
 228                     e.printStackTrace();
 229                 }
 230             }
 231         }
 232 
 233         // platform default
 234         if(uri.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) {
 235             debugPrintln("attempting to use the platform default W3C DOM XPath lib");
 236             return createInstance("com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", true);
 237         }
 238 
 239         debugPrintln("all things were tried, but none was found. bailing out.");
 240         return null;
 241     }
 242 
 243     /** <p>Create class using appropriate ClassLoader.</p>
 244      *
 245      * @param className Name of class to create.
 246      * @return Created class or <code>null</code>.
 247      */
 248     private Class createClass(String className) {
 249             Class clazz;
 250         // make sure we have access to restricted packages
 251         boolean internal = false;
 252         if (System.getSecurityManager() != null) {
 253             if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
 254                 internal = true;
 255             }
 256         }
 257 
 258         // use approprite ClassLoader
 259         try {
 260             if (classLoader != null && !internal) {
 261                     clazz = classLoader.loadClass(className);
 262             } else {
 263                     clazz = Class.forName(className);
 264             }
 265         } catch (Throwable t) {
 266             if(debug)   t.printStackTrace();


 267                 return null;
 268         }
 269 
 270             return clazz;
 271     }
 272 
 273     /**
 274      * <p>Creates an instance of the specified and returns it.</p>
 275      *
 276      * @param className
 277      *      fully qualified class name to be instanciated.
 278      *
 279      * @return null
 280      *      if it fails. Error messages will be printed by this method.
 281      */
 282     XPathFactory createInstance( String className ) {


 283         return createInstance( className, false );
 284     }
 285     XPathFactory createInstance( String className, boolean useServicesMechanism  ) {



 286         XPathFactory xPathFactory = null;
 287 
 288         debugPrintln("createInstance(" + className + ")");
 289 
 290         // get Class from className
 291         Class clazz = createClass(className);
 292         if (clazz == null) {
 293                 debugPrintln("failed to getClass(" + className + ")");
 294                 return null;
 295         }
 296         debugPrintln("loaded " + className + " from " + which(clazz));
 297 
 298         // instantiate Class as a XPathFactory
 299         try {
 300             if (!useServicesMechanism) {
 301                 xPathFactory = (XPathFactory) newInstanceNoServiceLoader(clazz);
 302             }
 303             if (xPathFactory == null) {
 304                 xPathFactory = (XPathFactory) clazz.newInstance();
 305             }
 306         } catch (ClassCastException classCastException) {
 307                 debugPrintln("could not instantiate " + clazz.getName());
 308                 if (debug) {
 309                         classCastException.printStackTrace();
 310                 }
 311                 return null;
 312         } catch (IllegalAccessException illegalAccessException) {
 313                 debugPrintln("could not instantiate " + clazz.getName());
 314                 if (debug) {
 315                         illegalAccessException.printStackTrace();
 316                 }
 317                 return null;
 318         } catch (InstantiationException instantiationException) {
 319                 debugPrintln("could not instantiate " + clazz.getName());
 320                 if (debug) {
 321                         instantiationException.printStackTrace();
 322                 }
 323                 return null;
 324         }
 325 
 326         return xPathFactory;
 327     }
 328     /**
 329      * Try to construct using newXPathFactoryNoServiceLoader
 330      *   method if available.
 331      */
 332     private static Object newInstanceNoServiceLoader(
 333          Class<?> providerClass
 334     ) {
 335         // Retain maximum compatibility if no security manager.
 336         if (System.getSecurityManager() == null) {
 337             return null;
 338         }
 339         try {
 340             Method creationMethod =
 341                 providerClass.getDeclaredMethod(
 342                     "newXPathFactoryNoServiceLoader"
 343                 );
 344                 return creationMethod.invoke(null, (Object[])null);
 345             } catch (NoSuchMethodException exc) {
 346                 return null;
 347             } catch (Exception exc) {
 348                 return null;
 349         }
 350     }
 351 
 352     /**
 353      * <p>Look up a value in a property file.</p>
 354      *
 355      * <p>Set <code>debug</code> to <code>true</code> to trace property evaluation.</p>
 356      *
 357      * @param objectModel URI of object model to support.
 358      * @param inputName Name of <code>InputStream</code>.
 359      * @param in <code>InputStream</code> of properties.
 360      *
 361      * @return <code>XPathFactory</code> as determined by <code>keyName</code> value or <code>null</code> if there was an error.
 362      *
 363      * @throws IOException If IO error reading from <code>in</code>.
 364      */
 365     private XPathFactory loadFromService(
 366             String objectModel,
 367             String inputName,
 368             InputStream in)
 369             throws IOException {
 370 
 371             XPathFactory xPathFactory = null;
 372             final Class[] stringClassArray = {"".getClass()};
 373             final Object[] objectModelObjectArray = {objectModel};
 374             final String isObjectModelSupportedMethod = "isObjectModelSupported";
 375 
 376             debugPrintln("Reading " + inputName);
 377 
 378             // read from InputStream until a match is found
 379             BufferedReader configFile = new BufferedReader(new InputStreamReader(in));
 380             String line = null;
 381             while ((line = configFile.readLine()) != null) {
 382                     // '#' is comment char
 383                     int comment = line.indexOf("#");
 384                     switch (comment) {
 385                             case -1: break; // no comment
 386                             case 0: line = ""; break; // entire line is a comment
 387                             default: line = line.substring(0, comment); break; // trim comment
 388                     }
 389 
 390                     // trim whitespace
 391                     line = line.trim();
 392 
 393                     // any content left on line?
 394                     if (line.length() == 0) {
 395                             continue;
 396                     }
 397 
 398                     // line content is now the name of the class
 399                     Class clazz = createClass(line);
 400                     if (clazz == null) {
 401                             continue;
 402                     }
 403 
 404                     // create an instance of the Class
 405                     try {
 406                             xPathFactory = (XPathFactory) clazz.newInstance();
 407                     } catch (ClassCastException classCastExcpetion) {
 408                             xPathFactory = null;
 409                             continue;
 410                     } catch (InstantiationException instantiationException) {
 411                             xPathFactory = null;
 412                             continue;
 413                     } catch (IllegalAccessException illegalAccessException) {
 414                             xPathFactory = null;
 415                             continue;
 416                     }
 417 
 418                     // does this Class support desired object model?
 419                     try {
 420                             Method isObjectModelSupported = clazz.getMethod(isObjectModelSupportedMethod, stringClassArray);
 421                             Boolean supported = (Boolean) isObjectModelSupported.invoke(xPathFactory, objectModelObjectArray);
 422                             if (supported.booleanValue()) {
 423                                     break;
 424                             }
 425 
 426                     } catch (NoSuchMethodException noSuchMethodException) {
 427 
 428                     } catch (IllegalAccessException illegalAccessException) {
 429 
 430                     } catch (InvocationTargetException invocationTargetException) {
 431 





 432                     }
 433                     xPathFactory = null;





 434             }
 435 
 436             // clean up
 437             configFile.close();
 438 
 439             // return new instance of XPathFactory or null
 440             return xPathFactory;
 441     }
 442 
 443     /** Iterator that lazily computes one value and returns it. */
 444     private static abstract class SingleIterator implements Iterator {
 445         private boolean seen = false;
 446 
 447         public final void remove() { throw new UnsupportedOperationException(); }
 448         public final boolean hasNext() { return !seen; }
 449         public final Object next() {
 450             if(seen)    throw new NoSuchElementException();
 451             seen = true;
 452             return value();
 453         }
 454 
 455         protected abstract Object value();
 456     }
 457 
 458     /**
 459      * Looks up a value in a property file
 460      * while producing all sorts of debug messages.
 461      *
 462      * @return null
 463      *      if there was an error.


 464      */
 465     private XPathFactory loadFromProperty( String keyName, String resourceName, InputStream in )
 466         throws IOException {
 467         debugPrintln("Reading "+resourceName );
 468 
 469         Properties props = new Properties();
 470         props.load(in);
 471         in.close();
 472         String factoryClassName = props.getProperty(keyName);
 473         if(factoryClassName != null){
 474             debugPrintln("found "+keyName+" = " + factoryClassName);
 475             return createInstance(factoryClassName, true);
 476         } else {
 477             debugPrintln(keyName+" is not in the property file");
 478             return null;
 479         }
 480     }
 481 
 482     /**
 483      * Returns an {@link Iterator} that enumerates all
 484      * the META-INF/services files that we care.
 485      */
 486     private Iterator createServiceFileIterator() {
 487         if (classLoader == null) {
 488             return new SingleIterator() {
 489                 protected Object value() {
 490                     ClassLoader classLoader = XPathFactoryFinder.class.getClassLoader();
 491                     return ss.getResourceAsURL(classLoader, SERVICE_ID);
 492                     //return (ClassLoader.getSystemResource( SERVICE_ID ));
 493                 }
 494             };
 495         } else {
 496             try {
 497                 //final Enumeration e = classLoader.getResources(SERVICE_ID);
 498                 final Enumeration e = ss.getResources(classLoader, SERVICE_ID);
 499                 if(!e.hasMoreElements()) {
 500                     debugPrintln("no "+SERVICE_ID+" file was found");





 501                 }
 502 
 503                 // wrap it into an Iterator.
 504                 return new Iterator() {
 505                     public void remove() {
 506                         throw new UnsupportedOperationException();
 507                     }
 508 
 509                     public boolean hasNext() {
 510                         return e.hasMoreElements();
 511                     }
 512 
 513                     public Object next() {
 514                         return e.nextElement();
 515                     }
 516                 };
 517             } catch (IOException e) {
 518                 debugPrintln("failed to enumerate resources "+SERVICE_ID);
 519                 if(debug)   e.printStackTrace();
 520                 return new ArrayList().iterator();  // empty iterator
 521             }
 522         }
 523     }
 524 
 525     private static final Class SERVICE_CLASS = XPathFactory.class;
 526     private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName();
 527 
 528 

 529 
 530     private static String which( Class clazz ) {
 531         return which( clazz.getName(), clazz.getClassLoader() );
 532     }
 533 
 534     /**
 535      * <p>Search the specified classloader for the given classname.</p>
 536      *
 537      * @param classname the fully qualified name of the class to search for
 538      * @param loader the classloader to search
 539      *
 540      * @return the source location of the resource, or null if it wasn't found
 541      */
 542     private static String which(String classname, ClassLoader loader) {
 543 
 544         String classnameAsResource = classname.replace('.', '/') + ".class";
 545 
 546         if( loader==null )  loader = ClassLoader.getSystemClassLoader();
 547 
 548         //URL it = loader.getResource(classnameAsResource);
   1 /*
   2  * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.xml.xpath;
  27 

  28 import java.io.File;




  29 import java.lang.reflect.Method;
  30 import java.lang.reflect.Modifier;
  31 import java.net.URL;
  32 import java.security.AccessControlContext;
  33 import java.security.AccessController;
  34 import java.security.PrivilegedAction;

  35 import java.util.Properties;
  36 import java.util.ServiceConfigurationError;
  37 import java.util.ServiceLoader;
  38 
  39 /**
  40  * Implementation of {@link XPathFactory#newInstance(String)}.
  41  *
  42  * @author <a href="Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
  43  * @version $Revision: 1.7 $, $Date: 2010-11-01 04:36:14 $
  44  * @since 1.5
  45  */
  46 class XPathFactoryFinder  {
  47     private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xpath.internal";
  48 
  49     private static final SecuritySupport ss = new SecuritySupport() ;
  50     /** debug support code. */
  51     private static boolean debug = false;
  52     static {
  53         // Use try/catch block to support applets
  54         try {
  55             debug = ss.getSystemProperty("jaxp.debug") != null;
  56         } catch (Exception unused) {
  57             debug = false;
  58         }
  59     }
  60 
  61     /**
  62      * <p>Cache properties for performance.</p>
  63      */
  64     private static final Properties cacheProps = new Properties();
  65 
  66     /**
  67      * <p>First time requires initialization overhead.</p>
  68      */
  69     private volatile static boolean firstTime = true;
  70 
  71     /**
  72      * <p>Conditional debug printing.</p>
  73      *
  74      * @param msg to print
  75      */
  76     private static void debugPrintln(String msg) {
  77         if (debug) {
  78             System.err.println("JAXP: " + msg);
  79         }
  80     }
  81 
  82     /**
  83      * <p><code>ClassLoader</code> to use to find <code>XPathFactory</code>.</p>
  84      */
  85     private final ClassLoader classLoader;
  86 
  87     /**
  88      * <p>Constructor that specifies <code>ClassLoader</code> to use
  89      * to find <code>XPathFactory</code>.</p>
  90      *
  91      * @param loader
  92      *      to be used to load resource and {@link XPathFactory}
  93      *      implementations during the resolution process.

  94      *      If this parameter is null, the default system class loader
  95      *      will be used.
  96      */
  97     public XPathFactoryFinder(ClassLoader loader) {
  98         this.classLoader = loader;
  99         if( debug ) {
 100             debugDisplayClassLoader();
 101         }
 102     }
 103 
 104     private void debugDisplayClassLoader() {
 105         try {
 106             if( classLoader == ss.getContextClassLoader() ) {
 107                 debugPrintln("using thread context class loader ("+classLoader+") for search");
 108                 return;
 109             }
 110         } catch( Throwable unused ) {
 111              // getContextClassLoader() undefined in JDK1.1
 112         }
 113 
 114         if( classLoader==ClassLoader.getSystemClassLoader() ) {
 115             debugPrintln("using system class loader ("+classLoader+") for search");
 116             return;
 117         }
 118 
 119         debugPrintln("using class loader ("+classLoader+") for search");
 120     }
 121 
 122     /**
 123      * <p>Creates a new {@link XPathFactory} object for the specified
 124      * object model.</p>
 125      *
 126      * @param uri
 127      *       Identifies the underlying object model.
 128      *
 129      * @return <code>null</code> if the callee fails to create one.
 130      *
 131      * @throws NullPointerException
 132      *      If the parameter is null.
 133      */
 134     public XPathFactory newFactory(String uri) throws XPathFactoryConfigurationException {
 135         if (uri == null) {
 136             throw new NullPointerException();
 137         }
 138         XPathFactory f = _newFactory(uri);
 139         if (f != null) {
 140             debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri);
 141         } else {
 142             debugPrintln("unable to find a factory for " + uri);
 143         }
 144         return f;
 145     }
 146 
 147     /**
 148      * <p>Lookup a {@link XPathFactory} for the given object model.</p>
 149      *
 150      * @param uri identifies the object model.
 151      *
 152      * @return {@link XPathFactory} for the given object model.
 153      */
 154     private XPathFactory _newFactory(String uri) throws XPathFactoryConfigurationException {
 155         XPathFactory xpathFactory = null;
 156 
 157         String propertyName = SERVICE_CLASS.getName() + ":" + uri;
 158 
 159         // system property look up
 160         try {
 161             debugPrintln("Looking up system property '"+propertyName+"'" );
 162             String r = ss.getSystemProperty(propertyName);
 163             if(r!=null) {
 164                 debugPrintln("The value is '"+r+"'");
 165                 xpathFactory = createInstance(r, true);
 166                 if (xpathFactory != null) {
 167                     return xpathFactory;
 168                 }
 169             } else
 170                 debugPrintln("The property is undefined.");
 171         } catch( Throwable t ) {
 172             if( debug ) {
 173                 debugPrintln("failed to look up system property '"+propertyName+"'" );
 174                 t.printStackTrace();
 175             }
 176         }
 177 
 178         String javah = ss.getSystemProperty( "java.home" );
 179         String configFile = javah + File.separator +
 180         "lib" + File.separator + "jaxp.properties";
 181 


 182         // try to read from $java.home/lib/jaxp.properties
 183         try {
 184             if(firstTime){
 185                 synchronized(cacheProps){
 186                     if(firstTime){
 187                         File f=new File( configFile );
 188                         firstTime = false;
 189                         if(ss.doesFileExist(f)){
 190                             debugPrintln("Read properties file " + f);
 191                             cacheProps.load(ss.getFileInputStream(f));
 192                         }
 193                     }
 194                 }
 195             }
 196             final String factoryClassName = cacheProps.getProperty(propertyName);
 197             debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
 198 
 199             if (factoryClassName != null) {
 200                 xpathFactory = createInstance(factoryClassName, true);
 201                 if(xpathFactory != null){
 202                     return xpathFactory;
 203                 }
 204             }
 205         } catch (Exception ex) {
 206             if (debug) {
 207                 ex.printStackTrace();
 208             }
 209         }
 210 
 211         // Try with ServiceLoader
 212         assert xpathFactory == null;
 213         xpathFactory = findServiceProvider(uri);
 214 
 215         // The following assertion should always be true.
 216         // Uncomment it, recompile, and run with -ea in case of doubts:
 217         // assert xpathFactory == null || xpathFactory.isObjectModelSupported(uri);
 218 
 219         if (xpathFactory != null) {
 220             return xpathFactory;
 221         }







 222 
 223         // platform default
 224         if(uri.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) {
 225             debugPrintln("attempting to use the platform default W3C DOM XPath lib");
 226             return createInstance("com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", true);
 227         }
 228 
 229         debugPrintln("all things were tried, but none was found. bailing out.");
 230         return null;
 231     }
 232 
 233     /** <p>Create class using appropriate ClassLoader.</p>
 234      *
 235      * @param className Name of class to create.
 236      * @return Created class or <code>null</code>.
 237      */
 238     private Class<?> createClass(String className) {
 239         Class clazz;
 240         // make sure we have access to restricted packages
 241         boolean internal = false;
 242         if (System.getSecurityManager() != null) {
 243             if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
 244                 internal = true;
 245             }
 246         }
 247 
 248         // use approprite ClassLoader
 249         try {
 250             if (classLoader != null && !internal) {
 251                     clazz = Class.forName(className, false, classLoader);
 252             } else {
 253                     clazz = Class.forName(className);
 254             }
 255         } catch (Throwable t) {
 256             if(debug) {
 257                 t.printStackTrace();
 258             }
 259             return null;
 260         }
 261 
 262         return clazz;
 263     }
 264 
 265     /**
 266      * <p>Creates an instance of the specified and returns it.</p>
 267      *
 268      * @param className
 269      *      fully qualified class name to be instantiated.
 270      *
 271      * @return null
 272      *      if it fails. Error messages will be printed by this method.
 273      */
 274     XPathFactory createInstance( String className )
 275             throws XPathFactoryConfigurationException
 276     {
 277         return createInstance( className, false );
 278     }
 279 
 280     XPathFactory createInstance( String className, boolean useServicesMechanism  )
 281             throws XPathFactoryConfigurationException
 282     {
 283         XPathFactory xPathFactory = null;
 284 
 285         debugPrintln("createInstance(" + className + ")");
 286 
 287         // get Class from className
 288         Class<?> clazz = createClass(className);
 289         if (clazz == null) {
 290             debugPrintln("failed to getClass(" + className + ")");
 291             return null;
 292         }
 293         debugPrintln("loaded " + className + " from " + which(clazz));
 294 
 295         // instantiate Class as a XPathFactory
 296         try {
 297             if (!useServicesMechanism) {
 298                 xPathFactory = newInstanceNoServiceLoader(clazz);
 299             }
 300             if (xPathFactory == null) {
 301                 xPathFactory = (XPathFactory) clazz.newInstance();
 302             }
 303         } catch (ClassCastException classCastException) {
 304                 debugPrintln("could not instantiate " + clazz.getName());
 305                 if (debug) {
 306                         classCastException.printStackTrace();
 307                 }
 308                 return null;
 309         } catch (IllegalAccessException illegalAccessException) {
 310                 debugPrintln("could not instantiate " + clazz.getName());
 311                 if (debug) {
 312                         illegalAccessException.printStackTrace();
 313                 }
 314                 return null;
 315         } catch (InstantiationException instantiationException) {
 316                 debugPrintln("could not instantiate " + clazz.getName());
 317                 if (debug) {
 318                         instantiationException.printStackTrace();
 319                 }
 320                 return null;
 321         }
 322 
 323         return xPathFactory;
 324     }
 325     /**
 326      * Try to construct using newXPathFactoryNoServiceLoader
 327      *   method if available.
 328      */
 329     private static XPathFactory newInstanceNoServiceLoader(
 330          Class<?> providerClass
 331     ) throws XPathFactoryConfigurationException {
 332         // Retain maximum compatibility if no security manager.
 333         if (System.getSecurityManager() == null) {
 334             return null;
 335         }
 336         try {
 337             Method creationMethod =
 338                     providerClass.getDeclaredMethod(
 339                         "newXPathFactoryNoServiceLoader"
 340                     );
 341             final int modifiers = creationMethod.getModifiers();

























 342 
 343             // Do not call "newXPathFactoryNoServiceLoader" if it's
 344             // not public static.
 345             if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
 346                 return null;

















































 347             }
 348 
 349             // Only calls "newXPathFactoryNoServiceLoader" if it's
 350             // declared to return an instance of XPathFactory.
 351             final Class<?> returnType = creationMethod.getReturnType();
 352             if (SERVICE_CLASS.isAssignableFrom(returnType)) {
 353                 return SERVICE_CLASS.cast(creationMethod.invoke(null, (Object[])null));
 354             } else {
 355                 // Should not happen since
 356                 // XPathFactoryImpl.newXPathFactoryNoServiceLoader is
 357                 // declared to return XPathFactory.
 358                 throw new ClassCastException(returnType
 359                             + " cannot be cast to " + SERVICE_CLASS);
 360             }
 361         } catch (ClassCastException e) {
 362             throw new XPathFactoryConfigurationException(e);
 363         } catch (NoSuchMethodException exc) {
 364             return null;
 365         } catch (Exception exc) {
 366             return null;
 367         }






 368     }
 369 
 370     // Call isObjectModelSupportedBy with initial context.
 371     private boolean isObjectModelSupportedBy(final XPathFactory factory,
 372             final String objectModel,
 373             AccessControlContext acc) {
 374         return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
 375                     public Boolean run() {
 376                         return factory.isObjectModelSupported(objectModel);



 377                     }
 378                 }, acc);

 379     }
 380 
 381     /**
 382      * Finds a service provider subclass of XPathFactory that supports the
 383      * given object model using the ServiceLoader.
 384      *
 385      * @param objectModel URI of object model to support.
 386      * @return An XPathFactory supporting the specified object model, or null
 387      *         if none is found.
 388      * @throws XPathFactoryConfigurationException if a configuration error is found.
 389      */
 390     private XPathFactory findServiceProvider(final String objectModel)
 391             throws XPathFactoryConfigurationException {














 392 
 393         assert objectModel != null;
 394         // store current context.
 395         final AccessControlContext acc = AccessController.getContext();











 396         try {
 397             return AccessController.doPrivileged(new PrivilegedAction<XPathFactory>() {
 398                 public XPathFactory run() {
 399                     final ServiceLoader<XPathFactory> loader =
 400                             ServiceLoader.load(SERVICE_CLASS);
 401                     for (XPathFactory factory : loader) {
 402                         // restore initial context to call
 403                         // factory.isObjectModelSupportedBy
 404                         if (isObjectModelSupportedBy(factory, objectModel, acc)) {
 405                             return factory;
 406                         }





 407                     }
 408                     return null; // no factory found.


 409                 }
 410             });
 411         } catch (ServiceConfigurationError error) {
 412             throw new XPathFactoryConfigurationException(error);
 413         }





 414     }






 415 
 416     private static final Class<XPathFactory> SERVICE_CLASS = XPathFactory.class;
 417 
 418     private static String which( Class clazz ) {
 419         return which( clazz.getName(), clazz.getClassLoader() );
 420     }
 421 
 422     /**
 423      * <p>Search the specified classloader for the given classname.</p>
 424      *
 425      * @param classname the fully qualified name of the class to search for
 426      * @param loader the classloader to search
 427      *
 428      * @return the source location of the resource, or null if it wasn't found
 429      */
 430     private static String which(String classname, ClassLoader loader) {
 431 
 432         String classnameAsResource = classname.replace('.', '/') + ".class";
 433 
 434         if( loader==null )  loader = ClassLoader.getSystemClassLoader();
 435 
 436         //URL it = loader.getResource(classnameAsResource);