KickJava   Java API By Example, From Geeks To Geeks.

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

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

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

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

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

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

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

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

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

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

275     //
276
// Private static methods
277
//
278

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

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

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

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

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

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

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

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

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

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

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

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

540         //
541
// methods
542
//
543

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

549     } // class ConfigurationError
550

551 } // class ObjectFactory
552
Popular Tags