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 ed...@apache.org on 2002/07/19 01:47:56 UTC

cvs commit: xml-commons/java/external/src/javax/xml/parsers SecuritySupport12.java SecuritySupport.java FactoryFinder.java

edwingo     2002/07/18 16:47:56

  Modified:    java/external/src/javax/xml/transform Tag: java2-branch
                        FactoryFinder.java
               java/external/src/javax/xml/parsers Tag: java2-branch
                        FactoryFinder.java
  Added:       java/external/src/javax/xml/transform Tag: java2-branch
                        SecuritySupport12.java SecuritySupport.java
               java/external/src/javax/xml/parsers Tag: java2-branch
                        SecuritySupport12.java SecuritySupport.java
  Log:
  New version of FactoryFinder adds doPrivilege blocks to code so it will run
  properly in environments that use SecurityManagers such as in servlet
  containers or J2EE servers.  Also tries to load Service Provider from
  context ClassLoader and then current ClassLoader.  Note: Because of
  complexities with Java security and reflection, code will not compile with
  JDK 1.1 but will run in JDK 1.1 and above.
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.7.4.1   +138 -120  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.7
  retrieving revision 1.7.4.1
  diff -u -r1.7 -r1.7.4.1
  --- FactoryFinder.java	26 Oct 2001 00:23:47 -0000	1.7
  +++ FactoryFinder.java	18 Jul 2002 23:47:56 -0000	1.7.4.1
  @@ -55,17 +55,15 @@
   
   package javax.xml.transform;
   
  -import java.io.InputStream;
  -import java.io.IOException;
   import java.io.File;
   import java.io.FileInputStream;
  +import java.io.FileNotFoundException;
  +import java.io.InputStream;
  +import java.io.IOException;
   
  -import java.util.Properties;
   import java.io.BufferedReader;
   import java.io.InputStreamReader;
  -
  -import java.lang.reflect.Method;
  -import java.lang.reflect.InvocationTargetException;
  +import java.util.Properties;
   
   /**
    * This class is duplicated for each JAXP subpackage so keep it in sync.
  @@ -73,65 +71,69 @@
    * API.
    *
    * 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
  - * when bundled as part of the JDK.
  + * feature.  The code runs both as part of an unbundled jar file and also
  + * when bundled as part of the JDK.  Ideally the code should both compile
  + * and run on JDK version 1.1 and later.  However, due to the complexities
  + * of invoking Java 2 security methods via reflection, this code will only
  + * compile on Java 2 although it will run under JDK 1.1 VMs.  As of 1may02
  + * this file is on a "java2-branch".
  + *
  + * @author Edwin Goei
    */
   class FactoryFinder {
  -    /** Set to true for debugging */
  -    private static final boolean debug = false;
  -
  -    private static void debugPrintln(String msg) {
  -        if (debug) {
  -            System.err.println("JAXP: " + msg);
  -        }
  -    }
  -
  -    /**
  -     * Figure out which ClassLoader to use.  For JDK 1.2 and later use
  -     * the context ClassLoader.
  -     */           
  -    private static ClassLoader findClassLoader()
  -        throws ConfigurationError
  -    {
  -        Method m = null;
  +    /** Controls debugging output to stderr */
  +    private static boolean debug;
   
  +    // Define system property "jaxp.debug" to get output
  +    static {
           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 FactoryFinder.class.getClassLoader();
  +            String val =
  +                SecuritySupport.getInstance().getSystemProperty("jaxp.debug");
  +            // Allow simply setting the prop to turn on debug
  +            debug = val != null && (! "false".equals(val));
  +        } catch (SecurityException se) {
  +            debug = false;
           }
  +    }
   
  -        try {
  -            return (ClassLoader) m.invoke(Thread.currentThread(), null);
  -        } 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);
  +    private static void dPrint(String msg) {
  +        if (debug) {
  +            System.err.println("JAXP: " + msg);
           }
       }
   
       /**
  -     * Create an instance of a class using the specified ClassLoader
  +     * Create an instance of a class using the specified ClassLoader.
  +     *
  +     * @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
        */
  -    private static Object newInstance(String className,
  -                                      ClassLoader classLoader)
  +    private static Object newInstance(String className, ClassLoader cl)
           throws ConfigurationError
       {
  +        // assert(className != null);
           try {
               Class spiClass;
  -            if (classLoader == null) {
  +            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.
                   spiClass = Class.forName(className);
               } else {
  -                spiClass = classLoader.loadClass(className);
  +                spiClass = cl.loadClass(className);
               }
  -            return spiClass.newInstance();
  +            Object instance = spiClass.newInstance();
  +            dPrint("created new instance of " + spiClass);
  +            return instance;
           } catch (ClassNotFoundException x) {
               throw new ConfigurationError(
                   "Provider " + className + " not found", x);
  @@ -143,101 +145,117 @@
       }
   
       /**
  -     * 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.
  +     * Main entry point.  Finds and creates a new instance of a concrete
  +     * factory implementation in the specified order as stated in the JAXP
  +     * spec.  This code attempts to find a factory implementation in
  +     * serveral locations.  If one fails, the next one is tried.  To be
  +     * more robust, this occurs even if a SecurityException is thrown, but
  +     * perhaps it may be better to propogate the SecurityException instead,
  +     * so SecurityException-s are not masked.
        *
  -     * @exception FactoryFinder.ConfigurationError
  +     * @return A new instance of the concrete factory class, 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 not to use a fallback.
  +     *
  +     * @throws FactoryFinder.ConfigurationError
  +     *         If a factory instance cannot be returned
        *
        * Package private so this code can be shared.
        */
       static Object find(String factoryId, String fallbackClassName)
           throws ConfigurationError
       {
  -        debugPrintln("debug is on");
  +        SecuritySupport ss = SecuritySupport.getInstance();
  +
  +        // Figure out which ClassLoader to use for loading the SPI class
  +        // and resources.  First try the Context ClassLoader then the
  +        // current ClassLoader.
  +        ClassLoader cl = ss.getContextClassLoader();
  +        if (cl == null) {
  +            // Use the current ClassLoader
  +            cl = FactoryFinder.class.getClassLoader();
  +        }
   
  -        ClassLoader classLoader = findClassLoader();
  +        dPrint("find factoryId=" + factoryId);
   
           // 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) {
  +                dPrint("found system property, value=" + systemProp);
  +                return newInstance(systemProp, cl);
               }
           } catch (SecurityException se) {
  +            // Ignore and continue w/ next location
           }
   
  -        // try to read from $java.home/lib/xml.properties
  +        // Try to read from $java.home/lib/jaxp.properties
           try {
  -            String javah=System.getProperty( "java.home" );
  +            String javah = ss.getSystemProperty("java.home");
               String configFile = javah + File.separator +
                   "lib" + File.separator + "jaxp.properties";
  -            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);
  +            FileInputStream fis = ss.getFileInputStream(new File(configFile));
  +            Properties props = new Properties();
  +            props.load(fis);
  +            String factoryClassName = props.getProperty(factoryId);
  +            if (factoryClassName != null) {
  +                dPrint("found in jaxp.properties, value=" + factoryClassName);
  +                return newInstance(factoryClassName, cl);
               }
  -        } catch(Exception ex ) {
  -            if( debug ) ex.printStackTrace();
  -        }
  -
  -        String serviceId = "META-INF/services/" + factoryId;
  -        // try to find services in CLASSPATH
  -        try {
  -            InputStream is=null;
  -            if (classLoader == null) {
  -                is=ClassLoader.getSystemResourceAsStream( serviceId );
  -            } else {
  -                is=classLoader.getResourceAsStream( serviceId );
  +        } catch (Exception x) {
  +            // assert(x instanceof FileNotFoundException
  +            //        || x instanceof SecurityException)
  +            // In both cases, ignore and continue w/ next location
  +        }
  +
  +        // Try to find service provider in CLASSPATH
  +        final String serviceId = "META-INF/services/" + factoryId;
  +        InputStream is = ss.getResourceAsStream(cl, serviceId);
  +        if (is != null) {
  +            dPrint("found resource=" + 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));
               }
           
  -            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();
  +            String factoryClassName = null;
  +            try {
  +                factoryClassName = rd.readLine();
                   rd.close();
  +            } catch (IOException x) {
  +                // Ignore and continue w/ next location
  +            }
   
  -                if (factoryClassName != null &&
  -                    ! "".equals(factoryClassName)) {
  -                    debugPrintln("loaded from services: " + factoryClassName);
  -                    return newInstance(factoryClassName, classLoader);
  -                }
  +            if (factoryClassName != null &&
  +                ! "".equals(factoryClassName)) {
  +                dPrint("found in resource, value="
  +                       + factoryClassName);
  +                return newInstance(factoryClassName, cl);
               }
  -        } catch( Exception ex ) {
  -            if( debug ) ex.printStackTrace();
           }
   
           if (fallbackClassName == null) {
  @@ -245,8 +263,8 @@
                   "Provider for " + factoryId + " cannot be found", null);
           }
   
  -        debugPrintln("loaded from fallback value: " + fallbackClassName);
  -        return newInstance(fallbackClassName, classLoader);
  +        dPrint("using fallback, value=" + fallbackClassName);
  +        return newInstance(fallbackClassName, cl);
       }
   
       static class ConfigurationError extends Error {
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.1   +125 -0    xml-commons/java/external/src/javax/xml/transform/Attic/SecuritySupport12.java
  
  
  
  
  1.1.2.1   +140 -0    xml-commons/java/external/src/javax/xml/transform/Attic/SecuritySupport.java
  
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.7.2.2   +48 -100   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.7.2.1
  retrieving revision 1.7.2.2
  diff -u -r1.7.2.1 -r1.7.2.2
  --- FactoryFinder.java	2 May 2002 00:52:43 -0000	1.7.2.1
  +++ FactoryFinder.java	18 Jul 2002 23:47:56 -0000	1.7.2.2
  @@ -63,26 +63,22 @@
   
   import java.io.BufferedReader;
   import java.io.InputStreamReader;
  -import java.security.AccessController;
  -import java.security.PrivilegedAction;
  -import java.security.PrivilegedExceptionAction;
   import java.util.Properties;
   
  -import java.lang.reflect.Method;
  -import java.lang.reflect.InvocationTargetException;
  -
   /**
    * 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.
    *
    * 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
  - * when bundled as part of the JDK.  Note: due to the complexities of
  - * invoking Java 2 security methods via reflection, this code will only
  - * compile and run on Java 2 so as of 1may02 this file is on a
  - * "java2-branch".
  + * feature.  The code runs both as part of an unbundled jar file and also
  + * when bundled as part of the JDK.  Ideally the code should both compile
  + * and run on JDK version 1.1 and later.  However, due to the complexities
  + * of invoking Java 2 security methods via reflection, this code will only
  + * compile on Java 2 although it will run under JDK 1.1 VMs.  As of 1may02
  + * this file is on a "java2-branch".
  + *
  + * @author Edwin Goei
    */
   class FactoryFinder {
       /** Controls debugging output to stderr */
  @@ -91,8 +87,10 @@
       // Define system property "jaxp.debug" to get output
       static {
           try {
  -            debug = AccessController.doPrivileged(
  -                new GetPropertyAction("jaxp.debug")) != null;
  +            String val =
  +                SecuritySupport.getInstance().getSystemProperty("jaxp.debug");
  +            // Allow simply setting the prop to turn on debug
  +            debug = val != null && (! "false".equals(val));
           } catch (SecurityException se) {
               debug = false;
           }
  @@ -105,54 +103,33 @@
       }
   
       /**
  -     * Figure out which ClassLoader to use.  For JDK 1.2 and later use
  -     * the context ClassLoader.  This allows the same code to run when
  -     * bundled as part of J2SE or installed as an optional package as well
  -     * as on the application classpath.
  +     * Create an instance of a class using the specified ClassLoader.
        *
  -     * @return  The appropriate ClassLoader or null, which means to use the
  -     *          "system" ClassLoader.
  -     */           
  -    private static ClassLoader findClassLoader()
  -        throws ConfigurationError
  -    {
  -        Method m = null;
  -
  -        try {
  -            m = Thread.class.getMethod("getContextClassLoader", null);
  -        } catch (NoSuchMethodException e) {
  -            // Assume that we are running JDK 1.1, use the current ClassLoader
  -            dPrint("assuming JDK 1.1");
  -            return FactoryFinder.class.getClassLoader();
  -        }
  -
  -        try {
  -            return (ClassLoader) m.invoke(Thread.currentThread(), null);
  -        } 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);
  -        }
  -    }
  -
  -    /**
  -     * Create an instance of a class using the specified ClassLoader
  +     * @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
        */
  -    private static Object newInstance(String className,
  -                                      ClassLoader classLoader)
  +    private static Object newInstance(String className, ClassLoader cl)
           throws ConfigurationError
       {
           // assert(className != null);
           try {
               Class spiClass;
  -            if (classLoader == null) {
  +            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.
                   spiClass = Class.forName(className);
               } else {
  -                spiClass = classLoader.loadClass(className);
  +                spiClass = cl.loadClass(className);
               }
               Object instance = spiClass.newInstance();
               dPrint("created new instance of " + spiClass);
  @@ -193,17 +170,25 @@
       static Object find(String factoryId, String fallbackClassName)
           throws ConfigurationError
       {
  -        final ClassLoader classLoader = findClassLoader();
  +        SecuritySupport ss = SecuritySupport.getInstance();
  +
  +        // Figure out which ClassLoader to use for loading the SPI class
  +        // and resources.  First try the Context ClassLoader then the
  +        // current ClassLoader.
  +        ClassLoader cl = ss.getContextClassLoader();
  +        if (cl == null) {
  +            // Use the current ClassLoader
  +            cl = FactoryFinder.class.getClassLoader();
  +        }
   
           dPrint("find factoryId=" + factoryId);
   
           // Use the system property first
           try {
  -            String systemProp = (String)
  -                AccessController.doPrivileged(new GetPropertyAction(factoryId));
  +            String systemProp = ss.getSystemProperty(factoryId);
               if (systemProp != null) {
                   dPrint("found system property, value=" + systemProp);
  -                return newInstance(systemProp, classLoader);
  +                return newInstance(systemProp, cl);
               }
           } catch (SecurityException se) {
               // Ignore and continue w/ next location
  @@ -211,23 +196,16 @@
   
           // Try to read from $java.home/lib/jaxp.properties
           try {
  -            String javah = (String)AccessController.doPrivileged(
  -                new GetPropertyAction("java.home"));
  +            String javah = ss.getSystemProperty("java.home");
               String configFile = javah + File.separator +
                   "lib" + File.separator + "jaxp.properties";
  -            final File f = new File(configFile);
  -            FileInputStream fis = (FileInputStream)
  -                AccessController.doPrivileged(new PrivilegedExceptionAction() {
  -                    public Object run() throws FileNotFoundException {
  -                        return new FileInputStream(f);
  -                    }
  -                });
  +            FileInputStream fis = ss.getFileInputStream(new File(configFile));
               Properties props = new Properties();
               props.load(fis);
               String factoryClassName = props.getProperty(factoryId);
               if (factoryClassName != null) {
                   dPrint("found in jaxp.properties, value=" + factoryClassName);
  -                return newInstance(factoryClassName, classLoader);
  +                return newInstance(factoryClassName, cl);
               }
           } catch (Exception x) {
               // assert(x instanceof FileNotFoundException
  @@ -237,19 +215,7 @@
   
           // Try to find service provider in CLASSPATH
           final String serviceId = "META-INF/services/" + factoryId;
  -        InputStream is = (InputStream)
  -            AccessController.doPrivileged(new PrivilegedAction() {
  -                public Object run() {
  -                    InputStream ris;
  -                    if (classLoader == null) {
  -                        ris = ClassLoader.getSystemResourceAsStream(serviceId);
  -                    } else {
  -                        ris = classLoader.getResourceAsStream(serviceId);
  -                    }
  -                    return ris;
  -                }
  -            });
  -
  +        InputStream is = ss.getResourceAsStream(cl, serviceId);
           if (is != null) {
               dPrint("found resource=" + serviceId);
   
  @@ -288,7 +254,7 @@
                   ! "".equals(factoryClassName)) {
                   dPrint("found in resource, value="
                          + factoryClassName);
  -                return newInstance(factoryClassName, classLoader);
  +                return newInstance(factoryClassName, cl);
               }
           }
   
  @@ -298,7 +264,7 @@
           }
   
           dPrint("using fallback, value=" + fallbackClassName);
  -        return newInstance(fallbackClassName, classLoader);
  +        return newInstance(fallbackClassName, cl);
       }
   
       static class ConfigurationError extends Error {
  @@ -315,24 +281,6 @@
   
           Exception getException() {
               return exception;
  -        }
  -    }
  -
  -    private static class GetPropertyAction implements PrivilegedAction {
  -        private String property;
  -        private String value;
  -
  -        public GetPropertyAction(String prop) {
  -            property = prop;
  -        }
  -
  -        public Object run() {
  -            value = System.getProperty(property);
  -            return value;
  -        }
  -
  -        public String getValue() {
  -            return value;
           }
       }
   }
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.1   +125 -0    xml-commons/java/external/src/javax/xml/parsers/Attic/SecuritySupport12.java
  
  
  
  
  1.1.2.1   +140 -0    xml-commons/java/external/src/javax/xml/parsers/Attic/SecuritySupport.java