1 /*
2 * Copyright (c) 2004, 2005, 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.BufferedReader;
29 import java.io.File;
30 import java.io.FileInputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.InputStreamReader;
34 import java.lang.reflect.Method;
35 import java.lang.reflect.InvocationTargetException;
36 import java.net.URL;
37 import java.util.ArrayList;
38 import java.util.Enumeration;
39 import java.util.Iterator;
40 import java.util.NoSuchElementException;
41 import java.util.Properties;
42
43 /**
44 * Implementation of {@link XPathFactory#newInstance(String)}.
45 *
46 * @author <a href="Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
47 * @version $Revision: 1.7 $, $Date: 2010-11-01 04:36:14 $
48 * @since 1.5
49 */
50 class XPathFactoryFinder {
51 private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xpath.internal";
52
53 private static SecuritySupport ss = new SecuritySupport() ;
54 /** debug support code. */
55 private static boolean debug = false;
56 static {
57 // Use try/catch block to support applets
58 try {
59 debug = ss.getSystemProperty("jaxp.debug") != null;
60 } catch (Exception unused) {
61 debug = false;
62 }
63 }
64
65 /**
66 * <p>Cache properties for performance.</p>
67 */
68 private static Properties cacheProps = new Properties();
69
70 /**
71 * <p>First time requires initialization overhead.</p>
72 */
73 private volatile static boolean firstTime = true;
74
75 /**
76 * <p>Conditional debug printing.</p>
77 *
78 * @param msg to print
79 */
80 private static void debugPrintln(String msg) {
81 if (debug) {
82 System.err.println("JAXP: " + msg);
83 }
84 }
85
86 /**
87 * <p><code>ClassLoader</code> to use to find <code>XPathFactory</code>.</p>
88 */
89 private final ClassLoader classLoader;
90
91 /**
92 * <p>Constructor that specifies <code>ClassLoader</code> to use
93 * to find <code>XPathFactory</code>.</p>
94 *
95 * @param loader
96 * to be used to load resource, {@link XPathFactory}, and
97 * {@link SchemaFactoryLoader} implementations during
98 * the resolution process.
99 * If this parameter is null, the default system class loader
100 * will be used.
101 */
102 public XPathFactoryFinder(ClassLoader loader) {
103 this.classLoader = loader;
104 if( debug ) {
105 debugDisplayClassLoader();
106 }
107 }
108
109 private void debugDisplayClassLoader() {
110 try {
111 if( classLoader == ss.getContextClassLoader() ) {
112 debugPrintln("using thread context class loader ("+classLoader+") for search");
113 return;
114 }
115 } catch( Throwable unused ) {
116 ; // getContextClassLoader() undefined in JDK1.1
117 }
118
119 if( classLoader==ClassLoader.getSystemClassLoader() ) {
120 debugPrintln("using system class loader ("+classLoader+") for search");
121 return;
122 }
123
124 debugPrintln("using class loader ("+classLoader+") for search");
125 }
126
127 /**
128 * <p>Creates a new {@link XPathFactory} object for the specified
129 * schema language.</p>
130 *
131 * @param uri
132 * Identifies the underlying object model.
133 *
134 * @return <code>null</code> if the callee fails to create one.
135 *
136 * @throws NullPointerException
137 * If the parameter is null.
138 */
139 public XPathFactory newFactory(String uri) {
140 if(uri==null) throw new NullPointerException();
141 XPathFactory f = _newFactory(uri);
142 if (f != null) {
143 debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri);
144 } else {
145 debugPrintln("unable to find a factory for " + uri);
146 }
147 return f;
148 }
149
150 /**
151 * <p>Lookup a {@link XPathFactory} for the given object model.</p>
152 *
153 * @param uri identifies the object model.
154 *
155 * @return {@link XPathFactory} for the given object model.
156 */
157 private XPathFactory _newFactory(String uri) {
158 XPathFactory xpathFactory;
159
160 String propertyName = SERVICE_CLASS.getName() + ":" + uri;
161
162 // system property look up
163 try {
164 debugPrintln("Looking up system property '"+propertyName+"'" );
165 String r = ss.getSystemProperty(propertyName);
166 if(r!=null) {
167 debugPrintln("The value is '"+r+"'");
168 xpathFactory = createInstance(r, true);
169 if(xpathFactory != null) return xpathFactory;
170 } else
171 debugPrintln("The property is undefined.");
172 } catch( Throwable t ) {
173 if( debug ) {
174 debugPrintln("failed to look up system property '"+propertyName+"'" );
175 t.printStackTrace();
176 }
177 }
178
179 String javah = ss.getSystemProperty( "java.home" );
180 String configFile = javah + File.separator +
181 "lib" + File.separator + "jaxp.properties";
182
183 String factoryClassName = null ;
184
185 // try to read from $java.home/lib/jaxp.properties
186 try {
187 if(firstTime){
188 synchronized(cacheProps){
189 if(firstTime){
190 File f=new File( configFile );
191 firstTime = false;
192 if(ss.doesFileExist(f)){
193 debugPrintln("Read properties file " + f);
194 cacheProps.load(ss.getFileInputStream(f));
195 }
196 }
197 }
198 }
199 factoryClassName = cacheProps.getProperty(propertyName);
200 debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
201
202 if (factoryClassName != null) {
203 xpathFactory = createInstance(factoryClassName, true);
204 if(xpathFactory != null){
205 return xpathFactory;
206 }
207 }
208 } catch (Exception ex) {
209 if (debug) {
210 ex.printStackTrace();
211 }
212 }
213
214 // try META-INF/services files
215 Iterator sitr = createServiceFileIterator();
216 while(sitr.hasNext()) {
217 URL resource = (URL)sitr.next();
218 debugPrintln("looking into " + resource);
219 try {
220 xpathFactory = loadFromService(uri, resource.toExternalForm(),
221 ss.getURLInputStream(resource));
222 if (xpathFactory != null) {
223 return xpathFactory;
224 }
225 } catch(IOException e) {
226 if( debug ) {
227 debugPrintln("failed to read "+resource);
228 e.printStackTrace();
229 }
230 }
231 }
232
233 // platform default
234 if(uri.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) {
235 debugPrintln("attempting to use the platform default W3C DOM XPath lib");
236 return createInstance("com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", true);
237 }
238
239 debugPrintln("all things were tried, but none was found. bailing out.");
240 return null;
241 }
242
243 /** <p>Create class using appropriate ClassLoader.</p>
244 *
245 * @param className Name of class to create.
246 * @return Created class or <code>null</code>.
247 */
248 private Class createClass(String className) {
249 Class clazz;
250 // make sure we have access to restricted packages
251 boolean internal = false;
252 if (System.getSecurityManager() != null) {
253 if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
254 internal = true;
255 }
256 }
257
258 // use approprite ClassLoader
259 try {
260 if (classLoader != null && !internal) {
261 clazz = classLoader.loadClass(className);
262 } else {
263 clazz = Class.forName(className);
264 }
265 } catch (Throwable t) {
266 if(debug) t.printStackTrace();
267 return null;
268 }
269
270 return clazz;
271 }
272
273 /**
274 * <p>Creates an instance of the specified and returns it.</p>
275 *
276 * @param className
277 * fully qualified class name to be instanciated.
278 *
279 * @return null
280 * if it fails. Error messages will be printed by this method.
281 */
282 XPathFactory createInstance( String className ) {
283 return createInstance( className, false );
284 }
285 XPathFactory createInstance( String className, boolean useServicesMechanism ) {
286 XPathFactory xPathFactory = null;
287
288 debugPrintln("createInstance(" + className + ")");
289
290 // get Class from className
291 Class clazz = createClass(className);
292 if (clazz == null) {
293 debugPrintln("failed to getClass(" + className + ")");
294 return null;
295 }
296 debugPrintln("loaded " + className + " from " + which(clazz));
297
298 // instantiate Class as a XPathFactory
299 try {
300 if (!useServicesMechanism) {
301 xPathFactory = (XPathFactory) newInstanceNoServiceLoader(clazz);
302 }
303 if (xPathFactory == null) {
304 xPathFactory = (XPathFactory) clazz.newInstance();
305 }
306 } catch (ClassCastException classCastException) {
307 debugPrintln("could not instantiate " + clazz.getName());
308 if (debug) {
309 classCastException.printStackTrace();
310 }
311 return null;
312 } catch (IllegalAccessException illegalAccessException) {
313 debugPrintln("could not instantiate " + clazz.getName());
314 if (debug) {
315 illegalAccessException.printStackTrace();
316 }
317 return null;
318 } catch (InstantiationException instantiationException) {
319 debugPrintln("could not instantiate " + clazz.getName());
320 if (debug) {
321 instantiationException.printStackTrace();
322 }
323 return null;
324 }
325
326 return xPathFactory;
327 }
328 /**
329 * Try to construct using newXPathFactoryNoServiceLoader
330 * method if available.
331 */
332 private static Object newInstanceNoServiceLoader(
333 Class<?> providerClass
334 ) {
335 // Retain maximum compatibility if no security manager.
336 if (System.getSecurityManager() == null) {
337 return null;
338 }
339 try {
340 Method creationMethod =
341 providerClass.getDeclaredMethod(
342 "newXPathFactoryNoServiceLoader"
343 );
344 return creationMethod.invoke(null, (Object[])null);
345 } catch (NoSuchMethodException exc) {
346 return null;
347 } catch (Exception exc) {
348 return null;
349 }
350 }
351
352 /**
353 * <p>Look up a value in a property file.</p>
354 *
355 * <p>Set <code>debug</code> to <code>true</code> to trace property evaluation.</p>
356 *
357 * @param objectModel URI of object model to support.
358 * @param inputName Name of <code>InputStream</code>.
359 * @param in <code>InputStream</code> of properties.
360 *
361 * @return <code>XPathFactory</code> as determined by <code>keyName</code> value or <code>null</code> if there was an error.
362 *
363 * @throws IOException If IO error reading from <code>in</code>.
364 */
365 private XPathFactory loadFromService(
366 String objectModel,
367 String inputName,
368 InputStream in)
369 throws IOException {
370
371 XPathFactory xPathFactory = null;
372 final Class[] stringClassArray = {"".getClass()};
373 final Object[] objectModelObjectArray = {objectModel};
374 final String isObjectModelSupportedMethod = "isObjectModelSupported";
375
376 debugPrintln("Reading " + inputName);
377
378 // read from InputStream until a match is found
379 BufferedReader configFile = new BufferedReader(new InputStreamReader(in));
380 String line = null;
381 while ((line = configFile.readLine()) != null) {
382 // '#' is comment char
383 int comment = line.indexOf("#");
384 switch (comment) {
385 case -1: break; // no comment
386 case 0: line = ""; break; // entire line is a comment
387 default: line = line.substring(0, comment); break; // trim comment
388 }
389
390 // trim whitespace
391 line = line.trim();
392
393 // any content left on line?
394 if (line.length() == 0) {
395 continue;
396 }
397
398 // line content is now the name of the class
399 Class clazz = createClass(line);
400 if (clazz == null) {
401 continue;
402 }
403
404 // create an instance of the Class
405 try {
406 xPathFactory = (XPathFactory) clazz.newInstance();
407 } catch (ClassCastException classCastExcpetion) {
408 xPathFactory = null;
409 continue;
410 } catch (InstantiationException instantiationException) {
411 xPathFactory = null;
412 continue;
413 } catch (IllegalAccessException illegalAccessException) {
414 xPathFactory = null;
415 continue;
416 }
417
418 // does this Class support desired object model?
419 try {
420 Method isObjectModelSupported = clazz.getMethod(isObjectModelSupportedMethod, stringClassArray);
421 Boolean supported = (Boolean) isObjectModelSupported.invoke(xPathFactory, objectModelObjectArray);
422 if (supported.booleanValue()) {
423 break;
424 }
425
426 } catch (NoSuchMethodException noSuchMethodException) {
427
428 } catch (IllegalAccessException illegalAccessException) {
429
430 } catch (InvocationTargetException invocationTargetException) {
431
432 }
433 xPathFactory = null;
434 }
435
436 // clean up
437 configFile.close();
438
439 // return new instance of XPathFactory or null
440 return xPathFactory;
441 }
442
443 /** Iterator that lazily computes one value and returns it. */
444 private static abstract class SingleIterator implements Iterator {
445 private boolean seen = false;
446
447 public final void remove() { throw new UnsupportedOperationException(); }
448 public final boolean hasNext() { return !seen; }
449 public final Object next() {
450 if(seen) throw new NoSuchElementException();
451 seen = true;
452 return value();
453 }
454
455 protected abstract Object value();
456 }
457
458 /**
459 * Looks up a value in a property file
460 * while producing all sorts of debug messages.
461 *
462 * @return null
463 * if there was an error.
464 */
465 private XPathFactory loadFromProperty( String keyName, String resourceName, InputStream in )
466 throws IOException {
467 debugPrintln("Reading "+resourceName );
468
469 Properties props = new Properties();
470 props.load(in);
471 in.close();
472 String factoryClassName = props.getProperty(keyName);
473 if(factoryClassName != null){
474 debugPrintln("found "+keyName+" = " + factoryClassName);
475 return createInstance(factoryClassName, true);
476 } else {
477 debugPrintln(keyName+" is not in the property file");
478 return null;
479 }
480 }
481
482 /**
483 * Returns an {@link Iterator} that enumerates all
484 * the META-INF/services files that we care.
485 */
486 private Iterator createServiceFileIterator() {
487 if (classLoader == null) {
488 return new SingleIterator() {
489 protected Object value() {
490 ClassLoader classLoader = XPathFactoryFinder.class.getClassLoader();
491 return ss.getResourceAsURL(classLoader, SERVICE_ID);
492 //return (ClassLoader.getSystemResource( SERVICE_ID ));
493 }
494 };
495 } else {
496 try {
497 //final Enumeration e = classLoader.getResources(SERVICE_ID);
498 final Enumeration e = ss.getResources(classLoader, SERVICE_ID);
499 if(!e.hasMoreElements()) {
500 debugPrintln("no "+SERVICE_ID+" file was found");
501 }
502
503 // wrap it into an Iterator.
504 return new Iterator() {
505 public void remove() {
506 throw new UnsupportedOperationException();
507 }
508
509 public boolean hasNext() {
510 return e.hasMoreElements();
511 }
512
513 public Object next() {
514 return e.nextElement();
515 }
516 };
517 } catch (IOException e) {
518 debugPrintln("failed to enumerate resources "+SERVICE_ID);
519 if(debug) e.printStackTrace();
520 return new ArrayList().iterator(); // empty iterator
521 }
522 }
523 }
524
525 private static final Class SERVICE_CLASS = XPathFactory.class;
526 private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName();
527
528
529
530 private static String which( Class clazz ) {
531 return which( clazz.getName(), clazz.getClassLoader() );
532 }
533
534 /**
535 * <p>Search the specified classloader for the given classname.</p>
536 *
537 * @param classname the fully qualified name of the class to search for
538 * @param loader the classloader to search
539 *
540 * @return the source location of the resource, or null if it wasn't found
541 */
542 private static String which(String classname, ClassLoader loader) {
543
544 String classnameAsResource = classname.replace('.', '/') + ".class";
545
546 if( loader==null ) loader = ClassLoader.getSystemClassLoader();
547
548 //URL it = loader.getResource(classnameAsResource);
|
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.net.URL;
32 import java.security.AccessControlContext;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.util.Properties;
36 import java.util.ServiceConfigurationError;
37 import java.util.ServiceLoader;
38
39 /**
40 * Implementation of {@link XPathFactory#newInstance(String)}.
41 *
42 * @author <a href="Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
43 * @version $Revision: 1.7 $, $Date: 2010-11-01 04:36:14 $
44 * @since 1.5
45 */
46 class XPathFactoryFinder {
47 private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xpath.internal";
48
49 private static final SecuritySupport ss = new SecuritySupport() ;
50 /** debug support code. */
51 private static boolean debug = false;
52 static {
53 // Use try/catch block to support applets
54 try {
55 debug = ss.getSystemProperty("jaxp.debug") != null;
56 } catch (Exception unused) {
57 debug = false;
58 }
59 }
60
61 /**
62 * <p>Cache properties for performance.</p>
63 */
64 private static final Properties cacheProps = new Properties();
65
66 /**
67 * <p>First time requires initialization overhead.</p>
68 */
69 private volatile static boolean firstTime = true;
70
71 /**
72 * <p>Conditional debug printing.</p>
73 *
74 * @param msg to print
75 */
76 private static void debugPrintln(String msg) {
77 if (debug) {
78 System.err.println("JAXP: " + msg);
79 }
80 }
81
82 /**
83 * <p><code>ClassLoader</code> to use to find <code>XPathFactory</code>.</p>
84 */
85 private final ClassLoader classLoader;
86
87 /**
88 * <p>Constructor that specifies <code>ClassLoader</code> to use
89 * to find <code>XPathFactory</code>.</p>
90 *
91 * @param loader
92 * to be used to load resource and {@link XPathFactory}
93 * implementations during the resolution process.
94 * If this parameter is null, the default system class loader
95 * will be used.
96 */
97 public XPathFactoryFinder(ClassLoader loader) {
98 this.classLoader = loader;
99 if( debug ) {
100 debugDisplayClassLoader();
101 }
102 }
103
104 private void debugDisplayClassLoader() {
105 try {
106 if( classLoader == ss.getContextClassLoader() ) {
107 debugPrintln("using thread context class loader ("+classLoader+") for search");
108 return;
109 }
110 } catch( Throwable unused ) {
111 // getContextClassLoader() undefined in JDK1.1
112 }
113
114 if( classLoader==ClassLoader.getSystemClassLoader() ) {
115 debugPrintln("using system class loader ("+classLoader+") for search");
116 return;
117 }
118
119 debugPrintln("using class loader ("+classLoader+") for search");
120 }
121
122 /**
123 * <p>Creates a new {@link XPathFactory} object for the specified
124 * object model.</p>
125 *
126 * @param uri
127 * Identifies the underlying object model.
128 *
129 * @return <code>null</code> if the callee fails to create one.
130 *
131 * @throws NullPointerException
132 * If the parameter is null.
133 */
134 public XPathFactory newFactory(String uri) throws XPathFactoryConfigurationException {
135 if (uri == null) {
136 throw new NullPointerException();
137 }
138 XPathFactory f = _newFactory(uri);
139 if (f != null) {
140 debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri);
141 } else {
142 debugPrintln("unable to find a factory for " + uri);
143 }
144 return f;
145 }
146
147 /**
148 * <p>Lookup a {@link XPathFactory} for the given object model.</p>
149 *
150 * @param uri identifies the object model.
151 *
152 * @return {@link XPathFactory} for the given object model.
153 */
154 private XPathFactory _newFactory(String uri) throws XPathFactoryConfigurationException {
155 XPathFactory xpathFactory = null;
156
157 String propertyName = SERVICE_CLASS.getName() + ":" + uri;
158
159 // system property look up
160 try {
161 debugPrintln("Looking up system property '"+propertyName+"'" );
162 String r = ss.getSystemProperty(propertyName);
163 if(r!=null) {
164 debugPrintln("The value is '"+r+"'");
165 xpathFactory = createInstance(r, true);
166 if (xpathFactory != null) {
167 return xpathFactory;
168 }
169 } else
170 debugPrintln("The property is undefined.");
171 } catch( Throwable t ) {
172 if( debug ) {
173 debugPrintln("failed to look up system property '"+propertyName+"'" );
174 t.printStackTrace();
175 }
176 }
177
178 String javah = ss.getSystemProperty( "java.home" );
179 String configFile = javah + File.separator +
180 "lib" + File.separator + "jaxp.properties";
181
182 // try to read from $java.home/lib/jaxp.properties
183 try {
184 if(firstTime){
185 synchronized(cacheProps){
186 if(firstTime){
187 File f=new File( configFile );
188 firstTime = false;
189 if(ss.doesFileExist(f)){
190 debugPrintln("Read properties file " + f);
191 cacheProps.load(ss.getFileInputStream(f));
192 }
193 }
194 }
195 }
196 final String factoryClassName = cacheProps.getProperty(propertyName);
197 debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
198
199 if (factoryClassName != null) {
200 xpathFactory = createInstance(factoryClassName, true);
201 if(xpathFactory != null){
202 return xpathFactory;
203 }
204 }
205 } catch (Exception ex) {
206 if (debug) {
207 ex.printStackTrace();
208 }
209 }
210
211 // Try with ServiceLoader
212 assert xpathFactory == null;
213 xpathFactory = findServiceProvider(uri);
214
215 // The following assertion should always be true.
216 // Uncomment it, recompile, and run with -ea in case of doubts:
217 // assert xpathFactory == null || xpathFactory.isObjectModelSupported(uri);
218
219 if (xpathFactory != null) {
220 return xpathFactory;
221 }
222
223 // platform default
224 if(uri.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) {
225 debugPrintln("attempting to use the platform default W3C DOM XPath lib");
226 return createInstance("com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", true);
227 }
228
229 debugPrintln("all things were tried, but none was found. bailing out.");
230 return null;
231 }
232
233 /** <p>Create class using appropriate ClassLoader.</p>
234 *
235 * @param className Name of class to create.
236 * @return Created class or <code>null</code>.
237 */
238 private Class<?> createClass(String className) {
239 Class clazz;
240 // make sure we have access to restricted packages
241 boolean internal = false;
242 if (System.getSecurityManager() != null) {
243 if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
244 internal = true;
245 }
246 }
247
248 // use approprite ClassLoader
249 try {
250 if (classLoader != null && !internal) {
251 clazz = Class.forName(className, false, classLoader);
252 } else {
253 clazz = Class.forName(className);
254 }
255 } catch (Throwable t) {
256 if(debug) {
257 t.printStackTrace();
258 }
259 return null;
260 }
261
262 return clazz;
263 }
264
265 /**
266 * <p>Creates an instance of the specified and returns it.</p>
267 *
268 * @param className
269 * fully qualified class name to be instantiated.
270 *
271 * @return null
272 * if it fails. Error messages will be printed by this method.
273 */
274 XPathFactory createInstance( String className )
275 throws XPathFactoryConfigurationException
276 {
277 return createInstance( className, false );
278 }
279
280 XPathFactory createInstance( String className, boolean useServicesMechanism )
281 throws XPathFactoryConfigurationException
282 {
283 XPathFactory xPathFactory = null;
284
285 debugPrintln("createInstance(" + className + ")");
286
287 // get Class from className
288 Class<?> clazz = createClass(className);
289 if (clazz == null) {
290 debugPrintln("failed to getClass(" + className + ")");
291 return null;
292 }
293 debugPrintln("loaded " + className + " from " + which(clazz));
294
295 // instantiate Class as a XPathFactory
296 try {
297 if (!useServicesMechanism) {
298 xPathFactory = newInstanceNoServiceLoader(clazz);
299 }
300 if (xPathFactory == null) {
301 xPathFactory = (XPathFactory) clazz.newInstance();
302 }
303 } catch (ClassCastException classCastException) {
304 debugPrintln("could not instantiate " + clazz.getName());
305 if (debug) {
306 classCastException.printStackTrace();
307 }
308 return null;
309 } catch (IllegalAccessException illegalAccessException) {
310 debugPrintln("could not instantiate " + clazz.getName());
311 if (debug) {
312 illegalAccessException.printStackTrace();
313 }
314 return null;
315 } catch (InstantiationException instantiationException) {
316 debugPrintln("could not instantiate " + clazz.getName());
317 if (debug) {
318 instantiationException.printStackTrace();
319 }
320 return null;
321 }
322
323 return xPathFactory;
324 }
325 /**
326 * Try to construct using newXPathFactoryNoServiceLoader
327 * method if available.
328 */
329 private static XPathFactory newInstanceNoServiceLoader(
330 Class<?> providerClass
331 ) throws XPathFactoryConfigurationException {
332 // Retain maximum compatibility if no security manager.
333 if (System.getSecurityManager() == null) {
334 return null;
335 }
336 try {
337 Method creationMethod =
338 providerClass.getDeclaredMethod(
339 "newXPathFactoryNoServiceLoader"
340 );
341 final int modifiers = creationMethod.getModifiers();
342
343 // Do not call "newXPathFactoryNoServiceLoader" if it's
344 // not public static.
345 if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
346 return null;
347 }
348
349 // Only calls "newXPathFactoryNoServiceLoader" if it's
350 // declared to return an instance of XPathFactory.
351 final Class<?> returnType = creationMethod.getReturnType();
352 if (SERVICE_CLASS.isAssignableFrom(returnType)) {
353 return SERVICE_CLASS.cast(creationMethod.invoke(null, (Object[])null));
354 } else {
355 // Should not happen since
356 // XPathFactoryImpl.newXPathFactoryNoServiceLoader is
357 // declared to return XPathFactory.
358 throw new ClassCastException(returnType
359 + " cannot be cast to " + SERVICE_CLASS);
360 }
361 } catch (ClassCastException e) {
362 throw new XPathFactoryConfigurationException(e);
363 } catch (NoSuchMethodException exc) {
364 return null;
365 } catch (Exception exc) {
366 return null;
367 }
368 }
369
370 // Call isObjectModelSupportedBy with initial context.
371 private boolean isObjectModelSupportedBy(final XPathFactory factory,
372 final String objectModel,
373 AccessControlContext acc) {
374 return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
375 public Boolean run() {
376 return factory.isObjectModelSupported(objectModel);
377 }
378 }, acc);
379 }
380
381 /**
382 * Finds a service provider subclass of XPathFactory that supports the
383 * given object model using the ServiceLoader.
384 *
385 * @param objectModel URI of object model to support.
386 * @return An XPathFactory supporting the specified object model, or null
387 * if none is found.
388 * @throws XPathFactoryConfigurationException if a configuration error is found.
389 */
390 private XPathFactory findServiceProvider(final String objectModel)
391 throws XPathFactoryConfigurationException {
392
393 assert objectModel != null;
394 // store current context.
395 final AccessControlContext acc = AccessController.getContext();
396 try {
397 return AccessController.doPrivileged(new PrivilegedAction<XPathFactory>() {
398 public XPathFactory run() {
399 final ServiceLoader<XPathFactory> loader =
400 ServiceLoader.load(SERVICE_CLASS);
401 for (XPathFactory factory : loader) {
402 // restore initial context to call
403 // factory.isObjectModelSupportedBy
404 if (isObjectModelSupportedBy(factory, objectModel, acc)) {
405 return factory;
406 }
407 }
408 return null; // no factory found.
409 }
410 });
411 } catch (ServiceConfigurationError error) {
412 throw new XPathFactoryConfigurationException(error);
413 }
414 }
415
416 private static final Class<XPathFactory> SERVICE_CLASS = XPathFactory.class;
417
418 private static String which( Class clazz ) {
419 return which( clazz.getName(), clazz.getClassLoader() );
420 }
421
422 /**
423 * <p>Search the specified classloader for the given classname.</p>
424 *
425 * @param classname the fully qualified name of the class to search for
426 * @param loader the classloader to search
427 *
428 * @return the source location of the resource, or null if it wasn't found
429 */
430 private static String which(String classname, ClassLoader loader) {
431
432 String classnameAsResource = classname.replace('.', '/') + ".class";
433
434 if( loader==null ) loader = ClassLoader.getSystemClassLoader();
435
436 //URL it = loader.getResource(classnameAsResource);
|