src/javax/xml/validation/SchemaFactoryFinder.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) 2003, 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.validation;
  27 
  28 import java.io.BufferedReader;
  29 import java.io.File;
  30 import java.io.IOException;
  31 import java.io.InputStream;
  32 import java.io.InputStreamReader;
  33 import java.lang.reflect.Method;
  34 import java.lang.reflect.InvocationTargetException;
  35 import java.net.URL;
  36 import java.util.ArrayList;
  37 import java.util.Enumeration;
  38 import java.util.Iterator;
  39 import java.util.NoSuchElementException;
  40 import java.util.Properties;


  41 
  42 /**
  43  * Implementation of {@link SchemaFactory#newInstance(String)}.
  44  *
  45  * @author <a href="Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
  46  * @version $Revision: 1.8 $, $Date: 2010-11-01 04:36:13 $
  47  * @since 1.5
  48  */
  49 class SchemaFactoryFinder  {
  50 
  51     /** debug support code. */
  52     private static boolean debug = false;
  53     /**
  54      *<p> Take care of restrictions imposed by java security model </p>
  55      */
  56     private static SecuritySupport ss = new SecuritySupport();
  57     private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal";
  58     /**
  59      * <p>Cache properties for performance.</p>
  60      */
  61         private static Properties cacheProps = new Properties();
  62 
  63         /**
  64          * <p>First time requires initialization overhead.</p>
  65          */
  66         private static volatile boolean firstTime = true;
  67 
  68     static {
  69         // Use try/catch block to support applets
  70         try {
  71             debug = ss.getSystemProperty("jaxp.debug") != null;
  72         } catch (Exception unused) {
  73             debug = false;
  74         }
  75     }
  76 
  77     /**
  78      * <p>Conditional debug printing.</p>
  79      *
  80      * @param msg to print
  81      */


  98      *      to be used to load resource, {@link SchemaFactory}, and
  99      *      {@link SchemaFactoryLoader} implementations during
 100      *      the resolution process.
 101      *      If this parameter is null, the default system class loader
 102      *      will be used.
 103      */
 104     public SchemaFactoryFinder(ClassLoader loader) {
 105         this.classLoader = loader;
 106         if( debug ) {
 107             debugDisplayClassLoader();
 108         }
 109     }
 110 
 111     private void debugDisplayClassLoader() {
 112         try {
 113             if( classLoader == ss.getContextClassLoader() ) {
 114                 debugPrintln("using thread context class loader ("+classLoader+") for search");
 115                 return;
 116             }
 117         } catch( Throwable unused ) {
 118             ; // getContextClassLoader() undefined in JDK1.1
 119         }
 120 
 121         if( classLoader==ClassLoader.getSystemClassLoader() ) {
 122             debugPrintln("using system class loader ("+classLoader+") for search");
 123             return;
 124         }
 125 
 126         debugPrintln("using class loader ("+classLoader+") for search");
 127     }
 128 
 129     /**
 130      * <p>Creates a new {@link SchemaFactory} object for the specified
 131      * schema language.</p>
 132      *
 133      * @param schemaLanguage
 134      *      See {@link SchemaFactory Schema Language} table in <code>SchemaFactory</code>
 135      *      for the list of available schema languages.
 136      *
 137      * @return <code>null</code> if the callee fails to create one.
 138      *
 139      * @throws NullPointerException
 140      *      If the <code>schemaLanguage</code> parameter is null.


 141      */
 142     public SchemaFactory newFactory(String schemaLanguage) {
 143         if(schemaLanguage==null)        throw new NullPointerException();


 144         SchemaFactory f = _newFactory(schemaLanguage);
 145         if (f != null) {
 146             debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage);
 147         } else {
 148             debugPrintln("unable to find a factory for " + schemaLanguage);
 149         }
 150         return f;
 151     }
 152 
 153     /**
 154      * <p>Lookup a <code>SchemaFactory</code> for the given <code>schemaLanguage</code>.</p>
 155      *
 156      * @param schemaLanguage Schema language to lookup <code>SchemaFactory</code> for.
 157      *
 158      * @return <code>SchemaFactory</code> for the given <code>schemaLanguage</code>.
 159      */
 160     private SchemaFactory _newFactory(String schemaLanguage) {
 161         SchemaFactory sf;
 162 
 163         String propertyName = SERVICE_CLASS.getName() + ":" + schemaLanguage;


 166         try {
 167             debugPrintln("Looking up system property '"+propertyName+"'" );
 168             String r = ss.getSystemProperty(propertyName);
 169             if(r!=null) {
 170                 debugPrintln("The value is '"+r+"'");
 171                 sf = createInstance(r, true);
 172                 if(sf!=null)    return sf;
 173             } else
 174                 debugPrintln("The property is undefined.");
 175         } catch( Throwable t ) {
 176             if( debug ) {
 177                 debugPrintln("failed to look up system property '"+propertyName+"'" );
 178                 t.printStackTrace();
 179             }
 180         }
 181 
 182         String javah = ss.getSystemProperty( "java.home" );
 183         String configFile = javah + File.separator +
 184         "lib" + File.separator + "jaxp.properties";
 185 
 186         String factoryClassName = null ;
 187 
 188         // try to read from $java.home/lib/jaxp.properties
 189         try {
 190             if(firstTime){
 191                 synchronized(cacheProps){
 192                     if(firstTime){
 193                         File f=new File( configFile );
 194                         firstTime = false;
 195                         if(ss.doesFileExist(f)){
 196                             debugPrintln("Read properties file " + f);
 197                             cacheProps.load(ss.getFileInputStream(f));
 198                         }
 199                     }
 200                 }
 201             }
 202             factoryClassName = cacheProps.getProperty(propertyName);
 203             debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
 204 
 205             if (factoryClassName != null) {
 206                 sf = createInstance(factoryClassName, true);
 207                 if(sf != null){
 208                     return sf;
 209                 }
 210             }
 211         } catch (Exception ex) {
 212             if (debug) {
 213                 ex.printStackTrace();
 214             }
 215         }
 216 
 217         // try META-INF/services files
 218         Iterator sitr = createServiceFileIterator();
 219         while(sitr.hasNext()) {
 220             URL resource = (URL)sitr.next();
 221             debugPrintln("looking into " + resource);
 222             try {
 223                 sf = loadFromService(schemaLanguage,resource.toExternalForm(),
 224                                                 ss.getURLInputStream(resource));
 225                 if(sf!=null)    return sf;
 226             } catch(IOException e) {
 227                 if( debug ) {
 228                     debugPrintln("failed to read "+resource);
 229                     e.printStackTrace();
 230                 }
 231             }
 232         }
 233 
 234         // platform default
 235         if(schemaLanguage.equals("http://www.w3.org/2001/XMLSchema")) {
 236             debugPrintln("attempting to use the platform default XML Schema validator");
 237             return createInstance("com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory", true);
 238         }
 239 
 240         debugPrintln("all things were tried, but none was found. bailing out.");
 241         return null;
 242     }
 243 
 244     /** <p>Create class using appropriate ClassLoader.</p>
 245      *
 246      * @param className Name of class to create.
 247      * @return Created class or <code>null</code>.
 248      */
 249     private Class createClass(String className) {
 250             Class clazz;
 251         // make sure we have access to restricted packages
 252         boolean internal = false;
 253         if (System.getSecurityManager() != null) {
 254             if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
 255                 internal = true;
 256             }
 257         }
 258 
 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     SchemaFactory createInstance( String className ) {
 283         return createInstance( className, false );
 284     }
 285 
 286     SchemaFactory createInstance( String className, boolean useServicesMechanism ) {
 287         SchemaFactory schemaFactory = null;
 288 
 289         debugPrintln("createInstance(" + className + ")");
 290 
 291         // get Class from className
 292         Class clazz = createClass(className);
 293         if (clazz == null) {
 294                 debugPrintln("failed to getClass(" + className + ")");
 295                 return null;
 296         }
 297         debugPrintln("loaded " + className + " from " + which(clazz));
 298 
 299         // instantiate Class as a SchemaFactory
 300         try {




 301             if (!useServicesMechanism) {
 302                 schemaFactory = (SchemaFactory) newInstanceNoServiceLoader(clazz);
 303             }
 304                 if (schemaFactory == null) {
 305                     schemaFactory = (SchemaFactory) clazz.newInstance();
 306                 }
 307         } catch (ClassCastException classCastException) {
 308                 debugPrintln("could not instantiate " + clazz.getName());
 309                 if (debug) {
 310                         classCastException.printStackTrace();
 311                 }
 312                 return null;
 313         } catch (IllegalAccessException illegalAccessException) {
 314                 debugPrintln("could not instantiate " + clazz.getName());
 315                 if (debug) {
 316                         illegalAccessException.printStackTrace();
 317                 }
 318                 return null;
 319         } catch (InstantiationException instantiationException) {
 320                 debugPrintln("could not instantiate " + clazz.getName());
 321                 if (debug) {
 322                         instantiationException.printStackTrace();
 323                 }
 324                 return null;
 325         }
 326 
 327         return schemaFactory;
 328     }

 329     /**
 330      * Try to construct using newTransformerFactoryNoServiceLoader
 331      *   method if available.
 332      */
 333     private static Object newInstanceNoServiceLoader(
 334          Class<?> providerClass
 335     ) {
 336         // Retain maximum compatibility if no security manager.
 337         if (System.getSecurityManager() == null) {
 338             return null;
 339         }
 340         try {
 341             Method creationMethod =
 342                 providerClass.getDeclaredMethod(
 343                     "newXMLSchemaFactoryNoServiceLoader"
 344                 );
 345                 return creationMethod.invoke(null, (Object[])null);
 346             } catch (NoSuchMethodException exc) {
 347                 return null;
 348             } catch (Exception exc) {
 349                 return null;
 350         }
 351     }
 352 
 353     /** Iterator that lazily computes one value and returns it. */
 354     private static abstract class SingleIterator implements Iterator {
 355         private boolean seen = false;
 356 
 357         public final void remove() { throw new UnsupportedOperationException(); }
 358         public final boolean hasNext() { return !seen; }
 359         public final Object next() {
 360             if(seen)    throw new NoSuchElementException();
 361             seen = true;
 362             return value();
 363         }
 364 
 365         protected abstract Object value();
 366     }
 367 
 368     /**
 369      * Looks up a value in a property file
 370      * while producing all sorts of debug messages.
 371      *
 372      * @return null
 373      *      if there was an error.
 374      */
 375     private SchemaFactory loadFromProperty( String keyName, String resourceName, InputStream in )
 376         throws IOException {
 377         debugPrintln("Reading "+resourceName );
 378 
 379         Properties props=new Properties();
 380         props.load(in);
 381         in.close();
 382         String factoryClassName = props.getProperty(keyName);
 383         if(factoryClassName != null){
 384             debugPrintln("found "+keyName+" = " + factoryClassName);
 385             return createInstance(factoryClassName);
 386         } else {
 387             debugPrintln(keyName+" is not in the property file");
 388             return null;
 389         }
 390     }
 391 
 392     /**
 393      * <p>Look up a value in a property file.</p>
 394      *
 395      * <p>Set <code>debug</code> to <code>true</code> to trace property evaluation.</p>
 396      *
 397      * @param schemaLanguage Schema Language to support.
 398      * @param inputName Name of <code>InputStream</code>.
 399      * @param in <code>InputStream</code> of properties.
 400      *
 401      * @return <code>SchemaFactory</code> as determined by <code>keyName</code> value or <code>null</code> if there was an error.
 402      *
 403      * @throws IOException If IO error reading from <code>in</code>.
 404      */
 405     private SchemaFactory loadFromService(
 406             String schemaLanguage,
 407             String inputName,
 408             InputStream in)
 409             throws IOException {
 410 
 411             SchemaFactory schemaFactory = null;
 412             final Class[] stringClassArray = {"".getClass()};
 413             final Object[] schemaLanguageObjectArray = {schemaLanguage};
 414             final String isSchemaLanguageSupportedMethod = "isSchemaLanguageSupported";
 415 
 416             debugPrintln("Reading " + inputName);
 417 
 418             // read from InputStream until a match is found
 419             BufferedReader configFile = new BufferedReader(new InputStreamReader(in));
 420             String line = null;
 421             while ((line = configFile.readLine()) != null) {
 422                     // '#' is comment char
 423                     int comment = line.indexOf("#");
 424                     switch (comment) {
 425                             case -1: break; // no comment
 426                             case 0: line = ""; break; // entire line is a comment
 427                             default: line = line.substring(0, comment); break; // trim comment
 428                     }
 429 
 430                     // trim whitespace
 431                     line = line.trim();
 432 
 433                     // any content left on line?
 434                     if (line.length() == 0) {
 435                             continue;
 436                     }
 437 
 438                     // line content is now the name of the class
 439                     Class clazz = createClass(line);
 440                     if (clazz == null) {
 441                             continue;







 442                     }
 443 
 444                     // create an instance of the Class
 445                     try {
 446                             schemaFactory = (SchemaFactory) clazz.newInstance();
 447                     } catch (ClassCastException classCastExcpetion) {
 448                             schemaFactory = null;
 449                             continue;
 450                     } catch (InstantiationException instantiationException) {
 451                             schemaFactory = null;
 452                             continue;
 453                     } catch (IllegalAccessException illegalAccessException) {
 454                             schemaFactory = null;
 455                             continue;
 456                     }
 457 
 458                     // does this Class support desired Schema?
 459                     try {
 460                             Method isSchemaLanguageSupported = clazz.getMethod(isSchemaLanguageSupportedMethod, stringClassArray);
 461                             Boolean supported = (Boolean) isSchemaLanguageSupported.invoke(schemaFactory, schemaLanguageObjectArray);
 462                             if (supported.booleanValue()) {
 463                                     break;
 464                             }
 465                     } catch (NoSuchMethodException noSuchMethodException) {
 466 
 467                     } catch (IllegalAccessException illegalAccessException) {
 468 
 469                     } catch (InvocationTargetException invocationTargetException) {
 470 







 471                     }
 472                     schemaFactory = null;
 473             }
 474 
 475             // clean up
 476             configFile.close();
 477 
 478             // return new instance of SchemaFactory or null
 479             return schemaFactory;
 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 = SchemaFactoryFinder.class.getClassLoader();
 491                     //return (ClassLoader.getSystemResource( SERVICE_ID ));
 492                     return ss.getResourceAsURL(classLoader, 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 = SchemaFactory.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);
 549         URL it = ss.getResourceAsURL(loader, classnameAsResource);
 550         if (it != null) {
   1 /*
   2  * Copyright (c) 2003, 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.validation;
  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 SchemaFactory#newInstance(String)}.
  41  *
  42  * @author <a href="Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
  43  * @version $Revision: 1.8 $, $Date: 2010-11-01 04:36:13 $
  44  * @since 1.5
  45  */
  46 class SchemaFactoryFinder  {
  47 
  48     /** debug support code. */
  49     private static boolean debug = false;
  50     /**
  51      *<p> Take care of restrictions imposed by java security model </p>
  52      */
  53     private static final SecuritySupport ss = new SecuritySupport();
  54     private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal";
  55     /**
  56      * <p>Cache properties for performance.</p>
  57      */
  58     private static final Properties cacheProps = new Properties();
  59 
  60     /**
  61      * <p>First time requires initialization overhead.</p>
  62      */
  63     private static volatile boolean firstTime = true;
  64 
  65     static {
  66         // Use try/catch block to support applets
  67         try {
  68             debug = ss.getSystemProperty("jaxp.debug") != null;
  69         } catch (Exception unused) {
  70             debug = false;
  71         }
  72     }
  73 
  74     /**
  75      * <p>Conditional debug printing.</p>
  76      *
  77      * @param msg to print
  78      */


  95      *      to be used to load resource, {@link SchemaFactory}, and
  96      *      {@link SchemaFactoryLoader} implementations during
  97      *      the resolution process.
  98      *      If this parameter is null, the default system class loader
  99      *      will be used.
 100      */
 101     public SchemaFactoryFinder(ClassLoader loader) {
 102         this.classLoader = loader;
 103         if( debug ) {
 104             debugDisplayClassLoader();
 105         }
 106     }
 107 
 108     private void debugDisplayClassLoader() {
 109         try {
 110             if( classLoader == ss.getContextClassLoader() ) {
 111                 debugPrintln("using thread context class loader ("+classLoader+") for search");
 112                 return;
 113             }
 114         } catch( Throwable unused ) {
 115             // getContextClassLoader() undefined in JDK1.1
 116         }
 117 
 118         if( classLoader==ClassLoader.getSystemClassLoader() ) {
 119             debugPrintln("using system class loader ("+classLoader+") for search");
 120             return;
 121         }
 122 
 123         debugPrintln("using class loader ("+classLoader+") for search");
 124     }
 125 
 126     /**
 127      * <p>Creates a new {@link SchemaFactory} object for the specified
 128      * schema language.</p>
 129      *
 130      * @param schemaLanguage
 131      *      See {@link SchemaFactory Schema Language} table in <code>SchemaFactory</code>
 132      *      for the list of available schema languages.
 133      *
 134      * @return <code>null</code> if the callee fails to create one.
 135      *
 136      * @throws NullPointerException
 137      *      If the <code>schemaLanguage</code> parameter is null.
 138      * @throws SchemaFactoryConfigurationError
 139      *      If a configuration error is encountered.
 140      */
 141     public SchemaFactory newFactory(String schemaLanguage) {
 142         if(schemaLanguage==null) {
 143             throw new NullPointerException();
 144         }
 145         SchemaFactory f = _newFactory(schemaLanguage);
 146         if (f != null) {
 147             debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage);
 148         } else {
 149             debugPrintln("unable to find a factory for " + schemaLanguage);
 150         }
 151         return f;
 152     }
 153 
 154     /**
 155      * <p>Lookup a <code>SchemaFactory</code> for the given <code>schemaLanguage</code>.</p>
 156      *
 157      * @param schemaLanguage Schema language to lookup <code>SchemaFactory</code> for.
 158      *
 159      * @return <code>SchemaFactory</code> for the given <code>schemaLanguage</code>.
 160      */
 161     private SchemaFactory _newFactory(String schemaLanguage) {
 162         SchemaFactory sf;
 163 
 164         String propertyName = SERVICE_CLASS.getName() + ":" + schemaLanguage;


 167         try {
 168             debugPrintln("Looking up system property '"+propertyName+"'" );
 169             String r = ss.getSystemProperty(propertyName);
 170             if(r!=null) {
 171                 debugPrintln("The value is '"+r+"'");
 172                 sf = createInstance(r, true);
 173                 if(sf!=null)    return sf;
 174             } else
 175                 debugPrintln("The property is undefined.");
 176         } catch( Throwable t ) {
 177             if( debug ) {
 178                 debugPrintln("failed to look up system property '"+propertyName+"'" );
 179                 t.printStackTrace();
 180             }
 181         }
 182 
 183         String javah = ss.getSystemProperty( "java.home" );
 184         String configFile = javah + File.separator +
 185         "lib" + File.separator + "jaxp.properties";
 186 

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






 226         }
 227 
 228         // platform default
 229         if(schemaLanguage.equals("http://www.w3.org/2001/XMLSchema")) {
 230             debugPrintln("attempting to use the platform default XML Schema validator");
 231             return createInstance("com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory", true);
 232         }
 233 
 234         debugPrintln("all things were tried, but none was found. bailing out.");
 235         return null;
 236     }
 237 
 238     /** <p>Create class using appropriate ClassLoader.</p>
 239      *
 240      * @param className Name of class to create.
 241      * @return Created class or <code>null</code>.
 242      */
 243     private Class<?> createClass(String className) {
 244         Class<?> clazz;
 245         // make sure we have access to restricted packages
 246         boolean internal = false;
 247         if (System.getSecurityManager() != null) {
 248             if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
 249                 internal = true;
 250             }
 251         }
 252 
 253         try {
 254             if (classLoader != null && !internal) {
 255                 clazz = Class.forName(className, false, classLoader);
 256             } else {
 257                 clazz = Class.forName(className);
 258             }
 259         } catch (Throwable t) {
 260             if(debug)  {
 261                 t.printStackTrace();
 262             }
 263             return null;
 264         }
 265 
 266         return clazz;
 267     }
 268 
 269     /**
 270      * <p>Creates an instance of the specified and returns it.</p>
 271      *
 272      * @param className
 273      *      fully qualified class name to be instantiated.
 274      *
 275      * @return null
 276      *      if it fails. Error messages will be printed by this method.
 277      */
 278     SchemaFactory createInstance( String className ) {
 279         return createInstance( className, false );
 280     }
 281 
 282     SchemaFactory createInstance( String className, boolean useServicesMechanism ) {
 283         SchemaFactory schemaFactory = 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 SchemaFactory
 296         try {
 297                 if (!SchemaFactory.class.isAssignableFrom(clazz)) {
 298                     throw new ClassCastException(clazz.getName()
 299                                 + " cannot be cast to " + SchemaFactory.class);
 300                 }
 301                 if (!useServicesMechanism) {
 302                     schemaFactory = newInstanceNoServiceLoader(clazz);
 303                 }
 304                 if (schemaFactory == null) {
 305                     schemaFactory = (SchemaFactory) clazz.newInstance();
 306                 }
 307         } catch (ClassCastException classCastException) {
 308                 debugPrintln("could not instantiate " + clazz.getName());
 309                 if (debug) {
 310                         classCastException.printStackTrace();
 311                 }
 312                 return null;
 313         } catch (IllegalAccessException illegalAccessException) {
 314                 debugPrintln("could not instantiate " + clazz.getName());
 315                 if (debug) {
 316                         illegalAccessException.printStackTrace();
 317                 }
 318                 return null;
 319         } catch (InstantiationException instantiationException) {
 320                 debugPrintln("could not instantiate " + clazz.getName());
 321                 if (debug) {
 322                         instantiationException.printStackTrace();
 323                 }
 324                 return null;
 325         }
 326 
 327         return schemaFactory;
 328     }
 329 
 330     /**
 331      * Try to construct using newXMLSchemaFactoryNoServiceLoader
 332      *   method if available.
 333      */
 334     private static SchemaFactory newInstanceNoServiceLoader(
 335          Class<?> providerClass
 336     ) {
 337         // Retain maximum compatibility if no security manager.
 338         if (System.getSecurityManager() == null) {
 339             return null;
 340         }
 341         try {
 342             final Method creationMethod =
 343                 providerClass.getDeclaredMethod(
 344                     "newXMLSchemaFactoryNoServiceLoader"
 345                 );
 346             final int modifiers = creationMethod.getModifiers();










 347 
 348             // Do not call the method if it's not public static.
 349             if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {





























 350                 return null;
 351             }















































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







 371         }







 372     }





 373 
 374     // Call isSchemaLanguageSupported with initial context.
 375     private boolean isSchemaLanguageSupportedBy(final SchemaFactory factory,
 376             final String schemaLanguage,
 377             AccessControlContext acc) {
 378         return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
 379             public Boolean run() {
 380                 return factory.isSchemaLanguageSupported(schemaLanguage);
 381             }
 382         }, acc);







 383     }
 384 
 385     /**
 386      * Finds a service provider subclass of SchemaFactory that supports the
 387      * given schema language using the ServiceLoader.
 388      *
 389      * @param schemaLanguage The schema language for which we seek a factory.
 390      * @return A SchemaFactory supporting the specified schema language, or null
 391      *         if none is found.
 392      * @throws SchemaFactoryConfigurationError if a configuration error is found.
 393      */
 394     private SchemaFactory findServiceProvider(final String schemaLanguage) {
 395         assert schemaLanguage != null;
 396         // store current context.
 397         final AccessControlContext acc = AccessController.getContext();






 398         try {
 399             return AccessController.doPrivileged(new PrivilegedAction<SchemaFactory>() {
 400                 public SchemaFactory run() {
 401                     final ServiceLoader<SchemaFactory> loader =
 402                             ServiceLoader.load(SERVICE_CLASS);
 403                     for (SchemaFactory factory : loader) {
 404                         // restore initial context to call
 405                         // factory.isSchemaLanguageSupported
 406                         if (isSchemaLanguageSupportedBy(factory, schemaLanguage, acc)) {
 407                             return factory;

 408                         }







 409                     }
 410                     return null; // no factory found.




 411                 }
 412             });
 413         } catch (ServiceConfigurationError error) {
 414             throw new SchemaFactoryConfigurationError(
 415                     "Provider for " + SERVICE_CLASS + " cannot be created", error);
 416         }
 417     }
 418 
 419     private static final Class<SchemaFactory> SERVICE_CLASS = SchemaFactory.class;


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