KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xml > internal > dtm > FactoryFinder


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2003 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
56 package com.sun.org.apache.xml.internal.dtm;
57
58 import java.io.BufferedReader JavaDoc;
59 import java.io.File JavaDoc;
60 import java.io.FileInputStream JavaDoc;
61 import java.io.IOException JavaDoc;
62 import java.io.InputStream JavaDoc;
63 import java.io.InputStreamReader JavaDoc;
64 import java.util.Properties JavaDoc;
65
66 /**
67  * This class is based on the FactoryFinder classes in the JAXP subpackages
68  * in the xml-commons project (xml-apis.jar)
69  *
70  * This copy of FactoryFinder is for the DTMManager. It caches the class
71  * name after it is found the first time, if the System.property is not set.
72  * If the System.property is set, then it is always used.
73  *
74  * It does not use context class loaders, but we will probably need to add
75  * this support in the future. Question: If we use context class loaders, can
76  * we still cache the class (do we need to also cache the class loader for
77  * comparison purposes)?
78  *
79  * @author Edwin Goei, Ilene Seelemann
80  */

81 class FactoryFinder {
82     /** Controls debugging output to stderr */
83     private static boolean debug;
84     
85    /**
86     * Avoid reading all the files when the findFactory
87     * method is called the second time (cache the result of
88     * finding the default impl).
89     */

90    private static String JavaDoc foundFactory = null;
91    
92
93     // Define system property "jaxp.debug" to get output
94
static {
95         try {
96             String JavaDoc val =
97                 SecuritySupport.getInstance().getSystemProperty("jaxp.debug");
98             // Allow simply setting the prop to turn on debug
99
debug = val != null && (! "false".equals(val));
100         } catch (SecurityException JavaDoc se) {
101             debug = false;
102         }
103     }
104
105     /**
106      * Main entry point. Finds and creates a new instance of a concrete
107      * factory implementation in the specified order as stated in the JAXP
108      * spec. This code attempts to find a factory implementation in
109      * serveral locations. If one fails, the next one is tried. To be
110      * more robust, this occurs even if a SecurityException is thrown, but
111      * perhaps it may be better to propogate the SecurityException instead,
112      * so SecurityException-s are not masked.
113      *
114      * @return A new instance of the concrete factory class, never null
115      *
116      * @param factoryId
117      * Name of the factory to find, same as a property name
118      *
119      * @param fallbackClassName
120      * Implementation class name, if nothing else is found. Use
121      * null to mean not to use a fallback.
122      *
123      * @throws FactoryFinder.ConfigurationError
124      * If a factory instance cannot be returned
125      *
126      * Package private so this code can be shared.
127      */

128     static Object JavaDoc find(String JavaDoc factoryId, String JavaDoc fallbackClassName)
129         throws ConfigurationError
130     {
131         SecuritySupport ss = SecuritySupport.getInstance();
132         ClassLoader JavaDoc cl = FactoryFinder.class.getClassLoader();
133         dPrint("find factoryId=" + factoryId);
134
135         // Use the system property first
136
try {
137             String JavaDoc systemProp = ss.getSystemProperty(factoryId);
138             if (systemProp != null) {
139                 dPrint("found system property, value=" + systemProp);
140                 
141                 return newInstance(systemProp, cl, true);
142             }
143             
144         } catch (SecurityException JavaDoc se) {
145             // Ignore and continue w/ next location
146
}
147
148    
149         synchronized (FactoryFinder.class) {
150             // This block will only run once, and then foundFactory will
151
// be set and immutable. Currently there is no support in this
152
// class for context class loaders. If the contents of the
153
// xalan.properties file changes, or the class loader changes,
154
// this will *not* affect the cached class.
155

156             if (foundFactory == null) {
157            
158                // Try to read from $java.home/lib/xalan.properties
159
Properties JavaDoc xalanProperties = null;
160                 try {
161                    String JavaDoc javah = ss.getSystemProperty("java.home");
162                    String JavaDoc configFile = javah + File.separator +
163                         "lib" + File.separator + "xalan.properties";
164
165                    File JavaDoc f = new File JavaDoc(configFile);
166                    FileInputStream JavaDoc fis = ss.getFileInputStream(f);
167                    xalanProperties = new Properties JavaDoc();
168                    xalanProperties.load(fis);
169                    fis.close();
170                    
171                } catch (Exception JavaDoc x) {
172                 // assert(x instanceof FileNotFoundException
173
// || x instanceof SecurityException)
174
// In both cases, ignore and continue w/ next location
175
}
176                
177                if (xalanProperties != null) {
178                    foundFactory = xalanProperties.getProperty(factoryId);
179                    if (foundFactory != null) {
180                        dPrint("found in xalan.properties, value=" + foundFactory);
181                    }
182                 } else {
183                     // Try Jar Service Provider Mechanism
184
// (foundFactory gets set in findJarServiceProvider method)
185
findJarServiceProvider(factoryId);
186         
187                     if (foundFactory == null) {
188                         if (fallbackClassName == null) {
189                             throw new ConfigurationError(
190                             "Provider for " + factoryId + " cannot be found", null);
191                         }
192
193                         dPrint("using fallback, value=" + fallbackClassName);
194                         foundFactory = fallbackClassName;
195                     }
196                }
197             }
198         }
199             
200         return newInstance(foundFactory, cl, true);
201     }
202
203     private static void dPrint(String JavaDoc msg) {
204         if (debug) {
205             System.err.println("JAXP: " + msg);
206         }
207     }
208
209     /**
210      * Create an instance of a class using the specified ClassLoader and
211      * optionally fall back to the current ClassLoader if not found.
212      *
213      * @param className Name of the concrete class corresponding to the
214      * service provider
215      *
216      * @param cl ClassLoader to use to load the class, null means to use
217      * the bootstrap ClassLoader
218      *
219      * @param doFallback true if the current ClassLoader should be tried as
220      * a fallback if the class is not found using cl
221      */

222     private static Object JavaDoc newInstance(String JavaDoc className, ClassLoader JavaDoc cl,
223                                       boolean doFallback)
224         throws ConfigurationError
225     {
226         // assert(className != null);
227

228         try {
229             Class JavaDoc providerClass;
230             if (cl == null) {
231                 // XXX Use the bootstrap ClassLoader. There is no way to
232
// load a class using the bootstrap ClassLoader that works
233
// in both JDK 1.1 and Java 2. However, this should still
234
// work b/c the following should be true:
235
//
236
// (cl == null) iff current ClassLoader == null
237
//
238
// Thus Class.forName(String) will use the current
239
// ClassLoader which will be the bootstrap ClassLoader.
240
providerClass = Class.forName(className);
241             } else {
242                 try {
243                     providerClass = cl.loadClass(className);
244                 } catch (ClassNotFoundException JavaDoc x) {
245                     if (doFallback) {
246                         // Fall back to current classloader
247
cl = FactoryFinder.class.getClassLoader();
248                         providerClass = cl.loadClass(className);
249                     } else {
250                         throw x;
251                     }
252                 }
253             }
254             Object JavaDoc instance = providerClass.newInstance();
255             dPrint("created new instance of " + providerClass +
256                    " using ClassLoader: " + cl);
257             return instance;
258         } catch (ClassNotFoundException JavaDoc x) {
259             throw new ConfigurationError(
260                 "Provider " + className + " not found", x);
261         } catch (Exception JavaDoc x) {
262             throw new ConfigurationError(
263                 "Provider " + className + " could not be instantiated: " + x,
264                 x);
265         }
266     }
267
268     /*
269      * Try to find provider using Jar Service Provider Mechanism
270      *
271      * @return instance of provider class if found or null
272      */

273     private static String JavaDoc findJarServiceProvider(String JavaDoc factoryId)
274         throws ConfigurationError
275     {
276         SecuritySupport ss = SecuritySupport.getInstance();
277         String JavaDoc serviceId = "META-INF/services/" + factoryId;
278         InputStream JavaDoc is = null;
279         // No support yet for context class loader
280
ClassLoader JavaDoc cl = FactoryFinder.class.getClassLoader();
281         is = ss.getResourceAsStream(cl, serviceId);
282
283         if (is == null) {
284             // No provider found
285
return null;
286         }
287
288         dPrint("found jar resource=" + serviceId +
289                " using ClassLoader: " + cl);
290
291         // Read the service provider name in UTF-8 as specified in
292
// the jar spec. Unfortunately this fails in Microsoft
293
// VJ++, which does not implement the UTF-8
294
// encoding. Theoretically, we should simply let it fail in
295
// that case, since the JVM is obviously broken if it
296
// doesn't support such a basic standard. But since there
297
// are still some users attempting to use VJ++ for
298
// development, we have dropped in a fallback which makes a
299
// second attempt using the platform's default encoding. In
300
// VJ++ this is apparently ASCII, which is a subset of
301
// UTF-8... and since the strings we'll be reading here are
302
// also primarily limited to the 7-bit ASCII range (at
303
// least, in English versions), this should work well
304
// enough to keep us on the air until we're ready to
305
// officially decommit from VJ++. [Edited comment from
306
// jkesselm]
307
BufferedReader JavaDoc rd;
308         try {
309             rd = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is, "UTF-8"));
310         } catch (java.io.UnsupportedEncodingException JavaDoc e) {
311             rd = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is));
312         }
313         
314         String JavaDoc factoryClassName = null;
315         try {
316             // XXX Does not handle all possible input as specified by the
317
// Jar Service Provider specification
318
factoryClassName = rd.readLine();
319             rd.close();
320         } catch (IOException JavaDoc x) {
321             // No provider found
322
return null;
323         }
324
325         if (factoryClassName != null &&
326             ! "".equals(factoryClassName)) {
327             dPrint("found in resource, value="
328                    + factoryClassName);
329
330             // Note: here we do not want to fall back to the current
331
// ClassLoader because we want to avoid the case where the
332
// resource file was found using one ClassLoader and the
333
// provider class was instantiated using a different one.
334
return factoryClassName;
335         }
336
337         // No provider found
338
return null;
339     }
340
341     static class ConfigurationError extends Error JavaDoc {
342         private Exception JavaDoc exception;
343
344         /**
345          * Construct a new instance with the specified detail string and
346          * exception.
347          */

348         ConfigurationError(String JavaDoc msg, Exception JavaDoc x) {
349             super(msg);
350             this.exception = x;
351         }
352
353         Exception JavaDoc getException() {
354             return exception;
355         }
356     }
357 }
358
Popular Tags