aruny       2004/02/23 09:29:36

  Modified:    java/src/org/apache/xalan/xsltc/compiler Constants.java
                        FunctionCall.java Param.java
               java/src/org/apache/xalan/xsltc/compiler/util
                        ReferenceType.java
  Added:       java/src/org/apache/xalan/xsltc/runtime CallFunction.java
                        ObjectFactory.java SecuritySupport.java
                        SecuritySupport12.java
  Log:
  Description : Adding the basic functionality for resolving external function 
dynamically. If static resolution fails then Dynamic resolution is used as last 
resort
  
  Revision  Changes    Path
  1.40      +5 -1      
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Constants.java
  
  Index: Constants.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Constants.java,v
  retrieving revision 1.39
  retrieving revision 1.40
  diff -u -r1.39 -r1.40
  --- Constants.java    16 Feb 2004 22:24:28 -0000      1.39
  +++ Constants.java    23 Feb 2004 17:29:35 -0000      1.40
  @@ -258,6 +258,8 @@
       public static final String TRANSLET_OUTPUT_BASE       
        = "org.apache.xalan.xsltc.TransletOutputBase";
       // output interface
  +    public static final String CALL_FUNCTION_CLASS
  +     = "org.apache.xalan.xsltc.runtime.CallFunction";
       public static final String TRANSLET_OUTPUT_INTERFACE
        = "org.apache.xml.serializer.SerializationHandler";
       public static final String BASIS_LIBRARY_CLASS 
  @@ -299,6 +301,8 @@
       public static final String TRANSLET_PNAME     
        = "translet";
   
  +    public static final String INVOKE_METHOD
  +     = "invokeMethod";
       public static final String GET_NODE_NAME      
        = "getNodeNameX";
       public static final String CHARACTERSW        
  
  
  
  1.38      +72 -3     
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/FunctionCall.java
  
  Index: FunctionCall.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/FunctionCall.java,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- FunctionCall.java 23 Feb 2004 10:29:35 -0000      1.37
  +++ FunctionCall.java 23 Feb 2004 17:29:35 -0000      1.38
  @@ -37,6 +37,13 @@
   import org.apache.bcel.generic.InvokeInstruction;
   import org.apache.bcel.generic.NEW;
   import org.apache.bcel.generic.PUSH;
  +import org.apache.bcel.generic.LocalVariableGen;
  +import org.apache.bcel.generic.ASTORE;
  +import org.apache.bcel.generic.ANEWARRAY;
  +import org.apache.bcel.generic.ALOAD;
  +import org.apache.bcel.generic.ACONST_NULL;
  +
  +
   import org.apache.xalan.xsltc.compiler.util.BooleanType;
   import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
   import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
  @@ -126,6 +133,9 @@
       // If the java method is static
       private boolean    _isStatic = false;
   
  +    // If unable to resolve statically then resolve dynamically
  +    private boolean  resolveDynamic = false;
  +    
       // Legal conversions between internal and Java types.
       private static final MultiHashtable _internal2Java = new 
MultiHashtable();
   
  @@ -484,10 +494,14 @@
        }
   
        if (_type != null) {
  -         return _type;
  +           return _type;
        }
  +        else{
  +          resolveDynamic = true;
  +        }  
   
  -     throw new TypeCheckError(ErrorMsg.ARGUMENT_CONVERSION_ERR, 
getMethodSignature(argsType));
  +        return  _type = (_clazz != null) ? Type.newObjectType(_clazz)
  +                    : Type.newObjectType(_className);
       }
   
   
  @@ -526,6 +540,11 @@
                    && _clazz != null
                    && 
_clazz.isAssignableFrom(((ObjectType)firstArgType).getJavaClass()))
                    hasThisArgument = true;
  +                else if(firstArgType instanceof ReferenceType){
  +                    resolveDynamic = true;
  +                         typeCheckArgs(stable);
  +                    return Type.String;
  +                }
                
                if (hasThisArgument) {
                    _thisArgument = (Expression) _arguments.elementAt(0);
  @@ -775,6 +794,56 @@
                                _chosenConstructor.getDeclaringClass());
            
        }
  +     else if(resolveDynamic) {
  +
  +          final LocalVariableGen _local = 
methodGen.addLocalVariable2("objects",
  +              org.apache.bcel.generic.Type.OBJECT, il.getEnd());
  +
  +          //Create the Object[].
  +          il.append(new PUSH(cpg, n + 1));
  +          il.append(new ANEWARRAY(cpg.addClass(OBJECT_CLASS)));
  +
  +          // Push "this" if it is an instance method
  +          il.append(DUP);
  +          if (_thisArgument != null) {
  +            il.append(new PUSH(cpg, 0));
  +            _thisArgument.translate(classGen, methodGen);
  +          }
  +          //else add null to the Object array
  +          else {
  +            il.append(new PUSH(cpg, 0));
  +            il.append(ACONST_NULL);
  +          }
  +          il.append(AASTORE);
  +
  +          //Add the parameters to Object[]
  +          for (int i = 0; i < n; i++) {
  +            il.append(DUP);
  +            il.append(new PUSH(cpg, i + 1));
  +            Expression exp = argument(i);
  +            exp.translate(classGen, methodGen);
  +            exp.startIterator(classGen, methodGen);
  +            exp.getType().translateTo(classGen, methodGen, Type.Reference);
  +            il.append(AASTORE);
  +          }
  +          il.append(new ASTORE(_local.getIndex()));
  +
  +          //call invoke parameter
  +          String methodName = null;
  +          if (_chosenMethod != null)
  +            methodName = _chosenMethod.getName();
  +          else
  +            methodName = _fname.getLocalPart();
  +
  +          il.append(new PUSH(cpg, _className));
  +          il.append(new PUSH(cpg, methodName));
  +          il.append(new ALOAD(_local.getIndex()));
  +
  +          index = cpg.addMethodref(CALL_FUNCTION_CLASS, INVOKE_METHOD,
  +              
"(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;");
  +          il.append(new INVOKESTATIC(index));
  +
  +        }
        // Invoke function calls that are handled in separate classes
        else {
            final String clazz = _chosenMethod.getDeclaringClass().getName();
  
  
  
  1.28      +3 -2      
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Param.java
  
  Index: Param.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Param.java,v
  retrieving revision 1.27
  retrieving revision 1.28
  diff -u -r1.27 -r1.28
  --- Param.java        16 Feb 2004 22:24:28 -0000      1.27
  +++ Param.java        23 Feb 2004 17:29:35 -0000      1.28
  @@ -34,6 +34,7 @@
   import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
   import org.apache.xalan.xsltc.compiler.util.ReferenceType;
   import org.apache.xalan.xsltc.compiler.util.Type;
  +import org.apache.xalan.xsltc.compiler.util.ObjectType;
   import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
   import org.apache.xalan.xsltc.runtime.BasisLibrary;
   
  @@ -149,7 +150,7 @@
       public Type typeCheck(SymbolTable stable) throws TypeCheckError {
        if (_select != null) {
            _type = _select.typeCheck(stable); 
  -         if (_type instanceof ReferenceType == false) {
  +         if (_type instanceof ReferenceType == false && !(_type instanceof 
ObjectType)) {
                _select = new CastExpr(_select, Type.Reference);
            }
        }
  
  
  
  1.19      +3 -1      
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util/ReferenceType.java
  
  Index: ReferenceType.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util/ReferenceType.java,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- ReferenceType.java        16 Feb 2004 22:26:44 -0000      1.18
  +++ ReferenceType.java        23 Feb 2004 17:29:35 -0000      1.19
  @@ -89,6 +89,8 @@
        else if (type == Type.Object) {
            translateTo(classGen, methodGen, (ObjectType) type);
        }
  +     else if (type == Type.Reference ) {
  +        }    
        else {
            ErrorMsg err = new ErrorMsg(ErrorMsg.INTERNAL_ERR, type.toString());
            classGen.getParser().reportError(Constants.FATAL, err);
  
  
  
  1.1                  
xml-xalan/java/src/org/apache/xalan/xsltc/runtime/CallFunction.java
  
  Index: CallFunction.java
  ===================================================================
  /*
   * Copyright 2001-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 org.apache.xalan.xsltc.runtime;
  
  import java.util.Vector;
  import java.lang.reflect.Modifier;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.lang.IllegalAccessException;
  import java.lang.IllegalArgumentException;
  import java.lang.InstantiationException;
  
  
  /**
   * Resolve the function dynamically
   */
  public final class CallFunction {
  
      public static String className;
      public static String methodName;
      public static int nArgs;
      public static Class clazz;
  
  
      public static String invokeMethod(String _className, String _methodName, 
Object [] _arguments){
          className = _className;
          methodName = _methodName;
          int size = _arguments.length-1;
          Object [] arguments = new Object[size];
          Object object= _arguments[0];
          clazz =null;
          try {
              clazz = ObjectFactory.findProviderClass(className, 
ObjectFactory.findClassLoader(), true);
              if (clazz == null) {
                     throw new RuntimeException("Couldn't load the class");
              }
          }catch (ClassNotFoundException e) {
              throw new RuntimeException("Couldn't load the class");
          }
        
          for(int i=0,j=1;i<size;i++,++j){
               arguments[i] = _arguments[j];
          }
          nArgs = size;
          if( methodName != null ){
                Method method;
                if((method = findMethods(arguments)) == null){
                    throw new RuntimeException("Method not found");
                }
  
                try{
                   Object obj =  method.invoke(object,arguments);
                   return obj.toString() ;
                }
                catch(IllegalAccessException e){
                    throw new RuntimeException("Error: Method is inaccessible");
                }
                catch(IllegalArgumentException e){
                     throw new RuntimeException("Error: Number of actual and 
formal argument differ ");
                }
                catch(InvocationTargetException e){
                     throw new RuntimeException("Error: underlying constructor 
throws an exception ");
                }
          }
          else {
              Constructor constructor;
              if((constructor = findConstructor(arguments)) == null){
                  throw new RuntimeException("Constructor not found");
              }
              try{
                 Object  obs = constructor.newInstance(arguments);
                 return obs.toString() ;
              }catch(InvocationTargetException e){
                  throw new RuntimeException("Error: constructor throws an 
exception ");
              }
              catch(IllegalAccessException e){
                  throw new RuntimeException("Error: constructor is 
inaccessible");
              }
              catch(IllegalArgumentException e){
                  throw new RuntimeException("Error: Number of actual and 
formal argument differ ");
              }
              catch(InstantiationException e){
                  throw new RuntimeException("Error: Class that declares the 
underlying constructor represents an abstract class");
              }
          }
  
      }
  
      /**
       * Returns a Constructor
       */
      private static Constructor findConstructor(Object[] arguments) {
          Vector constructors =null;
  
  
              final Constructor[] c_constructors = clazz.getConstructors();
  
              for (int i = 0; i < c_constructors.length; i++) {
                  final int mods = c_constructors[i].getModifiers();
                  // Is it public, static and same number of args ?
                  if (Modifier.isPublic(mods) && 
c_constructors[i].getParameterTypes().length == nArgs){
                      if (constructors == null) {
                          constructors = new Vector();
                      }
                      constructors.addElement(c_constructors[i]);
                  }
              }
  
  
          if (constructors == null) {
            // Method not found in this class
           throw new RuntimeException("CONSTRUCTOR_NOT_FOUND_ERR" + className 
+":"+ methodName);
        }
  
          int nConstructors = constructors.size();
          boolean accept=false;
          for (int j, i = 0; i < nConstructors; i++) {
            // Check if all parameters to this constructor can be converted
            final Constructor constructor = 
(Constructor)constructors.elementAt(i);
            final Class[] paramTypes = constructor.getParameterTypes();
  
              for (j = 0; j < nArgs; j++) {
                  Class argumentClass = arguments[j].getClass();
                  if (argumentClass == paramTypes[j]){
                      accept= true;
                  }
                  else if(argumentClass.isAssignableFrom(paramTypes[j])){
                      accept=true;
                  }
                  else {
                       accept =false;
                       break;
                  }
            }
            if (accept)
                return constructor;
          }
          return null;
      }
  
  
  
      /**
       * Return the Method
       */
      private static Method findMethods(Object[] arguments) {
          Vector methods = null;
  
              final Method[] m_methods = clazz.getMethods();
  
              for (int i = 0; i < m_methods.length; i++){
                  final int mods = m_methods[i].getModifiers();
                  // Is it public and same number of args ?
                if(  Modifier.isPublic(mods)
                       && m_methods[i].getName().equals(methodName)
                       && m_methods[i].getParameterTypes().length == nArgs){
                    if (methods == null){
                             methods = new Vector();
                      }
                      methods.addElement(m_methods[i]);
                }
              }
  
  
           if (methods == null) {
            // Method not found in this class
           throw new RuntimeException("METHOD_NOT_FOUND_ERR" + className +":"+ 
methodName);
        }
          int nMethods = methods.size();
          boolean accept=false;
          for (int j, i = 0; i < nMethods; i++) {
            // Check if all parameters to this constructor can be converted
            final Method method = (Method)methods.elementAt(i);
            final Class[] paramTypes = method.getParameterTypes();
  
              for (j = 0; j < nArgs; j++) {
                  Class argumentClass = arguments[j].getClass();
                  if (argumentClass == paramTypes[j]){
                      accept= true;
                  }
                  else if(argumentClass.isAssignableFrom(paramTypes[j])){
                      accept=true;
                  }
                  else if(paramTypes[j].isPrimitive() ){
                      arguments[j] = isPrimitive(paramTypes[j],arguments[j]);
                      accept = true;
                  }
                  else {
                      accept =false;
                      break;
                  }
  
              }
              if (accept)
                  return method;
          }
  
          return null;
      }
  
      public  static Object isPrimitive(Class paramType, Object argument){
  
          if( argument.getClass()  ==  Integer.class )
               return  typeCast(paramType,(Integer)argument);
          else if( argument.getClass() == Float.class )
               return  typeCast(paramType,(Float)argument);
          else if( argument.getClass() == Double.class )
               return  typeCast(paramType,(Double)argument);
          else if( argument.getClass() == Long.class )
               return  typeCast(paramType,(Long)argument);
          else if( argument.getClass() == Boolean.class )
                return (Boolean)argument;
          else if( argument.getClass() == Byte.class )
               return  (Byte)argument;
          else
              return null;
      }
  
      static Object typeCast(Class paramType, Double object){
          if (paramType == Long.TYPE)
              return  new Long(object.longValue());
          else if (paramType == Integer.TYPE)
              return  new Integer(object.intValue());
          else if (paramType == Float.TYPE)
              return  new Float(object.floatValue());
          else if (paramType == Short.TYPE)
              return  new Short(object.shortValue());
          else if (paramType == Byte.TYPE)
              return  new Byte(object.byteValue());
          else
              return object;
      }
  
      static Object typeCast(Class paramType, Long object){
          if (paramType == Integer.TYPE)
              return  new Integer(object.intValue());
          else if (paramType == Float.TYPE)
              return  new Float(object.floatValue());
          else if (paramType == Short.TYPE)
              return  new Short(object.shortValue());
          else if (paramType == Byte.TYPE)
              return  new Byte(object.byteValue());
          else
              return object;
      }
  
      static Object typeCast(Class paramType, Integer object){
          if(paramType == Double.TYPE)
              return  new Double(object.doubleValue());
          else if (paramType == Float.TYPE)
              return  new Float(object.floatValue());
          else if (paramType == Short.TYPE)
              return  new Short(object.shortValue());
          else if (paramType == Byte.TYPE)
              return  new Byte(object.byteValue());
          else
              return object;
      }
  
      static Object typeCast(Class paramType, Float object){
          if(paramType == Double.TYPE)
              return  new Double(object.doubleValue());
          else if (paramType == Integer.TYPE)
              return  new Float(object.intValue());
          else if (paramType == Short.TYPE)
              return  new Short(object.shortValue());
          else if (paramType == Byte.TYPE)
              return  new Byte(object.byteValue());
          else
              return object;
      }
  
  }
  
  
  
  1.1                  
xml-xalan/java/src/org/apache/xalan/xsltc/runtime/ObjectFactory.java
  
  Index: ObjectFactory.java
  ===================================================================
  /*
   * Copyright 2001-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: ObjectFactory.java,v 1.1 2004/02/23 17:29:35 aruny Exp $
   */
  
  package org.apache.xalan.xsltc.runtime;
  
  import java.io.InputStream;
  import java.io.IOException;
  import java.io.File;
  import java.io.FileInputStream;
  
  import java.util.Properties;
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  
  /**
   * 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.
   * <p>
   * 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, 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.ObjectFactory</code>
   * class and modified to be used as a general utility for creating objects 
   * dynamically.
   *
   * @version $Id: ObjectFactory.java,v 1.1 2004/02/23 17:29:35 aruny Exp $
   */
  class ObjectFactory {
  
      //
      // Constants
      //
  
      // name of default properties file to look for in JDK's jre/lib directory
      private static final String DEFAULT_PROPERTIES_FILENAME =
                                                       "xalan.properties";
  
      private static final String SERVICES_PATH = "META-INF/services/";
  
      /** Set to true for debugging */
      private static final boolean DEBUG = false;
  
      /** cache the contents of the xalan.properties file.
       *  Until an attempt has been made to read this file, this will
       * be null; if the file does not exist or we encounter some other error
       * during the read, this will be empty.
       */
      private static Properties fXalanProperties = null;
  
      /***
       * Cache the time stamp of the xalan.properties file so
       * that we know if it's been modified and can invalidate
       * the cache when necessary.
       */
      private static long fLastModified = -1;
  
      //
      // Public static methods
      //
  
      /**
       * Finds the implementation Class object in the specified order.  The
       * specified order is the following:
       * <ol>
       *  <li>query the system property using <code>System.getProperty</code>
       *  <li>read <code>META-INF/services/<i>factoryId</i></code> file
       *  <li>use fallback classname
       * </ol>
       *
       * @return instance 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.
       *
       * @exception ObjectFactory.ConfigurationError
       */
      static Object createObject(String factoryId, String fallbackClassName)
          throws ConfigurationError {
          return createObject(factoryId, null, fallbackClassName);
      } // createObject(String,String):Object
  
      /**
       * Finds the implementation Class object in the specified order.  The
       * specified order is the following:
       * <ol>
       *  <li>query the system property using <code>System.getProperty</code>
       *  <li>read <code>$java.home/lib/<i>propertiesFilename</i></code> file
       *  <li>read <code>META-INF/services/<i>factoryId</i></code> file
       *  <li>use fallback classname
       * </ol>
       *
       * @return instance of factory, never null
       *
       * @param factoryId             Name of the factory to find, same as
       *                              a property name
       * @param propertiesFilename The filename in the $java.home/lib directory
       *                           of the properties file.  If none specified,
       *                           ${java.home}/lib/xalan.properties will be 
used.
       * @param fallbackClassName     Implementation class name, if nothing else
       *                              is found.  Use null to mean no fallback.
       *
       * @exception ObjectFactory.ConfigurationError
       */
      static Object createObject(String factoryId, 
                                        String propertiesFilename,
                                        String fallbackClassName)
          throws ConfigurationError
      {
          Class factoryClass = lookUpFactoryClass(factoryId,
                                                  propertiesFilename,
                                                  fallbackClassName);
  
          if (factoryClass == null) {
              throw new ConfigurationError(
                  "Provider for " + factoryId + " cannot be found", null);
          }
  
          try{
              Object instance = factoryClass.newInstance();
              debugPrintln("created new instance of factory " + factoryId);
              return instance;
          } catch (Exception x) {
              throw new ConfigurationError(
                  "Provider for factory " + factoryId
                      + " could not be instantiated: " + x, x);
          }
      } // createObject(String,String,String):Object
  
      /**
       * Finds the implementation Class object in the specified order.  The
       * specified order is the following:
       * <ol>
       *  <li>query the system property using <code>System.getProperty</code>
       *  <li>read <code>$java.home/lib/<i>propertiesFilename</i></code> file
       *  <li>read <code>META-INF/services/<i>factoryId</i></code> file
       *  <li>use fallback classname
       * </ol>
       *
       * @return Class object of factory, never null
       *
       * @param factoryId             Name of the factory to find, same as
       *                              a property name
       * @param propertiesFilename The filename in the $java.home/lib directory
       *                           of the properties file.  If none specified,
       *                           ${java.home}/lib/xalan.properties will be 
used.
       * @param fallbackClassName     Implementation class name, if nothing else
       *                              is found.  Use null to mean no fallback.
       *
       * @exception ObjectFactory.ConfigurationError
       */
      static Class lookUpFactoryClass(String factoryId) 
          throws ConfigurationError
      {
          return lookUpFactoryClass(factoryId, null, null);
      } // lookUpFactoryClass(String):Class
  
      /**
       * Finds the implementation Class object in the specified order.  The
       * specified order is the following:
       * <ol>
       *  <li>query the system property using <code>System.getProperty</code>
       *  <li>read <code>$java.home/lib/<i>propertiesFilename</i></code> file
       *  <li>read <code>META-INF/services/<i>factoryId</i></code> file
       *  <li>use fallback classname
       * </ol>
       *
       * @return Class object that provides factory service, never null
       *
       * @param factoryId             Name of the factory to find, same as
       *                              a property name
       * @param propertiesFilename The filename in the $java.home/lib directory
       *                           of the properties file.  If none specified,
       *                           ${java.home}/lib/xalan.properties will be 
used.
       * @param fallbackClassName     Implementation class name, if nothing else
       *                              is found.  Use null to mean no fallback.
       *
       * @exception ObjectFactory.ConfigurationError
       */
      static Class lookUpFactoryClass(String factoryId,
                                             String propertiesFilename,
                                             String fallbackClassName)
          throws ConfigurationError
      {
          String factoryClassName = lookUpFactoryClassName(factoryId,
                                                           propertiesFilename,
                                                           fallbackClassName);
          ClassLoader cl = findClassLoader();
  
          if (factoryClassName == null) {
              factoryClassName = fallbackClassName;
          }
  
          // assert(className != null);
          try{
              Class providerClass = findProviderClass(factoryClassName,
                                                      cl,
                                                      true);
              debugPrintln("created new instance of " + providerClass +
                     " using ClassLoader: " + cl);
              return providerClass;
          } catch (ClassNotFoundException x) {
              throw new ConfigurationError(
                  "Provider " + factoryClassName + " not found", x);
          } catch (Exception x) {
              throw new ConfigurationError(
                  "Provider "+factoryClassName+" could not be instantiated: "+x,
                  x);
          }
      } // lookUpFactoryClass(String,String,String):Class
  
      /**
       * Finds the name of the required implementation class in the specified
       * order.  The specified order is the following:
       * <ol>
       *  <li>query the system property using <code>System.getProperty</code>
       *  <li>read <code>$java.home/lib/<i>propertiesFilename</i></code> file
       *  <li>read <code>META-INF/services/<i>factoryId</i></code> file
       *  <li>use fallback classname
       * </ol>
       *
       * @return name of class that provides factory service, never null
       *
       * @param factoryId             Name of the factory to find, same as
       *                              a property name
       * @param propertiesFilename The filename in the $java.home/lib directory
       *                           of the properties file.  If none specified,
       *                           ${java.home}/lib/xalan.properties will be 
used.
       * @param fallbackClassName     Implementation class name, if nothing else
       *                              is found.  Use null to mean no fallback.
       *
       * @exception ObjectFactory.ConfigurationError
       */
      static String lookUpFactoryClassName(String factoryId,
                                                  String propertiesFilename,
                                                  String fallbackClassName)
      {
          SecuritySupport ss = SecuritySupport.getInstance();
  
          // Use the system property first
          try {
              String systemProp = ss.getSystemProperty(factoryId);
              if (systemProp != null) {
                  debugPrintln("found system property, value=" + systemProp);
                  return systemProp;
              }
          } catch (SecurityException se) {
              // Ignore and continue w/ next location
          }
  
          // Try to read from propertiesFilename, or
          // $java.home/lib/xalan.properties
          String factoryClassName = null;
          // no properties file name specified; use
          // $JAVA_HOME/lib/xalan.properties:
          if (propertiesFilename == null) {
              File propertiesFile = null;
              boolean propertiesFileExists = false;
              try {
                  String javah = ss.getSystemProperty("java.home");
                  propertiesFilename = javah + File.separator +
                      "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME;
                  propertiesFile = new File(propertiesFilename);
                  propertiesFileExists = ss.getFileExists(propertiesFile);
              } catch (SecurityException e) {
                  // try again...
                  fLastModified = -1;
                  fXalanProperties = null;
              }
  
              synchronized (ObjectFactory.class) {
                  boolean loadProperties = false;
                  try {
                      // file existed last time
                      if(fLastModified >= 0) {
                          if(propertiesFileExists &&
                                  (fLastModified < (fLastModified = 
ss.getLastModified(propertiesFile)))) {
                              loadProperties = true;
                          } else {
                              // file has stopped existing...
                              if(!propertiesFileExists) {
                                  fLastModified = -1;
                                  fXalanProperties = null;
                              } // else, file wasn't modified!
                          }
                      } else {
                          // file has started to exist:
                          if(propertiesFileExists) {
                              loadProperties = true;
                              fLastModified = 
ss.getLastModified(propertiesFile);
                          } // else, nothing's changed
                      }
                      if(loadProperties) {
                          // must never have attempted to read xalan.properties
                          // before (or it's outdeated)
                          fXalanProperties = new Properties();
                          FileInputStream fis =
                                           
ss.getFileInputStream(propertiesFile);
                          fXalanProperties.load(fis);
                          fis.close();
                      }
                    } catch (Exception x) {
                        fXalanProperties = null;
                        fLastModified = -1;
                          // assert(x instanceof FileNotFoundException
                        //        || x instanceof SecurityException)
                        // In both cases, ignore and continue w/ next location
                    }
              }
              if(fXalanProperties != null) {
                  factoryClassName = fXalanProperties.getProperty(factoryId);
              }
          } else {
              try {
                  FileInputStream fis =
                             ss.getFileInputStream(new 
File(propertiesFilename));
                  Properties props = new Properties();
                  props.load(fis);
                  fis.close();
                  factoryClassName = props.getProperty(factoryId);
              } catch (Exception x) {
                  // assert(x instanceof FileNotFoundException
                  //        || x instanceof SecurityException)
                  // In both cases, ignore and continue w/ next location
              }
          }
          if (factoryClassName != null) {
              debugPrintln("found in " + propertiesFilename + ", value="
                            + factoryClassName);
              return factoryClassName;
          }
  
          // Try Jar Service Provider Mechanism
          return findJarServiceProviderName(factoryId);
      } // lookUpFactoryClass(String,String):String
  
      //
      // Private static methods
      //
  
      /** Prints a message to standard error if debugging is enabled. */
      private static void debugPrintln(String msg) {
          if (DEBUG) {
              System.err.println("JAXP: " + msg);
          }
      } // debugPrintln(String)
  
      /**
       * Figure out which ClassLoader to use.  For JDK 1.2 and later use
       * the context ClassLoader.
       */
      static ClassLoader findClassLoader()
          throws ConfigurationError
      { 
          SecuritySupport ss = SecuritySupport.getInstance();
  
          // Figure out which ClassLoader to use for loading the provider
          // class.  If there is a Context ClassLoader then use it.
          ClassLoader context = ss.getContextClassLoader();
          ClassLoader system = ss.getSystemClassLoader();
  
          ClassLoader chain = system;
          while (true) {
              if (context == chain) {
                  // Assert: we are on JDK 1.1 or we have no Context ClassLoader
                  // or any Context ClassLoader in chain of system classloader
                  // (including extension ClassLoader) so extend to widest
                  // ClassLoader (always look in system ClassLoader if Xalan
                  // is in boot/extension/system classpath and in current
                  // ClassLoader otherwise); normal classloaders delegate
                  // back to system ClassLoader first so this widening doesn't
                  // change the fact that context ClassLoader will be consulted
                  ClassLoader current = ObjectFactory.class.getClassLoader();
  
                  chain = system;
                  while (true) {
                      if (current == chain) {
                          // Assert: Current ClassLoader in chain of
                          // boot/extension/system ClassLoaders
                          return system;
                      }
                      if (chain == null) {
                          break;
                      }
                      chain = ss.getParentClassLoader(chain);
                  }
  
                  // Assert: Current ClassLoader not in chain of
                  // boot/extension/system ClassLoaders
                  return current;
              }
  
              if (chain == null) {
                  // boot ClassLoader reached
                  break;
              }
  
              // Check for any extension ClassLoaders in chain up to
              // boot ClassLoader
              chain = ss.getParentClassLoader(chain);
          };
  
          // Assert: Context ClassLoader not in chain of
          // boot/extension/system ClassLoaders
          return context;
      } // findClassLoader():ClassLoader
  
      /**
       * Create an instance of a class using the specified ClassLoader
       */ 
      static Object newInstance(String className, ClassLoader cl,
                                        boolean doFallback)
          throws ConfigurationError
      {
          // assert(className != null);
          try{
              Class providerClass = findProviderClass(className, cl, 
doFallback);
              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);
          } catch (Exception x) {
              throw new ConfigurationError(
                  "Provider " + className + " could not be instantiated: " + x,
                  x);
          }
      }
  
      /**
       * Find a Class using the specified ClassLoader
       */ 
      static Class findProviderClass(String className, ClassLoader cl,
                                             boolean doFallback)
          throws ClassNotFoundException, ConfigurationError
      {   
          //throw security exception if the calling thread is not allowed to 
access the
          //class. Restrict the access to the package classes as specified in 
java.security policy.
          SecurityManager security = System.getSecurityManager();
          try{
              if (security != null){
                  security.checkPackageAccess(className);
               }   
          }catch(SecurityException e){
              throw e;
          }
          
          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 {
                  providerClass = cl.loadClass(className);
              } catch (ClassNotFoundException x) {
                  if (doFallback) {
                      // Fall back to current classloader
                      ClassLoader current = 
ObjectFactory.class.getClassLoader();
                      if (current == null) {
                          providerClass = Class.forName(className);
                      } else if (cl != current) {
                          cl = current;
                          providerClass = cl.loadClass(className);
                      } else {
                          throw x;
                      }
                  } else {
                      throw x;
                  }
              }
          }
  
          return providerClass;
      }
  
      /**
       * Find the name of service provider using Jar Service Provider Mechanism
       *
       * @return instance of provider class if found or null
       */
      private static String findJarServiceProviderName(String factoryId)
      {
          SecuritySupport ss = SecuritySupport.getInstance();
          String serviceId = SERVICES_PATH + factoryId;
          InputStream is = null;
  
          // First try the Context ClassLoader
          ClassLoader cl = findClassLoader();
  
          is = ss.getResourceAsStream(cl, serviceId);
  
          // If no provider found then try the current ClassLoader
          if (is == null) {
              ClassLoader current = ObjectFactory.class.getClassLoader();
              if (cl != current) {
                  cl = current;
                  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 factoryClassName;
          }
  
          // No provider found
          return null;
      }
  
      //
      // Classes
      //
  
      /**
       * A configuration error.
       */
      static class ConfigurationError 
          extends Error {
  
          //
          // Data
          //
  
          /** Exception. */
          private Exception exception;
  
          //
          // Constructors
          //
  
          /**
           * Construct a new instance with the specified detail string and
           * exception.
           */
          ConfigurationError(String msg, Exception x) {
              super(msg);
              this.exception = x;
          } // <init>(String,Exception)
  
          //
          // Public methods
          //
  
          /** Returns the exception associated to this error. */
          Exception getException() {
              return exception;
          } // getException():Exception
  
      } // class ConfigurationError
  
  } // class ObjectFactory
  
  
  
  1.1                  
xml-xalan/java/src/org/apache/xalan/xsltc/runtime/SecuritySupport.java
  
  Index: SecuritySupport.java
  ===================================================================
  /*
   * Copyright 2002-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: SecuritySupport.java,v 1.1 2004/02/23 17:29:35 aruny Exp $
   */
  
  package org.apache.xalan.xsltc.runtime;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.InputStream;
  
  import java.util.Properties;
  
  /**
   * This class is duplicated for each Xalan-Java subpackage so keep it in sync.
   * It is package private and therefore is not exposed as part of the 
Xalan-Java
   * 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.
       */
      static SecuritySupport getInstance() {
        return (SecuritySupport)securitySupport;
      }
  
      ClassLoader getContextClassLoader() {
        return null;
      }
  
      ClassLoader getSystemClassLoader() {
          return null;
      }
  
      ClassLoader getParentClassLoader(ClassLoader cl) {
          return null;
      }
  
      String getSystemProperty(String propName) {
          return System.getProperty(propName);
      }
  
      FileInputStream getFileInputStream(File file)
          throws FileNotFoundException
      {
          return new FileInputStream(file);
      }
  
      InputStream getResourceAsStream(ClassLoader cl, String name) {
          InputStream ris;
          if (cl == null) {
              ris = ClassLoader.getSystemResourceAsStream(name);
          } else {
              ris = cl.getResourceAsStream(name);
          }
          return ris;
      }
      
      boolean getFileExists(File f) {
          return f.exists();
      }
      
      long getLastModified(File f) {
          return f.lastModified();
      }    
  }
  
  
  
  1.1                  
xml-xalan/java/src/org/apache/xalan/xsltc/runtime/SecuritySupport12.java
  
  Index: SecuritySupport12.java
  ===================================================================
  /*
   * Copyright 2002-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: SecuritySupport12.java,v 1.1 2004/02/23 17:29:35 aruny Exp $
   */
  
  package org.apache.xalan.xsltc.runtime;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.InputStream;
  
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  import java.security.PrivilegedActionException;
  import java.security.PrivilegedExceptionAction;
  
  import java.util.Properties;
  
  /**
   * This class is duplicated for each Xalan-Java subpackage so keep it in sync.
   * It is package private and therefore is not exposed as part of the 
Xalan-Java
   * API.
   *
   * Security related methods that only work on J2SE 1.2 and newer.
   */
  class SecuritySupport12 extends SecuritySupport {
  
      ClassLoader getContextClassLoader() {
          return (ClassLoader)
                  AccessController.doPrivileged(new PrivilegedAction() {
              public Object run() {
                  ClassLoader cl = null;
                  try {
                      cl = Thread.currentThread().getContextClassLoader();
                  } catch (SecurityException ex) { }
                  return cl;
              }
          });
      }
  
      ClassLoader getSystemClassLoader() {
          return (ClassLoader)
              AccessController.doPrivileged(new PrivilegedAction() {
                  public Object run() {
                      ClassLoader cl = null;
                      try {
                          cl = ClassLoader.getSystemClassLoader();
                      } catch (SecurityException ex) {}
                      return cl;
                  }
              });
      }
  
      ClassLoader getParentClassLoader(final ClassLoader cl) {
          return (ClassLoader)
              AccessController.doPrivileged(new PrivilegedAction() {
                  public Object run() {
                      ClassLoader parent = null;
                      try {
                          parent = cl.getParent();
                      } catch (SecurityException ex) {}
  
                      // eliminate loops in case of the boot
                      // ClassLoader returning itself as a parent
                      return (parent == cl) ? null : parent;
                  }
              });
      }
  
      String getSystemProperty(final String propName) {
          return (String)
              AccessController.doPrivileged(new PrivilegedAction() {
                  public Object run() {
                      return System.getProperty(propName);
                  }
              });
      }
  
      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();
          }
      }
  
      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;
                  }
              });
      }
      
      boolean getFileExists(final File f) {
      return ((Boolean)
              AccessController.doPrivileged(new PrivilegedAction() {
                  public Object run() {
                      return new Boolean(f.exists());
                  }
              })).booleanValue();
      }
      
      long getLastModified(final File f) {
      return ((Long)
              AccessController.doPrivileged(new PrivilegedAction() {
                  public Object run() {
                      return new Long(f.lastModified());
                  }
              })).longValue();
      }
          
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to