neilg 2002/08/26 16:57:11
Modified: java/src/org/apache/xerces/util ObjectFactory.java
Added: java/src/org/apache/xerces/util SecuritySupport.java
SecuritySupport12.java
Log:
porting change by Edwin Goie intended to address problems with class loading in
environments
with security managers to our internal ObjectFactory code.
Revision Changes Path
1.6 +162 -104 xml-xerces/java/src/org/apache/xerces/util/ObjectFactory.java
Index: ObjectFactory.java
===================================================================
RCS file: /home/cvs/xml-xerces/java/src/org/apache/xerces/util/ObjectFactory.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- ObjectFactory.java 10 Jun 2002 23:36:51 -0000 1.5
+++ ObjectFactory.java 26 Aug 2002 23:57:10 -0000 1.6
@@ -73,11 +73,12 @@
* API.
* <p>
* This code is designed to implement the JAXP 1.1 spec pluggability
- * feature and is designed to both compile and run on JDK version 1.1 and
- * later. The code also runs both as part of an unbundled jar file and
+ * feature and is designed to run on JDK version 1.1 and
+ * later, and to compile on JDK 1.2 and onward.
+ * The code also runs both as part of an unbundled jar file and
* when bundled as part of the JDK.
* <p>
- * This class was moved from the <code>javax.xml.parsers.FactoryFinder</code>
+ * This class was moved from the <code>javax.xml.parsers.ObjectFactory</code>
* class and modified to be used as a general utility for creating objects
* dynamically.
*
@@ -147,85 +148,43 @@
{
debugPrintln("debug is on");
- ClassLoader classLoader = findClassLoader();
+ SecuritySupport ss = SecuritySupport.getInstance();
+ ClassLoader cl = findClassLoader();
// Use the system property first
try {
- String systemProp =
- System.getProperty( factoryId );
- if( systemProp!=null) {
- debugPrintln("found system property " + systemProp);
- return newInstance(systemProp, classLoader);
+ String systemProp = ss.getSystemProperty(factoryId);
+ if (systemProp != null) {
+ debugPrintln("found system property, value=" + systemProp);
+ return newInstance(systemProp, cl, true);
}
} catch (SecurityException se) {
+ // Ignore and continue w/ next location
}
- // try to read from $java.home/lib/xml.properties
- if (propertiesFilename != null) {
- try {
- String javah=System.getProperty( "java.home" );
- String configFile = javah + File.separator +
- "lib" + File.separator + propertiesFilename;
- File f=new File( configFile );
- if( f.exists()) {
- Properties props=new Properties();
- props.load( new FileInputStream(f));
- String factoryClassName = props.getProperty(factoryId);
- debugPrintln("found java.home property " + factoryClassName);
- return newInstance(factoryClassName, classLoader);
- }
- } catch(Exception ex ) {
- if( DEBUG ) ex.printStackTrace();
- }
- }
-
- // try to find services in CLASSPATH
- String serviceId = "META-INF/services/" + factoryId;
+ // Try to read from $java.home/lib/jaxp.properties
try {
- InputStream is=null;
- if (classLoader == null) {
- is=ClassLoader.getSystemResourceAsStream( serviceId );
- } else {
- is=classLoader.getResourceAsStream( serviceId );
+ String javah = ss.getSystemProperty("java.home");
+ String configFile = javah + File.separator +
+ "lib" + File.separator + "propertiesFilename";
+ FileInputStream fis = ss.getFileInputStream(new File(configFile));
+ Properties props = new Properties();
+ props.load(fis);
+ String factoryClassName = props.getProperty(factoryId);
+ if (factoryClassName != null) {
+ debugPrintln("found in jaxp.properties, value=" + factoryClassName);
+ return newInstance(factoryClassName, cl, true);
}
-
- if( is!=null ) {
- debugPrintln("found " + serviceId);
-
- // 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 = rd.readLine();
- rd.close();
+ } catch (Exception x) {
+ // assert(x instanceof FileNotFoundException
+ // || x instanceof SecurityException)
+ // In both cases, ignore and continue w/ next location
+ }
- if (factoryClassName != null &&
- ! "".equals(factoryClassName)) {
- debugPrintln("loaded from services: " + factoryClassName);
- 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) {
@@ -233,9 +192,8 @@
"Provider for " + factoryId + " cannot be found", null);
}
- debugPrintln("loaded from fallback value: " + fallbackClassName);
- return newInstance(fallbackClassName, classLoader);
-
+ debugPrintln("using fallback, value=" + fallbackClassName);
+ return newInstance(fallbackClassName, cl, true);
} // createObject(String,String,String):Object
//
@@ -255,47 +213,60 @@
*/
public static ClassLoader findClassLoader()
throws ConfigurationError
- {
- Method m = null;
+ {
+ SecuritySupport ss = SecuritySupport.getInstance();
- try {
- m = Thread.class.getMethod("getContextClassLoader", null);
- } catch (NoSuchMethodException e) {
- // Assume that we are running JDK 1.1, use the current ClassLoader
- debugPrintln("assuming JDK 1.1");
- return ObjectFactory.class.getClassLoader();
+ // Figure out which ClassLoader to use for loading the provider
+ // class. If there is a Context ClassLoader then use it.
+ ClassLoader cl = ss.getContextClassLoader();
+ if (cl == null) {
+ // Assert: we are on JDK 1.1 or we have no Context ClassLoader
+ // so use the current ClassLoader
+ cl = ObjectFactory.class.getClassLoader();
}
+ return cl;
- try {
- ClassLoader loader = (ClassLoader) m.invoke(Thread.currentThread(),
null);
- return loader != null ? loader : ObjectFactory.class.getClassLoader();
- } catch (IllegalAccessException e) {
- // assert(false)
- throw new ConfigurationError("Unexpected IllegalAccessException",
- e);
- } catch (InvocationTargetException e) {
- // assert(e.getTargetException() instanceof SecurityException)
- throw new ConfigurationError("Unexpected InvocationTargetException",
- e);
- }
} // findClassLoader():ClassLoader
/**
* Create an instance of a class using the specified ClassLoader
- */
- public static Object newInstance(String className,
- ClassLoader classLoader)
+ */
+ public static Object newInstance(String className, ClassLoader cl,
+ boolean doFallback)
throws ConfigurationError
{
+ // assert(className != null);
+
try {
- if (classLoader != null) {
+ Class providerClass;
+ if (cl == null) {
+ // XXX Use the bootstrap ClassLoader. There is no way to
+ // load a class using the bootstrap ClassLoader that works
+ // in both JDK 1.1 and Java 2. However, this should still
+ // work b/c the following should be true:
+ //
+ // (cl == null) iff current ClassLoader == null
+ //
+ // Thus Class.forName(String) will use the current
+ // ClassLoader which will be the bootstrap ClassLoader.
+ providerClass = Class.forName(className);
+ } else {
try {
- return classLoader.loadClass(className).newInstance ();
+ providerClass = cl.loadClass(className);
} catch (ClassNotFoundException x) {
- // try again
+ if (doFallback) {
+ // Fall back to current classloader
+ cl = ObjectFactory.class.getClassLoader();
+ providerClass = cl.loadClass(className);
+ } else {
+ throw x;
+ }
}
}
- return Class.forName(className).newInstance();
+ Object instance = providerClass.newInstance();
+ debugPrintln("created new instance of " + providerClass +
+ " using ClassLoader: " + cl);
+ return instance;
} catch (ClassNotFoundException x) {
throw new ConfigurationError(
"Provider " + className + " not found", x);
@@ -304,7 +275,94 @@
"Provider " + className + " could not be instantiated: " + x,
x);
}
- } // newInstance(String,ClassLoader):Object
+ }
+
+ /*
+ * 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
+ {
+ SecuritySupport ss = SecuritySupport.getInstance();
+ 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 = ObjectFactory.class.getClassLoader();
+ is = ss.getResourceAsStream(cl, serviceId);
+ }
+ } else {
+ // No Context ClassLoader or JDK 1.1 so try the current
+ // ClassLoader
+ cl = ObjectFactory.class.getClassLoader();
+ is = ss.getResourceAsStream(cl, serviceId);
+ }
+
+ if (is == null) {
+ // No provider found
+ return null;
+ }
+
+ debugPrintln("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)) {
+ debugPrintln("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;
+ }
//
// Classes
1.1 xml-xerces/java/src/org/apache/xerces/util/SecuritySupport.java
Index: SecuritySupport.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The name "Apache Software Foundation" must not be used to endorse or
* promote products derived from this software without prior written
* permission. For written permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999-2002, Sun Microsystems,
* Inc., http://www.sun.com. For more information on the Apache Software
* Foundation, please see <http://www.apache.org/>.
*/
package org.apache.xerces.util;
import java.lang.reflect.*;
import java.net.*;
import java.io.*;
/**
* This class is duplicated for each JAXP subpackage so keep it in sync.
* It is package private and therefore is not exposed as part of the JAXP
* API.
*
* Base class with security related methods that work on JDK 1.1.
*/
class SecuritySupport {
/*
* Make this of type Object so that the verifier won't try to
* prove its type, thus possibly trying to load the SecuritySupport12
* class.
*/
private static final Object securitySupport;
static {
SecuritySupport ss = null;
try {
Class c = Class.forName("java.security.AccessController");
// if that worked, we're on 1.2.
/*
// don't reference the class explicitly so it doesn't
// get dragged in accidentally.
c = Class.forName("javax.mail.SecuritySupport12");
Constructor cons = c.getConstructor(new Class[] { });
ss = (SecuritySupport)cons.newInstance(new Object[] { });
*/
/*
* Unfortunately, we can't load the class using reflection
* because the class is package private. And the class has
* to be package private so the APIs aren't exposed to other
* code that could use them to circumvent security. Thus,
* we accept the risk that the direct reference might fail
* on some JDK 1.1 JVMs, even though we would never execute
* this code in such a case. Sigh...
*/
ss = new SecuritySupport12();
} catch (Exception ex) {
// ignore it
} finally {
if (ss == null)
ss = new SecuritySupport();
securitySupport = ss;
}
}
/**
* Return an appropriate instance of this class, depending on whether
* we're on a JDK 1.1 or J2SE 1.2 (or later) system.
*/
public static SecuritySupport getInstance() {
return (SecuritySupport)securitySupport;
}
public ClassLoader getContextClassLoader() {
return null;
}
public String getSystemProperty(String propName) {
return System.getProperty(propName);
}
public FileInputStream getFileInputStream(File file)
throws FileNotFoundException
{
return new FileInputStream(file);
}
public InputStream getResourceAsStream(ClassLoader cl, String name) {
InputStream ris;
if (cl == null) {
ris = ClassLoader.getSystemResourceAsStream(name);
} else {
ris = cl.getResourceAsStream(name);
}
return ris;
}
}
1.1
xml-xerces/java/src/org/apache/xerces/util/SecuritySupport12.java
Index: SecuritySupport12.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The name "Apache Software Foundation" must not be used to endorse or
* promote products derived from this software without prior written
* permission. For written permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999-2002, Sun Microsystems,
* Inc., http://www.sun.com. For more information on the Apache Software
* Foundation, please see <http://www.apache.org/>.
*/
package org.apache.xerces.util;
import java.security.*;
import java.net.*;
import java.io.*;
import java.util.*;
/**
* This class is duplicated for each JAXP subpackage so keep it in sync.
* It is package private and therefore is not exposed as part of the JAXP
* API.
*
* Security related methods that only work on J2SE 1.2 and newer.
*/
class SecuritySupport12 extends SecuritySupport {
public ClassLoader getContextClassLoader() {
return (ClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (SecurityException ex) { }
return cl;
}
});
}
public String getSystemProperty(final String propName) {
return (String)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return System.getProperty(propName);
}
});
}
public FileInputStream getFileInputStream(final File file)
throws FileNotFoundException
{
try {
return (FileInputStream)
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws FileNotFoundException {
return new FileInputStream(file);
}
});
} catch (PrivilegedActionException e) {
throw (FileNotFoundException)e.getException();
}
}
public InputStream getResourceAsStream(final ClassLoader cl,
final String name)
{
return (InputStream)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
InputStream ris;
if (cl == null) {
ris = ClassLoader.getSystemResourceAsStream(name);
} else {
ris = cl.getResourceAsStream(name);
}
return ris;
}
});
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]