diff -r fd16c54261b3 -r 7f561c08de6b jaxp/src/share/classes/javax/xml/validation/SchemaFactoryFinder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/share/classes/javax/xml/validation/SchemaFactoryFinder.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,538 @@ +/* + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.xml.validation; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Properties; + +/** + * Implementation of {@link SchemaFactory#newInstance(String)}. + * + * @author Kohsuke Kawaguchi + * @since 1.5 + */ +class SchemaFactoryFinder { + + /** debug support code. */ + private static boolean debug = false; + /** + *
Take care of restrictions imposed by java security model
+ */ + private static SecuritySupport ss = new SecuritySupport(); + /** + *Cache properties for performance.
+ */ + private static Properties cacheProps = new Properties(); + + /** + *First time requires initialization overhead.
+ */ + private static boolean firstTime = true; + + static { + // Use try/catch block to support applets + try { + debug = ss.getSystemProperty("jaxp.debug") != null; + } catch (Exception _) { + debug = false; + } + } + + /** + *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();
+ SchemaFactory f = _newFactory(schemaLanguage);
+ if (f != null) {
+ debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage);
+ } else {
+ debugPrintln("unable to find a factory for " + schemaLanguage);
+ }
+ return f;
+ }
+
+ /**
+ * 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 {
+ debugPrintln("Looking up system property '"+propertyName+"'" );
+ String r = ss.getSystemProperty(propertyName);
+ if(r!=null) {
+ debugPrintln("The value is '"+r+"'");
+ sf = createInstance(r);
+ if(sf!=null) return sf;
+ } else
+ debugPrintln("The property is undefined.");
+ } catch( Throwable t ) {
+ if( debug ) {
+ debugPrintln("failed to look up system property '"+propertyName+"'" );
+ t.printStackTrace();
+ }
+ }
+
+ String javah = ss.getSystemProperty( "java.home" );
+ String configFile = javah + File.separator +
+ "lib" + File.separator + "jaxp.properties";
+
+ String factoryClassName = null ;
+
+ // try to read from $java.home/lib/jaxp.properties
+ try {
+ if(firstTime){
+ synchronized(cacheProps){
+ if(firstTime){
+ File f=new File( configFile );
+ firstTime = false;
+ if(ss.doesFileExist(f)){
+ debugPrintln("Read properties file " + f);
+ cacheProps.load(ss.getFileInputStream(f));
+ }
+ }
+ }
+ }
+ factoryClassName = cacheProps.getProperty(propertyName);
+ 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 to read from $java.home/lib/jaxp.properties
+ try {
+ String javah = ss.getSystemProperty( "java.home" );
+ String configFile = javah + File.separator +
+ "lib" + File.separator + "jaxp.properties";
+ File f = new File( configFile );
+ if( ss.doesFileExist(f)) {
+ sf = loadFromProperty(
+ propertyName,f.getAbsolutePath(), new FileInputStream(f));
+ if(sf!=null) return sf;
+ } else {
+ debugPrintln("Tried to read "+ f.getAbsolutePath()+", but it doesn't exist.");
+ }
+ } catch(Throwable e) {
+ if( debug ) {
+ debugPrintln("failed to read $java.home/lib/jaxp.properties");
+ e.printStackTrace();
+ }
+ }
+ */
+
+ // try META-INF/services files
+ Iterator sitr = createServiceFileIterator();
+ while(sitr.hasNext()) {
+ URL resource = (URL)sitr.next();
+ debugPrintln("looking into " + resource);
+ try {
+ sf = loadFromService(schemaLanguage,resource.toExternalForm(),
+ ss.getURLInputStream(resource));
+ if(sf!=null) return sf;
+ } catch(IOException e) {
+ if( debug ) {
+ debugPrintln("failed to read "+resource);
+ e.printStackTrace();
+ }
+ }
+ }
+
+ // platform default
+ if(schemaLanguage.equals("http://www.w3.org/2001/XMLSchema")) {
+ debugPrintln("attempting to use the platform default XML Schema validator");
+ return createInstance("com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory");
+ }
+
+ debugPrintln("all things were tried, but none was found. bailing out.");
+ return null;
+ }
+
+ /** Create class using appropriate ClassLoader.
+ * + * @param className Name of class to create. + * @return Created class ornull
.
+ */
+ private Class createClass(String className) {
+ Class clazz;
+
+ // use approprite ClassLoader
+ try {
+ if (classLoader != null) {
+ clazz = classLoader.loadClass(className);
+ } else {
+ clazz = Class.forName(className);
+ }
+ } catch (Throwable t) {
+ if(debug) t.printStackTrace();
+ return null;
+ }
+
+ return clazz;
+ }
+
+ /**
+ * Creates an instance of the specified and returns it.
+ * + * @param className + * fully qualified class name to be instanciated. + * + * @return null + * if it fails. Error messages will be printed by this method. + */ + SchemaFactory createInstance( String className ) { + SchemaFactory schemaFactory = null; + + debugPrintln("createInstance(" + className + ")"); + + // get Class from className + Class clazz = createClass(className); + if (clazz == null) { + debugPrintln("failed to getClass(" + className + ")"); + return null; + } + debugPrintln("loaded " + className + " from " + which(clazz)); + + // instantiate Class as a SchemaFactory + try { + schemaFactory = (SchemaFactory) clazz.newInstance(); + } catch (ClassCastException classCastException) { + debugPrintln("could not instantiate " + clazz.getName()); + if (debug) { + classCastException.printStackTrace(); + } + return null; + } catch (IllegalAccessException illegalAccessException) { + debugPrintln("could not instantiate " + clazz.getName()); + if (debug) { + illegalAccessException.printStackTrace(); + } + return null; + } catch (InstantiationException instantiationException) { + debugPrintln("could not instantiate " + clazz.getName()); + if (debug) { + instantiationException.printStackTrace(); + } + return null; + } + + return schemaFactory; + } + + /** 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(); + } + + protected abstract Object value(); + } + + /** + * Looks up a value in a property file + * while producing all sorts of debug messages. + * + * @return null + * if there was an error. + */ + private SchemaFactory 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); + } else { + debugPrintln(keyName+" is not in the property file"); + return null; + } + } + + /** + *Look up a value in a property file.
+ * + *Set debug
to true
to trace property evaluation.
InputStream
.
+ * @param in InputStream
of properties.
+ *
+ * @return SchemaFactory
as determined by keyName
value or null
if there was an error.
+ *
+ * @throws IOException If IO error reading from in
.
+ */
+ private SchemaFactory loadFromService(
+ String schemaLanguage,
+ String inputName,
+ InputStream in)
+ throws IOException {
+
+ SchemaFactory schemaFactory = null;
+ final Class[] stringClassArray = {"".getClass()};
+ final Object[] schemaLanguageObjectArray = {schemaLanguage};
+ final String isSchemaLanguageSupportedMethod = "isSchemaLanguageSupported";
+
+ 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
+ try {
+ schemaFactory = (SchemaFactory) clazz.newInstance();
+ } catch (ClassCastException classCastExcpetion) {
+ schemaFactory = null;
+ continue;
+ } catch (InstantiationException instantiationException) {
+ schemaFactory = null;
+ continue;
+ } catch (IllegalAccessException illegalAccessException) {
+ schemaFactory = null;
+ continue;
+ }
+
+ // does this Class support desired Schema?
+ try {
+ Method isSchemaLanguageSupported = clazz.getMethod(isSchemaLanguageSupportedMethod, stringClassArray);
+ Boolean supported = (Boolean) isSchemaLanguageSupported.invoke(schemaFactory, schemaLanguageObjectArray);
+ if (supported.booleanValue()) {
+ break;
+ }
+ } catch (NoSuchMethodException noSuchMethodException) {
+
+ } catch (IllegalAccessException illegalAccessException) {
+
+ } catch (InvocationTargetException invocationTargetException) {
+
+ }
+ schemaFactory = null;
+ }
+
+ // clean up
+ configFile.close();
+
+ // return new instance of SchemaFactory or null
+ return schemaFactory;
+ }
+
+ /**
+ * Returns an {@link Iterator} that enumerates all
+ * the META-INF/services files that we care.
+ */
+ private Iterator createServiceFileIterator() {
+ if (classLoader == null) {
+ return new SingleIterator() {
+ protected Object value() {
+ ClassLoader classLoader = SchemaFactoryFinder.class.getClassLoader();
+ //return (ClassLoader.getSystemResource( SERVICE_ID ));
+ return ss.getResourceAsURL(classLoader, SERVICE_ID);
+ }
+ };
+ } else {
+ 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();
+ }
+
+ public boolean hasNext() {
+ return e.hasMoreElements();
+ }
+
+ 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
+ }
+ }
+ }
+
+ private static final Class SERVICE_CLASS = SchemaFactory.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() );
+ }
+
+ /**
+ * Search 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); + URL it = ss.getResourceAsURL(loader, classnameAsResource); + if (it != null) { + return it.toString(); + } else { + return null; + } + } +}