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