1 /* 2 * Copyright (c) 2003, 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.transform; 27 28 import java.io.BufferedReader; 29 import java.io.File; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.InputStreamReader; 33 import java.lang.reflect.Method; 34 import java.util.Properties; 35 36 /** 37 * <p>Implements pluggable Datatypes.</p> 38 * 39 * <p>This class is duplicated for each JAXP subpackage so keep it in 40 * sync. It is package private for secure class loading.</p> 41 * 42 * @author Santiago.PericasGeertsen@sun.com 43 * @author Huizhe.Wang@oracle.com 44 */ 45 class FactoryFinder { 46 private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xalan.internal."; 47 48 /** 49 * Internal debug flag. 50 */ 51 private static boolean debug = false; 52 53 /** 54 * Cache for properties in java.home/lib/jaxp.properties 55 */ 56 static Properties cacheProps = new Properties(); 57 58 /** 59 * Flag indicating if properties from java.home/lib/jaxp.properties 60 * have been cached. 61 */ 62 static volatile boolean firstTime = true; 63 64 /** 65 * Security support class use to check access control before 66 * getting certain system resources. 67 */ 68 static SecuritySupport ss = new SecuritySupport(); 69 70 // Define system property "jaxp.debug" to get output 71 static { 72 // Use try/catch block to support applets, which throws 73 // SecurityException out of this code. 74 try { 75 String val = ss.getSystemProperty("jaxp.debug"); 76 // Allow simply setting the prop to turn on debug 77 debug = val != null && !"false".equals(val); 78 } 79 catch (SecurityException se) { 80 debug = false; 81 } 82 } 83 84 private static void dPrint(String msg) { 85 if (debug) { 86 System.err.println("JAXP: " + msg); 87 } 88 } 89 90 /** 91 * Attempt to load a class using the class loader supplied. If that fails 92 * and fall back is enabled, the current (i.e. bootstrap) class loader is 93 * tried. 94 * 95 * If the class loader supplied is <code>null</code>, first try using the 96 * context class loader followed by the current (i.e. bootstrap) class 97 * loader. 98 * 99 * Use bootstrap classLoader if cl = null and useBSClsLoader is true 100 */ 101 static private Class getProviderClass(String className, ClassLoader cl, 102 boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException 103 { 104 try { 105 if (cl == null) { 106 if (useBSClsLoader) { 107 return Class.forName(className, true, FactoryFinder.class.getClassLoader()); 108 } else { 109 cl = ss.getContextClassLoader(); 110 if (cl == null) { 111 throw new ClassNotFoundException(); 112 } 113 else { 114 return cl.loadClass(className); 115 } 116 } 117 } 118 else { 119 return cl.loadClass(className); 120 } 121 } 122 catch (ClassNotFoundException e1) { 123 if (doFallback) { 124 // Use current class loader - should always be bootstrap CL 125 return Class.forName(className, true, FactoryFinder.class.getClassLoader()); 126 } 127 else { 128 throw e1; 129 } 130 } 131 } 132 133 /** 134 * Create an instance of a class. Delegates to method 135 * <code>getProviderClass()</code> in order to load the class. 136 * 137 * @param className Name of the concrete class corresponding to the 138 * service provider 139 * 140 * @param cl <code>ClassLoader</code> used to load the factory class. If <code>null</code> 141 * current <code>Thread</code>'s context classLoader is used to load the factory class. 142 * 143 * @param doFallback True if the current ClassLoader should be tried as 144 * a fallback if the class is not found using cl 145 */ 146 static Object newInstance(String className, ClassLoader cl, boolean doFallback) 147 throws ConfigurationError 148 { 149 return newInstance(className, cl, doFallback, false, false); 150 } 151 152 /** 153 * Create an instance of a class. Delegates to method 154 * <code>getProviderClass()</code> in order to load the class. 155 * 156 * @param className Name of the concrete class corresponding to the 157 * service provider 158 * 159 * @param cl <code>ClassLoader</code> used to load the factory class. If <code>null</code> 160 * current <code>Thread</code>'s context classLoader is used to load the factory class. 161 * 162 * @param doFallback True if the current ClassLoader should be tried as 163 * a fallback if the class is not found using cl 164 * 165 * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter 166 * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. 167 * 168 * @param useServicesMechanism True use services mechanism 169 */ 170 static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader, boolean useServicesMechanism) 171 throws ConfigurationError 172 { 173 // make sure we have access to restricted packages 174 if (System.getSecurityManager() != null) { 175 if (className != null && className.startsWith(DEFAULT_PACKAGE)) { 176 cl = null; 177 useBSClsLoader = true; 178 } 179 } 180 181 try { 182 Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); 183 Object instance = null; 184 if (!useServicesMechanism) { 185 instance = newInstanceNoServiceLoader(providerClass); 186 } 187 if (instance == null) { 188 instance = providerClass.newInstance(); 189 } 190 if (debug) { // Extra check to avoid computing cl strings 191 dPrint("created new instance of " + providerClass + 192 " using ClassLoader: " + cl); 193 } 194 return instance; 195 } 196 catch (ClassNotFoundException x) { 197 throw new ConfigurationError( 198 "Provider " + className + " not found", x); 199 } 200 catch (Exception x) { 201 throw new ConfigurationError( 202 "Provider " + className + " could not be instantiated: " + x, 203 x); 204 } 205 } 206 /** 207 * Try to construct using newTransformerFactoryNoServiceLoader 208 * method if available. 209 */ 210 private static Object newInstanceNoServiceLoader( 211 Class<?> providerClass 212 ) { 213 // Retain maximum compatibility if no security manager. 214 if (System.getSecurityManager() == null) { 215 return null; 216 } 217 try { 218 Method creationMethod = 219 providerClass.getDeclaredMethod( 220 "newTransformerFactoryNoServiceLoader" 221 ); 222 return creationMethod.invoke(null, (Object[])null); 223 } catch (NoSuchMethodException exc) { 224 return null; 225 } catch (Exception exc) { 226 return null; 227 } 228 } 229 /** 230 * Finds the implementation Class object in the specified order. Main 231 * entry point. 232 * @return Class object of factory, never null 233 * 234 * @param factoryId Name of the factory to find, same as 235 * a property name 236 * @param fallbackClassName Implementation class name, if nothing else 237 * is found. Use null to mean no fallback. 238 * 239 * Package private so this code can be shared. 240 */ 241 static Object find(String factoryId, String fallbackClassName) 242 throws ConfigurationError 243 { 244 dPrint("find factoryId =" + factoryId); 245 // Use the system property first 246 try { 247 String systemProp = ss.getSystemProperty(factoryId); 248 if (systemProp != null) { 249 dPrint("found system property, value=" + systemProp); 250 return newInstance(systemProp, null, true, false, true); 251 } 252 } 253 catch (SecurityException se) { 254 if (debug) se.printStackTrace(); 255 } 256 257 // try to read from $java.home/lib/jaxp.properties 258 try { 259 String factoryClassName = null; 260 if (firstTime) { 261 synchronized (cacheProps) { 262 if (firstTime) { 263 String configFile = ss.getSystemProperty("java.home") + File.separator + 264 "lib" + File.separator + "jaxp.properties"; 265 File f = new File(configFile); 266 firstTime = false; 267 if (ss.doesFileExist(f)) { 268 dPrint("Read properties file "+f); 269 cacheProps.load(ss.getFileInputStream(f)); 270 } 271 } 272 } 273 } 274 factoryClassName = cacheProps.getProperty(factoryId); 275 276 if (factoryClassName != null) { 277 dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); 278 return newInstance(factoryClassName, null, true, false, true); 279 } 280 } 281 catch (Exception ex) { 282 if (debug) ex.printStackTrace(); 283 } 284 285 // Try Jar Service Provider Mechanism 286 Object provider = findJarServiceProvider(factoryId); 287 if (provider != null) { 288 return provider; 289 } 290 if (fallbackClassName == null) { 291 throw new ConfigurationError( 292 "Provider for " + factoryId + " cannot be found", null); 293 } 294 295 dPrint("loaded from fallback value: " + fallbackClassName); 296 return newInstance(fallbackClassName, null, true, false, true); 297 } 298 299 /* 300 * Try to find provider using Jar Service Provider Mechanism 301 * 302 * @return instance of provider class if found or null 303 */ 304 private static Object findJarServiceProvider(String factoryId) 305 throws ConfigurationError 306 { 307 String serviceId = "META-INF/services/" + factoryId; 308 InputStream is = null; 309 310 // First try the Context ClassLoader 311 ClassLoader cl = ss.getContextClassLoader(); 312 boolean useBSClsLoader = false; 313 if (cl != null) { 314 is = ss.getResourceAsStream(cl, serviceId); 315 316 // If no provider found then try the current ClassLoader 317 if (is == null) { 318 cl = FactoryFinder.class.getClassLoader(); 319 is = ss.getResourceAsStream(cl, serviceId); 320 useBSClsLoader = true; 321 } 322 } else { 323 // No Context ClassLoader, try the current ClassLoader 324 cl = FactoryFinder.class.getClassLoader(); 325 is = ss.getResourceAsStream(cl, serviceId); 326 useBSClsLoader = true; 327 } 328 329 if (is == null) { 330 // No provider found 331 return null; 332 } 333 334 if (debug) { // Extra check to avoid computing cl strings 335 dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); 336 } 337 338 BufferedReader rd; 339 try { 340 rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); 341 } 342 catch (java.io.UnsupportedEncodingException e) { 343 rd = new BufferedReader(new InputStreamReader(is)); 344 } 345 346 String factoryClassName = null; 347 try { 348 // XXX Does not handle all possible input as specified by the 349 // Jar Service Provider specification 350 factoryClassName = rd.readLine(); 351 rd.close(); 352 } catch (IOException x) { 353 // No provider found 354 return null; 355 } 356 357 if (factoryClassName != null && !"".equals(factoryClassName)) { 358 dPrint("found in resource, value=" + factoryClassName); 359 360 // Note: here we do not want to fall back to the current 361 // ClassLoader because we want to avoid the case where the 362 // resource file was found using one ClassLoader and the 363 // provider class was instantiated using a different one. 364 return newInstance(factoryClassName, cl, false, useBSClsLoader, true); 365 } 366 367 // No provider found 368 return null; 369 } 370 371 static class ConfigurationError extends Error { 372 private Exception exception; 373 374 /** 375 * Construct a new instance with the specified detail string and 376 * exception. 377 */ 378 ConfigurationError(String msg, Exception x) { 379 super(msg); 380 this.exception = x; 381 } 382 383 Exception getException() { 384 return exception; 385 } 386 /** 387 * use the exception chaining mechanism of JDK1.4 388 */ 389 @Override 390 public Throwable getCause() { 391 return exception; 392 } 393 } 394 395 }