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