KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > html > 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 package com.sun.org.apache.html.internal.dom;
57
58 import java.io.InputStream JavaDoc;
59 import java.io.IOException JavaDoc;
60 import java.io.File JavaDoc;
61 import java.io.FileInputStream JavaDoc;
62
63 import java.util.Properties JavaDoc;
64 import java.io.BufferedReader JavaDoc;
65 import java.io.InputStreamReader JavaDoc;
66
67 /**
68  * This class is duplicated for each JAXP subpackage so keep it in sync.
69  * It is package private and therefore is not exposed as part of the JAXP
70  * API.
71  * <p>
72  * This code is designed to implement the JAXP 1.1 spec pluggability
73  * feature and is designed to run on JDK version 1.1 and
74  * later, and to compile on JDK 1.2 and onward.
75  * The code also runs both as part of an unbundled jar file and
76  * when bundled as part of the JDK.
77  * <p>
78  *
79  * @version $Id: ObjectFactory.java,v 1.1.1.1 2004/02/25 08:59:24 vk112360 Exp $
80  */

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

87     // name of default properties file to look for in JDK's jre/lib directory
88
private static final String JavaDoc DEFAULT_PROPERTIES_FILENAME = "xerces.properties";
89
90     /** Set to true for debugging */
91     private static final boolean DEBUG = false;
92
93     /** cache the contents of the xerces.properties file.
94      * Until an attempt has been made to read this file, this will
95      * be null; if the file does not exist or we encounter some other error
96      * during the read, this will be empty.
97      */

98     private static Properties JavaDoc fXercesProperties = null;
99
100     /***
101      * Cache the time stamp of the xerces.properties file so
102      * that we know if it's been modified and can invalidate
103      * the cache when necessary.
104      */

105     private static long fLastModified = -1;
106
107     //
108
// static methods
109
//
110

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

129     static Object JavaDoc createObject(String JavaDoc factoryId, String JavaDoc fallbackClassName)
130         throws ConfigurationError {
131         return createObject(factoryId, null, fallbackClassName);
132     } // createObject(String,String):Object
133

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

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

268     //
269
// Private static methods
270
//
271

272     /** Prints a message to standard error if debugging is enabled. */
273     private static void debugPrintln(String JavaDoc msg) {
274         if (DEBUG) {
275             System.err.println("JAXP: " + msg);
276         }
277     } // debugPrintln(String)
278

279     /**
280      * Figure out which ClassLoader to use. For JDK 1.2 and later use
281      * the context ClassLoader.
282      */

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

339     /**
340      * Create an instance of a class using the specified ClassLoader
341      */

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

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

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

504     /**
505      * A configuration error.
506      */

507     static class ConfigurationError
508         extends Error JavaDoc {
509
510         //
511
// Data
512
//
513

514         /** Exception. */
515         private Exception JavaDoc exception;
516
517         //
518
// Constructors
519
//
520

521         /**
522          * Construct a new instance with the specified detail string and
523          * exception.
524          */

525         ConfigurationError(String JavaDoc msg, Exception JavaDoc x) {
526             super(msg);
527             this.exception = x;
528         } // <init>(String,Exception)
529

530         //
531
// methods
532
//
533

534         /** Returns the exception associated to this error. */
535         Exception JavaDoc getException() {
536             return exception;
537         } // getException():Exception
538

539     } // class ConfigurationError
540

541 } // class ObjectFactory
542
Popular Tags