1320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson/* 2320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one or more 3320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * contributor license agreements. See the NOTICE file distributed with 4320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * this work for additional information regarding copyright ownership. 5320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * The ASF licenses this file to You under the Apache License, Version 2.0 6320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * (the "License"); you may not use this file except in compliance with 7320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * the License. You may obtain a copy of the License at 8320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * 9320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 10320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * 11320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Unless required by applicable law or agreed to in writing, software 12320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 13320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * See the License for the specific language governing permissions and 15320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * limitations under the License. 16320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 17320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson// $Id: SchemaFactoryFinder.java 727367 2008-12-17 13:05:26Z mrglavas $ 18320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 19320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonpackage javax.xml.validation; 20320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 21320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.BufferedReader; 22320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.File; 23670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilsonimport java.io.FileInputStream; 24320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.IOException; 25320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.InputStream; 26320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.InputStreamReader; 27320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.net.URL; 28670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilsonimport java.util.Collections; 29320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.util.Enumeration; 30320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.util.Iterator; 31320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.util.Properties; 32320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport javax.xml.XMLConstants; 33a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilsonimport libcore.io.IoUtils; 34320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 35320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson/** 36320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Implementation of {@link SchemaFactory#newInstance(String)}. 37f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 38320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @author <a href="Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a> 39320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @version $Revision: 727367 $, $Date: 2008-12-17 05:05:26 -0800 (Wed, 17 Dec 2008) $ 40320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @since 1.5 41320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 42320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonfinal class SchemaFactoryFinder { 43f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 44320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** XML Schema language identifiers. */ 45320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static final String W3C_XML_SCHEMA10_NS_URI = "http://www.w3.org/XML/XMLSchema/v1.0"; 46f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes private static final String W3C_XML_SCHEMA11_NS_URI = "http://www.w3.org/XML/XMLSchema/v1.1"; 47320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 48320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** debug support code. */ 49320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static boolean debug = false; 50320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 51320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 52320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Cache properties for performance.</p> 53320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 54d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes private static Properties cacheProps = new Properties(); 55f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 56d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes /** 57d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes * <p>First time requires initialization overhead.</p> 58d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes */ 59d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes private static boolean firstTime = true; 60f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 61320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 62320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Default columns per line. 63320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 64320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static final int DEFAULT_LINE_LENGTH = 80; 65f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 66320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson static { 67670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson String val = System.getProperty("jaxp.debug"); 68670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson // Allow simply setting the prop to turn on debug 69670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson debug = val != null && (! "false".equals(val)); 70320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 71320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 72320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 73320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Conditional debug printing.</p> 74f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 75320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param msg to print 76320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 77320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static void debugPrintln(String msg) { 78320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) { 79320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson System.err.println("JAXP: " + msg); 80320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 81320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 82f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 83320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 84320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p><code>ClassLoader</code> to use to find <code>SchemaFactory</code>.</p> 85320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 86320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private final ClassLoader classLoader; 87f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 88320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 89320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Constructor that specifies <code>ClassLoader</code> to use 90320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * to find <code>SchemaFactory</code>.</p> 91f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 92320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param loader 93320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * to be used to load resource, {@link SchemaFactory}, and 94320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * {@link SchemaFactoryLoader} implementations during 95320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * the resolution process. 96320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * If this parameter is null, the default system class loader 97320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * will be used. 98320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 99320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson public SchemaFactoryFinder(ClassLoader loader) { 100320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson this.classLoader = loader; 101320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if( debug ) { 102320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson debugDisplayClassLoader(); 103320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 104320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 105f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 106320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private void debugDisplayClassLoader() { 107670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if (classLoader == Thread.currentThread().getContextClassLoader()) { 108670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson debugPrintln("using thread context class loader ("+classLoader+") for search"); 109670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson return; 110320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 111f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 112670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if (classLoader == ClassLoader.getSystemClassLoader()) { 113320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson debugPrintln("using system class loader ("+classLoader+") for search"); 114320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return; 115320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 116320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 117670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson debugPrintln("using class loader (" + classLoader + ") for search"); 118320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 119f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 120320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 121320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Creates a new {@link SchemaFactory} object for the specified 122320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * schema language.</p> 123f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 124320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param schemaLanguage 125320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * See {@link SchemaFactory Schema Language} table in <code>SchemaFactory</code> 126320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * for the list of available schema languages. 127f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 128320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @return <code>null</code> if the callee fails to create one. 129f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 130320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @throws NullPointerException 131320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * If the <tt>schemaLanguage</tt> parameter is null. 132320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 133320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson public SchemaFactory newFactory(String schemaLanguage) { 13486acc043d3334651ee26c65467d78d6cefedd397Kenny Root if (schemaLanguage == null) { 13586acc043d3334651ee26c65467d78d6cefedd397Kenny Root throw new NullPointerException("schemaLanguage == null"); 13686acc043d3334651ee26c65467d78d6cefedd397Kenny Root } 137320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson SchemaFactory f = _newFactory(schemaLanguage); 138320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) { 139320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (f != null) { 140320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage); 141320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } else { 142320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson debugPrintln("unable to find a factory for " + schemaLanguage); 143320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 144320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 145320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return f; 146320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 147f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 148320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 149320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Lookup a <code>SchemaFactory</code> for the given <code>schemaLanguage</code>.</p> 150f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 151320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param schemaLanguage Schema language to lookup <code>SchemaFactory</code> for. 152f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 153320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @return <code>SchemaFactory</code> for the given <code>schemaLanguage</code>. 154320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 155320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private SchemaFactory _newFactory(String schemaLanguage) { 156320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson SchemaFactory sf; 157320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson String propertyName = SERVICE_CLASS.getName() + ":" + schemaLanguage; 158f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 159320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // system property look up 160320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 161320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln("Looking up system property '"+propertyName+"'" ); 162670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson String r = System.getProperty(propertyName); 163320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (r != null && r.length() > 0) { 164320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln("The value is '"+r+"'"); 165320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson sf = createInstance(r); 166320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if(sf!=null) return sf; 167f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes } 168320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson else if (debug) { 169320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson debugPrintln("The property is undefined."); 170320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 171320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 172320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // The VM ran out of memory or there was some other serious problem. Re-throw. 173320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson catch (VirtualMachineError vme) { 174320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson throw vme; 175320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 176320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // ThreadDeath should always be re-thrown 177320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson catch (ThreadDeath td) { 178320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson throw td; 179320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 180320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson catch (Throwable t) { 181320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if( debug ) { 182320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson debugPrintln("failed to look up system property '"+propertyName+"'" ); 183320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson t.printStackTrace(); 184320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 185320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 186320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 187670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson String javah = System.getProperty("java.home"); 188320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson String configFile = javah + File.separator + 189320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson "lib" + File.separator + "jaxp.properties"; 190320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 191320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson String factoryClassName = null ; 192320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 193320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // try to read from $java.home/lib/jaxp.properties 194320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 195320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if(firstTime){ 196320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson synchronized(cacheProps){ 197320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if(firstTime){ 198320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson File f=new File( configFile ); 199320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson firstTime = false; 200670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if(f.exists()){ 201f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (debug) debugPrintln("Read properties file " + f); 202670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson cacheProps.load(new FileInputStream(f)); 203320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 204320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 205320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 206320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 207f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes factoryClassName = cacheProps.getProperty(propertyName); 208f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties"); 209320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 210320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (factoryClassName != null) { 211320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson sf = createInstance(factoryClassName); 212320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if(sf != null){ 213320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return sf; 214320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 215320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 216320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } catch (Exception ex) { 217320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) { 218320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson ex.printStackTrace(); 219f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes } 220320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 221320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 222320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // try META-INF/services files 223670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson for (URL resource : createServiceFileIterator()) { 224320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln("looking into " + resource); 225320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 226670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson sf = loadFromServicesFile(schemaLanguage,resource.toExternalForm(), 227670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson resource.openStream()); 228320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if(sf!=null) return sf; 229320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } catch(IOException e) { 230320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if( debug ) { 231320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson debugPrintln("failed to read "+resource); 232320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson e.printStackTrace(); 233320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 234320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 235320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 236f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 237320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // platform defaults 238320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI) || schemaLanguage.equals(W3C_XML_SCHEMA10_NS_URI)) { 239320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln("attempting to use the platform default XML Schema 1.0 validator"); 240320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return createInstance("org.apache.xerces.jaxp.validation.XMLSchemaFactory"); 241320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 242320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson else if (schemaLanguage.equals(W3C_XML_SCHEMA11_NS_URI)) { 243320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln("attempting to use the platform default XML Schema 1.1 validator"); 244320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return createInstance("org.apache.xerces.jaxp.validation.XMLSchema11Factory"); 245320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 246f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 247320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln("all things were tried, but none was found. bailing out."); 248320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return null; 249320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 250f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 251320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 252320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Creates an instance of the specified and returns it.</p> 253f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 254320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param className 255320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * fully qualified class name to be instantiated. 256f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 257320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @return null 258f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * if it fails. Error messages will be printed by this method. 259320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 260320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson SchemaFactory createInstance( String className ) { 261320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 262670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if (debug) debugPrintln("instantiating "+className); 263320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson Class clazz; 264320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if( classLoader!=null ) 265320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson clazz = classLoader.loadClass(className); 266320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson else 267320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson clazz = Class.forName(className); 268320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if(debug) debugPrintln("loaded it from "+which(clazz)); 269320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson Object o = clazz.newInstance(); 270f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 271320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if( o instanceof SchemaFactory ) 272320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return (SchemaFactory)o; 273f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 274320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln(className+" is not assignable to "+SERVICE_CLASS.getName()); 275320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 276320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // The VM ran out of memory or there was some other serious problem. Re-throw. 277320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson catch (VirtualMachineError vme) { 278320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson throw vme; 279320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 280320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // ThreadDeath should always be re-thrown 281320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson catch (ThreadDeath td) { 282320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson throw td; 283320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 284320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson catch (Throwable t) { 285670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson debugPrintln("failed to instantiate "+className); 286320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if(debug) t.printStackTrace(); 287320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 288320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return null; 289320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 290f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 291320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 292f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * Returns an {@link Iterator} that enumerates all 293320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * the META-INF/services files that we care. 294320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 295670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson private Iterable<URL> createServiceFileIterator() { 296320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (classLoader == null) { 297670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson ClassLoader classLoader = SchemaFactoryFinder.class.getClassLoader(); 298670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson return Collections.singleton(classLoader.getResource(SERVICE_ID)); 299320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } else { 300320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 301670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson Enumeration<URL> e = classLoader.getResources(SERVICE_ID); 302670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if (debug && !e.hasMoreElements()) { 303320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson debugPrintln("no "+SERVICE_ID+" file was found"); 304320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 305f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 306320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // wrap it into an Iterator. 307670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson return Collections.list(e); 308320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } catch (IOException e) { 309320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) { 310320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson debugPrintln("failed to enumerate resources "+SERVICE_ID); 311320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson e.printStackTrace(); 312320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 313670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson return Collections.emptySet(); 314320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 315320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 316320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 317f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 318320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** Searches for a SchemaFactory for a given schema language in a META-INF/services file. */ 319320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private SchemaFactory loadFromServicesFile(String schemaLanguage, String resourceName, InputStream in) { 320320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 321320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln("Reading "+resourceName ); 322f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 323320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // Read the service provider name in UTF-8 as specified in 324320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // the jar spec. Unfortunately this fails in Microsoft 325320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // VJ++, which does not implement the UTF-8 326320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // encoding. Theoretically, we should simply let it fail in 327320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // that case, since the JVM is obviously broken if it 328320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // doesn't support such a basic standard. But since there 329320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // are still some users attempting to use VJ++ for 330320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // development, we have dropped in a fallback which makes a 331320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // second attempt using the platform's default encoding. In 332320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // VJ++ this is apparently ASCII, which is a subset of 333320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // UTF-8... and since the strings we'll be reading here are 334320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // also primarily limited to the 7-bit ASCII range (at 335320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // least, in English versions), this should work well 336320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // enough to keep us on the air until we're ready to 337320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // officially decommit from VJ++. [Edited comment from 338320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // jkesselm] 339320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson BufferedReader rd; 340320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 341320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson rd = new BufferedReader(new InputStreamReader(in, "UTF-8"), DEFAULT_LINE_LENGTH); 342320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } catch (java.io.UnsupportedEncodingException e) { 343320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson rd = new BufferedReader(new InputStreamReader(in), DEFAULT_LINE_LENGTH); 344320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 345f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 346320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson String factoryClassName = null; 347320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson SchemaFactory resultFactory = null; 348320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // See spec for provider-configuration files: http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Provider%20Configuration%20File 349320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson while (true) { 350320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 351f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes factoryClassName = rd.readLine(); 352320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } catch (IOException x) { 353320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // No provider found 354320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson break; 355320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 356320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (factoryClassName != null) { 357320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // Ignore comments in the provider-configuration file 358320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson int hashIndex = factoryClassName.indexOf('#'); 359320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (hashIndex != -1) { 360320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson factoryClassName = factoryClassName.substring(0, hashIndex); 361320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 362f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 363320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // Ignore leading and trailing whitespace 364320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson factoryClassName = factoryClassName.trim(); 365f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 366320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // If there's no text left or if this was a blank line, go to the next one. 367320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (factoryClassName.length() == 0) { 368320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson continue; 369320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 370f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 371320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 372320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // Found the right SchemaFactory if its isSchemaLanguageSupported(schemaLanguage) method returns true. 373320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson SchemaFactory foundFactory = (SchemaFactory) createInstance(factoryClassName); 374320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (foundFactory.isSchemaLanguageSupported(schemaLanguage)) { 375320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson resultFactory = foundFactory; 376320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson break; 377320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 378320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 379670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson catch (Exception ignored) {} 380320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 381320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson else { 382320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson break; 383320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 384320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 385f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 386a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson IoUtils.closeQuietly(rd); 387f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 388320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return resultFactory; 389320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 390f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 391320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static final Class SERVICE_CLASS = SchemaFactory.class; 392320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName(); 393f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 394320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static String which( Class clazz ) { 395320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return which( clazz.getName(), clazz.getClassLoader() ); 396320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 397320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 398320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 399320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Search the specified classloader for the given classname.</p> 400320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * 401320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param classname the fully qualified name of the class to search for 402320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param loader the classloader to search 403f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 404320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @return the source location of the resource, or null if it wasn't found 405320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 406320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static String which(String classname, ClassLoader loader) { 407320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson String classnameAsResource = classname.replace('.', '/') + ".class"; 408f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 409670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if (loader == null) loader = ClassLoader.getSystemClassLoader(); 410f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 411670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson URL it = loader.getResource(classnameAsResource); 412670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson return it != null ? it.toString() : null; 413320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 414320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson} 415