KickJava   Java API By Example, From Geeks To Geeks.

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


1 // $Id: FactoryFinder.java,v 1.1.10.2 2004/09/21 12:59:26 nb131165 Exp $
2
/*
3  * @(#)FactoryFinder.java 1.5 05/01/04
4  *
5  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
6  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
7  */

8
9 package javax.xml.datatype;
10
11 import java.io.File JavaDoc;
12 import java.io.FileInputStream JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.InputStream JavaDoc;
15
16 import java.util.Properties JavaDoc;
17 import java.io.BufferedReader JavaDoc;
18 import java.io.InputStreamReader JavaDoc;
19 import java.net.URL JavaDoc;
20
21 /**
22  * <p>Implement pluggabile Datatypes.</p>
23  *
24  * <p>This class is duplicated for each JAXP subpackage so keep it in
25  * sync. It is package private for secure class loading.</p>
26  *
27  * @author <a HREF="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
28  * @version $Revision: 1.1.10.2 $, $Date: 2004/09/21 12:59:26 $
29  * @since 1.5
30  */

31 class FactoryFinder {
32     
33     /**
34      * <p>Name of class to display in output messages.</p>
35      */

36     private static final String JavaDoc CLASS_NAME = "javax.xml.datatype.FactoryFinder";
37     
38     /**
39      * <p>Debug flag to trace loading process.</p>
40      */

41     private static boolean debug = false;
42     
43     /**
44      * <p>Cache properties for performance.</p>
45      */

46     private static Properties JavaDoc cacheProps = new Properties JavaDoc();
47     
48     /**
49      * <p>First time requires initialization overhead.</p>
50      */

51     private static boolean firstTime = true;
52     
53     /**
54      *<p> Take care of restrictions imposed by java security model </p>
55      */

56     private static SecuritySupport JavaDoc ss = new SecuritySupport JavaDoc();
57     
58     /**
59      * <p>Check to see if debugging enabled by property.</p>
60      *
61      * <p>Use try/catch block to support applets, which throws
62      * SecurityException out of this code.</p>
63      *
64      */

65     static {
66         try {
67             debug = ss.getSystemProperty("jaxp.debug") != null;
68         } catch (Exception JavaDoc x) {
69             ; // NOP, ignore exception
70
}
71     }
72
73     /**
74      * <p>Output debugging messages.</p>
75      *
76      * @param msg <code>String</code> to print to <code>stderr</code>.
77      */

78     private static void debugPrintln(String JavaDoc msg) {
79         if (debug) {
80             System.err.println(
81                 CLASS_NAME
82                 + ":"
83                 + msg);
84         }
85     }
86
87     /**
88      * <p>Find the appropriate <code>ClassLoader</code> to use.</p>
89      *
90      * <p>The context ClassLoader is prefered.</p>
91      *
92      * @return <code>ClassLoader</code> to use.
93      *
94      * @throws ConfigurationError If a valid <code>ClassLoader</code> cannot be identified.
95      */

96     private static ClassLoader JavaDoc findClassLoader()
97         throws ConfigurationError {
98         ClassLoader JavaDoc classLoader;
99
100         // Figure out which ClassLoader to use for loading the provider
101
// class. If there is a Context ClassLoader then use it.
102

103         classLoader = ss.getContextClassLoader();
104
105         debugPrintln(
106             "Using context class loader: "
107             + classLoader);
108
109         if (classLoader == null) {
110             // if we have no Context ClassLoader
111
// so use the current ClassLoader
112
classLoader = FactoryFinder JavaDoc.class.getClassLoader();
113             debugPrintln(
114                 "Using the class loader of FactoryFinder: "
115                 + classLoader);
116         }
117                     
118         return classLoader;
119     }
120
121     /**
122      * <p>Create an instance of a class using the specified ClassLoader.</p>
123      *
124      * @param className Name of class to create.
125      * @param classLoader ClassLoader to use to create named class.
126      *
127      * @return New instance of specified class created using the specified ClassLoader.
128      *
129      * @throws ConfigurationError If class could not be created.
130      */

131     private static Object JavaDoc newInstance(
132         String JavaDoc className,
133         ClassLoader JavaDoc classLoader)
134         throws ConfigurationError {
135             
136         try {
137             Class JavaDoc spiClass;
138             if (classLoader == null) {
139                 spiClass = Class.forName(className);
140             } else {
141                 spiClass = classLoader.loadClass(className);
142             }
143             
144             if (debug) {
145                 debugPrintln("Loaded " + className + " from " + which(spiClass));
146             }
147              
148             return spiClass.newInstance();
149         } catch (ClassNotFoundException JavaDoc x) {
150             throw new ConfigurationError(
151                 "Provider " + className + " not found", x);
152         } catch (Exception JavaDoc x) {
153             throw new ConfigurationError(
154                 "Provider " + className + " could not be instantiated: " + x,
155                 x);
156         }
157     }
158
159     /**
160      * Finds the implementation Class object in the specified order. Main
161      * entry point.
162      * Package private so this code can be shared.
163      *
164      * @param factoryId Name of the factory to find, same as a property name
165      * @param fallbackClassName Implementation class name, if nothing else is found. Use null to mean no fallback.
166      *
167      * @return Class Object of factory, never null
168      *
169      * @throws ConfigurationError If Class cannot be found.
170      */

171     static Object JavaDoc find(String JavaDoc factoryId, String JavaDoc fallbackClassName)
172         throws ConfigurationError {
173             
174         ClassLoader JavaDoc classLoader = findClassLoader();
175
176         // Use the system property first
177
try {
178             String JavaDoc systemProp = ss.getSystemProperty(factoryId);
179             if (systemProp != null) {
180                 debugPrintln("found " + systemProp + " in the system property " + factoryId);
181                 return newInstance(systemProp, classLoader);
182             }
183         } catch (SecurityException JavaDoc se) {
184             ; // NOP, explicitly ignore SecurityException
185
}
186
187         // try to read from $java.home/lib/jaxp.properties
188
try {
189             String JavaDoc javah = ss.getSystemProperty("java.home");
190             String JavaDoc configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
191             String JavaDoc factoryClassName = null;
192             if (firstTime) {
193                 synchronized (cacheProps) {
194                     if (firstTime) {
195                         File JavaDoc f = new File JavaDoc(configFile);
196                         firstTime = false;
197                         if (ss.doesFileExist(f)) {
198                             debugPrintln("Read properties file " + f);
199                             cacheProps.load(ss.getFileInputStream(f));
200                         }
201                     }
202                 }
203             }
204             factoryClassName = cacheProps.getProperty(factoryId);
205             debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
206             
207             if (factoryClassName != null) {
208                 return newInstance(factoryClassName, classLoader);
209             }
210         } catch (Exception JavaDoc ex) {
211             if (debug) {
212                 ex.printStackTrace();
213             }
214         }
215         
216         // Try Jar Service Provider Mechanism
217
Object JavaDoc provider = findJarServiceProvider(factoryId);
218         if (provider != null) {
219             return provider;
220         }
221
222         if (fallbackClassName == null) {
223             throw new ConfigurationError(
224                 "Provider for " + factoryId + " cannot be found", null);
225         }
226
227         debugPrintln("loaded from fallback value: " + fallbackClassName);
228         return newInstance(fallbackClassName, classLoader);
229     }
230
231     /*
232      * Try to find provider using Jar Service Provider Mechanism
233      *
234      * @return instance of provider class if found or null
235      */

236     private static Object JavaDoc findJarServiceProvider(String JavaDoc factoryId)
237         throws ConfigurationError
238     {
239
240         String JavaDoc serviceId = "META-INF/services/" + factoryId;
241         InputStream JavaDoc is = null;
242
243         // First try the Context ClassLoader
244
ClassLoader JavaDoc cl = ss.getContextClassLoader();
245         if (cl != null) {
246             is = ss.getResourceAsStream(cl, serviceId);
247
248             // If no provider found then try the current ClassLoader
249
if (is == null) {
250                 cl = FactoryFinder JavaDoc.class.getClassLoader();
251                 is = ss.getResourceAsStream(cl, serviceId);
252             }
253         } else {
254             // No Context ClassLoader, try the current
255
// ClassLoader
256
cl = FactoryFinder JavaDoc.class.getClassLoader();
257             is = ss.getResourceAsStream(cl, serviceId);
258         }
259
260         if (is == null) {
261             // No provider found
262
return null;
263         }
264
265         debugPrintln("found jar resource=" + serviceId +
266                " using ClassLoader: " + cl);
267
268         BufferedReader JavaDoc rd;
269         try {
270             rd = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is, "UTF-8"));
271         } catch (java.io.UnsupportedEncodingException JavaDoc e) {
272             rd = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is));
273         }
274         
275         String JavaDoc factoryClassName = null;
276         try {
277             // XXX Does not handle all possible input as specified by the
278
// Jar Service Provider specification
279
factoryClassName = rd.readLine();
280             rd.close();
281         } catch (IOException JavaDoc x) {
282             // No provider found
283
return null;
284         }
285
286         if (factoryClassName != null &&
287             ! "".equals(factoryClassName)) {
288             debugPrintln("found in resource, value="
289                    + factoryClassName);
290
291             return newInstance(factoryClassName, cl);
292         }
293
294         // No provider found
295
return null;
296     }
297     
298     /**
299      * <p>Configuration Error.</p>
300      */

301     static class ConfigurationError extends Error JavaDoc {
302         
303         /**
304          * <p>Exception that caused the error.</p>
305          */

306         private Exception JavaDoc exception;
307
308         /**
309          * <p>Construct a new instance with the specified detail string and
310          * exception.</p>
311          *
312          * @param msg Detail message for this error.
313          * @param x Exception that caused the error.
314          */

315         ConfigurationError(String JavaDoc msg, Exception JavaDoc x) {
316             super(msg);
317             this.exception = x;
318         }
319
320         /**
321          * <p>Get the Exception that caused the error.</p>
322          *
323          * @return Exception that caused the error.
324          */

325         Exception JavaDoc getException() {
326             return exception;
327         }
328     }
329
330
331
332     /**
333      * Returns the location where the given Class is loaded from.
334      *
335      * @param clazz Class to find load location.
336      *
337      * @return Location where class would be loaded from.
338      */

339     private static String JavaDoc which(Class JavaDoc clazz) {
340         try {
341             String JavaDoc classnameAsResource = clazz.getName().replace('.', '/') + ".class";
342     
343             ClassLoader JavaDoc loader = clazz.getClassLoader();
344             
345             URL JavaDoc it;
346     
347             if (loader != null) {
348                 it = loader.getResource(classnameAsResource);
349             } else {
350                 it = ClassLoader.getSystemResource(classnameAsResource);
351             }
352     
353             if (it != null) {
354                 return it.toString();
355             }
356         } catch (Throwable JavaDoc t) {
357             // work defensively.
358
if (debug) {
359                 t.printStackTrace();
360             }
361         }
362         return "unknown location";
363     }
364
365
366
367     /**
368      * The following nested classes allow getContextClassLoader() to be
369      * called only on JDK 1.2 and yet run in older JDK 1.1 JVMs
370      */

371     private abstract static class ClassLoaderFinder {
372         
373         /**
374          * <p>Get Context Class loader.</p>
375          *
376          * @return Context class loader.
377          */

378         abstract ClassLoader JavaDoc getContextClassLoader();
379     }
380
381     /**
382      * <p>Actual ClassLoader finder implementation.</p>
383      */

384     static class ClassLoaderFinderConcrete extends ClassLoaderFinder {
385         
386         /**
387          * <p>Get Context Class loader.</p>
388          *
389          * @return Context class loader.
390          */

391         ClassLoader JavaDoc getContextClassLoader() {
392             return Thread.currentThread().getContextClassLoader();
393         }
394     }
395 }
396
Popular Tags