1 /* 2 * Copyright (c) 2003, 2016, 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.transform; 27 28 import java.io.File; 29 import java.lang.reflect.Method; 30 import java.lang.reflect.Modifier; 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 import java.util.Iterator; 34 import java.util.Properties; 35 import java.util.ServiceConfigurationError; 36 import java.util.ServiceLoader; 37 import java.util.function.Supplier; 38 39 /** 40 * <p>Implements pluggable Datatypes.</p> 41 * 42 * <p>This class is duplicated for each JAXP subpackage so keep it in 43 * sync. It is package private for secure class loading.</p> 44 * 45 * @author Santiago.PericasGeertsen@sun.com 46 * @author Huizhe.Wang@oracle.com 47 */ 48 class FactoryFinder { 49 private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xalan.internal."; 50 51 /** 52 * Internal debug flag. 53 */ 54 private static boolean debug = false; 55 56 /** 57 * Cache for properties in java.home/conf/jaxp.properties 58 */ 59 private final static Properties cacheProps = new Properties(); 60 61 /** 62 * Flag indicating if properties from java.home/conf/jaxp.properties 63 * have been cached. 64 */ 65 static volatile boolean firstTime = true; 66 67 /** 68 * Security support class use to check access control before 69 * getting certain system resources. 70 */ 71 private final static SecuritySupport ss = new SecuritySupport(); 72 73 // Define system property "jaxp.debug" to get output 74 static { 75 // Use try/catch block to support applets, which throws 76 // SecurityException out of this code. 77 try { 78 String val = ss.getSystemProperty("jaxp.debug"); 79 // Allow simply setting the prop to turn on debug 80 debug = val != null && !"false".equals(val); 81 } 82 catch (SecurityException se) { 83 debug = false; 84 } 85 } 86 87 private static void dPrint(Supplier<String> msgGen) { 88 if (debug) { 89 System.err.println("JAXP: " + msgGen.get()); 90 } 91 } 92 93 /** 94 * Attempt to load a class using the class loader supplied. If that fails 95 * and fall back is enabled, the current (i.e. bootstrap) class loader is 96 * tried. 97 * 98 * If the class loader supplied is <code>null</code>, first try using the 99 * context class loader followed by the current (i.e. bootstrap) class 100 * loader. 101 * 102 * Use bootstrap classLoader if cl = null and useBSClsLoader is true 103 */ 104 static private Class<?> getProviderClass(String className, ClassLoader cl, 105 boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException 106 { 107 try { 108 if (cl == null) { 109 if (useBSClsLoader) { 110 return Class.forName(className, false, FactoryFinder.class.getClassLoader()); 111 } else { 112 cl = ss.getContextClassLoader(); 113 if (cl == null) { 114 throw new ClassNotFoundException(); 115 } 116 else { 117 return Class.forName(className, false, cl); 118 } 119 } 120 } 121 else { 122 return Class.forName(className, false, cl); 123 } 124 } 125 catch (ClassNotFoundException e1) { 126 if (doFallback) { 127 // Use current class loader - should always be bootstrap CL 128 return Class.forName(className, false, FactoryFinder.class.getClassLoader()); 129 } 130 else { 131 throw e1; 132 } 133 } 134 } 135 136 /** 137 * Create an instance of a class. Delegates to method 138 * <code>getProviderClass()</code> in order to load the class. 139 * 140 * @param type Base class / Service interface of the factory to 141 * instantiate. 142 * 143 * @param className Name of the concrete class corresponding to the 144 * service provider 145 * 146 * @param cl <code>ClassLoader</code> used to load the factory class. If <code>null</code> 147 * current <code>Thread</code>'s context classLoader is used to load the factory class. 148 * 149 * @param doFallback True if the current ClassLoader should be tried as 150 * a fallback if the class is not found using cl 151 * 152 * @param useServicesMechanism True use services mechanism 153 */ 154 static <T> T newInstance(Class<T> type, String className, ClassLoader cl, 155 boolean doFallback, boolean useServicesMechanism) 156 throws TransformerFactoryConfigurationError 157 { 158 assert type != null; 159 160 boolean useBSClsLoader = false; 161 // make sure we have access to restricted packages 162 if (System.getSecurityManager() != null) { 163 if (className != null && className.startsWith(DEFAULT_PACKAGE)) { 164 cl = null; 165 useBSClsLoader = true; 166 } 167 } 168 169 try { 170 Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); 171 if (!type.isAssignableFrom(providerClass)) { 172 throw new ClassCastException(className + " cannot be cast to " + type.getName()); 173 } 174 Object instance = null; 175 if (!useServicesMechanism) { 176 instance = newInstanceNoServiceLoader(type, providerClass); 177 } 178 if (instance == null) { 179 instance = providerClass.newInstance(); 180 } 181 final ClassLoader clD = cl; 182 dPrint(()->"created new instance of " + providerClass + 183 " using ClassLoader: " + clD); 184 return type.cast(instance); 185 } 186 catch (ClassNotFoundException x) { 187 throw new TransformerFactoryConfigurationError(x, 188 "Provider " + className + " not found"); 189 } 190 catch (Exception x) { 191 throw new TransformerFactoryConfigurationError(x, 192 "Provider " + className + " could not be instantiated: " + x); 193 } 194 } 195 196 /** 197 * Try to construct using newTransformerFactoryNoServiceLoader 198 * method if available. 199 */ 200 private static <T> T newInstanceNoServiceLoader(Class<T> type, Class<?> providerClass) { 201 // Retain maximum compatibility if no security manager. 202 if (System.getSecurityManager() == null) { 203 return null; 204 } 205 try { 206 final Method creationMethod = 207 providerClass.getDeclaredMethod( 208 "newTransformerFactoryNoServiceLoader" 209 ); 210 final int modifiers = creationMethod.getModifiers(); 211 212 // Do not call the method if it's not public static. 213 if (!Modifier.isPublic(modifiers) || !Modifier.isStatic(modifiers)) { 214 return null; 215 } 216 217 // Only call the method if it's declared to return an instance of 218 // TransformerFactory 219 final Class<?> returnType = creationMethod.getReturnType(); 220 if (type.isAssignableFrom(returnType)) { 221 final Object result = creationMethod.invoke(null, (Object[])null); 222 return type.cast(result); 223 } else { 224 // This should not happen, as 225 // TransformerFactoryImpl.newTransformerFactoryNoServiceLoader is 226 // declared to return TransformerFactory. 227 throw new ClassCastException(returnType + " cannot be cast to " + type); 228 } 229 } catch (ClassCastException e) { 230 throw new TransformerFactoryConfigurationError(e, e.getMessage()); 231 } catch (NoSuchMethodException exc) { 232 return null; 233 } catch (Exception exc) { 234 return null; 235 } 236 } 237 238 /** 239 * Finds the implementation Class object in the specified order. Main 240 * entry point. 241 * @return Class object of factory, never null 242 * 243 * @param type Base class / Service interface of the 244 * factory to find. 245 * 246 * @param fallbackClassName Implementation class name, if nothing else 247 * is found. Use null to mean no fallback. 248 * 249 * Package private so this code can be shared. 250 */ 251 static <T> T find(Class<T> type, String fallbackClassName) 252 throws TransformerFactoryConfigurationError 253 { 254 assert type != null; 255 256 final String factoryId = type.getName(); 257 258 dPrint(()->"find factoryId =" + factoryId); 259 // Use the system property first 260 try { 261 String systemProp = ss.getSystemProperty(factoryId); 262 if (systemProp != null) { 263 dPrint(()->"found system property, value=" + systemProp); 264 return newInstance(type, systemProp, null, true, true); 265 } 266 } 267 catch (SecurityException se) { 268 if (debug) se.printStackTrace(); 269 } 270 271 // try to read from $java.home/conf/jaxp.properties 272 try { 273 if (firstTime) { 274 synchronized (cacheProps) { 275 if (firstTime) { 276 String configFile = ss.getSystemProperty("java.home") + File.separator + 277 "conf" + File.separator + "jaxp.properties"; 278 File f = new File(configFile); 279 firstTime = false; 280 if (ss.doesFileExist(f)) { 281 dPrint(()->"Read properties file "+f); 282 cacheProps.load(ss.getFileInputStream(f)); 283 } 284 } 285 } 286 } 287 final String factoryClassName = cacheProps.getProperty(factoryId); 288 289 if (factoryClassName != null) { 290 dPrint(()->"found in ${java.home}/conf/jaxp.properties, value=" + factoryClassName); 291 return newInstance(type, factoryClassName, null, true, true); 292 } 293 } 294 catch (Exception ex) { 295 if (debug) ex.printStackTrace(); 296 } 297 298 // Try Jar Service Provider Mechanism 299 T provider = findServiceProvider(type); 300 if (provider != null) { 301 return provider; 302 } 303 if (fallbackClassName == null) { 304 throw new TransformerFactoryConfigurationError(null, 305 "Provider for " + factoryId + " cannot be found"); 306 } 307 308 dPrint(()->"loaded from fallback value: " + fallbackClassName); 309 return newInstance(type, fallbackClassName, null, true, true); 310 } 311 312 /* 313 * Try to find provider using the ServiceLoader. 314 * 315 * @param type Base class / Service interface of the factory to find. 316 * 317 * @return instance of provider class if found or null 318 */ 319 private static <T> T findServiceProvider(final Class<T> type) 320 throws TransformerFactoryConfigurationError 321 { 322 try { 323 return AccessController.doPrivileged(new PrivilegedAction<T>() { 324 public T run() { 325 final ServiceLoader<T> serviceLoader = ServiceLoader.load(type); 326 final Iterator<T> iterator = serviceLoader.iterator(); 327 if (iterator.hasNext()) { 328 return iterator.next(); 329 } else { 330 return null; 331 } 332 } 333 }); 334 } catch(ServiceConfigurationError e) { 335 // It is not possible to wrap an error directly in 336 // FactoryConfigurationError - so we need to wrap the 337 // ServiceConfigurationError in a RuntimeException. 338 // The alternative would be to modify the logic in 339 // FactoryConfigurationError to allow setting a 340 // Throwable as the cause, but that could cause 341 // compatibility issues down the road. 342 final RuntimeException x = new RuntimeException( 343 "Provider for " + type + " cannot be created", e); 344 final TransformerFactoryConfigurationError error = 345 new TransformerFactoryConfigurationError(x, x.getMessage()); 346 throw error; 347 } 348 } 349 }