001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 2001 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The name "Apache Software Foundation" must not be used to endorse or
028: * promote products derived from this software without prior written
029: * permission. For written permission, please contact apache@apache.org.
030: *
031: * 5. Products derived from this software may not be called "Apache",
032: * nor may "Apache" appear in their name, without prior written
033: * permission of the Apache Software Foundation.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of the Apache Software Foundation and was
051: * originally based on software copyright (c) 1999-2001, Sun Microsystems,
052: * Inc., http://www.sun.com. For more information on the Apache Software
053: * Foundation, please see <http://www.apache.org/>.
054: */
055:
056: package javax.xml.parsers;
057:
058: import java.io.InputStream;
059: import java.io.IOException;
060: import java.io.File;
061: import java.io.FileInputStream;
062:
063: import java.util.Properties;
064: import java.io.BufferedReader;
065: import java.io.InputStreamReader;
066:
067: /**
068: * This class is duplicated for each JAXP subpackage so keep it in
069: * sync. It is package private.
070: *
071: * This code is designed to implement the JAXP 1.1 spec pluggability
072: * feature and is designed to run on JDK version 1.1 and later including
073: * JVMs that perform early linking like the Microsoft JVM in IE 5. Note
074: * however that it must be compiled on a JDK version 1.2 or later system
075: * since it calls Thread#getContextClassLoader(). The code also runs both
076: * as part of an unbundled jar file and when bundled as part of the JDK.
077: */
078: class FactoryFinder {
079: /** Temp debug code - this will be removed after we test everything
080: */
081: private static boolean debug = false;
082: static {
083: // Use try/catch block to support applets
084: try {
085: debug = System.getProperty("jaxp.debug") != null;
086: } catch (Exception x) {
087: }
088: }
089:
090: private static void debugPrintln(String msg) {
091: if (debug) {
092: System.err.println("JAXP: " + msg);
093: }
094: }
095:
096: /**
097: * Figure out which ClassLoader to use. For JDK 1.2 and later use the
098: * context ClassLoader if possible. Note: we defer linking the class
099: * that calls an API only in JDK 1.2 until runtime so that we can catch
100: * LinkageError so that this code will run in older non-Sun JVMs such
101: * as the Microsoft JVM in IE.
102: */
103: private static ClassLoader findClassLoader()
104: throws ConfigurationError {
105: ClassLoader classLoader;
106: try {
107: // Construct the name of the concrete class to instantiate
108: Class clazz = Class.forName(FactoryFinder.class.getName()
109: + "$ClassLoaderFinderConcrete");
110: ClassLoaderFinder clf = (ClassLoaderFinder) clazz
111: .newInstance();
112: classLoader = clf.getContextClassLoader();
113: } catch (LinkageError le) {
114: // Assume that we are running JDK 1.1, use the current ClassLoader
115: classLoader = FactoryFinder.class.getClassLoader();
116: } catch (ClassNotFoundException x) {
117: // This case should not normally happen. MS IE can throw this
118: // instead of a LinkageError the second time Class.forName() is
119: // called so assume that we are running JDK 1.1 and use the
120: // current ClassLoader
121: classLoader = FactoryFinder.class.getClassLoader();
122: } catch (Exception x) {
123: // Something abnormal happened so throw an error
124: throw new ConfigurationError(x.toString(), x);
125: }
126: return classLoader;
127: }
128:
129: /**
130: * Create an instance of a class using the specified ClassLoader
131: */
132: private static Object newInstance(String className,
133: ClassLoader classLoader) throws ConfigurationError {
134: try {
135: Class spiClass;
136: if (classLoader == null) {
137: spiClass = Class.forName(className);
138: } else {
139: spiClass = classLoader.loadClass(className);
140: }
141: return spiClass.newInstance();
142: } catch (ClassNotFoundException x) {
143: throw new ConfigurationError("Provider " + className
144: + " not found", x);
145: } catch (Exception x) {
146: throw new ConfigurationError("Provider " + className
147: + " could not be instantiated: " + x, x);
148: }
149: }
150:
151: /**
152: * Finds the implementation Class object in the specified order. Main
153: * entry point.
154: * @return Class object of factory, never null
155: *
156: * @param factoryId Name of the factory to find, same as
157: * a property name
158: * @param fallbackClassName Implementation class name, if nothing else
159: * is found. Use null to mean no fallback.
160: *
161: * Package private so this code can be shared.
162: */
163: static Object find(String factoryId, String fallbackClassName)
164: throws ConfigurationError {
165: ClassLoader classLoader = findClassLoader();
166:
167: // Use the system property first
168: try {
169: String systemProp = System.getProperty(factoryId);
170: if (systemProp != null) {
171: debugPrintln("found system property" + systemProp);
172: return newInstance(systemProp, classLoader);
173: }
174: } catch (SecurityException se) {
175: }
176:
177: // try to read from $java.home/lib/xml.properties
178: try {
179: String javah = System.getProperty("java.home");
180: String configFile = javah + File.separator + "lib"
181: + File.separator + "jaxp.properties";
182: File f = new File(configFile);
183: if (f.exists()) {
184: Properties props = new Properties();
185: props.load(new FileInputStream(f));
186: String factoryClassName = props.getProperty(factoryId);
187: debugPrintln("found java.home property "
188: + factoryClassName);
189: return newInstance(factoryClassName, classLoader);
190: }
191: } catch (Exception ex) {
192: if (debug)
193: ex.printStackTrace();
194: }
195:
196: String serviceId = "META-INF/services/" + factoryId;
197: // try to find services in CLASSPATH
198: try {
199: InputStream is = null;
200: if (classLoader == null) {
201: is = ClassLoader.getSystemResourceAsStream(serviceId);
202: } else {
203: is = classLoader.getResourceAsStream(serviceId);
204: }
205:
206: if (is != null) {
207: debugPrintln("found " + serviceId);
208: BufferedReader rd = new BufferedReader(
209: new InputStreamReader(is, "UTF-8"));
210:
211: String factoryClassName = rd.readLine();
212: rd.close();
213:
214: if (factoryClassName != null
215: && !"".equals(factoryClassName)) {
216: debugPrintln("loaded from services: "
217: + factoryClassName);
218: return newInstance(factoryClassName, classLoader);
219: }
220: }
221: } catch (Exception ex) {
222: if (debug)
223: ex.printStackTrace();
224: }
225:
226: if (fallbackClassName == null) {
227: throw new ConfigurationError("Provider for " + factoryId
228: + " cannot be found", null);
229: }
230:
231: debugPrintln("loaded from fallback value: " + fallbackClassName);
232: return newInstance(fallbackClassName, classLoader);
233: }
234:
235: static class ConfigurationError extends Error {
236: private Exception exception;
237:
238: /**
239: * Construct a new instance with the specified detail string and
240: * exception.
241: */
242: ConfigurationError(String msg, Exception x) {
243: super (msg);
244: this .exception = x;
245: }
246:
247: Exception getException() {
248: return exception;
249: }
250: }
251:
252: /*
253: * The following nested classes allow getContextClassLoader() to be
254: * called only on JDK 1.2 and yet run in older JDK 1.1 JVMs
255: */
256:
257: private static abstract class ClassLoaderFinder {
258: abstract ClassLoader getContextClassLoader();
259: }
260:
261: static class ClassLoaderFinderConcrete extends ClassLoaderFinder {
262: ClassLoader getContextClassLoader() {
263: return Thread.currentThread().getContextClassLoader();
264: }
265: }
266: }
|