2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 * $Id: ObjectFactory.java 468646 2006-10-28 06:57:58Z minchau $
22 package org.apache.xalan.xslt;
24 import java.io.InputStream;
25 import java.io.IOException;
27 import java.io.FileInputStream;
29 import java.util.Properties;
30 import java.io.BufferedReader;
31 import java.io.InputStreamReader;
34 * This class is duplicated for each JAXP subpackage so keep it in sync.
35 * It is package private and therefore is not exposed as part of the JAXP
38 * This code is designed to implement the JAXP 1.1 spec pluggability
39 * feature and is designed to run on JDK version 1.1 and
40 * later, and to compile on JDK 1.2 and onward.
41 * The code also runs both as part of an unbundled jar file and
42 * when bundled as part of the JDK.
44 * This class was moved from the <code>javax.xml.parsers.ObjectFactory</code>
45 * class and modified to be used as a general utility for creating objects
48 * @version $Id: ObjectFactory.java 468646 2006-10-28 06:57:58Z minchau $
56 // name of default properties file to look for in JDK's jre/lib directory
57 private static final String DEFAULT_PROPERTIES_FILENAME =
60 private static final String SERVICES_PATH = "META-INF/services/";
62 /** Set to true for debugging */
63 private static final boolean DEBUG = false;
65 /** cache the contents of the xalan.properties file.
66 * Until an attempt has been made to read this file, this will
67 * be null; if the file does not exist or we encounter some other error
68 * during the read, this will be empty.
70 private static Properties fXalanProperties = null;
73 * Cache the time stamp of the xalan.properties file so
74 * that we know if it's been modified and can invalidate
75 * the cache when necessary.
77 private static long fLastModified = -1;
80 // Public static methods
84 * Finds the implementation Class object in the specified order. The
85 * specified order is the following:
87 * <li>query the system property using <code>System.getProperty</code>
88 * <li>read <code>META-INF/services/<i>factoryId</i></code> file
89 * <li>use fallback classname
92 * @return instance of factory, never null
94 * @param factoryId Name of the factory to find, same as
96 * @param fallbackClassName Implementation class name, if nothing else
97 * is found. Use null to mean no fallback.
99 * @exception ObjectFactory.ConfigurationError
101 static Object createObject(String factoryId, String fallbackClassName)
102 throws ConfigurationError {
103 return createObject(factoryId, null, fallbackClassName);
104 } // createObject(String,String):Object
107 * Finds the implementation Class object in the specified order. The
108 * specified order is the following:
110 * <li>query the system property using <code>System.getProperty</code>
111 * <li>read <code>$java.home/lib/<i>propertiesFilename</i></code> file
112 * <li>read <code>META-INF/services/<i>factoryId</i></code> file
113 * <li>use fallback classname
116 * @return instance of factory, never null
118 * @param factoryId Name of the factory to find, same as
120 * @param propertiesFilename The filename in the $java.home/lib directory
121 * of the properties file. If none specified,
122 * ${java.home}/lib/xalan.properties will be used.
123 * @param fallbackClassName Implementation class name, if nothing else
124 * is found. Use null to mean no fallback.
126 * @exception ObjectFactory.ConfigurationError
128 static Object createObject(String factoryId,
129 String propertiesFilename,
130 String fallbackClassName)
131 throws ConfigurationError
133 Class factoryClass = lookUpFactoryClass(factoryId,
137 if (factoryClass == null) {
138 throw new ConfigurationError(
139 "Provider for " + factoryId + " cannot be found", null);
143 Object instance = factoryClass.newInstance();
144 debugPrintln("created new instance of factory " + factoryId);
146 } catch (Exception x) {
147 throw new ConfigurationError(
148 "Provider for factory " + factoryId
149 + " could not be instantiated: " + x, x);
151 } // createObject(String,String,String):Object
154 * Finds the implementation Class object in the specified order. The
155 * specified order is the following:
157 * <li>query the system property using <code>System.getProperty</code>
158 * <li>read <code>$java.home/lib/<i>propertiesFilename</i></code> file
159 * <li>read <code>META-INF/services/<i>factoryId</i></code> file
160 * <li>use fallback classname
163 * @return Class object of factory, never null
165 * @param factoryId Name of the factory to find, same as
167 * @param propertiesFilename The filename in the $java.home/lib directory
168 * of the properties file. If none specified,
169 * ${java.home}/lib/xalan.properties will be used.
170 * @param fallbackClassName Implementation class name, if nothing else
171 * is found. Use null to mean no fallback.
173 * @exception ObjectFactory.ConfigurationError
175 static Class lookUpFactoryClass(String factoryId)
176 throws ConfigurationError
178 return lookUpFactoryClass(factoryId, null, null);
179 } // lookUpFactoryClass(String):Class
182 * Finds the implementation Class object in the specified order. The
183 * specified order is the following:
185 * <li>query the system property using <code>System.getProperty</code>
186 * <li>read <code>$java.home/lib/<i>propertiesFilename</i></code> file
187 * <li>read <code>META-INF/services/<i>factoryId</i></code> file
188 * <li>use fallback classname
191 * @return Class object that provides factory service, never null
193 * @param factoryId Name of the factory to find, same as
195 * @param propertiesFilename The filename in the $java.home/lib directory
196 * of the properties file. If none specified,
197 * ${java.home}/lib/xalan.properties will be used.
198 * @param fallbackClassName Implementation class name, if nothing else
199 * is found. Use null to mean no fallback.
201 * @exception ObjectFactory.ConfigurationError
203 static Class lookUpFactoryClass(String factoryId,
204 String propertiesFilename,
205 String fallbackClassName)
206 throws ConfigurationError
208 String factoryClassName = lookUpFactoryClassName(factoryId,
211 ClassLoader cl = findClassLoader();
213 if (factoryClassName == null) {
214 factoryClassName = fallbackClassName;
217 // assert(className != null);
219 Class providerClass = findProviderClass(factoryClassName,
222 debugPrintln("created new instance of " + providerClass +
223 " using ClassLoader: " + cl);
224 return providerClass;
225 } catch (ClassNotFoundException x) {
226 throw new ConfigurationError(
227 "Provider " + factoryClassName + " not found", x);
228 } catch (Exception x) {
229 throw new ConfigurationError(
230 "Provider "+factoryClassName+" could not be instantiated: "+x,
233 } // lookUpFactoryClass(String,String,String):Class
236 * Finds the name of the required implementation class in the specified
237 * order. The specified order is the following:
239 * <li>query the system property using <code>System.getProperty</code>
240 * <li>read <code>$java.home/lib/<i>propertiesFilename</i></code> file
241 * <li>read <code>META-INF/services/<i>factoryId</i></code> file
242 * <li>use fallback classname
245 * @return name of class that provides factory service, never null
247 * @param factoryId Name of the factory to find, same as
249 * @param propertiesFilename The filename in the $java.home/lib directory
250 * of the properties file. If none specified,
251 * ${java.home}/lib/xalan.properties will be used.
252 * @param fallbackClassName Implementation class name, if nothing else
253 * is found. Use null to mean no fallback.
255 * @exception ObjectFactory.ConfigurationError
257 static String lookUpFactoryClassName(String factoryId,
258 String propertiesFilename,
259 String fallbackClassName)
261 SecuritySupport ss = SecuritySupport.getInstance();
263 // Use the system property first
265 String systemProp = ss.getSystemProperty(factoryId);
266 if (systemProp != null) {
267 debugPrintln("found system property, value=" + systemProp);
270 } catch (SecurityException se) {
271 // Ignore and continue w/ next location
274 // Try to read from propertiesFilename, or
275 // $java.home/lib/xalan.properties
276 String factoryClassName = null;
277 // no properties file name specified; use
278 // $JAVA_HOME/lib/xalan.properties:
279 if (propertiesFilename == null) {
280 File propertiesFile = null;
281 boolean propertiesFileExists = false;
283 String javah = ss.getSystemProperty("java.home");
284 propertiesFilename = javah + File.separator +
285 "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME;
286 propertiesFile = new File(propertiesFilename);
287 propertiesFileExists = ss.getFileExists(propertiesFile);
288 } catch (SecurityException e) {
291 fXalanProperties = null;
294 synchronized (ObjectFactory.class) {
295 boolean loadProperties = false;
296 FileInputStream fis = null;
298 // file existed last time
299 if(fLastModified >= 0) {
300 if(propertiesFileExists &&
301 (fLastModified < (fLastModified = ss.getLastModified(propertiesFile)))) {
302 loadProperties = true;
304 // file has stopped existing...
305 if(!propertiesFileExists) {
307 fXalanProperties = null;
308 } // else, file wasn't modified!
311 // file has started to exist:
312 if(propertiesFileExists) {
313 loadProperties = true;
314 fLastModified = ss.getLastModified(propertiesFile);
315 } // else, nothing's changed
318 // must never have attempted to read xalan.properties
319 // before (or it's outdeated)
320 fXalanProperties = new Properties();
321 fis = ss.getFileInputStream(propertiesFile);
322 fXalanProperties.load(fis);
324 } catch (Exception x) {
325 fXalanProperties = null;
327 // assert(x instanceof FileNotFoundException
328 // || x instanceof SecurityException)
329 // In both cases, ignore and continue w/ next location
332 // try to close the input stream if one was opened.
337 // Ignore the exception.
338 catch (IOException exc) {}
342 if(fXalanProperties != null) {
343 factoryClassName = fXalanProperties.getProperty(factoryId);
346 FileInputStream fis = null;
348 fis = ss.getFileInputStream(new File(propertiesFilename));
349 Properties props = new Properties();
351 factoryClassName = props.getProperty(factoryId);
352 } catch (Exception x) {
353 // assert(x instanceof FileNotFoundException
354 // || x instanceof SecurityException)
355 // In both cases, ignore and continue w/ next location
358 // try to close the input stream if one was opened.
363 // Ignore the exception.
364 catch (IOException exc) {}
368 if (factoryClassName != null) {
369 debugPrintln("found in " + propertiesFilename + ", value="
371 return factoryClassName;
374 // Try Jar Service Provider Mechanism
375 return findJarServiceProviderName(factoryId);
376 } // lookUpFactoryClass(String,String):String
379 // Private static methods
382 /** Prints a message to standard error if debugging is enabled. */
383 private static void debugPrintln(String msg) {
385 System.err.println("JAXP: " + msg);
387 } // debugPrintln(String)
390 * Figure out which ClassLoader to use. For JDK 1.2 and later use
391 * the context ClassLoader.
393 static ClassLoader findClassLoader()
394 throws ConfigurationError
396 SecuritySupport ss = SecuritySupport.getInstance();
398 // Figure out which ClassLoader to use for loading the provider
399 // class. If there is a Context ClassLoader then use it.
400 ClassLoader context = ss.getContextClassLoader();
401 ClassLoader system = ss.getSystemClassLoader();
403 ClassLoader chain = system;
405 if (context == chain) {
406 // Assert: we are on JDK 1.1 or we have no Context ClassLoader
407 // or any Context ClassLoader in chain of system classloader
408 // (including extension ClassLoader) so extend to widest
409 // ClassLoader (always look in system ClassLoader if Xalan
410 // is in boot/extension/system classpath and in current
411 // ClassLoader otherwise); normal classloaders delegate
412 // back to system ClassLoader first so this widening doesn't
413 // change the fact that context ClassLoader will be consulted
414 ClassLoader current = ObjectFactory.class.getClassLoader();
418 if (current == chain) {
419 // Assert: Current ClassLoader in chain of
420 // boot/extension/system ClassLoaders
426 chain = ss.getParentClassLoader(chain);
429 // Assert: Current ClassLoader not in chain of
430 // boot/extension/system ClassLoaders
435 // boot ClassLoader reached
439 // Check for any extension ClassLoaders in chain up to
441 chain = ss.getParentClassLoader(chain);
444 // Assert: Context ClassLoader not in chain of
445 // boot/extension/system ClassLoaders
447 } // findClassLoader():ClassLoader
450 * Create an instance of a class using the specified ClassLoader
452 static Object newInstance(String className, ClassLoader cl,
454 throws ConfigurationError
456 // assert(className != null);
458 Class providerClass = findProviderClass(className, cl, doFallback);
459 Object instance = providerClass.newInstance();
460 debugPrintln("created new instance of " + providerClass +
461 " using ClassLoader: " + cl);
463 } catch (ClassNotFoundException x) {
464 throw new ConfigurationError(
465 "Provider " + className + " not found", x);
466 } catch (Exception x) {
467 throw new ConfigurationError(
468 "Provider " + className + " could not be instantiated: " + x,
474 * Find a Class using the specified ClassLoader
476 static Class findProviderClass(String className, ClassLoader cl,
478 throws ClassNotFoundException, ConfigurationError
480 //throw security exception if the calling thread is not allowed to access the
481 //class. Restrict the access to the package classes as specified in java.security policy.
482 SecurityManager security = System.getSecurityManager();
484 if (security != null){
485 final int lastDot = className.lastIndexOf(".");
486 String packageName = className;
487 if (lastDot != -1) packageName = className.substring(0, lastDot);
488 security.checkPackageAccess(packageName);
490 }catch(SecurityException e){
496 // XXX Use the bootstrap ClassLoader. There is no way to
497 // load a class using the bootstrap ClassLoader that works
498 // in both JDK 1.1 and Java 2. However, this should still
499 // work b/c the following should be true:
501 // (cl == null) iff current ClassLoader == null
503 // Thus Class.forName(String) will use the current
504 // ClassLoader which will be the bootstrap ClassLoader.
505 providerClass = Class.forName(className);
508 providerClass = cl.loadClass(className);
509 } catch (ClassNotFoundException x) {
511 // Fall back to current classloader
512 ClassLoader current = ObjectFactory.class.getClassLoader();
513 if (current == null) {
514 providerClass = Class.forName(className);
515 } else if (cl != current) {
517 providerClass = cl.loadClass(className);
527 return providerClass;
531 * Find the name of service provider using Jar Service Provider Mechanism
533 * @return instance of provider class if found or null
535 private static String findJarServiceProviderName(String factoryId)
537 SecuritySupport ss = SecuritySupport.getInstance();
538 String serviceId = SERVICES_PATH + factoryId;
539 InputStream is = null;
541 // First try the Context ClassLoader
542 ClassLoader cl = findClassLoader();
544 is = ss.getResourceAsStream(cl, serviceId);
546 // If no provider found then try the current ClassLoader
548 ClassLoader current = ObjectFactory.class.getClassLoader();
551 is = ss.getResourceAsStream(cl, serviceId);
560 debugPrintln("found jar resource=" + serviceId +
561 " using ClassLoader: " + cl);
563 // Read the service provider name in UTF-8 as specified in
564 // the jar spec. Unfortunately this fails in Microsoft
565 // VJ++, which does not implement the UTF-8
566 // encoding. Theoretically, we should simply let it fail in
567 // that case, since the JVM is obviously broken if it
568 // doesn't support such a basic standard. But since there
569 // are still some users attempting to use VJ++ for
570 // development, we have dropped in a fallback which makes a
571 // second attempt using the platform's default encoding. In
572 // VJ++ this is apparently ASCII, which is a subset of
573 // UTF-8... and since the strings we'll be reading here are
574 // also primarily limited to the 7-bit ASCII range (at
575 // least, in English versions), this should work well
576 // enough to keep us on the air until we're ready to
577 // officially decommit from VJ++. [Edited comment from
581 rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
582 } catch (java.io.UnsupportedEncodingException e) {
583 rd = new BufferedReader(new InputStreamReader(is));
586 String factoryClassName = null;
588 // XXX Does not handle all possible input as specified by the
589 // Jar Service Provider specification
590 factoryClassName = rd.readLine();
591 } catch (IOException x) {
597 // try to close the reader.
600 // Ignore the exception.
601 catch (IOException exc) {}
604 if (factoryClassName != null &&
605 ! "".equals(factoryClassName)) {
606 debugPrintln("found in resource, value="
609 // Note: here we do not want to fall back to the current
610 // ClassLoader because we want to avoid the case where the
611 // resource file was found using one ClassLoader and the
612 // provider class was instantiated using a different one.
613 return factoryClassName;
625 * A configuration error.
627 static class ConfigurationError
629 static final long serialVersionUID = 2276082712114762609L;
635 private Exception exception;
642 * Construct a new instance with the specified detail string and
645 ConfigurationError(String msg, Exception x) {
648 } // <init>(String,Exception)
654 /** Returns the exception associated to this error. */
655 Exception getException() {
657 } // getException():Exception
659 } // class ConfigurationError
661 } // class ObjectFactory