1 /* 2 * Copyright (c) 2004, 2017, 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.Iterator; 32 import java.util.Properties; 33 import java.util.ServiceConfigurationError; 34 import java.util.ServiceLoader; 35 import java.util.function.Supplier; 36 import jdk.xml.internal.SecuritySupport; 37 38 /** 39 * <p>Implements pluggable Datatypes.</p> 40 * 41 * <p>This class is duplicated for each JAXP subpackage so keep it in 42 * sync. It is package private for secure class loading.</p> 43 * 44 * @author Santiago.PericasGeertsen@sun.com 45 */ 46 class FactoryFinder { 47 private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal"; 48 49 /** 50 * Internal debug flag. 51 */ 52 private static boolean debug = false; 53 54 /** 55 * Cache for properties in java.home/conf/jaxp.properties 56 */ 57 private final static Properties cacheProps = new Properties(); 58 59 /** 60 * Flag indicating if properties from java.home/conf/jaxp.properties 61 * have been cached. 62 */ 63 private static volatile boolean firstTime = true; 64 65 // Define system property "jaxp.debug" to get output 66 static { 67 // Use try/catch block to support applets, which throws 68 // SecurityException out of this code. 69 try { 70 String val = SecuritySupport.getSystemProperty("jaxp.debug"); 71 // Allow simply setting the prop to turn on debug 72 debug = val != null && !"false".equals(val); 73 } 74 catch (SecurityException se) { 75 debug = false; 76 } 77 } 78 79 private static void dPrint(Supplier<String> msgGen) { 80 if (debug) { 81 System.err.println("JAXP: " + msgGen.get()); 82 } 83 } 84 85 /** 86 * Attempt to load a class using the class loader supplied. If that fails 87 * and fall back is enabled, the current (i.e. bootstrap) class loader is 88 * tried. 89 * 90 * If the class loader supplied is <code>null</code>, first try using the 91 * context class loader followed by the current (i.e. bootstrap) class 92 * loader. 93 * 94 * Use bootstrap classLoader if cl = null and useBSClsLoader is true 95 */ 96 static private Class<?> getProviderClass(String className, ClassLoader cl, 97 boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException 98 { 99 try { 100 if (cl == null) { 101 if (useBSClsLoader) { 102 return Class.forName(className, false, FactoryFinder.class.getClassLoader()); 103 } else { 104 cl = SecuritySupport.getContextClassLoader(); 105 if (cl == null) { 106 throw new ClassNotFoundException(); 107 } 108 else { 109 return Class.forName(className, false, cl); 110 } 111 } 112 } 113 else { 114 return Class.forName(className, false, cl); 115 } 116 } 117 catch (ClassNotFoundException e1) { 118 if (doFallback) { 119 // Use current class loader - should always be bootstrap CL 120 return Class.forName(className, false, FactoryFinder.class.getClassLoader()); 121 } 122 else { 123 throw e1; 124 } 125 } 126 } 127 128 /** 129 * Create an instance of a class. Delegates to method 130 * <code>getProviderClass()</code> in order to load the class. 131 * 132 * @param type Base class / Service interface of the factory to 133 * instantiate. 134 * 135 * @param className Name of the concrete class corresponding to the 136 * service provider 137 * 138 * @param cl <code>ClassLoader</code> used to load the factory class. If <code>null</code> 139 * current <code>Thread</code>'s context classLoader is used to load the factory class. 140 * 141 * @param doFallback True if the current ClassLoader should be tried as 142 * a fallback if the class is not found using cl 143 */ 144 static <T> T newInstance(Class<T> type, String className, ClassLoader cl, boolean doFallback) 145 throws DatatypeConfigurationException 146 { 147 return newInstance(type, className, cl, doFallback, false); 148 } 149 150 /** 151 * Create an instance of a class. Delegates to method 152 * <code>getProviderClass()</code> in order to load the class. 153 * 154 * @param type Base class / Service interface of the factory to 155 * instantiate. 156 * 157 * @param className Name of the concrete class corresponding to the 158 * service provider 159 * 160 * @param cl ClassLoader to use to load the class, null means to use 161 * the bootstrap ClassLoader 162 * 163 * @param doFallback True if the current ClassLoader should be tried as 164 * a fallback if the class is not found using cl 165 * 166 * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter 167 * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. 168 */ 169 static <T> T newInstance(Class<T> type, String className, ClassLoader cl, 170 boolean doFallback, boolean useBSClsLoader) 171 throws DatatypeConfigurationException 172 { 173 assert type != null; 174 175 // make sure we have access to restricted packages 176 if (System.getSecurityManager() != null) { 177 if (className != null && className.startsWith(DEFAULT_PACKAGE)) { 178 cl = null; 179 useBSClsLoader = true; 180 } 181 } 182 183 try { 184 Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); 185 if (!type.isAssignableFrom(providerClass)) { 186 throw new ClassCastException(className + " cannot be cast to " + type.getName()); 187 } 188 Object instance = providerClass.getConstructor().newInstance(); 189 final ClassLoader clD = cl; 190 dPrint(()->"created new instance of " + providerClass + 191 " using ClassLoader: " + clD); 192 return type.cast(instance); 193 } 194 catch (ClassNotFoundException x) { 195 throw new DatatypeConfigurationException( 196 "Provider " + className + " not found", x); 197 } 198 catch (Exception x) { 199 throw new DatatypeConfigurationException( 200 "Provider " + className + " could not be instantiated: " + x, 201 x); 202 } 203 } 204 205 /** 206 * Finds the implementation Class object in the specified order. Main 207 * entry point. 208 * @return Class object of factory, never null 209 * 210 * @param type Base class / Service interface of the 211 * factory to find. 212 * @param fallbackClassName Implementation class name, if nothing else 213 * is found. Use null to mean no fallback. 214 * 215 * Package private so this code can be shared. 216 */ 217 static <T> T find(Class<T> type, String fallbackClassName) 218 throws DatatypeConfigurationException 219 { 220 final String factoryId = type.getName(); 221 dPrint(()->"find factoryId =" + factoryId); 222 223 // Use the system property first 224 try { 225 String systemProp = SecuritySupport.getSystemProperty(factoryId); 226 if (systemProp != null) { 227 dPrint(()->"found system property, value=" + systemProp); 228 return newInstance(type, systemProp, null, true); 229 } 230 } 231 catch (SecurityException se) { 232 if (debug) se.printStackTrace(); 233 } 234 235 // try to read from $java.home/conf/jaxp.properties 236 try { 237 if (firstTime) { 238 synchronized (cacheProps) { 239 if (firstTime) { 240 String configFile = SecuritySupport.getSystemProperty("java.home") + File.separator + 241 "conf" + File.separator + "jaxp.properties"; 242 File f = new File(configFile); 243 firstTime = false; 244 if (SecuritySupport.doesFileExist(f)) { 245 dPrint(()->"Read properties file "+f); 246 cacheProps.load(SecuritySupport.getFileInputStream(f)); 247 } 248 } 249 } 250 } 251 final String factoryClassName = cacheProps.getProperty(factoryId); 252 253 if (factoryClassName != null) { 254 dPrint(()->"found in ${java.home}/conf/jaxp.properties, value=" + factoryClassName); 255 return newInstance(type, factoryClassName, null, true); 256 } 257 } 258 catch (Exception ex) { 259 if (debug) ex.printStackTrace(); 260 } 261 262 // Try Jar Service Provider Mechanism 263 final T provider = findServiceProvider(type); 264 if (provider != null) { 265 return provider; 266 } 267 if (fallbackClassName == null) { 268 throw new DatatypeConfigurationException( 269 "Provider for " + factoryId + " cannot be found"); 270 } 271 272 dPrint(()->"loaded from fallback value: " + fallbackClassName); 273 return newInstance(type, fallbackClassName, null, true); 274 } 275 276 /* 277 * Try to find provider using the ServiceLoader API 278 * 279 * @param type Base class / Service interface of the factory to find. 280 * 281 * @return instance of provider class if found or null 282 */ 283 private static <T> T findServiceProvider(final Class<T> type) 284 throws DatatypeConfigurationException 285 { 286 try { 287 return AccessController.doPrivileged(new PrivilegedAction<T>() { 288 public T run() { 289 final ServiceLoader<T> serviceLoader = ServiceLoader.load(type); 290 final Iterator<T> iterator = serviceLoader.iterator(); 291 if (iterator.hasNext()) { 292 return iterator.next(); 293 } else { 294 return null; 295 } 296 } 297 }); 298 } catch(ServiceConfigurationError e) { 299 final DatatypeConfigurationException error = 300 new DatatypeConfigurationException( 301 "Provider for " + type + " cannot be found", e); 302 throw error; 303 } 304 } 305 306 }