/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // $Id: SchemaFactoryFinder.java 727367 2008-12-17 13:05:26Z mrglavas $ package javax.xml.validation; 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.net.URL; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.Properties; import javax.xml.XMLConstants; import libcore.io.IoUtils; /** * Implementation of {@link SchemaFactory#newInstance(String)}. * * @author Kohsuke Kawaguchi * @version $Revision: 727367 $, $Date: 2008-12-17 05:05:26 -0800 (Wed, 17 Dec 2008) $ * @since 1.5 */ final class SchemaFactoryFinder { /** XML Schema language identifiers. */ private static final String W3C_XML_SCHEMA10_NS_URI = "http://www.w3.org/XML/XMLSchema/v1.0"; private static final String W3C_XML_SCHEMA11_NS_URI = "http://www.w3.org/XML/XMLSchema/v1.1"; /** debug support code. */ private static boolean debug = false; /** *
Cache properties for performance. Use a static class to avoid double-checked * locking.
*/ private static class CacheHolder { private static Properties cacheProps = new Properties(); static { String javah = System.getProperty("java.home"); String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties"; File f = new File(configFile); if (f.exists()) { if (debug) debugPrintln("Read properties file " + f); try { cacheProps.load(new FileInputStream(f)); } catch (Exception ex) { if (debug) { ex.printStackTrace(); } } } } } /** * Default columns per line. */ private static final int DEFAULT_LINE_LENGTH = 80; static { String val = System.getProperty("jaxp.debug"); // Allow simply setting the prop to turn on debug debug = val != null && (! "false".equals(val)); } /** *Conditional debug printing.
* * @param msg to print */ private static void debugPrintln(String msg) { if (debug) { System.err.println("JAXP: " + msg); } } /** *ClassLoader
to use to find SchemaFactory
.
Constructor that specifies ClassLoader
to use
* to find SchemaFactory
.
Creates a new {@link SchemaFactory} object for the specified * schema language.
* * @param schemaLanguage * See {@link SchemaFactory Schema Language} table inSchemaFactory
* for the list of available schema languages.
*
* @return null
if the callee fails to create one.
*
* @throws NullPointerException
* If the schemaLanguage parameter is null.
*/
public SchemaFactory newFactory(String schemaLanguage) {
if (schemaLanguage == null) {
throw new NullPointerException("schemaLanguage == null");
}
SchemaFactory f = _newFactory(schemaLanguage);
if (debug) {
if (f != null) {
debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage);
} else {
debugPrintln("unable to find a factory for " + schemaLanguage);
}
}
return f;
}
/**
* Lookup a SchemaFactory
for the given schemaLanguage
.
SchemaFactory
for.
*
* @return SchemaFactory
for the given schemaLanguage
.
*/
private SchemaFactory _newFactory(String schemaLanguage) {
SchemaFactory sf;
String propertyName = SERVICE_CLASS.getName() + ":" + schemaLanguage;
// system property look up
try {
if (debug) debugPrintln("Looking up system property '"+propertyName+"'" );
String r = System.getProperty(propertyName);
if (r != null && r.length() > 0) {
if (debug) debugPrintln("The value is '"+r+"'");
sf = createInstance(r);
if(sf!=null) return sf;
}
else if (debug) {
debugPrintln("The property is undefined.");
}
}
// The VM ran out of memory or there was some other serious problem. Re-throw.
catch (VirtualMachineError vme) {
throw vme;
}
// ThreadDeath should always be re-thrown
catch (ThreadDeath td) {
throw td;
}
catch (Throwable t) {
if( debug ) {
debugPrintln("failed to look up system property '"+propertyName+"'" );
t.printStackTrace();
}
}
// try to read from $java.home/lib/jaxp.properties
try {
String factoryClassName = CacheHolder.cacheProps.getProperty(propertyName);
if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
if (factoryClassName != null) {
sf = createInstance(factoryClassName);
if(sf != null){
return sf;
}
}
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
}
}
// try META-INF/services files
for (URL resource : createServiceFileIterator()) {
if (debug) debugPrintln("looking into " + resource);
try {
sf = loadFromServicesFile(schemaLanguage,resource.toExternalForm(),
resource.openStream());
if(sf!=null) return sf;
} catch(IOException e) {
if( debug ) {
debugPrintln("failed to read "+resource);
e.printStackTrace();
}
}
}
// platform defaults
if (schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI) || schemaLanguage.equals(W3C_XML_SCHEMA10_NS_URI)) {
if (debug) debugPrintln("attempting to use the platform default XML Schema 1.0 validator");
return createInstance("org.apache.xerces.jaxp.validation.XMLSchemaFactory");
}
else if (schemaLanguage.equals(W3C_XML_SCHEMA11_NS_URI)) {
if (debug) debugPrintln("attempting to use the platform default XML Schema 1.1 validator");
return createInstance("org.apache.xerces.jaxp.validation.XMLSchema11Factory");
}
if (debug) debugPrintln("all things were tried, but none was found. bailing out.");
return null;
}
/**
* Creates an instance of the specified and returns it.
* * @param className * fully qualified class name to be instantiated. * * @return null * if it fails. Error messages will be printed by this method. */ SchemaFactory createInstance( String className ) { try { if (debug) debugPrintln("instantiating "+className); Class clazz; if( classLoader!=null ) clazz = classLoader.loadClass(className); else clazz = Class.forName(className); if(debug) debugPrintln("loaded it from "+which(clazz)); Object o = clazz.newInstance(); if( o instanceof SchemaFactory ) return (SchemaFactory)o; if (debug) debugPrintln(className+" is not assignable to "+SERVICE_CLASS.getName()); } // The VM ran out of memory or there was some other serious problem. Re-throw. catch (VirtualMachineError vme) { throw vme; } // ThreadDeath should always be re-thrown catch (ThreadDeath td) { throw td; } catch (Throwable t) { debugPrintln("failed to instantiate "+className); if(debug) t.printStackTrace(); } return null; } /** * Returns an {@link Iterator} that enumerates all * the META-INF/services files that we care. */ private IterableSearch the specified classloader for the given classname.
* * @param classname the fully qualified name of the class to search for * @param loader the classloader to search * * @return the source location of the resource, or null if it wasn't found */ private static String which(String classname, ClassLoader loader) { String classnameAsResource = classname.replace('.', '/') + ".class"; if (loader == null) loader = ClassLoader.getSystemClassLoader(); URL it = loader.getResource(classnameAsResource); return it != null ? it.toString() : null; } }