1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 2001-2004 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The name "Apache Software Foundation" must not be used to endorse or
  28. * promote products derived from this software without prior written
  29. * permission. For written permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache",
  32. * nor may "Apache" appear in their name, without prior written
  33. * permission of the Apache Software Foundation.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation and was
  51. * originally based on software copyright (c) 1999-2001, Sun Microsystems,
  52. * Inc., http://www.sun.com. For more information on the Apache Software
  53. * Foundation, please see <http://www.apache.org/>.
  54. */
  55. package com.sun.org.apache.xml.internal.serialize;
  56. import java.io.InputStream;
  57. import java.io.IOException;
  58. import java.io.File;
  59. import java.io.FileInputStream;
  60. import java.util.Properties;
  61. import java.io.BufferedReader;
  62. import java.io.InputStreamReader;
  63. /**
  64. * This class is duplicated for each JAXP subpackage so keep it in sync.
  65. * It is package private and therefore is not exposed as part of the JAXP
  66. * API.
  67. * <p>
  68. * This code is designed to implement the JAXP 1.1 spec pluggability
  69. * feature and is designed to run on JDK version 1.1 and
  70. * later, and to compile on JDK 1.2 and onward.
  71. * The code also runs both as part of an unbundled jar file and
  72. * when bundled as part of the JDK.
  73. * <p>
  74. *
  75. * @version $Id: ObjectFactory.java,v 1.1.1.1 2004/02/25 09:02:02 vk112360 Exp $
  76. */
  77. class ObjectFactory {
  78. //
  79. // Constants
  80. //
  81. // name of default properties file to look for in JDK's jre/lib directory
  82. private static final String DEFAULT_PROPERTIES_FILENAME = "xerces.properties";
  83. /** Set to true for debugging */
  84. private static final boolean DEBUG = false;
  85. /** cache the contents of the xerces.properties file.
  86. * Until an attempt has been made to read this file, this will
  87. * be null; if the file does not exist or we encounter some other error
  88. * during the read, this will be empty.
  89. */
  90. private static Properties fXercesProperties = null;
  91. /***
  92. * Cache the time stamp of the xerces.properties file so
  93. * that we know if it's been modified and can invalidate
  94. * the cache when necessary.
  95. */
  96. private static long fLastModified = -1;
  97. //
  98. // static methods
  99. //
  100. /**
  101. * Finds the implementation Class object in the specified order. The
  102. * specified order is the following:
  103. * <ol>
  104. * <li>query the system property using <code>System.getProperty</code>
  105. * <li>read <code>META-INF/services/<i>factoryId</i></code> file
  106. * <li>use fallback classname
  107. * </ol>
  108. *
  109. * @return Class object of factory, never null
  110. *
  111. * @param factoryId Name of the factory to find, same as
  112. * a property name
  113. * @param fallbackClassName Implementation class name, if nothing else
  114. * is found. Use null to mean no fallback.
  115. *
  116. * @exception ObjectFactory.ConfigurationError
  117. */
  118. static Object createObject(String factoryId, String fallbackClassName)
  119. throws ConfigurationError {
  120. return createObject(factoryId, null, fallbackClassName);
  121. } // createObject(String,String):Object
  122. /**
  123. * Finds the implementation Class object in the specified order. The
  124. * specified order is the following:
  125. * <ol>
  126. * <li>query the system property using <code>System.getProperty</code>
  127. * <li>read <code>$java.home/lib/<i>propertiesFilename</i></code> file
  128. * <li>read <code>META-INF/services/<i>factoryId</i></code> file
  129. * <li>use fallback classname
  130. * </ol>
  131. *
  132. * @return Class object of factory, never null
  133. *
  134. * @param factoryId Name of the factory to find, same as
  135. * a property name
  136. * @param propertiesFilename The filename in the $java.home/lib directory
  137. * of the properties file. If none specified,
  138. * ${java.home}/lib/xerces.properties will be used.
  139. * @param fallbackClassName Implementation class name, if nothing else
  140. * is found. Use null to mean no fallback.
  141. *
  142. * @exception ObjectFactory.ConfigurationError
  143. */
  144. static Object createObject(String factoryId,
  145. String propertiesFilename,
  146. String fallbackClassName)
  147. throws ConfigurationError
  148. {
  149. if (DEBUG) debugPrintln("debug is on");
  150. SecuritySupport ss = SecuritySupport.getInstance();
  151. ClassLoader cl = findClassLoader();
  152. // Use the system property first
  153. try {
  154. String systemProp = ss.getSystemProperty(factoryId);
  155. if (systemProp != null) {
  156. if (DEBUG) debugPrintln("found system property, value=" + systemProp);
  157. return newInstance(systemProp, cl, true);
  158. }
  159. } catch (SecurityException se) {
  160. // Ignore and continue w/ next location
  161. }
  162. // Try to read from propertiesFilename, or $java.home/lib/xerces.properties
  163. String factoryClassName = null;
  164. // no properties file name specified; use $JAVA_HOME/lib/xerces.properties:
  165. if (propertiesFilename == null) {
  166. File propertiesFile = null;
  167. boolean propertiesFileExists = false;
  168. try {
  169. String javah = ss.getSystemProperty("java.home");
  170. propertiesFilename = javah + File.separator +
  171. "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME;
  172. propertiesFile = new File(propertiesFilename);
  173. propertiesFileExists = ss.getFileExists(propertiesFile);
  174. } catch (SecurityException e) {
  175. // try again...
  176. fLastModified = -1;
  177. fXercesProperties = null;
  178. }
  179. synchronized (ObjectFactory.class) {
  180. boolean loadProperties = false;
  181. try {
  182. // file existed last time
  183. if(fLastModified >= 0) {
  184. if(propertiesFileExists &&
  185. (fLastModified < (fLastModified = ss.getLastModified(propertiesFile)))) {
  186. loadProperties = true;
  187. } else {
  188. // file has stopped existing...
  189. if(!propertiesFileExists) {
  190. fLastModified = -1;
  191. fXercesProperties = null;
  192. } // else, file wasn't modified!
  193. }
  194. } else {
  195. // file has started to exist:
  196. if(propertiesFileExists) {
  197. loadProperties = true;
  198. fLastModified = ss.getLastModified(propertiesFile);
  199. } // else, nothing's changed
  200. }
  201. if(loadProperties) {
  202. // must never have attempted to read xerces.properties before (or it's outdeated)
  203. fXercesProperties = new Properties();
  204. FileInputStream fis = ss.getFileInputStream(propertiesFile);
  205. fXercesProperties.load(fis);
  206. fis.close();
  207. }
  208. } catch (Exception x) {
  209. fXercesProperties = null;
  210. fLastModified = -1;
  211. // assert(x instanceof FileNotFoundException
  212. // || x instanceof SecurityException)
  213. // In both cases, ignore and continue w/ next location
  214. }
  215. }
  216. if(fXercesProperties != null) {
  217. factoryClassName = fXercesProperties.getProperty(factoryId);
  218. }
  219. } else {
  220. try {
  221. FileInputStream fis = ss.getFileInputStream(new File(propertiesFilename));
  222. Properties props = new Properties();
  223. props.load(fis);
  224. fis.close();
  225. factoryClassName = props.getProperty(factoryId);
  226. } catch (Exception x) {
  227. // assert(x instanceof FileNotFoundException
  228. // || x instanceof SecurityException)
  229. // In both cases, ignore and continue w/ next location
  230. }
  231. }
  232. if (factoryClassName != null) {
  233. if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName);
  234. return newInstance(factoryClassName, cl, true);
  235. }
  236. // Try Jar Service Provider Mechanism
  237. Object provider = findJarServiceProvider(factoryId);
  238. if (provider != null) {
  239. return provider;
  240. }
  241. if (fallbackClassName == null) {
  242. throw new ConfigurationError(
  243. "Provider for " + factoryId + " cannot be found", null);
  244. }
  245. if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName);
  246. return newInstance(fallbackClassName, cl, true);
  247. } // createObject(String,String,String):Object
  248. //
  249. // Private static methods
  250. //
  251. /** Prints a message to standard error if debugging is enabled. */
  252. private static void debugPrintln(String msg) {
  253. if (DEBUG) {
  254. System.err.println("JAXP: " + msg);
  255. }
  256. } // debugPrintln(String)
  257. /**
  258. * Figure out which ClassLoader to use. For JDK 1.2 and later use
  259. * the context ClassLoader.
  260. */
  261. static ClassLoader findClassLoader()
  262. throws ConfigurationError
  263. {
  264. SecuritySupport ss = SecuritySupport.getInstance();
  265. // Figure out which ClassLoader to use for loading the provider
  266. // class. If there is a Context ClassLoader then use it.
  267. ClassLoader context = ss.getContextClassLoader();
  268. ClassLoader system = ss.getSystemClassLoader();
  269. ClassLoader chain = system;
  270. while (true) {
  271. if (context == chain) {
  272. // Assert: we are on JDK 1.1 or we have no Context ClassLoader
  273. // or any Context ClassLoader in chain of system classloader
  274. // (including extension ClassLoader) so extend to widest
  275. // ClassLoader (always look in system ClassLoader if Xerces
  276. // is in boot/extension/system classpath and in current
  277. // ClassLoader otherwise); normal classloaders delegate
  278. // back to system ClassLoader first so this widening doesn't
  279. // change the fact that context ClassLoader will be consulted
  280. ClassLoader current = ObjectFactory.class.getClassLoader();
  281. chain = system;
  282. while (true) {
  283. if (current == chain) {
  284. // Assert: Current ClassLoader in chain of
  285. // boot/extension/system ClassLoaders
  286. return system;
  287. }
  288. if (chain == null) {
  289. break;
  290. }
  291. chain = ss.getParentClassLoader(chain);
  292. }
  293. // Assert: Current ClassLoader not in chain of
  294. // boot/extension/system ClassLoaders
  295. return current;
  296. }
  297. if (chain == null) {
  298. // boot ClassLoader reached
  299. break;
  300. }
  301. // Check for any extension ClassLoaders in chain up to
  302. // boot ClassLoader
  303. chain = ss.getParentClassLoader(chain);
  304. };
  305. // Assert: Context ClassLoader not in chain of
  306. // boot/extension/system ClassLoaders
  307. return context;
  308. } // findClassLoader():ClassLoader
  309. /**
  310. * Create an instance of a class using the specified ClassLoader
  311. */
  312. static Object newInstance(String className, ClassLoader cl,
  313. boolean doFallback)
  314. throws ConfigurationError
  315. {
  316. // assert(className != null);
  317. try{
  318. Class providerClass = findProviderClass(className, cl, doFallback);
  319. Object instance = providerClass.newInstance();
  320. if (DEBUG) debugPrintln("created new instance of " + providerClass +
  321. " using ClassLoader: " + cl);
  322. return instance;
  323. } catch (ClassNotFoundException x) {
  324. throw new ConfigurationError(
  325. "Provider " + className + " not found", x);
  326. } catch (Exception x) {
  327. throw new ConfigurationError(
  328. "Provider " + className + " could not be instantiated: " + x,
  329. x);
  330. }
  331. }
  332. /**
  333. * Find a Class using the specified ClassLoader
  334. */
  335. static Class findProviderClass(String className, ClassLoader cl,
  336. boolean doFallback)
  337. throws ClassNotFoundException, ConfigurationError
  338. {
  339. //throw security exception if the calling thread is not allowed to access the package
  340. //restrict the access to package as speicified in java.security policy
  341. SecurityManager security = System.getSecurityManager();
  342. try{
  343. if(security != null){
  344. security.checkPackageAccess(className);
  345. }
  346. }catch(SecurityException e){
  347. throw e ;
  348. }
  349. Class providerClass;
  350. if (cl == null) {
  351. // XXX Use the bootstrap ClassLoader. There is no way to
  352. // load a class using the bootstrap ClassLoader that works
  353. // in both JDK 1.1 and Java 2. However, this should still
  354. // work b/c the following should be true:
  355. //
  356. // (cl == null) iff current ClassLoader == null
  357. //
  358. // Thus Class.forName(String) will use the current
  359. // ClassLoader which will be the bootstrap ClassLoader.
  360. providerClass = Class.forName(className);
  361. } else {
  362. try {
  363. providerClass = cl.loadClass(className);
  364. } catch (ClassNotFoundException x) {
  365. if (doFallback) {
  366. // Fall back to current classloader
  367. ClassLoader current = ObjectFactory.class.getClassLoader();
  368. if (current == null) {
  369. providerClass = Class.forName(className);
  370. } else if (cl != current) {
  371. cl = current;
  372. providerClass = cl.loadClass(className);
  373. } else {
  374. throw x;
  375. }
  376. } else {
  377. throw x;
  378. }
  379. }
  380. }
  381. return providerClass;
  382. }
  383. /*
  384. * Try to find provider using Jar Service Provider Mechanism
  385. *
  386. * @return instance of provider class if found or null
  387. */
  388. private static Object findJarServiceProvider(String factoryId)
  389. throws ConfigurationError
  390. {
  391. SecuritySupport ss = SecuritySupport.getInstance();
  392. String serviceId = "META-INF/services/" + factoryId;
  393. InputStream is = null;
  394. // First try the Context ClassLoader
  395. ClassLoader cl = findClassLoader();
  396. is = ss.getResourceAsStream(cl, serviceId);
  397. // If no provider found then try the current ClassLoader
  398. if (is == null) {
  399. ClassLoader current = ObjectFactory.class.getClassLoader();
  400. if (cl != current) {
  401. cl = current;
  402. is = ss.getResourceAsStream(cl, serviceId);
  403. }
  404. }
  405. if (is == null) {
  406. // No provider found
  407. return null;
  408. }
  409. if (DEBUG) debugPrintln("found jar resource=" + serviceId +
  410. " using ClassLoader: " + cl);
  411. // Read the service provider name in UTF-8 as specified in
  412. // the jar spec. Unfortunately this fails in Microsoft
  413. // VJ++, which does not implement the UTF-8
  414. // encoding. Theoretically, we should simply let it fail in
  415. // that case, since the JVM is obviously broken if it
  416. // doesn't support such a basic standard. But since there
  417. // are still some users attempting to use VJ++ for
  418. // development, we have dropped in a fallback which makes a
  419. // second attempt using the platform's default encoding. In
  420. // VJ++ this is apparently ASCII, which is a subset of
  421. // UTF-8... and since the strings we'll be reading here are
  422. // also primarily limited to the 7-bit ASCII range (at
  423. // least, in English versions), this should work well
  424. // enough to keep us on the air until we're ready to
  425. // officially decommit from VJ++. [Edited comment from
  426. // jkesselm]
  427. BufferedReader rd;
  428. try {
  429. rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
  430. } catch (java.io.UnsupportedEncodingException e) {
  431. rd = new BufferedReader(new InputStreamReader(is));
  432. }
  433. String factoryClassName = null;
  434. try {
  435. // XXX Does not handle all possible input as specified by the
  436. // Jar Service Provider specification
  437. factoryClassName = rd.readLine();
  438. rd.close();
  439. } catch (IOException x) {
  440. // No provider found
  441. return null;
  442. }
  443. if (factoryClassName != null &&
  444. ! "".equals(factoryClassName)) {
  445. if (DEBUG) debugPrintln("found in resource, value="
  446. + factoryClassName);
  447. // Note: here we do not want to fall back to the current
  448. // ClassLoader because we want to avoid the case where the
  449. // resource file was found using one ClassLoader and the
  450. // provider class was instantiated using a different one.
  451. return newInstance(factoryClassName, cl, false);
  452. }
  453. // No provider found
  454. return null;
  455. }
  456. //
  457. // Classes
  458. //
  459. /**
  460. * A configuration error.
  461. */
  462. static class ConfigurationError
  463. extends Error {
  464. //
  465. // Data
  466. //
  467. /** Exception. */
  468. private Exception exception;
  469. //
  470. // Constructors
  471. //
  472. /**
  473. * Construct a new instance with the specified detail string and
  474. * exception.
  475. */
  476. ConfigurationError(String msg, Exception x) {
  477. super(msg);
  478. this.exception = x;
  479. } // <init>(String,Exception)
  480. //
  481. // methods
  482. //
  483. /** Returns the exception associated to this error. */
  484. Exception getException() {
  485. return exception;
  486. } // getException():Exception
  487. } // class ConfigurationError
  488. } // class ObjectFactory