xml-commons-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From edwi...@apache.org
Subject cvs commit: xml-commons/java/external/src/javax/xml/parsers FactoryFinder.java
Date Thu, 02 May 2002 00:52:43 GMT
edwingo     02/05/01 17:52:43

  Modified:    java/external/src/javax/xml/parsers Tag: java2-branch
                        FactoryFinder.java
  Log:
  Added doPrivileged calls to allow code to run in environments such as EJB
  and servlet containers which have SecurityManager-s installed.  Note this
  new code depends on Java2 and is therefore currently checked into a
  separate branch called "java2-branch".  Other changes:
  + Fixed 4989 NPE in TransformerFactory.newInstance() when jaxp.properties
  + Added runtime debug support if system prop "jaxp.debug" is set
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.7.2.1   +148 -78   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
  retrieving revision 1.7.2.1
  diff -u -r1.7 -r1.7.2.1
  --- FactoryFinder.java	26 Oct 2001 00:23:31 -0000	1.7
  +++ FactoryFinder.java	2 May 2002 00:52:43 -0000	1.7.2.1
  @@ -55,14 +55,18 @@
   
   package javax.xml.parsers;
   
  -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.security.AccessController;
  +import java.security.PrivilegedAction;
  +import java.security.PrivilegedExceptionAction;
  +import java.util.Properties;
   
   import java.lang.reflect.Method;
   import java.lang.reflect.InvocationTargetException;
  @@ -75,13 +79,26 @@
    * 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.
  + * 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".
    */
   class FactoryFinder {
  -    /** Set to true for debugging */
  -    private static final boolean debug = false;
  +    /** Controls debugging output to stderr */
  +    private static boolean debug;
  +
  +    // Define system property "jaxp.debug" to get output
  +    static {
  +        try {
  +            debug = AccessController.doPrivileged(
  +                new GetPropertyAction("jaxp.debug")) != null;
  +        } catch (SecurityException se) {
  +            debug = false;
  +        }
  +    }
   
  -    private static void debugPrintln(String msg) {
  +    private static void dPrint(String msg) {
           if (debug) {
               System.err.println("JAXP: " + msg);
           }
  @@ -89,7 +106,12 @@
   
       /**
        * Figure out which ClassLoader to use.  For JDK 1.2 and later use
  -     * the context ClassLoader.
  +     * 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.
  +     *
  +     * @return  The appropriate ClassLoader or null, which means to use the
  +     *          "system" ClassLoader.
        */           
       private static ClassLoader findClassLoader()
           throws ConfigurationError
  @@ -100,7 +122,7 @@
               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");
  +            dPrint("assuming JDK 1.1");
               return FactoryFinder.class.getClassLoader();
           }
   
  @@ -124,6 +146,7 @@
                                         ClassLoader classLoader)
           throws ConfigurationError
       {
  +        // assert(className != null);
           try {
               Class spiClass;
               if (classLoader == null) {
  @@ -131,7 +154,9 @@
               } else {
                   spiClass = classLoader.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 +168,128 @@
       }
   
       /**
  -     * 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.
  +     *
  +     * @return A new instance of the concrete factory class, never null
  +     *
  +     * @param factoryId
  +     *        Name of the factory to find, same as a property name
        *
  -     * @exception FactoryFinder.ConfigurationError
  +     * @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");
  +        final ClassLoader classLoader = findClassLoader();
   
  -        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);
  +            String systemProp = (String)
  +                AccessController.doPrivileged(new GetPropertyAction(factoryId));
  +            if (systemProp != null) {
  +                dPrint("found system property, value=" + systemProp);
                   return newInstance(systemProp, classLoader);
               }
           } 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 = (String)AccessController.doPrivileged(
  +                new GetPropertyAction("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);
  +            final File f = new File(configFile);
  +            FileInputStream fis = (FileInputStream)
  +                AccessController.doPrivileged(new PrivilegedExceptionAction() {
  +                    public Object run() throws FileNotFoundException {
  +                        return new FileInputStream(f);
  +                    }
  +                });
  +            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);
               }
  -        } catch(Exception ex ) {
  -            if( debug ) ex.printStackTrace();
  +        } catch (Exception x) {
  +            // assert(x instanceof FileNotFoundException
  +            //        || x instanceof SecurityException)
  +            // In both cases, ignore and continue w/ next location
           }
   
  -        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 );
  -            }
  -        
  -            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));
  +        // 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;
                   }
  +            });
  +
  +        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));
  +            }
           
  -                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, classLoader);
               }
  -        } catch( Exception ex ) {
  -            if( debug ) ex.printStackTrace();
           }
   
           if (fallbackClassName == null) {
  @@ -245,7 +297,7 @@
                   "Provider for " + factoryId + " cannot be found", null);
           }
   
  -        debugPrintln("loaded from fallback value: " + fallbackClassName);
  +        dPrint("using fallback, value=" + fallbackClassName);
           return newInstance(fallbackClassName, classLoader);
       }
   
  @@ -263,6 +315,24 @@
   
           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;
           }
       }
   }
  
  
  

Mime
View raw message