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]

Reply via email to