1 /* 2 * Copyright (c) 2004, 2006, 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.datatype; 27 28 import java.io.File; 29 import java.security.AccessController; 30 import java.security.PrivilegedAction; 31 import java.util.Properties; 32 import java.util.ServiceConfigurationError; 33 import java.util.ServiceLoader; 34 35 /** 36 * <p>Implements pluggable Datatypes.</p> 37 * 38 * <p>This class is duplicated for each JAXP subpackage so keep it in sync. It 39 * is package private for secure class loading.</p> 40 * 41 * @author Santiago.PericasGeertsen@sun.com 42 */ 43 class FactoryFinder { 44 45 /** 46 * Internal debug flag. 47 */ 48 private static boolean debug = false; 49 /** 50 * Cache for properties in java.home/lib/jaxp.properties 51 */ 52 static Properties cacheProps = new Properties(); 53 /** 54 * Flag indicating if properties from java.home/lib/jaxp.properties have 55 * been cached. 56 */ 57 static volatile boolean firstTime = true; 58 /** 59 * Security support class use to check access control before getting certain 60 * system resources. 61 */ 62 static SecuritySupport ss = new SecuritySupport(); 63 64 // Define system property "jaxp.debug" to get output 65 static { 66 // Use try/catch block to support applets, which throws 67 // SecurityException out of this code. 68 try { 69 String val = ss.getSystemProperty("jaxp.debug"); 70 // Allow simply setting the prop to turn on debug 71 debug = val != null && !"false".equals(val); 72 } catch (SecurityException se) { 73 debug = false; 74 } 75 } 76 77 private static void dPrint(String msg) { 78 if (debug) { 79 System.err.println("JAXP: " + msg); 80 } 81 } 82 83 /** 84 * Attempt to load a class using the class loader supplied. If that fails 85 * and fall back is enabled, the current (i.e. bootstrap) class loader is 86 * tried. 87 * 88 * If the class loader supplied is 89 * <code>null</code>, first try using the context class loader followed by 90 * the current (i.e. bootstrap) class loader. 91 */ 92 static private Class getProviderClass(String className, ClassLoader cl, 93 boolean doFallback) throws ClassNotFoundException { 94 try { 95 if (cl == null) { 96 cl = ss.getContextClassLoader(); 97 if (cl == null) { 98 throw new ClassNotFoundException(); 99 } else { 100 return cl.loadClass(className); 101 } 102 } else { 103 return cl.loadClass(className); 104 } 105 } catch (ClassNotFoundException e1) { 106 if (doFallback) { 107 // Use current class loader - should always be bootstrap CL 108 return Class.forName(className, true, FactoryFinder.class.getClassLoader()); 109 } else { 110 throw e1; 111 } 112 } 113 } 114 115 /** 116 * Create an instance of a class. Delegates to method 117 * <code>getProviderClass()</code> in order to load the class. 118 * 119 * @param className Name of the concrete class corresponding to the service 120 * provider 121 * 122 * @param cl ClassLoader to use to load the class, null means to use the 123 * bootstrap ClassLoader 124 * 125 * @param doFallback True if the current ClassLoader should be tried as a 126 * fallback if the class is not found using cl 127 */ 128 static Object newInstance(String className, ClassLoader cl, boolean doFallback) 129 throws DatatypeConfigurationException { 130 try { 131 Class providerClass = getProviderClass(className, cl, doFallback); 132 Object instance = providerClass.newInstance(); 133 if (debug) { // Extra check to avoid computing cl strings 134 dPrint("created new instance of " + providerClass 135 + " using ClassLoader: " + cl); 136 } 137 return instance; 138 } catch (ClassNotFoundException x) { 139 throw new DatatypeConfigurationException( 140 "Provider " + className + " not found", x); 141 } catch (Exception x) { 142 throw new DatatypeConfigurationException( 143 "Provider " + className + " could not be instantiated: " + x, 144 x); 145 } 146 } 147 148 /** 149 * Finds the implementation Class object in the specified order. Main entry 150 * point. 151 * 152 * @return Class object of factory, never null 153 * 154 * @param factoryId Name of the factory to find, same as a property name 155 * @param fallbackClassName Implementation class name, if nothing else is 156 * found. Use null to mean no fallback. 157 * 158 * Package private so this code can be shared. 159 */ 160 static Object find(Class factoryClass, String factoryId, String fallbackClassName) 161 throws DatatypeConfigurationException { 162 dPrint("find factoryId =" + factoryId); 163 164 // Use the system property first 165 try { 166 String systemProp = ss.getSystemProperty(factoryId); 167 if (systemProp != null) { 168 dPrint("found system property, value=" + systemProp); 169 return newInstance(systemProp, null, true); 170 } 171 } catch (SecurityException se) { 172 if (debug) { 173 se.printStackTrace(); 174 } 175 } 176 177 // try to read from $java.home/lib/jaxp.properties 178 try { 179 String factoryClassName = null; 180 if (firstTime) { 181 synchronized (cacheProps) { 182 if (firstTime) { 183 String configFile = ss.getSystemProperty("java.home") + File.separator 184 + "lib" + File.separator + "jaxp.properties"; 185 File f = new File(configFile); 186 firstTime = false; 187 if (ss.doesFileExist(f)) { 188 dPrint("Read properties file " + f); 189 cacheProps.load(ss.getFileInputStream(f)); 190 } 191 } 192 } 193 } 194 factoryClassName = cacheProps.getProperty(factoryId); 195 196 if (factoryClassName != null) { 197 dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); 198 return newInstance(factoryClassName, null, true); 199 } 200 } catch (Exception ex) { 201 if (debug) { 202 ex.printStackTrace(); 203 } 204 } 205 206 // Try service-provider loading facilities 207 Object provider = findServiceProvider(factoryClass, fallbackClassName); 208 if (provider != null) { 209 return provider; 210 } 211 if (fallbackClassName == null) { 212 throw new DatatypeConfigurationException( 213 "Provider for " + factoryId + " cannot be found", null); 214 } 215 216 dPrint("loaded from fallback value: " + fallbackClassName); 217 return newInstance(fallbackClassName, null, true); 218 } 219 220 /* 221 * Try to find a provider using Service Loader 222 * 223 * @return instance of provider class if found or null 224 */ 225 private static Object findServiceProvider(final Class factoryClass, final String fallbackClassName) 226 throws DatatypeConfigurationException { 227 try { 228 return AccessController.doPrivileged(new PrivilegedAction() { 229 public Object run() { 230 Object defaultProvider = null; 231 for (Object factory : ServiceLoader.load(factoryClass)) { 232 if (factory.getClass().getName().equals(fallbackClassName)) { 233 defaultProvider = factory; 234 } else { 235 return factory; 236 } 237 } 238 if (defaultProvider != null) { 239 return defaultProvider; 240 } 241 return null; 242 } 243 }); 244 } catch (ServiceConfigurationError e) { 245 throw new DatatypeConfigurationException(e.getMessage(), e.getCause()); 246 } 247 } 248 }