You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commons-cvs@xml.apache.org by mr...@apache.org on 2005/06/17 21:26:53 UTC
cvs commit: xml-commons/java/external/src/javax/xml/datatype FactoryFinder.java
mrglavas 2005/06/17 12:26:53
Modified: java/external/src/javax/xml/parsers FactoryFinder.java
java/external/src/javax/xml/transform FactoryFinder.java
java/external/src/javax/xml/datatype FactoryFinder.java
Log:
Merge in Performance Fix from the tck-jaxp-1_2_0 branch:
When reading the service provider name from a jar
a BufferedReader is used to read the first line from the
file. BufferedReader's default buffer size is 8K chars. Since
we're only reading one line (the name of a class) this is pretty
excessive. Reducing this size significantly to 80 chars.
Revision Changes Path
1.12 +317 -312 xml-commons/java/external/src/javax/xml/parsers/FactoryFinder.java
Index: FactoryFinder.java
===================================================================
RCS file: /home/cvs/xml-commons/java/external/src/javax/xml/parsers/FactoryFinder.java,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- FactoryFinder.java 8 Apr 2005 10:39:13 -0000 1.11
+++ FactoryFinder.java 17 Jun 2005 19:26:53 -0000 1.12
@@ -1,312 +1,317 @@
-/*
- * Copyright 2003-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// $Id$
-
-package javax.xml.parsers;
-
-import java.io.File;
-import java.io.FileInputStream;
-
-import java.util.Properties;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-
-/**
- * This class is duplicated for each JAXP subpackage so keep it in
- * sync. It is package private.
- *
- * This code is designed to implement the JAXP 1.1 spec pluggability
- * feature and is designed to run on JDK version 1.1 and later including
- * JVMs that perform early linking like the Microsoft JVM in IE 5. Note
- * however that it must be compiled on a JDK version 1.2 or later system
- * since it calls Thread#getContextClassLoader(). The code also runs both
- * as part of an unbundled jar file and when bundled as part of the JDK.
- */
-class FactoryFinder {
- /** Temp debug code - this will be removed after we test everything
- */
- private static boolean debug = false;
- static Properties cacheProps= new Properties();
- static SecuritySupport ss = new SecuritySupport() ;
- static boolean firstTime = true;
-
- // Define system property "jaxp.debug" to get output
- static {
- // Use try/catch block to support applets, which throws
- // SecurityException out of this code.
- try {
- String val = ss.getSystemProperty("jaxp.debug");
- // Allow simply setting the prop to turn on debug
- debug = val != null && (! "false".equals(val));
- } catch (SecurityException se) {
- debug = false;
- }
- }
-
-
- private static void dPrint(String msg) {
- if (debug) {
- System.err.println("JAXP: " + msg);
- }
- }
-
- /**
- * Create an instance of a class using the specified ClassLoader and
- * optionally fall back to the current ClassLoader if not found.
- *
- * @param className Name of the concrete class corresponding to the
- * service provider
- *
- * @param cl ClassLoader to use to load the class, null means to use
- * the bootstrap ClassLoader
- *
- * @param doFallback true if the current ClassLoader should be tried as
- * a fallback if the class is not found using cl
- */
- private static Object newInstance(String className, ClassLoader cl,
- boolean doFallback)
- throws ConfigurationError
- {
- // assert(className != null);
-
- try {
- Class providerClass;
- if (cl == null) {
- // If classloader is null Use the bootstrap ClassLoader.
- // Thus Class.forName(String) will use the current
- // ClassLoader which will be the bootstrap ClassLoader.
- providerClass = Class.forName(className);
- } else {
- try {
- providerClass = cl.loadClass(className);
- } catch (ClassNotFoundException x) {
- if (doFallback) {
- // Fall back to current classloader
- cl = FactoryFinder.class.getClassLoader();
- providerClass = cl.loadClass(className);
- } else {
- throw x;
- }
- }
- }
-
- Object instance = providerClass.newInstance();
- dPrint("created new instance of " + providerClass +
- " using ClassLoader: " + cl);
- return instance;
- } catch (ClassNotFoundException x) {
- throw new ConfigurationError(
- "Provider " + className + " not found", x);
- } catch (Exception x) {
- throw new ConfigurationError(
- "Provider " + className + " could not be instantiated: " + x,
- x);
- }
- }
-
- /**
- * Finds the implementation Class object in the specified order. Main
- * entry point.
- * @return Class object of factory, never null
- *
- * @param factoryId Name of the factory to find, same as
- * a property name
- * @param fallbackClassName Implementation class name, if nothing else
- * is found. Use null to mean no fallback.
- *
- * Package private so this code can be shared.
- */
- static Object find(String factoryId, String fallbackClassName)
- throws ConfigurationError
- {
-
- // Figure out which ClassLoader to use for loading the provider
- // class. If there is a Context ClassLoader then use it.
-
- ClassLoader classLoader = ss.getContextClassLoader();
-
- if (classLoader == null) {
- // if we have no Context ClassLoader
- // so use the current ClassLoader
- classLoader = FactoryFinder.class.getClassLoader();
- }
-
- dPrint("find factoryId =" + factoryId);
-
- // Use the system property first
- try {
- String systemProp = ss.getSystemProperty(factoryId);
- if( systemProp!=null) {
- dPrint("found system property, value=" + systemProp);
- return newInstance(systemProp, classLoader, true );
- }
- } catch (SecurityException se) {
- //if first option fails due to any reason we should try next option in the
- //look up algorithm.
- }
-
- // try to read from $java.home/lib/jaxp.properties
- try {
- String javah = ss.getSystemProperty("java.home");
- String configFile = javah + File.separator +
- "lib" + File.separator + "jaxp.properties";
- String factoryClassName = null;
- if(firstTime){
- synchronized(cacheProps){
- if(firstTime){
- File f=new File( configFile );
- firstTime = false;
- if(ss.doesFileExist(f)){
- dPrint("Read properties file "+f);
- //cacheProps.load( new FileInputStream(f));
- cacheProps.load(ss.getFileInputStream(f));
- }
- }
- }
- }
- factoryClassName = cacheProps.getProperty(factoryId);
-
- if(factoryClassName != null){
- dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
- return newInstance(factoryClassName, classLoader, true);
- }
- } catch(Exception ex ) {
- if( debug ) ex.printStackTrace();
- }
-
- // Try Jar Service Provider Mechanism
- Object provider = findJarServiceProvider(factoryId);
- if (provider != null) {
- return provider;
- }
- if (fallbackClassName == null) {
- throw new ConfigurationError(
- "Provider for " + factoryId + " cannot be found", null);
- }
-
- dPrint("loaded from fallback value: " + fallbackClassName);
- return newInstance(fallbackClassName, classLoader, true);
- }
-
- /*
- * Try to find provider using Jar Service Provider Mechanism
- *
- * @return instance of provider class if found or null
- */
- private static Object findJarServiceProvider(String factoryId)
- throws ConfigurationError
- {
-
- String serviceId = "META-INF/services/" + factoryId;
- InputStream is = null;
-
- // First try the Context ClassLoader
- ClassLoader cl = ss.getContextClassLoader();
- if (cl != null) {
- is = ss.getResourceAsStream(cl, serviceId);
-
- // If no provider found then try the current ClassLoader
- if (is == null) {
- cl = FactoryFinder.class.getClassLoader();
- is = ss.getResourceAsStream(cl, serviceId);
- }
- } else {
- // No Context ClassLoader, try the current
- // ClassLoader
- cl = FactoryFinder.class.getClassLoader();
- is = ss.getResourceAsStream(cl, serviceId);
- }
-
- if (is == null) {
- // No provider found
- return null;
- }
-
- dPrint("found jar resource=" + serviceId +
- " using ClassLoader: " + cl);
-
- // Read the service provider name in UTF-8 as specified in
- // the jar spec. Unfortunately this fails in Microsoft
- // VJ++, which does not implement the UTF-8
- // encoding. Theoretically, we should simply let it fail in
- // that case, since the JVM is obviously broken if it
- // doesn't support such a basic standard. But since there
- // are still some users attempting to use VJ++ for
- // development, we have dropped in a fallback which makes a
- // second attempt using the platform's default encoding. In
- // VJ++ this is apparently ASCII, which is a subset of
- // UTF-8... and since the strings we'll be reading here are
- // also primarily limited to the 7-bit ASCII range (at
- // least, in English versions), this should work well
- // enough to keep us on the air until we're ready to
- // officially decommit from VJ++. [Edited comment from
- // jkesselm]
- BufferedReader rd;
- try {
- rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
- } catch (java.io.UnsupportedEncodingException e) {
- rd = new BufferedReader(new InputStreamReader(is));
- }
-
- String factoryClassName = null;
- try {
- // XXX Does not handle all possible input as specified by the
- // Jar Service Provider specification
- factoryClassName = rd.readLine();
- rd.close();
- } catch (IOException x) {
- // No provider found
- return null;
- }
-
- if (factoryClassName != null &&
- ! "".equals(factoryClassName)) {
- dPrint("found in resource, value="
- + factoryClassName);
-
- // Note: here we do not want to fall back to the current
- // ClassLoader because we want to avoid the case where the
- // resource file was found using one ClassLoader and the
- // provider class was instantiated using a different one.
- return newInstance(factoryClassName, cl, false);
- }
-
- // No provider found
- return null;
- }
-
- static class ConfigurationError extends Error {
- private Exception exception;
-
- /**
- * Construct a new instance with the specified detail string and
- * exception.
- */
- ConfigurationError(String msg, Exception x) {
- super(msg);
- this.exception = x;
- }
-
- Exception getException() {
- return exception;
- }
- }
-
-}
+/*
+ * Copyright 2003-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// $Id$
+
+package javax.xml.parsers;
+
+import java.io.File;
+import java.io.FileInputStream;
+
+import java.util.Properties;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+/**
+ * This class is duplicated for each JAXP subpackage so keep it in
+ * sync. It is package private.
+ *
+ * This code is designed to implement the JAXP 1.1 spec pluggability
+ * feature and is designed to run on JDK version 1.1 and later including
+ * JVMs that perform early linking like the Microsoft JVM in IE 5. Note
+ * however that it must be compiled on a JDK version 1.2 or later system
+ * since it calls Thread#getContextClassLoader(). The code also runs both
+ * as part of an unbundled jar file and when bundled as part of the JDK.
+ */
+class FactoryFinder {
+ /** Temp debug code - this will be removed after we test everything
+ */
+ private static boolean debug = false;
+ static Properties cacheProps= new Properties();
+ static SecuritySupport ss = new SecuritySupport() ;
+ static boolean firstTime = true;
+
+ /**
+ * Default columns per line.
+ */
+ private static final int DEFAULT_LINE_LENGTH = 80;
+
+ // Define system property "jaxp.debug" to get output
+ static {
+ // Use try/catch block to support applets, which throws
+ // SecurityException out of this code.
+ try {
+ String val = ss.getSystemProperty("jaxp.debug");
+ // Allow simply setting the prop to turn on debug
+ debug = val != null && (! "false".equals(val));
+ } catch (SecurityException se) {
+ debug = false;
+ }
+ }
+
+
+ private static void dPrint(String msg) {
+ if (debug) {
+ System.err.println("JAXP: " + msg);
+ }
+ }
+
+ /**
+ * Create an instance of a class using the specified ClassLoader and
+ * optionally fall back to the current ClassLoader if not found.
+ *
+ * @param className Name of the concrete class corresponding to the
+ * service provider
+ *
+ * @param cl ClassLoader to use to load the class, null means to use
+ * the bootstrap ClassLoader
+ *
+ * @param doFallback true if the current ClassLoader should be tried as
+ * a fallback if the class is not found using cl
+ */
+ private static Object newInstance(String className, ClassLoader cl,
+ boolean doFallback)
+ throws ConfigurationError
+ {
+ // assert(className != null);
+
+ try {
+ Class providerClass;
+ if (cl == null) {
+ // If classloader is null Use the bootstrap ClassLoader.
+ // Thus Class.forName(String) will use the current
+ // ClassLoader which will be the bootstrap ClassLoader.
+ providerClass = Class.forName(className);
+ } else {
+ try {
+ providerClass = cl.loadClass(className);
+ } catch (ClassNotFoundException x) {
+ if (doFallback) {
+ // Fall back to current classloader
+ cl = FactoryFinder.class.getClassLoader();
+ providerClass = cl.loadClass(className);
+ } else {
+ throw x;
+ }
+ }
+ }
+
+ Object instance = providerClass.newInstance();
+ dPrint("created new instance of " + providerClass +
+ " using ClassLoader: " + cl);
+ return instance;
+ } catch (ClassNotFoundException x) {
+ throw new ConfigurationError(
+ "Provider " + className + " not found", x);
+ } catch (Exception x) {
+ throw new ConfigurationError(
+ "Provider " + className + " could not be instantiated: " + x,
+ x);
+ }
+ }
+
+ /**
+ * Finds the implementation Class object in the specified order. Main
+ * entry point.
+ * @return Class object of factory, never null
+ *
+ * @param factoryId Name of the factory to find, same as
+ * a property name
+ * @param fallbackClassName Implementation class name, if nothing else
+ * is found. Use null to mean no fallback.
+ *
+ * Package private so this code can be shared.
+ */
+ static Object find(String factoryId, String fallbackClassName)
+ throws ConfigurationError
+ {
+
+ // Figure out which ClassLoader to use for loading the provider
+ // class. If there is a Context ClassLoader then use it.
+
+ ClassLoader classLoader = ss.getContextClassLoader();
+
+ if (classLoader == null) {
+ // if we have no Context ClassLoader
+ // so use the current ClassLoader
+ classLoader = FactoryFinder.class.getClassLoader();
+ }
+
+ dPrint("find factoryId =" + factoryId);
+
+ // Use the system property first
+ try {
+ String systemProp = ss.getSystemProperty(factoryId);
+ if( systemProp!=null) {
+ dPrint("found system property, value=" + systemProp);
+ return newInstance(systemProp, classLoader, true );
+ }
+ } catch (SecurityException se) {
+ //if first option fails due to any reason we should try next option in the
+ //look up algorithm.
+ }
+
+ // try to read from $java.home/lib/jaxp.properties
+ try {
+ String javah = ss.getSystemProperty("java.home");
+ String configFile = javah + File.separator +
+ "lib" + File.separator + "jaxp.properties";
+ String factoryClassName = null;
+ if(firstTime){
+ synchronized(cacheProps){
+ if(firstTime){
+ File f=new File( configFile );
+ firstTime = false;
+ if(ss.doesFileExist(f)){
+ dPrint("Read properties file "+f);
+ //cacheProps.load( new FileInputStream(f));
+ cacheProps.load(ss.getFileInputStream(f));
+ }
+ }
+ }
+ }
+ factoryClassName = cacheProps.getProperty(factoryId);
+
+ if(factoryClassName != null){
+ dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
+ return newInstance(factoryClassName, classLoader, true);
+ }
+ } catch(Exception ex ) {
+ if( debug ) ex.printStackTrace();
+ }
+
+ // Try Jar Service Provider Mechanism
+ Object provider = findJarServiceProvider(factoryId);
+ if (provider != null) {
+ return provider;
+ }
+ if (fallbackClassName == null) {
+ throw new ConfigurationError(
+ "Provider for " + factoryId + " cannot be found", null);
+ }
+
+ dPrint("loaded from fallback value: " + fallbackClassName);
+ return newInstance(fallbackClassName, classLoader, true);
+ }
+
+ /*
+ * Try to find provider using Jar Service Provider Mechanism
+ *
+ * @return instance of provider class if found or null
+ */
+ private static Object findJarServiceProvider(String factoryId)
+ throws ConfigurationError
+ {
+
+ String serviceId = "META-INF/services/" + factoryId;
+ InputStream is = null;
+
+ // First try the Context ClassLoader
+ ClassLoader cl = ss.getContextClassLoader();
+ if (cl != null) {
+ is = ss.getResourceAsStream(cl, serviceId);
+
+ // If no provider found then try the current ClassLoader
+ if (is == null) {
+ cl = FactoryFinder.class.getClassLoader();
+ is = ss.getResourceAsStream(cl, serviceId);
+ }
+ } else {
+ // No Context ClassLoader, try the current
+ // ClassLoader
+ cl = FactoryFinder.class.getClassLoader();
+ is = ss.getResourceAsStream(cl, serviceId);
+ }
+
+ if (is == null) {
+ // No provider found
+ return null;
+ }
+
+ dPrint("found jar resource=" + serviceId +
+ " using ClassLoader: " + cl);
+
+ // Read the service provider name in UTF-8 as specified in
+ // the jar spec. Unfortunately this fails in Microsoft
+ // VJ++, which does not implement the UTF-8
+ // encoding. Theoretically, we should simply let it fail in
+ // that case, since the JVM is obviously broken if it
+ // doesn't support such a basic standard. But since there
+ // are still some users attempting to use VJ++ for
+ // development, we have dropped in a fallback which makes a
+ // second attempt using the platform's default encoding. In
+ // VJ++ this is apparently ASCII, which is a subset of
+ // UTF-8... and since the strings we'll be reading here are
+ // also primarily limited to the 7-bit ASCII range (at
+ // least, in English versions), this should work well
+ // enough to keep us on the air until we're ready to
+ // officially decommit from VJ++. [Edited comment from
+ // jkesselm]
+ BufferedReader rd;
+ try {
+ rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH);
+ } catch (java.io.UnsupportedEncodingException e) {
+ rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH);
+ }
+
+ String factoryClassName = null;
+ try {
+ // XXX Does not handle all possible input as specified by the
+ // Jar Service Provider specification
+ factoryClassName = rd.readLine();
+ rd.close();
+ } catch (IOException x) {
+ // No provider found
+ return null;
+ }
+
+ if (factoryClassName != null &&
+ ! "".equals(factoryClassName)) {
+ dPrint("found in resource, value="
+ + factoryClassName);
+
+ // Note: here we do not want to fall back to the current
+ // ClassLoader because we want to avoid the case where the
+ // resource file was found using one ClassLoader and the
+ // provider class was instantiated using a different one.
+ return newInstance(factoryClassName, cl, false);
+ }
+
+ // No provider found
+ return null;
+ }
+
+ static class ConfigurationError extends Error {
+ private Exception exception;
+
+ /**
+ * Construct a new instance with the specified detail string and
+ * exception.
+ */
+ ConfigurationError(String msg, Exception x) {
+ super(msg);
+ this.exception = x;
+ }
+
+ Exception getException() {
+ return exception;
+ }
+ }
+
+}
1.9 +317 -312 xml-commons/java/external/src/javax/xml/transform/FactoryFinder.java
Index: FactoryFinder.java
===================================================================
RCS file: /home/cvs/xml-commons/java/external/src/javax/xml/transform/FactoryFinder.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- FactoryFinder.java 8 Apr 2005 10:39:13 -0000 1.8
+++ FactoryFinder.java 17 Jun 2005 19:26:53 -0000 1.9
@@ -1,312 +1,317 @@
-/*
- * Copyright 2003-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// $Id$
-
-package javax.xml.transform;
-
-import java.io.File;
-import java.io.FileInputStream;
-
-import java.util.Properties;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-
-/**
- * This class is duplicated for each JAXP subpackage so keep it in
- * sync. It is package private.
- *
- * This code is designed to implement the JAXP 1.1 spec pluggability
- * feature and is designed to run on JDK version 1.1 and later including
- * JVMs that perform early linking like the Microsoft JVM in IE 5. Note
- * however that it must be compiled on a JDK version 1.2 or later system
- * since it calls Thread#getContextClassLoader(). The code also runs both
- * as part of an unbundled jar file and when bundled as part of the JDK.
- */
-class FactoryFinder {
- /** Temp debug code - this will be removed after we test everything
- */
- private static boolean debug = false;
- static Properties cacheProps= new Properties();
- static SecuritySupport ss = new SecuritySupport() ;
- static boolean firstTime = true;
-
- // Define system property "jaxp.debug" to get output
- static {
- // Use try/catch block to support applets, which throws
- // SecurityException out of this code.
- try {
- String val = ss.getSystemProperty("jaxp.debug");
- // Allow simply setting the prop to turn on debug
- debug = val != null && (! "false".equals(val));
- } catch (SecurityException se) {
- debug = false;
- }
- }
-
-
- private static void dPrint(String msg) {
- if (debug) {
- System.err.println("JAXP: " + msg);
- }
- }
-
- /**
- * Create an instance of a class using the specified ClassLoader and
- * optionally fall back to the current ClassLoader if not found.
- *
- * @param className Name of the concrete class corresponding to the
- * service provider
- *
- * @param cl ClassLoader to use to load the class, null means to use
- * the bootstrap ClassLoader
- *
- * @param doFallback true if the current ClassLoader should be tried as
- * a fallback if the class is not found using cl
- */
- private static Object newInstance(String className, ClassLoader cl,
- boolean doFallback)
- throws ConfigurationError
- {
- // assert(className != null);
-
- try {
- Class providerClass;
- if (cl == null) {
- // If classloader is null Use the bootstrap ClassLoader.
- // Thus Class.forName(String) will use the current
- // ClassLoader which will be the bootstrap ClassLoader.
- providerClass = Class.forName(className);
- } else {
- try {
- providerClass = cl.loadClass(className);
- } catch (ClassNotFoundException x) {
- if (doFallback) {
- // Fall back to current classloader
- cl = FactoryFinder.class.getClassLoader();
- providerClass = cl.loadClass(className);
- } else {
- throw x;
- }
- }
- }
-
- Object instance = providerClass.newInstance();
- dPrint("created new instance of " + providerClass +
- " using ClassLoader: " + cl);
- return instance;
- } catch (ClassNotFoundException x) {
- throw new ConfigurationError(
- "Provider " + className + " not found", x);
- } catch (Exception x) {
- throw new ConfigurationError(
- "Provider " + className + " could not be instantiated: " + x,
- x);
- }
- }
-
- /**
- * Finds the implementation Class object in the specified order. Main
- * entry point.
- * @return Class object of factory, never null
- *
- * @param factoryId Name of the factory to find, same as
- * a property name
- * @param fallbackClassName Implementation class name, if nothing else
- * is found. Use null to mean no fallback.
- *
- * Package private so this code can be shared.
- */
- static Object find(String factoryId, String fallbackClassName)
- throws ConfigurationError
- {
-
- // Figure out which ClassLoader to use for loading the provider
- // class. If there is a Context ClassLoader then use it.
-
- ClassLoader classLoader = ss.getContextClassLoader();
-
- if (classLoader == null) {
- // if we have no Context ClassLoader
- // so use the current ClassLoader
- classLoader = FactoryFinder.class.getClassLoader();
- }
-
- dPrint("find factoryId =" + factoryId);
-
- // Use the system property first
- try {
- String systemProp = ss.getSystemProperty(factoryId);
- if( systemProp!=null) {
- dPrint("found system property, value=" + systemProp);
- return newInstance(systemProp, classLoader, true );
- }
- } catch (SecurityException se) {
- //if first option fails due to any reason we should try next option in the
- //look up algorithm.
- }
-
- // try to read from $java.home/lib/jaxp.properties
- try {
- String javah = ss.getSystemProperty("java.home");
- String configFile = javah + File.separator +
- "lib" + File.separator + "jaxp.properties";
- String factoryClassName = null;
- if(firstTime){
- synchronized(cacheProps){
- if(firstTime){
- File f=new File( configFile );
- firstTime = false;
- if(ss.doesFileExist(f)){
- dPrint("Read properties file "+f);
- //cacheProps.load( new FileInputStream(f));
- cacheProps.load(ss.getFileInputStream(f));
- }
- }
- }
- }
- factoryClassName = cacheProps.getProperty(factoryId);
-
- if(factoryClassName != null){
- dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
- return newInstance(factoryClassName, classLoader, true);
- }
- } catch(Exception ex ) {
- if( debug ) ex.printStackTrace();
- }
-
- // Try Jar Service Provider Mechanism
- Object provider = findJarServiceProvider(factoryId);
- if (provider != null) {
- return provider;
- }
- if (fallbackClassName == null) {
- throw new ConfigurationError(
- "Provider for " + factoryId + " cannot be found", null);
- }
-
- dPrint("loaded from fallback value: " + fallbackClassName);
- return newInstance(fallbackClassName, classLoader, true);
- }
-
- /*
- * Try to find provider using Jar Service Provider Mechanism
- *
- * @return instance of provider class if found or null
- */
- private static Object findJarServiceProvider(String factoryId)
- throws ConfigurationError
- {
-
- String serviceId = "META-INF/services/" + factoryId;
- InputStream is = null;
-
- // First try the Context ClassLoader
- ClassLoader cl = ss.getContextClassLoader();
- if (cl != null) {
- is = ss.getResourceAsStream(cl, serviceId);
-
- // If no provider found then try the current ClassLoader
- if (is == null) {
- cl = FactoryFinder.class.getClassLoader();
- is = ss.getResourceAsStream(cl, serviceId);
- }
- } else {
- // No Context ClassLoader, try the current
- // ClassLoader
- cl = FactoryFinder.class.getClassLoader();
- is = ss.getResourceAsStream(cl, serviceId);
- }
-
- if (is == null) {
- // No provider found
- return null;
- }
-
- dPrint("found jar resource=" + serviceId +
- " using ClassLoader: " + cl);
-
- // Read the service provider name in UTF-8 as specified in
- // the jar spec. Unfortunately this fails in Microsoft
- // VJ++, which does not implement the UTF-8
- // encoding. Theoretically, we should simply let it fail in
- // that case, since the JVM is obviously broken if it
- // doesn't support such a basic standard. But since there
- // are still some users attempting to use VJ++ for
- // development, we have dropped in a fallback which makes a
- // second attempt using the platform's default encoding. In
- // VJ++ this is apparently ASCII, which is a subset of
- // UTF-8... and since the strings we'll be reading here are
- // also primarily limited to the 7-bit ASCII range (at
- // least, in English versions), this should work well
- // enough to keep us on the air until we're ready to
- // officially decommit from VJ++. [Edited comment from
- // jkesselm]
- BufferedReader rd;
- try {
- rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
- } catch (java.io.UnsupportedEncodingException e) {
- rd = new BufferedReader(new InputStreamReader(is));
- }
-
- String factoryClassName = null;
- try {
- // XXX Does not handle all possible input as specified by the
- // Jar Service Provider specification
- factoryClassName = rd.readLine();
- rd.close();
- } catch (IOException x) {
- // No provider found
- return null;
- }
-
- if (factoryClassName != null &&
- ! "".equals(factoryClassName)) {
- dPrint("found in resource, value="
- + factoryClassName);
-
- // Note: here we do not want to fall back to the current
- // ClassLoader because we want to avoid the case where the
- // resource file was found using one ClassLoader and the
- // provider class was instantiated using a different one.
- return newInstance(factoryClassName, cl, false);
- }
-
- // No provider found
- return null;
- }
-
- static class ConfigurationError extends Error {
- private Exception exception;
-
- /**
- * Construct a new instance with the specified detail string and
- * exception.
- */
- ConfigurationError(String msg, Exception x) {
- super(msg);
- this.exception = x;
- }
-
- Exception getException() {
- return exception;
- }
- }
-
-}
+/*
+ * Copyright 2003-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// $Id$
+
+package javax.xml.transform;
+
+import java.io.File;
+import java.io.FileInputStream;
+
+import java.util.Properties;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+/**
+ * This class is duplicated for each JAXP subpackage so keep it in
+ * sync. It is package private.
+ *
+ * This code is designed to implement the JAXP 1.1 spec pluggability
+ * feature and is designed to run on JDK version 1.1 and later including
+ * JVMs that perform early linking like the Microsoft JVM in IE 5. Note
+ * however that it must be compiled on a JDK version 1.2 or later system
+ * since it calls Thread#getContextClassLoader(). The code also runs both
+ * as part of an unbundled jar file and when bundled as part of the JDK.
+ */
+class FactoryFinder {
+ /** Temp debug code - this will be removed after we test everything
+ */
+ private static boolean debug = false;
+ static Properties cacheProps= new Properties();
+ static SecuritySupport ss = new SecuritySupport() ;
+ static boolean firstTime = true;
+
+ /**
+ * Default columns per line.
+ */
+ private static final int DEFAULT_LINE_LENGTH = 80;
+
+ // Define system property "jaxp.debug" to get output
+ static {
+ // Use try/catch block to support applets, which throws
+ // SecurityException out of this code.
+ try {
+ String val = ss.getSystemProperty("jaxp.debug");
+ // Allow simply setting the prop to turn on debug
+ debug = val != null && (! "false".equals(val));
+ } catch (SecurityException se) {
+ debug = false;
+ }
+ }
+
+
+ private static void dPrint(String msg) {
+ if (debug) {
+ System.err.println("JAXP: " + msg);
+ }
+ }
+
+ /**
+ * Create an instance of a class using the specified ClassLoader and
+ * optionally fall back to the current ClassLoader if not found.
+ *
+ * @param className Name of the concrete class corresponding to the
+ * service provider
+ *
+ * @param cl ClassLoader to use to load the class, null means to use
+ * the bootstrap ClassLoader
+ *
+ * @param doFallback true if the current ClassLoader should be tried as
+ * a fallback if the class is not found using cl
+ */
+ private static Object newInstance(String className, ClassLoader cl,
+ boolean doFallback)
+ throws ConfigurationError
+ {
+ // assert(className != null);
+
+ try {
+ Class providerClass;
+ if (cl == null) {
+ // If classloader is null Use the bootstrap ClassLoader.
+ // Thus Class.forName(String) will use the current
+ // ClassLoader which will be the bootstrap ClassLoader.
+ providerClass = Class.forName(className);
+ } else {
+ try {
+ providerClass = cl.loadClass(className);
+ } catch (ClassNotFoundException x) {
+ if (doFallback) {
+ // Fall back to current classloader
+ cl = FactoryFinder.class.getClassLoader();
+ providerClass = cl.loadClass(className);
+ } else {
+ throw x;
+ }
+ }
+ }
+
+ Object instance = providerClass.newInstance();
+ dPrint("created new instance of " + providerClass +
+ " using ClassLoader: " + cl);
+ return instance;
+ } catch (ClassNotFoundException x) {
+ throw new ConfigurationError(
+ "Provider " + className + " not found", x);
+ } catch (Exception x) {
+ throw new ConfigurationError(
+ "Provider " + className + " could not be instantiated: " + x,
+ x);
+ }
+ }
+
+ /**
+ * Finds the implementation Class object in the specified order. Main
+ * entry point.
+ * @return Class object of factory, never null
+ *
+ * @param factoryId Name of the factory to find, same as
+ * a property name
+ * @param fallbackClassName Implementation class name, if nothing else
+ * is found. Use null to mean no fallback.
+ *
+ * Package private so this code can be shared.
+ */
+ static Object find(String factoryId, String fallbackClassName)
+ throws ConfigurationError
+ {
+
+ // Figure out which ClassLoader to use for loading the provider
+ // class. If there is a Context ClassLoader then use it.
+
+ ClassLoader classLoader = ss.getContextClassLoader();
+
+ if (classLoader == null) {
+ // if we have no Context ClassLoader
+ // so use the current ClassLoader
+ classLoader = FactoryFinder.class.getClassLoader();
+ }
+
+ dPrint("find factoryId =" + factoryId);
+
+ // Use the system property first
+ try {
+ String systemProp = ss.getSystemProperty(factoryId);
+ if( systemProp!=null) {
+ dPrint("found system property, value=" + systemProp);
+ return newInstance(systemProp, classLoader, true );
+ }
+ } catch (SecurityException se) {
+ //if first option fails due to any reason we should try next option in the
+ //look up algorithm.
+ }
+
+ // try to read from $java.home/lib/jaxp.properties
+ try {
+ String javah = ss.getSystemProperty("java.home");
+ String configFile = javah + File.separator +
+ "lib" + File.separator + "jaxp.properties";
+ String factoryClassName = null;
+ if(firstTime){
+ synchronized(cacheProps){
+ if(firstTime){
+ File f=new File( configFile );
+ firstTime = false;
+ if(ss.doesFileExist(f)){
+ dPrint("Read properties file "+f);
+ //cacheProps.load( new FileInputStream(f));
+ cacheProps.load(ss.getFileInputStream(f));
+ }
+ }
+ }
+ }
+ factoryClassName = cacheProps.getProperty(factoryId);
+
+ if(factoryClassName != null){
+ dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
+ return newInstance(factoryClassName, classLoader, true);
+ }
+ } catch(Exception ex ) {
+ if( debug ) ex.printStackTrace();
+ }
+
+ // Try Jar Service Provider Mechanism
+ Object provider = findJarServiceProvider(factoryId);
+ if (provider != null) {
+ return provider;
+ }
+ if (fallbackClassName == null) {
+ throw new ConfigurationError(
+ "Provider for " + factoryId + " cannot be found", null);
+ }
+
+ dPrint("loaded from fallback value: " + fallbackClassName);
+ return newInstance(fallbackClassName, classLoader, true);
+ }
+
+ /*
+ * Try to find provider using Jar Service Provider Mechanism
+ *
+ * @return instance of provider class if found or null
+ */
+ private static Object findJarServiceProvider(String factoryId)
+ throws ConfigurationError
+ {
+
+ String serviceId = "META-INF/services/" + factoryId;
+ InputStream is = null;
+
+ // First try the Context ClassLoader
+ ClassLoader cl = ss.getContextClassLoader();
+ if (cl != null) {
+ is = ss.getResourceAsStream(cl, serviceId);
+
+ // If no provider found then try the current ClassLoader
+ if (is == null) {
+ cl = FactoryFinder.class.getClassLoader();
+ is = ss.getResourceAsStream(cl, serviceId);
+ }
+ } else {
+ // No Context ClassLoader, try the current
+ // ClassLoader
+ cl = FactoryFinder.class.getClassLoader();
+ is = ss.getResourceAsStream(cl, serviceId);
+ }
+
+ if (is == null) {
+ // No provider found
+ return null;
+ }
+
+ dPrint("found jar resource=" + serviceId +
+ " using ClassLoader: " + cl);
+
+ // Read the service provider name in UTF-8 as specified in
+ // the jar spec. Unfortunately this fails in Microsoft
+ // VJ++, which does not implement the UTF-8
+ // encoding. Theoretically, we should simply let it fail in
+ // that case, since the JVM is obviously broken if it
+ // doesn't support such a basic standard. But since there
+ // are still some users attempting to use VJ++ for
+ // development, we have dropped in a fallback which makes a
+ // second attempt using the platform's default encoding. In
+ // VJ++ this is apparently ASCII, which is a subset of
+ // UTF-8... and since the strings we'll be reading here are
+ // also primarily limited to the 7-bit ASCII range (at
+ // least, in English versions), this should work well
+ // enough to keep us on the air until we're ready to
+ // officially decommit from VJ++. [Edited comment from
+ // jkesselm]
+ BufferedReader rd;
+ try {
+ rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH);
+ } catch (java.io.UnsupportedEncodingException e) {
+ rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH);
+ }
+
+ String factoryClassName = null;
+ try {
+ // XXX Does not handle all possible input as specified by the
+ // Jar Service Provider specification
+ factoryClassName = rd.readLine();
+ rd.close();
+ } catch (IOException x) {
+ // No provider found
+ return null;
+ }
+
+ if (factoryClassName != null &&
+ ! "".equals(factoryClassName)) {
+ dPrint("found in resource, value="
+ + factoryClassName);
+
+ // Note: here we do not want to fall back to the current
+ // ClassLoader because we want to avoid the case where the
+ // resource file was found using one ClassLoader and the
+ // provider class was instantiated using a different one.
+ return newInstance(factoryClassName, cl, false);
+ }
+
+ // No provider found
+ return null;
+ }
+
+ static class ConfigurationError extends Error {
+ private Exception exception;
+
+ /**
+ * Construct a new instance with the specified detail string and
+ * exception.
+ */
+ ConfigurationError(String msg, Exception x) {
+ super(msg);
+ this.exception = x;
+ }
+
+ Exception getException() {
+ return exception;
+ }
+ }
+
+}
1.2 +410 -405 xml-commons/java/external/src/javax/xml/datatype/FactoryFinder.java
Index: FactoryFinder.java
===================================================================
RCS file: /home/cvs/xml-commons/java/external/src/javax/xml/datatype/FactoryFinder.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- FactoryFinder.java 11 Apr 2005 07:49:39 -0000 1.1
+++ FactoryFinder.java 17 Jun 2005 19:26:53 -0000 1.2
@@ -1,405 +1,410 @@
-/*
- * Copyright 2003-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// $Id$
-
-package javax.xml.datatype;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import java.util.Properties;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.net.URL;
-
-/**
- * <p>Implement pluggabile Datatypes.</p>
- *
- * <p>This class is duplicated for each JAXP subpackage so keep it in
- * sync. It is package private for secure class loading.</p>
- *
- * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
- * @version $Revision$, $Date$
- * @since 1.5
- */
-class FactoryFinder {
-
- /**
- * <p>Name of class to display in output messages.</p>
- */
- private static final String CLASS_NAME = "javax.xml.datatype.FactoryFinder";
-
- /**
- * <p>Debug flag to trace loading process.</p>
- */
- private static boolean debug = false;
-
- /**
- * <p>Cache properties for performance.</p>
- */
- private static Properties cacheProps = new Properties();
-
- /**
- * <p>First time requires initialization overhead.</p>
- */
- private static boolean firstTime = true;
-
- /**
- *<p> Take care of restrictions imposed by java security model </p>
- */
- private static SecuritySupport ss = new SecuritySupport();
-
- /**
- * <p>Check to see if debugging enabled by property.</p>
- *
- * <p>Use try/catch block to support applets, which throws
- * SecurityException out of this code.</p>
- *
- */
- static {
- try {
- debug = ss.getSystemProperty("jaxp.debug") != null;
- } catch (Exception x) {
- ; // NOP, ignore exception
- }
- }
-
- /**
- * <p>Output debugging messages.</p>
- *
- * @param msg <code>String</code> to print to <code>stderr</code>.
- */
- private static void debugPrintln(String msg) {
- if (debug) {
- System.err.println(
- CLASS_NAME
- + ":"
- + msg);
- }
- }
-
- /**
- * <p>Find the appropriate <code>ClassLoader</code> to use.</p>
- *
- * <p>The context ClassLoader is prefered.</p>
- *
- * @return <code>ClassLoader</code> to use.
- *
- * @throws ConfigurationError If a valid <code>ClassLoader</code> cannot be identified.
- */
- private static ClassLoader findClassLoader()
- throws ConfigurationError {
- ClassLoader classLoader;
-
- // Figure out which ClassLoader to use for loading the provider
- // class. If there is a Context ClassLoader then use it.
-
- classLoader = ss.getContextClassLoader();
-
- debugPrintln(
- "Using context class loader: "
- + classLoader);
-
- if (classLoader == null) {
- // if we have no Context ClassLoader
- // so use the current ClassLoader
- classLoader = FactoryFinder.class.getClassLoader();
- debugPrintln(
- "Using the class loader of FactoryFinder: "
- + classLoader);
- }
-
- return classLoader;
- }
-
- /**
- * <p>Create an instance of a class using the specified ClassLoader.</p>
- *
- * @param className Name of class to create.
- * @param classLoader ClassLoader to use to create named class.
- *
- * @return New instance of specified class created using the specified ClassLoader.
- *
- * @throws ConfigurationError If class could not be created.
- */
- private static Object newInstance(
- String className,
- ClassLoader classLoader)
- throws ConfigurationError {
-
- try {
- Class spiClass;
- if (classLoader == null) {
- spiClass = Class.forName(className);
- } else {
- spiClass = classLoader.loadClass(className);
- }
-
- if (debug) {
- debugPrintln("Loaded " + className + " from " + which(spiClass));
- }
-
- return spiClass.newInstance();
- } catch (ClassNotFoundException x) {
- throw new ConfigurationError(
- "Provider " + className + " not found", x);
- } catch (Exception x) {
- throw new ConfigurationError(
- "Provider " + className + " could not be instantiated: " + x,
- x);
- }
- }
-
- /**
- * Finds the implementation Class object in the specified order. Main
- * entry point.
- * Package private so this code can be shared.
- *
- * @param factoryId Name of the factory to find, same as a property name
- * @param fallbackClassName Implementation class name, if nothing else is found. Use null to mean no fallback.
- *
- * @return Class Object of factory, never null
- *
- * @throws ConfigurationError If Class cannot be found.
- */
- static Object find(String factoryId, String fallbackClassName)
- throws ConfigurationError {
-
- ClassLoader classLoader = findClassLoader();
-
- // Use the system property first
- try {
- String systemProp = ss.getSystemProperty(factoryId);
- if (systemProp != null) {
- debugPrintln("found " + systemProp + " in the system property " + factoryId);
- return newInstance(systemProp, classLoader);
- }
- } catch (SecurityException se) {
- ; // NOP, explicitly ignore SecurityException
- }
-
- // try to read from $java.home/lib/jaxp.properties
- try {
- String javah = ss.getSystemProperty("java.home");
- String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
- String factoryClassName = null;
- if (firstTime) {
- synchronized (cacheProps) {
- if (firstTime) {
- File f = new File(configFile);
- firstTime = false;
- if (ss.doesFileExist(f)) {
- debugPrintln("Read properties file " + f);
- cacheProps.load(ss.getFileInputStream(f));
- }
- }
- }
- }
- factoryClassName = cacheProps.getProperty(factoryId);
- debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
-
- if (factoryClassName != null) {
- return newInstance(factoryClassName, classLoader);
- }
- } catch (Exception ex) {
- if (debug) {
- ex.printStackTrace();
- }
- }
-
- // Try Jar Service Provider Mechanism
- Object provider = findJarServiceProvider(factoryId);
- if (provider != null) {
- return provider;
- }
-
- if (fallbackClassName == null) {
- throw new ConfigurationError(
- "Provider for " + factoryId + " cannot be found", null);
- }
-
- debugPrintln("loaded from fallback value: " + fallbackClassName);
- return newInstance(fallbackClassName, classLoader);
- }
-
- /*
- * Try to find provider using Jar Service Provider Mechanism
- *
- * @return instance of provider class if found or null
- */
- private static Object findJarServiceProvider(String factoryId)
- throws ConfigurationError
- {
-
- String serviceId = "META-INF/services/" + factoryId;
- InputStream is = null;
-
- // First try the Context ClassLoader
- ClassLoader cl = ss.getContextClassLoader();
- if (cl != null) {
- is = ss.getResourceAsStream(cl, serviceId);
-
- // If no provider found then try the current ClassLoader
- if (is == null) {
- cl = FactoryFinder.class.getClassLoader();
- is = ss.getResourceAsStream(cl, serviceId);
- }
- } else {
- // No Context ClassLoader, try the current
- // ClassLoader
- cl = FactoryFinder.class.getClassLoader();
- is = ss.getResourceAsStream(cl, serviceId);
- }
-
- if (is == null) {
- // No provider found
- return null;
- }
-
- debugPrintln("found jar resource=" + serviceId +
- " using ClassLoader: " + cl);
-
- BufferedReader rd;
- try {
- rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
- } catch (java.io.UnsupportedEncodingException e) {
- rd = new BufferedReader(new InputStreamReader(is));
- }
-
- String factoryClassName = null;
- try {
- // XXX Does not handle all possible input as specified by the
- // Jar Service Provider specification
- factoryClassName = rd.readLine();
- rd.close();
- } catch (IOException x) {
- // No provider found
- return null;
- }
-
- if (factoryClassName != null &&
- ! "".equals(factoryClassName)) {
- debugPrintln("found in resource, value="
- + factoryClassName);
-
- return newInstance(factoryClassName, cl);
- }
-
- // No provider found
- return null;
- }
-
- /**
- * <p>Configuration Error.</p>
- */
- static class ConfigurationError extends Error {
-
- /**
- * <p>Exception that caused the error.</p>
- */
- private Exception exception;
-
- /**
- * <p>Construct a new instance with the specified detail string and
- * exception.</p>
- *
- * @param msg Detail message for this error.
- * @param x Exception that caused the error.
- */
- ConfigurationError(String msg, Exception x) {
- super(msg);
- this.exception = x;
- }
-
- /**
- * <p>Get the Exception that caused the error.</p>
- *
- * @return Exception that caused the error.
- */
- Exception getException() {
- return exception;
- }
- }
-
-
-
- /**
- * Returns the location where the given Class is loaded from.
- *
- * @param clazz Class to find load location.
- *
- * @return Location where class would be loaded from.
- */
- private static String which(Class clazz) {
- try {
- String classnameAsResource = clazz.getName().replace('.', '/') + ".class";
-
- ClassLoader loader = clazz.getClassLoader();
-
- URL it;
-
- if (loader != null) {
- it = loader.getResource(classnameAsResource);
- } else {
- it = ClassLoader.getSystemResource(classnameAsResource);
- }
-
- if (it != null) {
- return it.toString();
- }
- } catch (Throwable t) {
- // work defensively.
- if (debug) {
- t.printStackTrace();
- }
- }
- return "unknown location";
- }
-
-
-
- /**
- * The following nested classes allow getContextClassLoader() to be
- * called only on JDK 1.2 and yet run in older JDK 1.1 JVMs
- */
- private abstract static class ClassLoaderFinder {
-
- /**
- * <p>Get Context Class loader.</p>
- *
- * @return Context class loader.
- */
- abstract ClassLoader getContextClassLoader();
- }
-
- /**
- * <p>Actual ClassLoader finder implementation.</p>
- */
- static class ClassLoaderFinderConcrete extends ClassLoaderFinder {
-
- /**
- * <p>Get Context Class loader.</p>
- *
- * @return Context class loader.
- */
- ClassLoader getContextClassLoader() {
- return Thread.currentThread().getContextClassLoader();
- }
- }
-}
+/*
+ * Copyright 2003-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// $Id$
+
+package javax.xml.datatype;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.util.Properties;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+/**
+ * <p>Implement pluggabile Datatypes.</p>
+ *
+ * <p>This class is duplicated for each JAXP subpackage so keep it in
+ * sync. It is package private for secure class loading.</p>
+ *
+ * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
+ * @version $Revision$, $Date$
+ * @since 1.5
+ */
+class FactoryFinder {
+
+ /**
+ * <p>Name of class to display in output messages.</p>
+ */
+ private static final String CLASS_NAME = "javax.xml.datatype.FactoryFinder";
+
+ /**
+ * <p>Debug flag to trace loading process.</p>
+ */
+ private static boolean debug = false;
+
+ /**
+ * <p>Cache properties for performance.</p>
+ */
+ private static Properties cacheProps = new Properties();
+
+ /**
+ * <p>First time requires initialization overhead.</p>
+ */
+ private static boolean firstTime = true;
+
+ /**
+ *<p> Take care of restrictions imposed by java security model </p>
+ */
+ private static SecuritySupport ss = new SecuritySupport();
+
+ /**
+ * Default columns per line.
+ */
+ private static final int DEFAULT_LINE_LENGTH = 80;
+
+ /**
+ * <p>Check to see if debugging enabled by property.</p>
+ *
+ * <p>Use try/catch block to support applets, which throws
+ * SecurityException out of this code.</p>
+ *
+ */
+ static {
+ try {
+ debug = ss.getSystemProperty("jaxp.debug") != null;
+ } catch (Exception x) {
+ ; // NOP, ignore exception
+ }
+ }
+
+ /**
+ * <p>Output debugging messages.</p>
+ *
+ * @param msg <code>String</code> to print to <code>stderr</code>.
+ */
+ private static void debugPrintln(String msg) {
+ if (debug) {
+ System.err.println(
+ CLASS_NAME
+ + ":"
+ + msg);
+ }
+ }
+
+ /**
+ * <p>Find the appropriate <code>ClassLoader</code> to use.</p>
+ *
+ * <p>The context ClassLoader is prefered.</p>
+ *
+ * @return <code>ClassLoader</code> to use.
+ *
+ * @throws ConfigurationError If a valid <code>ClassLoader</code> cannot be identified.
+ */
+ private static ClassLoader findClassLoader()
+ throws ConfigurationError {
+ ClassLoader classLoader;
+
+ // Figure out which ClassLoader to use for loading the provider
+ // class. If there is a Context ClassLoader then use it.
+
+ classLoader = ss.getContextClassLoader();
+
+ debugPrintln(
+ "Using context class loader: "
+ + classLoader);
+
+ if (classLoader == null) {
+ // if we have no Context ClassLoader
+ // so use the current ClassLoader
+ classLoader = FactoryFinder.class.getClassLoader();
+ debugPrintln(
+ "Using the class loader of FactoryFinder: "
+ + classLoader);
+ }
+
+ return classLoader;
+ }
+
+ /**
+ * <p>Create an instance of a class using the specified ClassLoader.</p>
+ *
+ * @param className Name of class to create.
+ * @param classLoader ClassLoader to use to create named class.
+ *
+ * @return New instance of specified class created using the specified ClassLoader.
+ *
+ * @throws ConfigurationError If class could not be created.
+ */
+ private static Object newInstance(
+ String className,
+ ClassLoader classLoader)
+ throws ConfigurationError {
+
+ try {
+ Class spiClass;
+ if (classLoader == null) {
+ spiClass = Class.forName(className);
+ } else {
+ spiClass = classLoader.loadClass(className);
+ }
+
+ if (debug) {
+ debugPrintln("Loaded " + className + " from " + which(spiClass));
+ }
+
+ return spiClass.newInstance();
+ } catch (ClassNotFoundException x) {
+ throw new ConfigurationError(
+ "Provider " + className + " not found", x);
+ } catch (Exception x) {
+ throw new ConfigurationError(
+ "Provider " + className + " could not be instantiated: " + x,
+ x);
+ }
+ }
+
+ /**
+ * Finds the implementation Class object in the specified order. Main
+ * entry point.
+ * Package private so this code can be shared.
+ *
+ * @param factoryId Name of the factory to find, same as a property name
+ * @param fallbackClassName Implementation class name, if nothing else is found. Use null to mean no fallback.
+ *
+ * @return Class Object of factory, never null
+ *
+ * @throws ConfigurationError If Class cannot be found.
+ */
+ static Object find(String factoryId, String fallbackClassName)
+ throws ConfigurationError {
+
+ ClassLoader classLoader = findClassLoader();
+
+ // Use the system property first
+ try {
+ String systemProp = ss.getSystemProperty(factoryId);
+ if (systemProp != null) {
+ debugPrintln("found " + systemProp + " in the system property " + factoryId);
+ return newInstance(systemProp, classLoader);
+ }
+ } catch (SecurityException se) {
+ ; // NOP, explicitly ignore SecurityException
+ }
+
+ // try to read from $java.home/lib/jaxp.properties
+ try {
+ String javah = ss.getSystemProperty("java.home");
+ String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
+ String factoryClassName = null;
+ if (firstTime) {
+ synchronized (cacheProps) {
+ if (firstTime) {
+ File f = new File(configFile);
+ firstTime = false;
+ if (ss.doesFileExist(f)) {
+ debugPrintln("Read properties file " + f);
+ cacheProps.load(ss.getFileInputStream(f));
+ }
+ }
+ }
+ }
+ factoryClassName = cacheProps.getProperty(factoryId);
+ debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
+
+ if (factoryClassName != null) {
+ return newInstance(factoryClassName, classLoader);
+ }
+ } catch (Exception ex) {
+ if (debug) {
+ ex.printStackTrace();
+ }
+ }
+
+ // Try Jar Service Provider Mechanism
+ Object provider = findJarServiceProvider(factoryId);
+ if (provider != null) {
+ return provider;
+ }
+
+ if (fallbackClassName == null) {
+ throw new ConfigurationError(
+ "Provider for " + factoryId + " cannot be found", null);
+ }
+
+ debugPrintln("loaded from fallback value: " + fallbackClassName);
+ return newInstance(fallbackClassName, classLoader);
+ }
+
+ /*
+ * Try to find provider using Jar Service Provider Mechanism
+ *
+ * @return instance of provider class if found or null
+ */
+ private static Object findJarServiceProvider(String factoryId)
+ throws ConfigurationError
+ {
+
+ String serviceId = "META-INF/services/" + factoryId;
+ InputStream is = null;
+
+ // First try the Context ClassLoader
+ ClassLoader cl = ss.getContextClassLoader();
+ if (cl != null) {
+ is = ss.getResourceAsStream(cl, serviceId);
+
+ // If no provider found then try the current ClassLoader
+ if (is == null) {
+ cl = FactoryFinder.class.getClassLoader();
+ is = ss.getResourceAsStream(cl, serviceId);
+ }
+ } else {
+ // No Context ClassLoader, try the current
+ // ClassLoader
+ cl = FactoryFinder.class.getClassLoader();
+ is = ss.getResourceAsStream(cl, serviceId);
+ }
+
+ if (is == null) {
+ // No provider found
+ return null;
+ }
+
+ debugPrintln("found jar resource=" + serviceId +
+ " using ClassLoader: " + cl);
+
+ BufferedReader rd;
+ try {
+ rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH);
+ } catch (java.io.UnsupportedEncodingException e) {
+ rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH);
+ }
+
+ String factoryClassName = null;
+ try {
+ // XXX Does not handle all possible input as specified by the
+ // Jar Service Provider specification
+ factoryClassName = rd.readLine();
+ rd.close();
+ } catch (IOException x) {
+ // No provider found
+ return null;
+ }
+
+ if (factoryClassName != null &&
+ ! "".equals(factoryClassName)) {
+ debugPrintln("found in resource, value="
+ + factoryClassName);
+
+ return newInstance(factoryClassName, cl);
+ }
+
+ // No provider found
+ return null;
+ }
+
+ /**
+ * <p>Configuration Error.</p>
+ */
+ static class ConfigurationError extends Error {
+
+ /**
+ * <p>Exception that caused the error.</p>
+ */
+ private Exception exception;
+
+ /**
+ * <p>Construct a new instance with the specified detail string and
+ * exception.</p>
+ *
+ * @param msg Detail message for this error.
+ * @param x Exception that caused the error.
+ */
+ ConfigurationError(String msg, Exception x) {
+ super(msg);
+ this.exception = x;
+ }
+
+ /**
+ * <p>Get the Exception that caused the error.</p>
+ *
+ * @return Exception that caused the error.
+ */
+ Exception getException() {
+ return exception;
+ }
+ }
+
+
+
+ /**
+ * Returns the location where the given Class is loaded from.
+ *
+ * @param clazz Class to find load location.
+ *
+ * @return Location where class would be loaded from.
+ */
+ private static String which(Class clazz) {
+ try {
+ String classnameAsResource = clazz.getName().replace('.', '/') + ".class";
+
+ ClassLoader loader = clazz.getClassLoader();
+
+ URL it;
+
+ if (loader != null) {
+ it = loader.getResource(classnameAsResource);
+ } else {
+ it = ClassLoader.getSystemResource(classnameAsResource);
+ }
+
+ if (it != null) {
+ return it.toString();
+ }
+ } catch (Throwable t) {
+ // work defensively.
+ if (debug) {
+ t.printStackTrace();
+ }
+ }
+ return "unknown location";
+ }
+
+
+
+ /**
+ * The following nested classes allow getContextClassLoader() to be
+ * called only on JDK 1.2 and yet run in older JDK 1.1 JVMs
+ */
+ private abstract static class ClassLoaderFinder {
+
+ /**
+ * <p>Get Context Class loader.</p>
+ *
+ * @return Context class loader.
+ */
+ abstract ClassLoader getContextClassLoader();
+ }
+
+ /**
+ * <p>Actual ClassLoader finder implementation.</p>
+ */
+ static class ClassLoaderFinderConcrete extends ClassLoaderFinder {
+
+ /**
+ * <p>Get Context Class loader.</p>
+ *
+ * @return Context class loader.
+ */
+ ClassLoader getContextClassLoader() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ }
+}