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