1 /* 2 * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 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.xpath; 27 28 import java.io.File; 29 import java.lang.reflect.Method; 30 import java.lang.reflect.Modifier; 31 import java.security.AccessControlContext; 32 import java.security.AccessController; 33 import java.security.PrivilegedAction; 34 import java.util.Properties; 35 import java.util.ServiceConfigurationError; 36 import java.util.ServiceLoader; 37 38 /** 39 * Implementation of {@link XPathFactory#newInstance(String)}. 40 * 41 * @author <a href="Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a> 42 * @since 1.5 43 */ 44 class XPathFactoryFinder { 45 private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xpath.internal"; 46 47 private static final SecuritySupport ss = new SecuritySupport() ; 48 /** debug support code. */ 49 private static boolean debug = false; 50 static { 51 // Use try/catch block to support applets 52 try { 53 debug = ss.getSystemProperty("jaxp.debug") != null; 54 } catch (Exception unused) { 55 debug = false; 56 } 57 } 58 59 /** 60 * <p>Cache properties for performance.</p> 61 */ 62 private static final Properties cacheProps = new Properties(); 63 64 /** 65 * <p>First time requires initialization overhead.</p> 66 */ 67 private volatile static boolean firstTime = true; 68 69 /** 70 * <p>Conditional debug printing.</p> 71 * 72 * @param msg to print 73 */ 74 private static void debugPrintln(String msg) { 75 if (debug) { 76 System.err.println("JAXP: " + msg); 77 } 78 } 79 80 /** 81 * <p><code>ClassLoader</code> to use to find <code>XPathFactory</code>.</p> 82 */ 83 private final ClassLoader classLoader; 84 85 /** 86 * <p>Constructor that specifies <code>ClassLoader</code> to use 87 * to find <code>XPathFactory</code>.</p> 88 * 89 * @param loader 90 * to be used to load resource and {@link XPathFactory} 91 * implementations during the resolution process. 92 * If this parameter is null, the default system class loader 93 * will be used. 94 */ 95 public XPathFactoryFinder(ClassLoader loader) { 96 this.classLoader = loader; 97 if( debug ) { 98 debugDisplayClassLoader(); 99 } 100 } 101 102 private void debugDisplayClassLoader() { 103 try { 104 if( classLoader == ss.getContextClassLoader() ) { 105 debugPrintln("using thread context class loader ("+classLoader+") for search"); 106 return; 107 } 108 } catch( Throwable unused ) { 109 // getContextClassLoader() undefined in JDK1.1 110 } 111 112 if( classLoader==ClassLoader.getSystemClassLoader() ) { 113 debugPrintln("using system class loader ("+classLoader+") for search"); 114 return; 115 } 116 117 debugPrintln("using class loader ("+classLoader+") for search"); 118 } 119 120 /** 121 * <p>Creates a new {@link XPathFactory} object for the specified 122 * object model.</p> 123 * 124 * @param uri 125 * Identifies the underlying object model. 126 * 127 * @return <code>null</code> if the callee fails to create one. 128 * 129 * @throws NullPointerException 130 * If the parameter is null. 131 */ 132 public XPathFactory newFactory(String uri) throws XPathFactoryConfigurationException { 133 if (uri == null) { 134 throw new NullPointerException(); 135 } 136 XPathFactory f = _newFactory(uri); 137 if (f != null) { 138 debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri); 139 } else { 140 debugPrintln("unable to find a factory for " + uri); 141 } 142 return f; 143 } 144 145 /** 146 * <p>Lookup a {@link XPathFactory} for the given object model.</p> 147 * 148 * @param uri identifies the object model. 149 * 150 * @return {@link XPathFactory} for the given object model. 151 */ 152 private XPathFactory _newFactory(String uri) throws XPathFactoryConfigurationException { 153 XPathFactory xpathFactory = null; 154 155 String propertyName = SERVICE_CLASS.getName() + ":" + uri; 156 157 // system property look up 158 try { 159 debugPrintln("Looking up system property '"+propertyName+"'" ); 160 String r = ss.getSystemProperty(propertyName); 161 if(r!=null) { 162 debugPrintln("The value is '"+r+"'"); 163 xpathFactory = createInstance(r, true); 164 if (xpathFactory != null) { 165 return xpathFactory; 166 } 167 } else 168 debugPrintln("The property is undefined."); 169 } catch( Throwable t ) { 170 if( debug ) { 171 debugPrintln("failed to look up system property '"+propertyName+"'" ); 172 t.printStackTrace(); 173 } 174 } 175 176 String javah = ss.getSystemProperty( "java.home" ); 177 String configFile = javah + File.separator + 178 "lib" + File.separator + "jaxp.properties"; 179 180 // try to read from $java.home/lib/jaxp.properties 181 try { 182 if(firstTime){ 183 synchronized(cacheProps){ 184 if(firstTime){ 185 File f=new File( configFile ); 186 firstTime = false; 187 if(ss.doesFileExist(f)){ 188 debugPrintln("Read properties file " + f); 189 cacheProps.load(ss.getFileInputStream(f)); 190 } 191 } 192 } 193 } 194 final String factoryClassName = cacheProps.getProperty(propertyName); 195 debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties"); 196 197 if (factoryClassName != null) { 198 xpathFactory = createInstance(factoryClassName, true); 199 if(xpathFactory != null){ 200 return xpathFactory; 201 } 202 } 203 } catch (Exception ex) { 204 if (debug) { 205 ex.printStackTrace(); 206 } 207 } 208 209 // Try with ServiceLoader 210 assert xpathFactory == null; 211 xpathFactory = findServiceProvider(uri); 212 213 // The following assertion should always be true. 214 // Uncomment it, recompile, and run with -ea in case of doubts: 215 // assert xpathFactory == null || xpathFactory.isObjectModelSupported(uri); 216 217 if (xpathFactory != null) { 218 return xpathFactory; 219 } 220 221 // platform default 222 if(uri.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) { 223 debugPrintln("attempting to use the platform default W3C DOM XPath lib"); 224 return createInstance("com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", true); 225 } 226 227 debugPrintln("all things were tried, but none was found. bailing out."); 228 return null; 229 } 230 231 /** <p>Create class using appropriate ClassLoader.</p> 232 * 233 * @param className Name of class to create. 234 * @return Created class or <code>null</code>. 235 */ 236 private Class<?> createClass(String className) { 237 Class clazz; 238 // make sure we have access to restricted packages 239 boolean internal = false; 240 if (System.getSecurityManager() != null) { 241 if (className != null && className.startsWith(DEFAULT_PACKAGE)) { 242 internal = true; 243 } 244 } 245 246 // use approprite ClassLoader 247 try { 263 /** 264 * <p>Creates an instance of the specified and returns it.</p> 265 * 266 * @param className 267 * fully qualified class name to be instantiated. 268 * 269 * @return null 270 * if it fails. Error messages will be printed by this method. 271 */ 272 XPathFactory createInstance( String className ) 273 throws XPathFactoryConfigurationException 274 { 275 return createInstance( className, false ); 276 } 277 278 XPathFactory createInstance( String className, boolean useServicesMechanism ) 279 throws XPathFactoryConfigurationException 280 { 281 XPathFactory xPathFactory = null; 282 283 debugPrintln("createInstance(" + className + ")"); 284 285 // get Class from className 286 Class<?> clazz = createClass(className); 287 if (clazz == null) { 288 debugPrintln("failed to getClass(" + className + ")"); 289 return null; 290 } 291 debugPrintln("loaded " + className + " from " + which(clazz)); 292 293 // instantiate Class as a XPathFactory 294 try { 295 if (!useServicesMechanism) { 296 xPathFactory = newInstanceNoServiceLoader(clazz); 297 } 298 if (xPathFactory == null) { 299 xPathFactory = (XPathFactory) clazz.newInstance(); 300 } 301 } catch (ClassCastException classCastException) { 302 debugPrintln("could not instantiate " + clazz.getName()); 303 if (debug) { 304 classCastException.printStackTrace(); 305 } 306 return null; 307 } catch (IllegalAccessException illegalAccessException) { 308 debugPrintln("could not instantiate " + clazz.getName()); 309 if (debug) { 310 illegalAccessException.printStackTrace(); 311 } 312 return null; 313 } catch (InstantiationException instantiationException) { 314 debugPrintln("could not instantiate " + clazz.getName()); 315 if (debug) { 316 instantiationException.printStackTrace(); 317 } 318 return null; 319 } 320 321 return xPathFactory; 322 } 323 /** 324 * Try to construct using newXPathFactoryNoServiceLoader 325 * method if available. 326 */ 327 private static XPathFactory newInstanceNoServiceLoader( 328 Class<?> providerClass 329 ) throws XPathFactoryConfigurationException { 330 // Retain maximum compatibility if no security manager. 331 if (System.getSecurityManager() == null) { 332 return null; 333 } 334 try { | 1 /* 2 * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 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.xpath; 27 28 import java.io.File; 29 import java.lang.reflect.Method; 30 import java.lang.reflect.Modifier; 31 import java.security.AccessControlContext; 32 import java.security.AccessController; 33 import java.security.PrivilegedAction; 34 import java.util.Properties; 35 import java.util.ServiceConfigurationError; 36 import java.util.ServiceLoader; 37 import java.util.function.Supplier; 38 39 /** 40 * Implementation of {@link XPathFactory#newInstance(String)}. 41 * 42 * @author <a href="Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a> 43 * @since 1.5 44 */ 45 class XPathFactoryFinder { 46 private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xpath.internal"; 47 48 private static final SecuritySupport ss = new SecuritySupport() ; 49 /** debug support code. */ 50 private static boolean debug = false; 51 static { 52 // Use try/catch block to support applets 53 try { 54 debug = ss.getSystemProperty("jaxp.debug") != null; 55 } catch (Exception unused) { 56 debug = false; 57 } 58 } 59 60 /** 61 * <p>Cache properties for performance.</p> 62 */ 63 private static final Properties cacheProps = new Properties(); 64 65 /** 66 * <p>First time requires initialization overhead.</p> 67 */ 68 private volatile static boolean firstTime = true; 69 70 /** 71 * <p>Conditional debug printing.</p> 72 * 73 * @param msgGen Supplier function that returns debug message 74 */ 75 private static void debugPrintln(Supplier<String> msgGen) { 76 if (debug) { 77 System.err.println("JAXP: " + msgGen.get()); 78 } 79 } 80 81 /** 82 * <p><code>ClassLoader</code> to use to find <code>XPathFactory</code>.</p> 83 */ 84 private final ClassLoader classLoader; 85 86 /** 87 * <p>Constructor that specifies <code>ClassLoader</code> to use 88 * to find <code>XPathFactory</code>.</p> 89 * 90 * @param loader 91 * to be used to load resource and {@link XPathFactory} 92 * implementations during the resolution process. 93 * If this parameter is null, the default system class loader 94 * will be used. 95 */ 96 public XPathFactoryFinder(ClassLoader loader) { 97 this.classLoader = loader; 98 if( debug ) { 99 debugDisplayClassLoader(); 100 } 101 } 102 103 private void debugDisplayClassLoader() { 104 try { 105 if( classLoader == ss.getContextClassLoader() ) { 106 debugPrintln(() -> "using thread context class loader ("+classLoader+") for search"); 107 return; 108 } 109 } catch( Throwable unused ) { 110 // getContextClassLoader() undefined in JDK1.1 111 } 112 113 if( classLoader==ClassLoader.getSystemClassLoader() ) { 114 debugPrintln(() -> "using system class loader ("+classLoader+") for search"); 115 return; 116 } 117 118 debugPrintln(() -> "using class loader ("+classLoader+") for search"); 119 } 120 121 /** 122 * <p>Creates a new {@link XPathFactory} object for the specified 123 * object model.</p> 124 * 125 * @param uri 126 * Identifies the underlying object model. 127 * 128 * @return <code>null</code> if the callee fails to create one. 129 * 130 * @throws NullPointerException 131 * If the parameter is null. 132 */ 133 public XPathFactory newFactory(String uri) throws XPathFactoryConfigurationException { 134 if (uri == null) { 135 throw new NullPointerException(); 136 } 137 XPathFactory f = _newFactory(uri); 138 if (f != null) { 139 debugPrintln(()->"factory '" + f.getClass().getName() + "' was found for " + uri); 140 } else { 141 debugPrintln(()->"unable to find a factory for " + uri); 142 } 143 return f; 144 } 145 146 /** 147 * <p>Lookup a {@link XPathFactory} for the given object model.</p> 148 * 149 * @param uri identifies the object model. 150 * 151 * @return {@link XPathFactory} for the given object model. 152 */ 153 private XPathFactory _newFactory(String uri) throws XPathFactoryConfigurationException { 154 XPathFactory xpathFactory = null; 155 156 String propertyName = SERVICE_CLASS.getName() + ":" + uri; 157 158 // system property look up 159 try { 160 debugPrintln(()->"Looking up system property '"+propertyName+"'" ); 161 String r = ss.getSystemProperty(propertyName); 162 if(r!=null) { 163 debugPrintln(()->"The value is '"+r+"'"); 164 xpathFactory = createInstance(r, true); 165 if (xpathFactory != null) { 166 return xpathFactory; 167 } 168 } else 169 debugPrintln(()->"The property is undefined."); 170 } catch( Throwable t ) { 171 if( debug ) { 172 debugPrintln(()->"failed to look up system property '"+propertyName+"'" ); 173 t.printStackTrace(); 174 } 175 } 176 177 String javah = ss.getSystemProperty( "java.home" ); 178 String configFile = javah + File.separator + 179 "lib" + File.separator + "jaxp.properties"; 180 181 // try to read from $java.home/lib/jaxp.properties 182 try { 183 if(firstTime){ 184 synchronized(cacheProps){ 185 if(firstTime){ 186 File f=new File( configFile ); 187 firstTime = false; 188 if(ss.doesFileExist(f)){ 189 debugPrintln(()->"Read properties file " + f); 190 cacheProps.load(ss.getFileInputStream(f)); 191 } 192 } 193 } 194 } 195 final String factoryClassName = cacheProps.getProperty(propertyName); 196 debugPrintln(()->"found " + factoryClassName + " in $java.home/jaxp.properties"); 197 198 if (factoryClassName != null) { 199 xpathFactory = createInstance(factoryClassName, true); 200 if(xpathFactory != null){ 201 return xpathFactory; 202 } 203 } 204 } catch (Exception ex) { 205 if (debug) { 206 ex.printStackTrace(); 207 } 208 } 209 210 // Try with ServiceLoader 211 assert xpathFactory == null; 212 xpathFactory = findServiceProvider(uri); 213 214 // The following assertion should always be true. 215 // Uncomment it, recompile, and run with -ea in case of doubts: 216 // assert xpathFactory == null || xpathFactory.isObjectModelSupported(uri); 217 218 if (xpathFactory != null) { 219 return xpathFactory; 220 } 221 222 // platform default 223 if(uri.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) { 224 debugPrintln(()->"attempting to use the platform default W3C DOM XPath lib"); 225 return createInstance("com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", true); 226 } 227 228 debugPrintln(()->"all things were tried, but none was found. bailing out."); 229 return null; 230 } 231 232 /** <p>Create class using appropriate ClassLoader.</p> 233 * 234 * @param className Name of class to create. 235 * @return Created class or <code>null</code>. 236 */ 237 private Class<?> createClass(String className) { 238 Class clazz; 239 // make sure we have access to restricted packages 240 boolean internal = false; 241 if (System.getSecurityManager() != null) { 242 if (className != null && className.startsWith(DEFAULT_PACKAGE)) { 243 internal = true; 244 } 245 } 246 247 // use approprite ClassLoader 248 try { 264 /** 265 * <p>Creates an instance of the specified and returns it.</p> 266 * 267 * @param className 268 * fully qualified class name to be instantiated. 269 * 270 * @return null 271 * if it fails. Error messages will be printed by this method. 272 */ 273 XPathFactory createInstance( String className ) 274 throws XPathFactoryConfigurationException 275 { 276 return createInstance( className, false ); 277 } 278 279 XPathFactory createInstance( String className, boolean useServicesMechanism ) 280 throws XPathFactoryConfigurationException 281 { 282 XPathFactory xPathFactory = null; 283 284 debugPrintln(()->"createInstance(" + className + ")"); 285 286 // get Class from className 287 Class<?> clazz = createClass(className); 288 if (clazz == null) { 289 debugPrintln(()->"failed to getClass(" + className + ")"); 290 return null; 291 } 292 debugPrintln(()->"loaded " + className + " from " + which(clazz)); 293 294 // instantiate Class as a XPathFactory 295 try { 296 if (!useServicesMechanism) { 297 xPathFactory = newInstanceNoServiceLoader(clazz); 298 } 299 if (xPathFactory == null) { 300 xPathFactory = (XPathFactory) clazz.newInstance(); 301 } 302 } catch (ClassCastException classCastException) { 303 debugPrintln(()->"could not instantiate " + clazz.getName()); 304 if (debug) { 305 classCastException.printStackTrace(); 306 } 307 return null; 308 } catch (IllegalAccessException illegalAccessException) { 309 debugPrintln(()->"could not instantiate " + clazz.getName()); 310 if (debug) { 311 illegalAccessException.printStackTrace(); 312 } 313 return null; 314 } catch (InstantiationException instantiationException) { 315 debugPrintln(()->"could not instantiate " + clazz.getName()); 316 if (debug) { 317 instantiationException.printStackTrace(); 318 } 319 return null; 320 } 321 322 return xPathFactory; 323 } 324 /** 325 * Try to construct using newXPathFactoryNoServiceLoader 326 * method if available. 327 */ 328 private static XPathFactory newInstanceNoServiceLoader( 329 Class<?> providerClass 330 ) throws XPathFactoryConfigurationException { 331 // Retain maximum compatibility if no security manager. 332 if (System.getSecurityManager() == null) { 333 return null; 334 } 335 try { |