001: package javax.xml.stream;
002:
003: import java.io.InputStream;
004: import java.io.IOException;
005: import java.io.File;
006: import java.io.FileInputStream;
007:
008: import java.util.Properties;
009: import java.io.BufferedReader;
010: import java.io.InputStreamReader;
011:
012: class FactoryFinder {
013: /** Temp debug code - this will be removed after we test everything
014: */
015: private static boolean debug = false;
016: static {
017: // Use try/catch block to support applets
018: try {
019: debug = System.getProperty("xml.stream.debug") != null;
020: } catch (Exception x) {
021: }
022: }
023:
024: private static void debugPrintln(String msg) {
025: if (debug) {
026: System.err.println("STREAM: " + msg);
027: }
028: }
029:
030: private static ClassLoader findClassLoader()
031: throws FactoryConfigurationError {
032: ClassLoader classLoader;
033: try {
034: // Construct the name of the concrete class to instantiate
035: Class clazz = Class.forName(FactoryFinder.class.getName()
036: + "$ClassLoaderFinderConcrete");
037: ClassLoaderFinder clf = (ClassLoaderFinder) clazz
038: .newInstance();
039: classLoader = clf.getContextClassLoader();
040: } catch (LinkageError le) {
041: // Assume that we are running JDK 1.1, use the current ClassLoader
042: classLoader = FactoryFinder.class.getClassLoader();
043: } catch (ClassNotFoundException x) {
044: // This case should not normally happen. MS IE can throw this
045: // instead of a LinkageError the second time Class.forName() is
046: // called so assume that we are running JDK 1.1 and use the
047: // current ClassLoader
048: classLoader = FactoryFinder.class.getClassLoader();
049: } catch (Exception x) {
050: // Something abnormal happened so throw an error
051: throw new FactoryConfigurationError(x.toString(), x);
052: }
053: return classLoader;
054: }
055:
056: /**
057: * Create an instance of a class using the specified ClassLoader
058: */
059: private static Object newInstance(String className,
060: ClassLoader classLoader) throws FactoryConfigurationError {
061: try {
062: Class spiClass;
063: if (classLoader == null) {
064: spiClass = Class.forName(className);
065: } else {
066: spiClass = classLoader.loadClass(className);
067: }
068: return spiClass.newInstance();
069: } catch (ClassNotFoundException x) {
070: throw new FactoryConfigurationError("Provider " + className
071: + " not found", x);
072: } catch (Exception x) {
073: throw new FactoryConfigurationError("Provider " + className
074: + " could not be instantiated: " + x, x);
075: }
076: }
077:
078: static Object find(String factoryId)
079: throws FactoryConfigurationError {
080: return find(factoryId, null);
081: }
082:
083: static Object find(String factoryId, String fallbackClassName)
084: throws FactoryConfigurationError {
085: ClassLoader classLoader = findClassLoader();
086: return find(factoryId, fallbackClassName, classLoader);
087: }
088:
089: /**
090: * Finds the implementation Class object in the specified order. Main
091: * entry point.
092: * @return Class object of factory, never null
093: *
094: * @param factoryId Name of the factory to find, same as
095: * a property name
096: * @param fallbackClassName Implementation class name, if nothing else
097: * is found. Use null to mean no fallback.
098: *
099: * Package private so this code can be shared.
100: */
101: static Object find(String factoryId, String fallbackClassName,
102: ClassLoader classLoader) throws FactoryConfigurationError {
103:
104: // Use the system property first
105: try {
106: String systemProp = System.getProperty(factoryId);
107: if (systemProp != null) {
108: debugPrintln("found system property" + systemProp);
109: return newInstance(systemProp, classLoader);
110: }
111: } catch (SecurityException se) {
112: }
113:
114: // try to read from $java.home/lib/xml.properties
115: try {
116: String javah = System.getProperty("java.home");
117: String configFile = javah + File.separator + "lib"
118: + File.separator + "jaxp.properties";
119: File f = new File(configFile);
120: if (f.exists()) {
121: Properties props = new Properties();
122: props.load(new FileInputStream(f));
123: String factoryClassName = props.getProperty(factoryId);
124: debugPrintln("found java.home property "
125: + factoryClassName);
126: return newInstance(factoryClassName, classLoader);
127: }
128: } catch (Exception ex) {
129: if (debug)
130: ex.printStackTrace();
131: }
132:
133: String serviceId = "META-INF/services/" + factoryId;
134: // try to find services in CLASSPATH
135: try {
136: InputStream is = null;
137: if (classLoader == null) {
138: is = ClassLoader.getSystemResourceAsStream(serviceId);
139: } else {
140: is = classLoader.getResourceAsStream(serviceId);
141: }
142:
143: if (is != null) {
144: debugPrintln("found " + serviceId);
145: BufferedReader rd = new BufferedReader(
146: new InputStreamReader(is, "UTF-8"));
147:
148: String factoryClassName = rd.readLine();
149: rd.close();
150:
151: if (factoryClassName != null
152: && !"".equals(factoryClassName)) {
153: debugPrintln("loaded from services: "
154: + factoryClassName);
155: return newInstance(factoryClassName, classLoader);
156: }
157: }
158: } catch (Exception ex) {
159: if (debug)
160: ex.printStackTrace();
161: }
162:
163: if (fallbackClassName == null) {
164: throw new FactoryConfigurationError("Provider for "
165: + factoryId + " cannot be found", null);
166: }
167:
168: debugPrintln("loaded from fallback value: " + fallbackClassName);
169: return newInstance(fallbackClassName, classLoader);
170: }
171:
172: /*
173: * The following nested classes allow getContextClassLoader() to be
174: * called only on JDK 1.2 and yet run in older JDK 1.1 JVMs
175: */
176:
177: private static abstract class ClassLoaderFinder {
178: abstract ClassLoader getContextClassLoader();
179: }
180:
181: static class ClassLoaderFinderConcrete extends ClassLoaderFinder {
182: ClassLoader getContextClassLoader() {
183: return Thread.currentThread().getContextClassLoader();
184: }
185: }
186: }
|