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.datatype; 27 28 import java.io.File; 29 import java.io.FileInputStream; 30 import java.io.IOException; 31 import java.io.InputStream; 32 33 import java.util.Properties; 34 import java.io.BufferedReader; 35 import java.io.InputStreamReader; 36 import java.net.URL; 37 38 /** 39 * <p>Implements pluggable Datatypes.</p> 40 * 41 * <p>This class is duplicated for each JAXP subpackage so keep it in 42 * sync. It is package private for secure class loading.</p> 43 * 44 * @author Santiago.PericasGeertsen@sun.com 45 */ 46 class FactoryFinder { 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 static private Class getProviderClass(String className, ClassLoader cl, 100 boolean doFallback) throws ClassNotFoundException 101 { 102 try { 103 if (cl == null) { 104 cl = ss.getContextClassLoader(); 105 if (cl == null) { 106 throw new ClassNotFoundException(); 107 } 108 else { 109 return cl.loadClass(className); 110 } 111 } 112 else { 113 return cl.loadClass(className); 114 } 115 } 116 catch (ClassNotFoundException e1) { 117 if (doFallback) { 118 // Use current class loader - should always be bootstrap CL 119 return Class.forName(className, true, FactoryFinder.class.getClassLoader()); 120 } 121 else { 122 throw e1; 123 } 124 } 125 } 126 127 /** 128 * Create an instance of a class. Delegates to method 129 * <code>getProviderClass()</code> in order to load the class. 130 * 131 * @param className Name of the concrete class corresponding to the 132 * service provider 133 * 134 * @param cl ClassLoader to use to load the class, null means to use 135 * the bootstrap ClassLoader 136 * 137 * @param doFallback True if the current ClassLoader should be tried as 138 * a fallback if the class is not found using cl 139 */ 140 static Object newInstance(String className, ClassLoader cl, boolean doFallback) 141 throws ConfigurationError 142 { 143 try { 144 Class providerClass = getProviderClass(className, cl, doFallback); 145 Object instance = providerClass.newInstance(); 146 if (debug) { // Extra check to avoid computing cl strings 147 dPrint("created new instance of " + providerClass + 148 " using ClassLoader: " + cl); 149 } 150 return instance; 151 } 152 catch (ClassNotFoundException x) { 153 throw new ConfigurationError( 154 "Provider " + className + " not found", x); 155 } 156 catch (Exception x) { 157 throw new ConfigurationError( 158 "Provider " + className + " could not be instantiated: " + x, 159 x); 160 } 161 } 162 163 /** 164 * Finds the implementation Class object in the specified order. Main 165 * entry point. 166 * @return Class object of factory, never null 167 * 168 * @param factoryId Name of the factory to find, same as 169 * a property name 170 * @param fallbackClassName Implementation class name, if nothing else 171 * is found. Use null to mean no fallback. 172 * 173 * Package private so this code can be shared. 174 */ 175 static Object find(String factoryId, String fallbackClassName) 176 throws ConfigurationError 177 { 178 dPrint("find factoryId =" + factoryId); 179 180 // Use the system property first 181 try { 182 String systemProp = ss.getSystemProperty(factoryId); 183 if (systemProp != null) { 184 dPrint("found system property, value=" + systemProp); 185 return newInstance(systemProp, null, true); 186 } 187 } 188 catch (SecurityException se) { 189 if (debug) se.printStackTrace(); 190 } 191 192 // try to read from $java.home/lib/jaxp.properties 193 try { 194 String factoryClassName = null; 195 if (firstTime) { 196 synchronized (cacheProps) { 197 if (firstTime) { 198 String configFile = ss.getSystemProperty("java.home") + File.separator + 199 "lib" + File.separator + "jaxp.properties"; 200 File f = new File(configFile); 201 firstTime = false; 202 if (ss.doesFileExist(f)) { 203 dPrint("Read properties file "+f); 204 cacheProps.load(ss.getFileInputStream(f)); 205 } 206 } 207 } 208 } 209 factoryClassName = cacheProps.getProperty(factoryId); 210 211 if (factoryClassName != null) { 212 dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); 213 return newInstance(factoryClassName, null, true); 214 } 215 } 216 catch (Exception ex) { 217 if (debug) ex.printStackTrace(); 218 } 219 220 // Try Jar Service Provider Mechanism 221 Object provider = findJarServiceProvider(factoryId); 222 if (provider != null) { 223 return provider; 224 } 225 if (fallbackClassName == null) { 226 throw new ConfigurationError( 227 "Provider for " + factoryId + " cannot be found", null); 228 } 229 230 dPrint("loaded from fallback value: " + fallbackClassName); 231 return newInstance(fallbackClassName, null, true); 232 } 233 234 /* 235 * Try to find provider using Jar Service Provider Mechanism 236 * 237 * @return instance of provider class if found or null 238 */ 239 private static Object findJarServiceProvider(String factoryId) 240 throws ConfigurationError 241 { 242 String serviceId = "META-INF/services/" + factoryId; 243 InputStream is = null; 244 245 // First try the Context ClassLoader 246 ClassLoader cl = ss.getContextClassLoader(); 247 if (cl != null) { 248 is = ss.getResourceAsStream(cl, serviceId); 249 250 // If no provider found then try the current ClassLoader 251 if (is == null) { 252 cl = FactoryFinder.class.getClassLoader(); 253 is = ss.getResourceAsStream(cl, serviceId); 254 } 255 } else { 256 // No Context ClassLoader, try the current ClassLoader 257 cl = FactoryFinder.class.getClassLoader(); 258 is = ss.getResourceAsStream(cl, serviceId); 259 } 260 261 if (is == null) { 262 // No provider found 263 return null; 264 } 265 266 if (debug) { // Extra check to avoid computing cl strings 267 dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); 268 } 269 270 BufferedReader rd; 271 try { 272 rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); 273 } 274 catch (java.io.UnsupportedEncodingException e) { 275 rd = new BufferedReader(new InputStreamReader(is)); 276 } 277 278 String factoryClassName = null; 279 try { 280 // XXX Does not handle all possible input as specified by the 281 // Jar Service Provider specification 282 factoryClassName = rd.readLine(); 283 rd.close(); 284 } catch (IOException x) { 285 // No provider found 286 return null; 287 } 288 289 if (factoryClassName != null && !"".equals(factoryClassName)) { 290 dPrint("found in resource, value=" + factoryClassName); 291 292 // Note: here we do not want to fall back to the current 293 // ClassLoader because we want to avoid the case where the 294 // resource file was found using one ClassLoader and the 295 // provider class was instantiated using a different one. 296 return newInstance(factoryClassName, cl, false); 297 } 298 299 // No provider found 300 return null; 301 } 302 303 static class ConfigurationError extends Error { 304 private Exception exception; 305 306 /** 307 * Construct a new instance with the specified detail string and 308 * exception. 309 */ 310 ConfigurationError(String msg, Exception x) { 311 super(msg); 312 this.exception = x; 313 } 314 315 Exception getException() { 316 return exception; 317 } 318 /** 319 * use the exception chaining mechanism of JDK1.4 320 */ 321 @Override 322 public Throwable getCause() { 323 return exception; 324 } 325 } 326 327 } | 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.datatype; 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 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 */ 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 private final static Properties cacheProps = new Properties(); 55 56 /** 57 * Flag indicating if properties from java.home/lib/jaxp.properties 58 * have been cached. 59 */ 60 private static volatile boolean firstTime = true; 61 62 /** 63 * Security support class use to check access control before 64 * getting certain system resources. 65 */ 66 private final 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 static private Class<?> getProviderClass(String className, ClassLoader cl, 98 boolean doFallback) throws ClassNotFoundException 99 { 100 try { 101 if (cl == null) { 102 cl = ss.getContextClassLoader(); 103 if (cl == null) { 104 throw new ClassNotFoundException(); 105 } 106 else { 107 return Class.forName(className, false, cl); 108 } 109 } 110 else { 111 return Class.forName(className, false, cl); 112 } 113 } 114 catch (ClassNotFoundException e1) { 115 if (doFallback) { 116 // Use current class loader - should always be bootstrap CL 117 return Class.forName(className, false, FactoryFinder.class.getClassLoader()); 118 } 119 else { 120 throw e1; 121 } 122 } 123 } 124 125 /** 126 * Create an instance of a class. Delegates to method 127 * <code>getProviderClass()</code> in order to load the class. 128 * 129 * @param type Base class / Service interface of the factory to 130 * instantiate. 131 * 132 * @param className Name of the concrete class corresponding to the 133 * service provider 134 * 135 * @param cl ClassLoader to use to load the class, null means to use 136 * the bootstrap ClassLoader 137 * 138 * @param doFallback True if the current ClassLoader should be tried as 139 * a fallback if the class is not found using cl 140 */ 141 static <T> T newInstance(Class<T> type, String className, ClassLoader cl, boolean doFallback) 142 throws DatatypeConfigurationException 143 { 144 assert type != null; 145 try { 146 Class<?> providerClass = getProviderClass(className, cl, doFallback); 147 if (!type.isAssignableFrom(providerClass)) { 148 throw new ClassCastException(className + " cannot be cast to " + type.getName()); 149 } 150 Object instance = providerClass.newInstance(); 151 if (debug) { // Extra check to avoid computing cl strings 152 dPrint("created new instance of " + providerClass + 153 " using ClassLoader: " + cl); 154 } 155 return type.cast(instance); 156 } 157 catch (ClassNotFoundException x) { 158 throw new DatatypeConfigurationException( 159 "Provider " + className + " not found", x); 160 } 161 catch (Exception x) { 162 throw new DatatypeConfigurationException( 163 "Provider " + className + " could not be instantiated: " + x, 164 x); 165 } 166 } 167 168 /** 169 * Finds the implementation Class object in the specified order. Main 170 * entry point. 171 * @return Class object of factory, never null 172 * 173 * @param type Base class / Service interface of the 174 * factory to find. 175 * @param fallbackClassName Implementation class name, if nothing else 176 * is found. Use null to mean no fallback. 177 * 178 * Package private so this code can be shared. 179 */ 180 static <T> T find(Class<T> type, String fallbackClassName) 181 throws DatatypeConfigurationException 182 { 183 final String factoryId = type.getName(); 184 dPrint("find factoryId =" + factoryId); 185 186 // Use the system property first 187 try { 188 String systemProp = ss.getSystemProperty(factoryId); 189 if (systemProp != null) { 190 dPrint("found system property, value=" + systemProp); 191 return newInstance(type, systemProp, null, true); 192 } 193 } 194 catch (SecurityException se) { 195 if (debug) se.printStackTrace(); 196 } 197 198 // try to read from $java.home/lib/jaxp.properties 199 try { 200 String factoryClassName; 201 if (firstTime) { 202 synchronized (cacheProps) { 203 if (firstTime) { 204 String configFile = ss.getSystemProperty("java.home") + File.separator + 205 "lib" + File.separator + "jaxp.properties"; 206 File f = new File(configFile); 207 firstTime = false; 208 if (ss.doesFileExist(f)) { 209 dPrint("Read properties file "+f); 210 cacheProps.load(ss.getFileInputStream(f)); 211 } 212 } 213 } 214 } 215 factoryClassName = cacheProps.getProperty(factoryId); 216 217 if (factoryClassName != null) { 218 dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); 219 return newInstance(type, factoryClassName, null, true); 220 } 221 } 222 catch (Exception ex) { 223 if (debug) ex.printStackTrace(); 224 } 225 226 // Try Jar Service Provider Mechanism 227 final T provider = findServiceProvider(type); 228 if (provider != null) { 229 return provider; 230 } 231 if (fallbackClassName == null) { 232 throw new DatatypeConfigurationException( 233 "Provider for " + factoryId + " cannot be found"); 234 } 235 236 dPrint("loaded from fallback value: " + fallbackClassName); 237 return newInstance(type, fallbackClassName, null, true); 238 } 239 240 /* 241 * Try to find provider using the ServiceLoader API 242 * 243 * @param type Base class / Service interface of the factory to find. 244 * 245 * @return instance of provider class if found or null 246 */ 247 private static <T> T findServiceProvider(final Class<T> type) 248 throws DatatypeConfigurationException 249 { 250 try { 251 return AccessController.doPrivileged(new PrivilegedAction<T>() { 252 public T run() { 253 final ServiceLoader<T> serviceLoader = ServiceLoader.load(type); 254 final Iterator<T> iterator = serviceLoader.iterator(); 255 if (iterator.hasNext()) { 256 return iterator.next(); 257 } else { 258 return null; 259 } 260 } 261 }); 262 } catch(ServiceConfigurationError e) { 263 final DatatypeConfigurationException error = 264 new DatatypeConfigurationException( 265 "Provider for " + type + " cannot be found", e); 266 throw error; 267 } 268 } 269 270 } |