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 18320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson// $Id: FactoryFinder.java 670432 2008-06-23 02:02:08Z mrglavas $ 19320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 20320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonpackage javax.xml.datatype; 21320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 22320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.BufferedReader; 23320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.File; 24670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilsonimport java.io.FileInputStream; 25320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.IOException; 26320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.InputStream; 27320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.InputStreamReader; 28320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.net.URL; 29320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.util.Properties; 30a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilsonimport libcore.io.IoUtils; 31320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 32320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson/** 33670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson * <p>Implement pluggable data types.</p> 34f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 35320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>This class is duplicated for each JAXP subpackage so keep it in 36320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * sync. It is package private for secure class loading.</p> 37320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * 38320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a> 39320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @version $Revision: 670432 $, $Date: 2008-06-22 19:02:08 -0700 (Sun, 22 Jun 2008) $ 40320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @since 1.5 41320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 42320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonfinal class FactoryFinder { 43f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 44670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson /** <p>Name of class to display in output messages.</p> */ 45d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes private static final String CLASS_NAME = "javax.xml.datatype.FactoryFinder"; 46f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 47670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson /** <p>Debug flag to trace loading process.</p> */ 48320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static boolean debug = false; 49f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 50670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson /** <p>Cache properties for performance.</p> */ 51d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes private static Properties cacheProps = new Properties(); 52f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 53670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson /** <p>First time requires initialization overhead.</p> */ 54d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes private static boolean firstTime = true; 55f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 56670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson /** Default columns per line. */ 57320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static final int DEFAULT_LINE_LENGTH = 80; 58f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 59d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes /** 60d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes * <p>Check to see if debugging enabled by property.</p> 61f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 62d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes * <p>Use try/catch block to support applets, which throws 63320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * SecurityException out of this code.</p> 64d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes */ 65320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson static { 66670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson String val = System.getProperty("jaxp.debug"); 67670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson // Allow simply setting the prop to turn on debug 68670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson debug = val != null && (! "false".equals(val)); 69320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 70f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 71320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private FactoryFinder() {} 72320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 73d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes /** 74d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes * <p>Output debugging messages.</p> 75f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 76d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes * @param msg <code>String</code> to print to <code>stderr</code>. 77d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes */ 78320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static void debugPrintln(String msg) { 79320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) { 80320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson System.err.println( 81d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes CLASS_NAME 82d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes + ":" 83d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes + msg); 84320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 85320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 86320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 87320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 88320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Find the appropriate <code>ClassLoader</code> to use.</p> 89f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 90670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson * <p>The context ClassLoader is preferred.</p> 91f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 92320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @return <code>ClassLoader</code> to use. 93f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 94f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * @throws ConfigurationError If a valid <code>ClassLoader</code> cannot be identified. 95320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 96670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson private static ClassLoader findClassLoader() throws ConfigurationError { 97320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // Figure out which ClassLoader to use for loading the provider 98320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // class. If there is a Context ClassLoader then use it. 99320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 100670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 101320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 102320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln( 103320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson "Using context class loader: " 104320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson + classLoader); 105320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 106320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (classLoader == null) { 107320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // if we have no Context ClassLoader 108320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // so use the current ClassLoader 109320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson classLoader = FactoryFinder.class.getClassLoader(); 110320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln( 111320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson "Using the class loader of FactoryFinder: " 112f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes + classLoader); 113320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 114f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 115320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return classLoader; 116320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 117320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 118320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 119320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Create an instance of a class using the specified ClassLoader.</p> 120f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 121320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param className Name of class to create. 122320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param classLoader ClassLoader to use to create named class. 123f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 124320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @return New instance of specified class created using the specified ClassLoader. 125f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 126320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @throws ConfigurationError If class could not be created. 127320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 128320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson static Object newInstance( 129d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes String className, 130320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson ClassLoader classLoader) 131320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson throws ConfigurationError { 132f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 133320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 134320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson Class spiClass; 135320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (classLoader == null) { 136320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson spiClass = Class.forName(className); 137320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } else { 138320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson spiClass = classLoader.loadClass(className); 139320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 140f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 141320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) { 142d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes debugPrintln("Loaded " + className + " from " + which(spiClass)); 143320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 144f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 145320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return spiClass.newInstance(); 146320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } catch (ClassNotFoundException x) { 147320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson throw new ConfigurationError( 148320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson "Provider " + className + " not found", x); 149320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } catch (Exception x) { 150320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson throw new ConfigurationError( 151670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson "Provider " + className + " could not be instantiated: " + x, x); 152320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 153320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 154320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 155320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 156320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Finds the implementation Class object in the specified order. Main 157320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * entry point. 158320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Package private so this code can be shared. 159320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * 160320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param factoryId Name of the factory to find, same as a property name 161320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param fallbackClassName Implementation class name, if nothing else is found. Use null to mean no fallback. 162320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * 163320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @return Class Object of factory, never null 164f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 165320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @throws ConfigurationError If Class cannot be found. 166320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 167670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson static Object find(String factoryId, String fallbackClassName) throws ConfigurationError { 168f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 169320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson ClassLoader classLoader = findClassLoader(); 170320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 171320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // Use the system property first 172670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson String systemProp = System.getProperty(factoryId); 173670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if (systemProp != null && systemProp.length() > 0) { 174670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if (debug) debugPrintln("found " + systemProp + " in the system property " + factoryId); 175670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson return newInstance(systemProp, classLoader); 176320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 177320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 178320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // try to read from $java.home/lib/jaxp.properties 179320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 180670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson String javah = System.getProperty("java.home"); 181320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties"; 182d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes String factoryClassName = null; 183d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes if (firstTime) { 184d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes synchronized (cacheProps) { 185d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes if (firstTime) { 186d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes File f = new File(configFile); 187d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes firstTime = false; 188670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if (f.exists()) { 189d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes if (debug) debugPrintln("Read properties file " + f); 190670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson cacheProps.load(new FileInputStream(f)); 191d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes } 192d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes } 193d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes } 194d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes } 195d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes factoryClassName = cacheProps.getProperty(factoryId); 196f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties"); 197f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 198d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes if (factoryClassName != null) { 199d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes return newInstance(factoryClassName, classLoader); 200d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes } 201320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } catch (Exception ex) { 202320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) { 203d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes ex.printStackTrace(); 204f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes } 205320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 206f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 207320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // Try Jar Service Provider Mechanism 208320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson Object provider = findJarServiceProvider(factoryId); 209320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (provider != null) { 210320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return provider; 211320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 212320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 213320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (fallbackClassName == null) { 214320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson throw new ConfigurationError( 215320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson "Provider for " + factoryId + " cannot be found", null); 216320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 217320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 218320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln("loaded from fallback value: " + fallbackClassName); 219320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return newInstance(fallbackClassName, classLoader); 220320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 221320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 222320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /* 223320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Try to find provider using Jar Service Provider Mechanism 224320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * 225320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @return instance of provider class if found or null 226320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 227670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson private static Object findJarServiceProvider(String factoryId) throws ConfigurationError { 228320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson String serviceId = "META-INF/services/" + factoryId; 229320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson InputStream is = null; 230320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 231320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // First try the Context ClassLoader 232670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson ClassLoader cl = Thread.currentThread().getContextClassLoader(); 233320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (cl != null) { 234670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson is = cl.getResourceAsStream(serviceId); 235670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson } 236320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 237670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if (is == null) { 238320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson cl = FactoryFinder.class.getClassLoader(); 239670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson is = cl.getResourceAsStream(serviceId); 240320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 241320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 242320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (is == null) { 243320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // No provider found 244320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return null; 245320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 246320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 247670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson if (debug) debugPrintln("found jar resource=" + serviceId + " using ClassLoader: " + cl); 248320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 249320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson BufferedReader rd; 250320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 251320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH); 252320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } catch (java.io.UnsupportedEncodingException e) { 253320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH); 254320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 255f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 256320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson String factoryClassName = null; 257320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 258320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // XXX Does not handle all possible input as specified by the 259320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // Jar Service Provider specification 260320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson factoryClassName = rd.readLine(); 261a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson } catch (IOException x) { 262320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // No provider found 263320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return null; 264a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson } finally { 265a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson IoUtils.closeQuietly(rd); 266320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 267320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 268320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (factoryClassName != null && 269320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson ! "".equals(factoryClassName)) { 270320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) debugPrintln("found in resource, value=" 271320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson + factoryClassName); 272320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 273320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return newInstance(factoryClassName, cl); 274320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 275320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 276320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // No provider found 277320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return null; 278320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 279f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 280d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes /** 281d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes * <p>Configuration Error.</p> 282d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes */ 283320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson static class ConfigurationError extends Error { 284f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 285320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static final long serialVersionUID = -3644413026244211347L; 286f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 287d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes /** 288d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes * <p>Exception that caused the error.</p> 289d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes */ 290320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private Exception exception; 291320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 292320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 293320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Construct a new instance with the specified detail string and 294320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * exception.</p> 295f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 296320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param msg Detail message for this error. 297320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @param x Exception that caused the error. 298320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 299320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson ConfigurationError(String msg, Exception x) { 300320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson super(msg); 301320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson this.exception = x; 302320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 303320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 304d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes /** 305d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes * <p>Get the Exception that caused the error.</p> 306f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 307d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes * @return Exception that caused the error. 308d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes */ 309320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson Exception getException() { 310320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return exception; 311320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 312320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 313320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 314320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson /** 315320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Returns the location where the given Class is loaded from. 316320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */ 317320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson private static String which(Class clazz) { 318320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson try { 319320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson String classnameAsResource = clazz.getName().replace('.', '/') + ".class"; 320f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 321320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson ClassLoader loader = clazz.getClassLoader(); 322f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 323320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson URL it; 324f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 325320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (loader != null) { 326d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes it = loader.getResource(classnameAsResource); 327320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } else { 328d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes it = ClassLoader.getSystemResource(classnameAsResource); 329f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes } 330f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 331320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (it != null) { 332d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes return it.toString(); 333f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes } 334320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 335320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // The VM ran out of memory or there was some other serious problem. Re-throw. 336320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson catch (VirtualMachineError vme) { 337320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson throw vme; 338320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 339320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // ThreadDeath should always be re-thrown 340320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson catch (ThreadDeath td) { 341320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson throw td; 342320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 343320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson catch (Throwable t) { 344320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson // work defensively. 345320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson if (debug) { 346d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes t.printStackTrace(); 347f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes } 348320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 349320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson return "unknown location"; 350320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 351320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson} 352