245 * is found. Use null to mean no fallback. 246 * 247 * Package private so this code can be shared. 248 */ 249 static <T> T find(Class<T> type, String factoryId, ClassLoader cl, String fallbackClassName) 250 throws FactoryConfigurationError 251 { 252 dPrint("find factoryId =" + factoryId); 253 254 // Use the system property first 255 try { 256 257 final String systemProp; 258 if (type.getName().equals(factoryId)) { 259 systemProp = ss.getSystemProperty(factoryId); 260 } else { 261 systemProp = System.getProperty(factoryId); 262 } 263 if (systemProp != null) { 264 dPrint("found system property, value=" + systemProp); 265 // There's a bug here - because 'cl' is ignored. 266 // This will be handled separately. 267 return newInstance(type, systemProp, null, true); 268 } 269 } 270 catch (SecurityException se) { 271 throw new FactoryConfigurationError( 272 "Failed to read factoryId '" + factoryId + "'", se); 273 } 274 275 // Try read $java.home/lib/stax.properties followed by 276 // $java.home/lib/jaxp.properties if former not present 277 String configFile = null; 278 try { 279 if (firstTime) { 280 synchronized (cacheProps) { 281 if (firstTime) { 282 configFile = ss.getSystemProperty("java.home") + File.separator + 283 "lib" + File.separator + "stax.properties"; 284 File f = new File(configFile); 285 firstTime = false; 286 if (ss.doesFileExist(f)) { 287 dPrint("Read properties file "+f); 288 cacheProps.load(ss.getFileInputStream(f)); 289 } 290 else { 291 configFile = ss.getSystemProperty("java.home") + File.separator + 292 "lib" + File.separator + "jaxp.properties"; 293 f = new File(configFile); 294 if (ss.doesFileExist(f)) { 295 dPrint("Read properties file "+f); 296 cacheProps.load(ss.getFileInputStream(f)); 297 } 298 } 299 } 300 } 301 } 302 final String factoryClassName = cacheProps.getProperty(factoryId); 303 304 if (factoryClassName != null) { 305 dPrint("found in " + configFile + " value=" + factoryClassName); 306 // There's a bug here - because 'cl' is ignored. 307 // This will be handled separately. 308 return newInstance(type, factoryClassName, null, true); 309 } 310 } 311 catch (Exception ex) { 312 if (debug) ex.printStackTrace(); 313 } 314 315 if (type.getName().equals(factoryId)) { 316 // Try Jar Service Provider Mechanism 317 final T provider = findServiceProvider(type); 318 if (provider != null) { 319 return provider; 320 } 321 } else { 322 // We're in the case where a 'custom' factoryId was provided, 323 // and in every case where that happens, we expect that 324 // fallbackClassName will be null. 325 assert fallbackClassName == null; 326 } 327 if (fallbackClassName == null) { 328 throw new FactoryConfigurationError( 329 "Provider for " + factoryId + " cannot be found", null); 330 } 331 332 dPrint("loaded from fallback value: " + fallbackClassName); 333 return newInstance(type, fallbackClassName, cl, true); 334 } 335 336 /* 337 * Try to find provider using the ServiceLoader API 338 * 339 * @param type Base class / Service interface of the factory to find. 340 * 341 * @return instance of provider class if found or null 342 */ 343 private static <T> T findServiceProvider(final Class<T> type) { 344 try { 345 return AccessController.doPrivileged(new PrivilegedAction<T>() { 346 @Override 347 public T run() { 348 final ServiceLoader<T> serviceLoader = ServiceLoader.load(type); 349 final Iterator<T> iterator = serviceLoader.iterator(); 350 if (iterator.hasNext()) { 351 return iterator.next(); 352 } else { 353 return null; 354 } 355 } 356 }); 357 } catch(ServiceConfigurationError e) { 358 // It is not possible to wrap an error directly in 359 // FactoryConfigurationError - so we need to wrap the 360 // ServiceConfigurationError in a RuntimeException. 361 // The alternative would be to modify the logic in 362 // FactoryConfigurationError to allow setting a 363 // Throwable as the cause, but that could cause 364 // compatibility issues down the road. 365 final RuntimeException x = new RuntimeException( 366 "Provider for " + type + " cannot be created", e); 367 final FactoryConfigurationError error = 368 new FactoryConfigurationError(x, x.getMessage()); | 245 * is found. Use null to mean no fallback. 246 * 247 * Package private so this code can be shared. 248 */ 249 static <T> T find(Class<T> type, String factoryId, ClassLoader cl, String fallbackClassName) 250 throws FactoryConfigurationError 251 { 252 dPrint("find factoryId =" + factoryId); 253 254 // Use the system property first 255 try { 256 257 final String systemProp; 258 if (type.getName().equals(factoryId)) { 259 systemProp = ss.getSystemProperty(factoryId); 260 } else { 261 systemProp = System.getProperty(factoryId); 262 } 263 if (systemProp != null) { 264 dPrint("found system property, value=" + systemProp); 265 return newInstance(type, systemProp, cl, true); 266 } 267 } 268 catch (SecurityException se) { 269 throw new FactoryConfigurationError( 270 "Failed to read factoryId '" + factoryId + "'", se); 271 } 272 273 // Try read $java.home/lib/stax.properties followed by 274 // $java.home/lib/jaxp.properties if former not present 275 String configFile = null; 276 try { 277 if (firstTime) { 278 synchronized (cacheProps) { 279 if (firstTime) { 280 configFile = ss.getSystemProperty("java.home") + File.separator + 281 "lib" + File.separator + "stax.properties"; 282 File f = new File(configFile); 283 firstTime = false; 284 if (ss.doesFileExist(f)) { 285 dPrint("Read properties file "+f); 286 cacheProps.load(ss.getFileInputStream(f)); 287 } 288 else { 289 configFile = ss.getSystemProperty("java.home") + File.separator + 290 "lib" + File.separator + "jaxp.properties"; 291 f = new File(configFile); 292 if (ss.doesFileExist(f)) { 293 dPrint("Read properties file "+f); 294 cacheProps.load(ss.getFileInputStream(f)); 295 } 296 } 297 } 298 } 299 } 300 final String factoryClassName = cacheProps.getProperty(factoryId); 301 302 if (factoryClassName != null) { 303 dPrint("found in " + configFile + " value=" + factoryClassName); 304 return newInstance(type, factoryClassName, cl, true); 305 } 306 } 307 catch (Exception ex) { 308 if (debug) ex.printStackTrace(); 309 } 310 311 if (type.getName().equals(factoryId)) { 312 // Try Jar Service Provider Mechanism 313 final T provider = findServiceProvider(type, cl); 314 if (provider != null) { 315 return provider; 316 } 317 } else { 318 // We're in the case where a 'custom' factoryId was provided, 319 // and in every case where that happens, we expect that 320 // fallbackClassName will be null. 321 assert fallbackClassName == null; 322 } 323 if (fallbackClassName == null) { 324 throw new FactoryConfigurationError( 325 "Provider for " + factoryId + " cannot be found", null); 326 } 327 328 dPrint("loaded from fallback value: " + fallbackClassName); 329 return newInstance(type, fallbackClassName, cl, true); 330 } 331 332 /* 333 * Try to find provider using the ServiceLoader API 334 * 335 * @param type Base class / Service interface of the factory to find. 336 * 337 * @return instance of provider class if found or null 338 */ 339 private static <T> T findServiceProvider(final Class<T> type, final ClassLoader cl) { 340 try { 341 return AccessController.doPrivileged(new PrivilegedAction<T>() { 342 @Override 343 public T run() { 344 final ServiceLoader<T> serviceLoader; 345 if (cl == null) { 346 //the current thread's context class loader 347 serviceLoader = ServiceLoader.load(type); 348 } else { 349 serviceLoader = ServiceLoader.load(type, cl); 350 } 351 final Iterator<T> iterator = serviceLoader.iterator(); 352 if (iterator.hasNext()) { 353 return iterator.next(); 354 } else { 355 return null; 356 } 357 } 358 }); 359 } catch(ServiceConfigurationError e) { 360 // It is not possible to wrap an error directly in 361 // FactoryConfigurationError - so we need to wrap the 362 // ServiceConfigurationError in a RuntimeException. 363 // The alternative would be to modify the logic in 364 // FactoryConfigurationError to allow setting a 365 // Throwable as the cause, but that could cause 366 // compatibility issues down the road. 367 final RuntimeException x = new RuntimeException( 368 "Provider for " + type + " cannot be created", e); 369 final FactoryConfigurationError error = 370 new FactoryConfigurationError(x, x.getMessage()); |