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.Properties; 32 import java.util.ServiceConfigurationError; 33 import java.util.ServiceLoader; 34 35 /** 36 * <p>Implements pluggable Datatypes.</p> 37 * 38 * <p>This class is duplicated for each JAXP subpackage so keep it in sync. It 39 * 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 * Cache for properties in java.home/lib/jaxp.properties 52 */ 53 static Properties cacheProps = new Properties(); 54 /** 55 * Flag indicating if properties from java.home/lib/jaxp.properties have 56 * been cached. 57 */ 58 static volatile boolean firstTime = true; 59 /** 60 * Security support class use to check access control before getting certain 61 * system resources. 62 */ 63 static SecuritySupport ss = new SecuritySupport(); 64 65 // Define system property "jaxp.debug" to get output 66 static { 67 // Use try/catch block to support applets, which throws 68 // SecurityException out of this code. 69 try { 70 String val = ss.getSystemProperty("jaxp.debug"); 71 // Allow simply setting the prop to turn on debug 72 debug = val != null && !"false".equals(val); 73 } catch (SecurityException se) { 74 debug = false; 75 } 76 } 77 78 private static void dPrint(String msg) { 79 if (debug) { 80 System.err.println("JAXP: " + msg); 81 } 82 } 83 84 /** 85 * Attempt to load a class using the class loader supplied. If that fails 86 * and fall back is enabled, the current (i.e. bootstrap) class loader is 87 * tried. 88 * 89 * If the class loader supplied is 90 * <code>null</code>, first try using the context class loader followed by 91 * the current (i.e. bootstrap) class loader. 92 * 93 * Use bootstrap classLoader if cl = null and useBSClsLoader is true 94 */ 95 static private Class getProviderClass(String className, ClassLoader cl, 96 boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { 97 try { 98 if (cl == null) { 99 if (useBSClsLoader) { 100 return Class.forName(className, true, FactoryFinder.class.getClassLoader()); 101 } else { 102 cl = ss.getContextClassLoader(); 103 if (cl == null) { 104 throw new ClassNotFoundException(); 105 } else { 106 return cl.loadClass(className); 107 } 108 } 109 } else { 110 return cl.loadClass(className); 111 } 112 } catch (ClassNotFoundException e1) { 113 if (doFallback) { 114 // Use current class loader - should always be bootstrap CL 115 return Class.forName(className, true, FactoryFinder.class.getClassLoader()); 116 } else { 117 throw e1; 118 } 119 } 120 } 121 122 /** 123 * Create an instance of a class. Delegates to method 124 * <code>getProviderClass()</code> in order to load the class. 125 * 126 * @param className Name of the concrete class corresponding to the service 127 * provider 128 * 129 * @param cl <code>ClassLoader</code> used to load the factory class. 130 * If <code>null</code> current <code>Thread</code>'s context classLoader is 131 * used to load the factory class. 132 * 133 * @param doFallback True if the current ClassLoader should be tried as a 134 * fallback if the class is not found using cl 135 */ 136 static Object newInstance(String className, ClassLoader cl, boolean doFallback) 137 throws FactoryConfigurationError { 138 return newInstance(className, cl, doFallback, false); 139 } 140 141 /** 142 * Create an instance of a class. Delegates to method 143 * <code>getProviderClass()</code> in order to load the class. 144 * 145 * @param className Name of the concrete class corresponding to the service 146 * provider 147 * 148 * @param cl <code>ClassLoader</code> used to load the factory class. 149 * If <code>null</code> current <code>Thread</code>'s context classLoader is 150 * used to load the factory class. 151 * 152 * @param doFallback True if the current ClassLoader should be tried as a 153 * fallback if the class is not found using cl 154 * 155 * @param useBSClsLoader True if cl=null actually meant bootstrap 156 * classLoader. This parameter is needed since 157 * DocumentBuilderFactory/SAXParserFactory defined null as context 158 * classLoader. 159 */ 160 static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) 161 throws FactoryConfigurationError { 162 try { 163 Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); 164 Object instance = providerClass.newInstance(); 165 if (debug) { // Extra check to avoid computing cl strings 166 dPrint("created new instance of " + providerClass 167 + " using ClassLoader: " + cl); 168 } 169 return instance; 170 } catch (ClassNotFoundException x) { 171 throw new FactoryConfigurationError(x, 172 "Provider " + className + " not found"); 173 } catch (Exception x) { 174 throw new FactoryConfigurationError(x, 175 "Provider " + className + " could not be instantiated: " + x); 176 } 177 } 178 179 /** 180 * Finds the implementation Class object in the specified order. Main entry 181 * point. 182 * 183 * @return Class object of factory, never null 184 * 185 * @param factoryId Name of the factory to find, same as a property name 186 * @param fallbackClassName Implementation class name, if nothing else is 187 * found. Use null to mean no fallback. 188 * 189 * Package private so this code can be shared. 190 */ 191 static Object find(Class factoryClass, String factoryId, String fallbackClassName) 192 throws FactoryConfigurationError { 193 dPrint("find factoryId =" + factoryId); 194 195 // Use the system property first 196 try { 197 String systemProp = ss.getSystemProperty(factoryId); 198 if (systemProp != null) { 199 dPrint("found system property, value=" + systemProp); 200 return newInstance(systemProp, null, true); 201 } 202 } catch (SecurityException se) { 203 if (debug) { 204 se.printStackTrace(); 205 } 206 } 207 208 // try to read from $java.home/lib/jaxp.properties 209 try { 210 String factoryClassName = null; 211 if (firstTime) { 212 synchronized (cacheProps) { 213 if (firstTime) { 214 String configFile = ss.getSystemProperty("java.home") + File.separator 215 + "lib" + File.separator + "jaxp.properties"; 216 File f = new File(configFile); 217 firstTime = false; 218 if (ss.doesFileExist(f)) { 219 dPrint("Read properties file " + f); 220 cacheProps.load(ss.getFileInputStream(f)); 221 } 222 } 223 } 224 } 225 factoryClassName = cacheProps.getProperty(factoryId); 226 227 if (factoryClassName != null) { 228 dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); 229 return newInstance(factoryClassName, null, true); 230 } 231 } catch (Exception ex) { 232 if (debug) { 233 ex.printStackTrace(); 234 } 235 } 236 237 // Try service-provider loading facilities 238 try { 239 Object provider = findServiceProvider(factoryClass, fallbackClassName); 240 if (provider != null) { 241 return provider; 242 } 243 } catch (FactoryConfigurationError e) { 244 throw e; 245 } 246 247 // Last, check if fallback is requested 248 if (fallbackClassName == null) { 249 throw new FactoryConfigurationError("Provider for " + factoryId + " cannot be found"); 250 } 251 252 dPrint("loaded from fallback value: " + fallbackClassName); 253 return newInstance(fallbackClassName, null, true); 254 } 255 256 /* 257 * Try to find a provider using Service Loader 258 * 259 * @return instance of provider class if found or null 260 */ 261 private static Object findServiceProvider(final Class factoryClass, final String fallbackClassName) 262 throws FactoryConfigurationError { 263 try { 264 return AccessController.doPrivileged(new PrivilegedAction() { 265 public Object run() { 266 Object defaultProvider = null; 267 for (Object factory : ServiceLoader.load(factoryClass)) { 268 if (factory.getClass().getName().equals(fallbackClassName)) { 269 defaultProvider = factory; 270 } else { 271 return factory; 272 } 273 } 274 if (defaultProvider != null) { 275 return defaultProvider; 276 } 277 return null; 278 } 279 }); 280 } catch (ServiceConfigurationError e) { 281 throw new FactoryConfigurationError((Exception) e.getCause(), e.getMessage()); 282 } 283 } 284 } |