KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > xml > parsers > FactoryFinder


1 // $Id: FactoryFinder.java,v 1.7 2004/03/17 10:31:30 nb131165 Exp $
2
/*
3  * @(#)FactoryFinder.java 1.8 06/09/06
4  *
5  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
6  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
7  */

8
9 package javax.xml.parsers;
10
11 import java.io.File JavaDoc;
12 import java.io.FileInputStream JavaDoc;
13
14 import java.util.Properties JavaDoc;
15 import java.io.BufferedReader JavaDoc;
16 import java.io.IOException JavaDoc;
17 import java.io.InputStream JavaDoc;
18 import java.io.InputStreamReader JavaDoc;
19 import java.net.URL JavaDoc;
20
21 /**
22  * This class is duplicated for each JAXP subpackage so keep it in
23  * sync. It is package private.
24  *
25  * This code is designed to implement the JAXP 1.1 spec pluggability
26  * feature and is designed to run on JDK version 1.1 and later including
27  * JVMs that perform early linking like the Microsoft JVM in IE 5. Note
28  * however that it must be compiled on a JDK version 1.2 or later system
29  * since it calls Thread#getContextClassLoader(). The code also runs both
30  * as part of an unbundled jar file and when bundled as part of the JDK.
31  */

32 class FactoryFinder {
33     /** Temp debug code - this will be removed after we test everything
34      */

35     private static boolean debug = false;
36     static Properties JavaDoc cacheProps= new Properties JavaDoc();
37     static SecuritySupport JavaDoc ss = new SecuritySupport JavaDoc() ;
38     static boolean firstTime = true;
39
40     // Define system property "jaxp.debug" to get output
41
static {
42         // Use try/catch block to support applets, which throws
43
// SecurityException out of this code.
44
try {
45             String JavaDoc val = ss.getSystemProperty("jaxp.debug");
46             // Allow simply setting the prop to turn on debug
47
debug = val != null && (! "false".equals(val));
48         } catch (SecurityException JavaDoc se) {
49             debug = false;
50         }
51     }
52     
53
54     private static void dPrint(String JavaDoc msg) {
55         if (debug) {
56             System.err.println("JAXP: " + msg);
57         }
58     }
59     
60     /**
61      * Create an instance of a class using the specified ClassLoader and
62      * optionally fall back to the current ClassLoader if not found.
63      *
64      * @param className Name of the concrete class corresponding to the
65      * service provider
66      *
67      * @param cl ClassLoader to use to load the class, null means to use
68      * the bootstrap ClassLoader
69      *
70      * @param doFallback true if the current ClassLoader should be tried as
71      * a fallback if the class is not found using cl
72      */

73     private static Object JavaDoc newInstance(String JavaDoc className, ClassLoader JavaDoc cl,
74                                       boolean doFallback)
75         throws ConfigurationError
76     {
77         // assert(className != null);
78

79         try {
80             Class JavaDoc providerClass;
81             if (cl == null) {
82                 // If classloader is null Use the bootstrap ClassLoader.
83
// Thus Class.forName(String) will use the current
84
// ClassLoader which will be the bootstrap ClassLoader.
85
providerClass = Class.forName(className);
86             } else {
87                 try {
88                     providerClass = cl.loadClass(className);
89                 } catch (ClassNotFoundException JavaDoc x) {
90                     if (doFallback) {
91                         // Fall back to current classloader
92
cl = FactoryFinder JavaDoc.class.getClassLoader();
93                         providerClass = Class.forName(className, true, cl);
94                     } else {
95                         throw x;
96                     }
97                 }
98             }
99                         
100             Object JavaDoc instance = providerClass.newInstance();
101             dPrint("created new instance of " + providerClass +
102                    " using ClassLoader: " + cl);
103             return instance;
104         } catch (ClassNotFoundException JavaDoc x) {
105             throw new ConfigurationError(
106                 "Provider " + className + " not found", x);
107         } catch (Exception JavaDoc x) {
108             throw new ConfigurationError(
109                 "Provider " + className + " could not be instantiated: " + x,
110                 x);
111         }
112     }
113     
114     /**
115      * Finds the implementation Class object in the specified order. Main
116      * entry point.
117      * @return Class object of factory, never null
118      *
119      * @param factoryId Name of the factory to find, same as
120      * a property name
121      * @param fallbackClassName Implementation class name, if nothing else
122      * is found. Use null to mean no fallback.
123      *
124      * Package private so this code can be shared.
125      */

126     static Object JavaDoc find(String JavaDoc factoryId, String JavaDoc fallbackClassName)
127         throws ConfigurationError
128     {
129
130         // Figure out which ClassLoader to use for loading the provider
131
// class. If there is a Context ClassLoader then use it.
132

133         ClassLoader JavaDoc classLoader = ss.getContextClassLoader();
134         
135         if (classLoader == null) {
136             // if we have no Context ClassLoader
137
// so use the current ClassLoader
138
classLoader = FactoryFinder JavaDoc.class.getClassLoader();
139         }
140
141         dPrint("find factoryId =" + factoryId);
142         
143         // Use the system property first
144
try {
145             String JavaDoc systemProp = ss.getSystemProperty(factoryId);
146             if( systemProp!=null) {
147                 dPrint("found system property, value=" + systemProp);
148                 return newInstance(systemProp, classLoader, true );
149             }
150         } catch (SecurityException JavaDoc se) {
151             //if first option fails due to any reason we should try next option in the
152
//look up algorithm.
153
}
154
155         // try to read from $java.home/lib/jaxp.properties
156
try {
157             String JavaDoc javah = ss.getSystemProperty("java.home");
158             String JavaDoc configFile = javah + File.separator +
159                 "lib" + File.separator + "jaxp.properties";
160             String JavaDoc factoryClassName = null;
161             if(firstTime){
162                 synchronized(cacheProps){
163                     if(firstTime){
164                         File JavaDoc f=new File JavaDoc( configFile );
165                         firstTime = false;
166                         if(ss.doesFileExist(f)){
167                             dPrint("Read properties file "+f);
168                             //cacheProps.load( new FileInputStream(f));
169
cacheProps.load(ss.getFileInputStream(f));
170                         }
171                     }
172                 }
173             }
174             factoryClassName = cacheProps.getProperty(factoryId);
175
176             if(factoryClassName != null){
177                 dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
178                 return newInstance(factoryClassName, classLoader, true);
179             }
180         } catch(Exception JavaDoc ex ) {
181             if( debug ) ex.printStackTrace();
182         }
183
184         // Try Jar Service Provider Mechanism
185
Object JavaDoc provider = findJarServiceProvider(factoryId);
186         if (provider != null) {
187             return provider;
188         }
189         if (fallbackClassName == null) {
190             throw new ConfigurationError(
191                 "Provider for " + factoryId + " cannot be found", null);
192         }
193
194         dPrint("loaded from fallback value: " + fallbackClassName);
195         return newInstance(fallbackClassName, classLoader, true);
196     }
197     
198     /*
199      * Try to find provider using Jar Service Provider Mechanism
200      *
201      * @return instance of provider class if found or null
202      */

203     private static Object JavaDoc findJarServiceProvider(String JavaDoc factoryId)
204         throws ConfigurationError
205     {
206
207         String JavaDoc serviceId = "META-INF/services/" + factoryId;
208         InputStream JavaDoc is = null;
209
210         // First try the Context ClassLoader
211
ClassLoader JavaDoc cl = ss.getContextClassLoader();
212         if (cl != null) {
213             is = ss.getResourceAsStream(cl, serviceId);
214
215             // If no provider found then try the current ClassLoader
216
if (is == null) {
217                 cl = FactoryFinder JavaDoc.class.getClassLoader();
218                 is = ss.getResourceAsStream(cl, serviceId);
219             }
220         } else {
221             // No Context ClassLoader, try the current
222
// ClassLoader
223
cl = FactoryFinder JavaDoc.class.getClassLoader();
224             is = ss.getResourceAsStream(cl, serviceId);
225         }
226
227         if (is == null) {
228             // No provider found
229
return null;
230         }
231
232         dPrint("found jar resource=" + serviceId +
233                " using ClassLoader: " + cl);
234
235         // Read the service provider name in UTF-8 as specified in
236
// the jar spec. Unfortunately this fails in Microsoft
237
// VJ++, which does not implement the UTF-8
238
// encoding. Theoretically, we should simply let it fail in
239
// that case, since the JVM is obviously broken if it
240
// doesn't support such a basic standard. But since there
241
// are still some users attempting to use VJ++ for
242
// development, we have dropped in a fallback which makes a
243
// second attempt using the platform's default encoding. In
244
// VJ++ this is apparently ASCII, which is a subset of
245
// UTF-8... and since the strings we'll be reading here are
246
// also primarily limited to the 7-bit ASCII range (at
247
// least, in English versions), this should work well
248
// enough to keep us on the air until we're ready to
249
// officially decommit from VJ++. [Edited comment from
250
// jkesselm]
251
BufferedReader JavaDoc rd;
252         try {
253             rd = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is, "UTF-8"));
254         } catch (java.io.UnsupportedEncodingException JavaDoc e) {
255             rd = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is));
256         }
257         
258         String JavaDoc factoryClassName = null;
259         try {
260             // XXX Does not handle all possible input as specified by the
261
// Jar Service Provider specification
262
factoryClassName = rd.readLine();
263             rd.close();
264         } catch (IOException JavaDoc x) {
265             // No provider found
266
return null;
267         }
268
269         if (factoryClassName != null &&
270             ! "".equals(factoryClassName)) {
271             dPrint("found in resource, value="
272                    + factoryClassName);
273
274         // Note: here we do not want to fall back to the current
275
// ClassLoader because we want to avoid the case where the
276
// resource file was found using one ClassLoader and the
277
// provider class was instantiated using a different one.
278
return newInstance(factoryClassName, cl, false);
279         }
280
281         // No provider found
282
return null;
283     }
284
285     static class ConfigurationError extends Error JavaDoc {
286         private Exception JavaDoc exception;
287
288         /**
289          * Construct a new instance with the specified detail string and
290          * exception.
291          */

292         ConfigurationError(String JavaDoc msg, Exception JavaDoc x) {
293             super(msg);
294             this.exception = x;
295         }
296
297         Exception JavaDoc getException() {
298             return exception;
299         }
300     }
301
302 }
303
Popular Tags