KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > dom > ObjectFactory


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2004 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
57 package com.sun.org.apache.xerces.internal.dom;
58
59 import java.io.InputStream JavaDoc;
60 import java.io.IOException JavaDoc;
61 import java.io.File JavaDoc;
62 import java.io.FileInputStream JavaDoc;
63
64 import java.util.Properties JavaDoc;
65 import java.io.BufferedReader JavaDoc;
66 import java.io.InputStreamReader JavaDoc;
67
68 /**
69  * This class is duplicated for each JAXP subpackage so keep it in sync.
70  * It is package private and therefore is not exposed as part of the JAXP
71  * API.
72  * <p>
73  * This code is designed to implement the JAXP 1.1 spec pluggability
74  * feature and is designed to run on JDK version 1.1 and
75  * later, and to compile on JDK 1.2 and onward.
76  * The code also runs both as part of an unbundled jar file and
77  * when bundled as part of the JDK.
78  * <p>
79  *
80  * @version $Id: ObjectFactory.java,v 1.3 2004/05/08 11:07:40 vk112360 Exp $
81  */

82 class ObjectFactory {
83
84     //
85
// Constants
86
//
87

88     // name of default properties file to look for in JDK's jre/lib directory
89
private static final String JavaDoc DEFAULT_PROPERTIES_FILENAME = "xerces.properties";
90
91     /** Set to true for debugging */
92     private static final boolean DEBUG = false;
93
94     /**
95      * Default columns per line.
96      */

97     private static final int DEFAULT_LINE_LENGTH = 80;
98
99     /** cache the contents of the xerces.properties file.
100      * Until an attempt has been made to read this file, this will
101      * be null; if the file does not exist or we encounter some other error
102      * during the read, this will be empty.
103      */

104     private static Properties JavaDoc fXercesProperties = null;
105
106     /***
107      * Cache the time stamp of the xerces.properties file so
108      * that we know if it's been modified and can invalidate
109      * the cache when necessary.
110      */

111     private static long fLastModified = -1;
112
113     //
114
// static methods
115
//
116

117     /**
118      * Finds the implementation Class object in the specified order. The
119      * specified order is the following:
120      * <ol>
121      * <li>query the system property using <code>System.getProperty</code>
122      * <li>read <code>META-INF/services/<i>factoryId</i></code> file
123      * <li>use fallback classname
124      * </ol>
125      *
126      * @return Class object of factory, never null
127      *
128      * @param factoryId Name of the factory to find, same as
129      * a property name
130      * @param fallbackClassName Implementation class name, if nothing else
131      * is found. Use null to mean no fallback.
132      *
133      * @exception ObjectFactory.ConfigurationError
134      */

135     static Object JavaDoc createObject(String JavaDoc factoryId, String JavaDoc fallbackClassName)
136         throws ConfigurationError {
137         return createObject(factoryId, null, fallbackClassName);
138     } // createObject(String,String):Object
139

140     /**
141      * Finds the implementation Class object in the specified order. The
142      * specified order is the following:
143      * <ol>
144      * <li>query the system property using <code>System.getProperty</code>
145      * <li>read <code>$java.home/lib/<i>propertiesFilename</i></code> file
146      * <li>read <code>META-INF/services/<i>factoryId</i></code> file
147      * <li>use fallback classname
148      * </ol>
149      *
150      * @return Class object of factory, never null
151      *
152      * @param factoryId Name of the factory to find, same as
153      * a property name
154      * @param propertiesFilename The filename in the $java.home/lib directory
155      * of the properties file. If none specified,
156      * ${java.home}/lib/xerces.properties will be used.
157      * @param fallbackClassName Implementation class name, if nothing else
158      * is found. Use null to mean no fallback.
159      *
160      * @exception ObjectFactory.ConfigurationError
161      */

162     static Object JavaDoc createObject(String JavaDoc factoryId,
163                                       String JavaDoc propertiesFilename,
164                                       String JavaDoc fallbackClassName)
165         throws ConfigurationError
166     {
167         if (DEBUG) debugPrintln("debug is on");
168
169         SecuritySupport ss = SecuritySupport.getInstance();
170         ClassLoader JavaDoc cl = findClassLoader();
171
172         // Use the system property first
173
try {
174             String JavaDoc systemProp = ss.getSystemProperty(factoryId);
175             if (systemProp != null) {
176                 if (DEBUG) debugPrintln("found system property, value=" + systemProp);
177                 return newInstance(systemProp, cl, true);
178             }
179         } catch (SecurityException JavaDoc se) {
180             // Ignore and continue w/ next location
181
}
182
183         // Try to read from propertiesFilename, or $java.home/lib/xerces.properties
184
String JavaDoc factoryClassName = null;
185         // no properties file name specified; use $JAVA_HOME/lib/xerces.properties:
186
if (propertiesFilename == null) {
187             File JavaDoc propertiesFile = null;
188             boolean propertiesFileExists = false;
189             try {
190                 String JavaDoc javah = ss.getSystemProperty("java.home");
191                 propertiesFilename = javah + File.separator +
192                     "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME;
193                 propertiesFile = new File JavaDoc(propertiesFilename);
194                 propertiesFileExists = ss.getFileExists(propertiesFile);
195             } catch (SecurityException JavaDoc e) {
196                 // try again...
197
fLastModified = -1;
198                 fXercesProperties = null;
199             }
200
201             synchronized (ObjectFactory.class) {
202                 boolean loadProperties = false;
203                 try {
204                     // file existed last time
205
if(fLastModified >= 0) {
206                         if(propertiesFileExists &&
207                                 (fLastModified < (fLastModified = ss.getLastModified(propertiesFile)))) {
208                             loadProperties = true;
209                         } else {
210                             // file has stopped existing...
211
if(!propertiesFileExists) {
212                                 fLastModified = -1;
213                                 fXercesProperties = null;
214                             } // else, file wasn't modified!
215
}
216                     } else {
217                         // file has started to exist:
218
if(propertiesFileExists) {
219                             loadProperties = true;
220                             fLastModified = ss.getLastModified(propertiesFile);
221                         } // else, nothing's changed
222
}
223                     if(loadProperties) {
224                         // must never have attempted to read xerces.properties before (or it's outdeated)
225
fXercesProperties = new Properties JavaDoc();
226                         FileInputStream JavaDoc fis = ss.getFileInputStream(propertiesFile);
227                         fXercesProperties.load(fis);
228                         fis.close();
229                     }
230                 } catch (Exception JavaDoc x) {
231                     fXercesProperties = null;
232                     fLastModified = -1;
233                     // assert(x instanceof FileNotFoundException
234
// || x instanceof SecurityException)
235
// In both cases, ignore and continue w/ next location
236
}
237             }
238             if(fXercesProperties != null) {
239                 factoryClassName = fXercesProperties.getProperty(factoryId);
240             }
241         } else {
242             try {
243                 FileInputStream JavaDoc fis = ss.getFileInputStream(new File JavaDoc(propertiesFilename));
244                 Properties JavaDoc props = new Properties JavaDoc();
245                 props.load(fis);
246                 fis.close();
247                 factoryClassName = props.getProperty(factoryId);
248             } catch (Exception JavaDoc x) {
249                 // assert(x instanceof FileNotFoundException
250
// || x instanceof SecurityException)
251
// In both cases, ignore and continue w/ next location
252
}
253         }
254         if (factoryClassName != null) {
255             if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName);
256             return newInstance(factoryClassName, cl, true);
257         }
258
259         // Try Jar Service Provider Mechanism
260
Object JavaDoc provider = findJarServiceProvider(factoryId);
261         if (provider != null) {
262             return provider;
263         }
264
265         if (fallbackClassName == null) {
266             throw new ConfigurationError(
267                 "Provider for " + factoryId + " cannot be found", null);
268         }
269
270         if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName);
271         return newInstance(fallbackClassName, cl, true);
272     } // createObject(String,String,String):Object
273

274     //
275
// Private static methods
276
//
277

278     /** Prints a message to standard error if debugging is enabled. */
279     private static void debugPrintln(String JavaDoc msg) {
280         if (DEBUG) {
281             System.err.println("JAXP: " + msg);
282         }
283     } // debugPrintln(String)
284

285     /**
286      * Figure out which ClassLoader to use. For JDK 1.2 and later use
287      * the context ClassLoader.
288      */

289     static ClassLoader JavaDoc findClassLoader()
290         throws ConfigurationError
291     {
292         SecuritySupport ss = SecuritySupport.getInstance();
293
294         // Figure out which ClassLoader to use for loading the provider
295
// class. If there is a Context ClassLoader then use it.
296
ClassLoader JavaDoc context = ss.getContextClassLoader();
297         ClassLoader JavaDoc system = ss.getSystemClassLoader();
298
299         ClassLoader JavaDoc chain = system;
300         while (true) {
301             if (context == chain) {
302                 // Assert: we are on JDK 1.1 or we have no Context ClassLoader
303
// or any Context ClassLoader in chain of system classloader
304
// (including extension ClassLoader) so extend to widest
305
// ClassLoader (always look in system ClassLoader if Xerces
306
// is in boot/extension/system classpath and in current
307
// ClassLoader otherwise); normal classloaders delegate
308
// back to system ClassLoader first so this widening doesn't
309
// change the fact that context ClassLoader will be consulted
310
ClassLoader JavaDoc current = ObjectFactory.class.getClassLoader();
311
312                 chain = system;
313                 while (true) {
314                     if (current == chain) {
315                         // Assert: Current ClassLoader in chain of
316
// boot/extension/system ClassLoaders
317
return system;
318                     }
319                     if (chain == null) {
320                         break;
321                     }
322                     chain = ss.getParentClassLoader(chain);
323                 }
324
325                 // Assert: Current ClassLoader not in chain of
326
// boot/extension/system ClassLoaders
327
return current;
328             }
329
330             if (chain == null) {
331                 // boot ClassLoader reached
332
break;
333             }
334
335             // Check for any extension ClassLoaders in chain up to
336
// boot ClassLoader
337
chain = ss.getParentClassLoader(chain);
338         };
339
340         // Assert: Context ClassLoader not in chain of
341
// boot/extension/system ClassLoaders
342
return context;
343     } // findClassLoader():ClassLoader
344

345     /**
346      * Create an instance of a class using the specified ClassLoader
347      */

348     static Object JavaDoc newInstance(String JavaDoc className, ClassLoader JavaDoc cl,
349                                       boolean doFallback)
350         throws ConfigurationError
351     {
352         // assert(className != null);
353
try{
354             Class JavaDoc providerClass = findProviderClass(className, cl, doFallback);
355             Object JavaDoc instance = providerClass.newInstance();
356             if (DEBUG) debugPrintln("created new instance of " + providerClass +
357                    " using ClassLoader: " + cl);
358             return instance;
359         } catch (ClassNotFoundException JavaDoc x) {
360             throw new ConfigurationError(
361                 "Provider " + className + " not found", x);
362         } catch (Exception JavaDoc x) {
363             throw new ConfigurationError(
364                 "Provider " + className + " could not be instantiated: " + x,
365                 x);
366         }
367     }
368
369     /**
370      * Find a Class using the specified ClassLoader
371      */

372     static Class JavaDoc findProviderClass(String JavaDoc className, ClassLoader JavaDoc cl,
373                                       boolean doFallback)
374         throws ClassNotFoundException JavaDoc, ConfigurationError
375     {
376         //throw security exception if the calling thread is not allowed to access the package
377
//restrict the access to package as speicified in java.security policy
378
SecurityManager JavaDoc security = System.getSecurityManager();
379         try{
380             if (security != null) {
381                 final int lastDot = className.lastIndexOf(".");
382                 String JavaDoc packageName = className;
383                 if (lastDot != -1) packageName = className.substring(0, lastDot);
384                 security.checkPackageAccess(packageName);
385             }
386         }catch(SecurityException JavaDoc e){
387             throw e ;
388         }
389         Class JavaDoc providerClass;
390         if (cl == null) {
391             // XXX Use the bootstrap ClassLoader. There is no way to
392
// load a class using the bootstrap ClassLoader that works
393
// in both JDK 1.1 and Java 2. However, this should still
394
// work b/c the following should be true:
395
//
396
// (cl == null) iff current ClassLoader == null
397
//
398
// Thus Class.forName(String) will use the current
399
// ClassLoader which will be the bootstrap ClassLoader.
400
providerClass = Class.forName(className);
401         } else {
402             try {
403                 providerClass = cl.loadClass(className);
404             } catch (ClassNotFoundException JavaDoc x) {
405                 if (doFallback) {
406                     // Fall back to current classloader
407
ClassLoader JavaDoc current = ObjectFactory.class.getClassLoader();
408                     if (current == null) {
409                         providerClass = Class.forName(className);
410                     } else if (cl != current) {
411                         cl = current;
412                         providerClass = cl.loadClass(className);
413                     } else {
414                         throw x;
415                     }
416                 } else {
417                     throw x;
418                 }
419             }
420         }
421
422         return providerClass;
423     }
424
425     /*
426      * Try to find provider using Jar Service Provider Mechanism
427      *
428      * @return instance of provider class if found or null
429      */

430     private static Object JavaDoc findJarServiceProvider(String JavaDoc factoryId)
431         throws ConfigurationError
432     {
433         SecuritySupport ss = SecuritySupport.getInstance();
434         String JavaDoc serviceId = "META-INF/services/" + factoryId;
435         InputStream JavaDoc is = null;
436
437         // First try the Context ClassLoader
438
ClassLoader JavaDoc cl = findClassLoader();
439
440         is = ss.getResourceAsStream(cl, serviceId);
441
442         // If no provider found then try the current ClassLoader
443
if (is == null) {
444             ClassLoader JavaDoc current = ObjectFactory.class.getClassLoader();
445             if (cl != current) {
446                 cl = current;
447                 is = ss.getResourceAsStream(cl, serviceId);
448             }
449         }
450
451         if (is == null) {
452             // No provider found
453
return null;
454         }
455
456         if (DEBUG) debugPrintln("found jar resource=" + serviceId +
457                " using ClassLoader: " + cl);
458
459         // Read the service provider name in UTF-8 as specified in
460
// the jar spec. Unfortunately this fails in Microsoft
461
// VJ++, which does not implement the UTF-8
462
// encoding. Theoretically, we should simply let it fail in
463
// that case, since the JVM is obviously broken if it
464
// doesn't support such a basic standard. But since there
465
// are still some users attempting to use VJ++ for
466
// development, we have dropped in a fallback which makes a
467
// second attempt using the platform's default encoding. In
468
// VJ++ this is apparently ASCII, which is a subset of
469
// UTF-8... and since the strings we'll be reading here are
470
// also primarily limited to the 7-bit ASCII range (at
471
// least, in English versions), this should work well
472
// enough to keep us on the air until we're ready to
473
// officially decommit from VJ++. [Edited comment from
474
// jkesselm]
475
BufferedReader JavaDoc rd;
476         try {
477             rd = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is, "UTF-8"), DEFAULT_LINE_LENGTH);
478         } catch (java.io.UnsupportedEncodingException JavaDoc e) {
479             rd = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is), DEFAULT_LINE_LENGTH);
480         }
481
482         String JavaDoc factoryClassName = null;
483         try {
484             // XXX Does not handle all possible input as specified by the
485
// Jar Service Provider specification
486
factoryClassName = rd.readLine();
487             rd.close();
488         } catch (IOException JavaDoc x) {
489             // No provider found
490
return null;
491         }
492
493         if (factoryClassName != null &&
494             ! "".equals(factoryClassName)) {
495             if (DEBUG) debugPrintln("found in resource, value="
496                    + factoryClassName);
497
498             // Note: here we do not want to fall back to the current
499
// ClassLoader because we want to avoid the case where the
500
// resource file was found using one ClassLoader and the
501
// provider class was instantiated using a different one.
502
return newInstance(factoryClassName, cl, false);
503         }
504
505         // No provider found
506
return null;
507     }
508
509     //
510
// Classes
511
//
512

513     /**
514      * A configuration error.
515      */

516     static class ConfigurationError
517         extends Error JavaDoc {
518
519         //
520
// Data
521
//
522

523         /** Exception. */
524         private Exception JavaDoc exception;
525
526         //
527
// Constructors
528
//
529

530         /**
531          * Construct a new instance with the specified detail string and
532          * exception.
533          */

534         ConfigurationError(String JavaDoc msg, Exception JavaDoc x) {
535             super(msg);
536             this.exception = x;
537         } // <init>(String,Exception)
538

539         //
540
// methods
541
//
542

543         /** Returns the exception associated to this error. */
544         Exception JavaDoc getException() {
545             return exception;
546         } // getException():Exception
547

548     } // class ConfigurationError
549

550 } // class ObjectFactory
551
Popular Tags