1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Oct 2017
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xalan.internal.utils;
  23 
  24 import java.util.function.Supplier;
  25 import jdk.xml.internal.SecuritySupport;
  26 
  27 /**
  28  * This class is duplicated for each JAXP subpackage so keep it in sync.
  29  * It is package private and therefore is not exposed as part of the JAXP
  30  * API.
  31  * <p>
  32  * This class was moved from the <code>javax.xml.parsers.ObjectFactory</code>
  33  * class and modified to be used as a general utility for creating objects
  34  * dynamically.
  35  *
  36  */
  37 public class ObjectFactory {
  38 
  39     //
  40     // Constants
  41     //
  42      private static final String JAXP_INTERNAL = "com.sun.org.apache";
  43      private static final String STAX_INTERNAL = "com.sun.xml.internal";
  44 
  45     /** Set to true for debugging */
  46     private static final boolean DEBUG = false;
  47 
  48 
  49     /** Prints a message to standard error if debugging is enabled. */
  50     private static void debugPrintln(Supplier<String> msgGen) {
  51         if (DEBUG) {
  52             System.err.println("JAXP: " + msgGen.get());
  53         }
  54     } // debugPrintln(String)
  55 
  56     /**
  57      * Figure out which ClassLoader to use.  For JDK 1.2 and later use
  58      * the context ClassLoader.
  59      */
  60     public static ClassLoader findClassLoader()
  61     {
  62         if (System.getSecurityManager()!=null) {
  63             //this will ensure bootclassloader is used
  64             return null;
  65         }
  66 
  67         // Figure out which ClassLoader to use for loading the provider
  68         // class.  If there is a Context ClassLoader then use it.
  69         ClassLoader context = SecuritySupport.getContextClassLoader();
  70         ClassLoader system = SecuritySupport.getSystemClassLoader();
  71 
  72         ClassLoader chain = system;
  73         while (true) {
  74             if (context == chain) {
  75                 // Assert: we are on JDK 1.1 or we have no Context ClassLoader
  76                 // or any Context ClassLoader in chain of system classloader
  77                 // (including extension ClassLoader) so extend to widest
  78                 // ClassLoader (always look in system ClassLoader if Xalan
  79                 // is in boot/extension/system classpath and in current
  80                 // ClassLoader otherwise); normal classloaders delegate
  81                 // back to system ClassLoader first so this widening doesn't
  82                 // change the fact that context ClassLoader will be consulted
  83                 ClassLoader current = ObjectFactory.class.getClassLoader();
  84 
  85                 chain = system;
  86                 while (true) {
  87                     if (current == chain) {
  88                         // Assert: Current ClassLoader in chain of
  89                         // boot/extension/system ClassLoaders
  90                         return system;
  91                     }
  92                     if (chain == null) {
  93                         break;
  94                     }
  95                     chain = SecuritySupport.getParentClassLoader(chain);
  96                 }
  97 
  98                 // Assert: Current ClassLoader not in chain of
  99                 // boot/extension/system ClassLoaders
 100                 return current;
 101             }
 102 
 103             if (chain == null) {
 104                 // boot ClassLoader reached
 105                 break;
 106             }
 107 
 108             // Check for any extension ClassLoaders in chain up to
 109             // boot ClassLoader
 110             chain = SecuritySupport.getParentClassLoader(chain);
 111         }
 112 
 113         // Assert: Context ClassLoader not in chain of
 114         // boot/extension/system ClassLoaders
 115         return context;
 116     } // findClassLoader():ClassLoader
 117 
 118     /**
 119      * Create an instance of a class using the same class loader for the ObjectFactory by default
 120      * or boot class loader when Security Manager is in place
 121      */
 122     public static Object newInstance(String className, boolean doFallback)
 123         throws ConfigurationError
 124     {
 125         ClassLoader cl = System.getSecurityManager()!=null ? null : findClassLoader();
 126         try{
 127             Class<?> providerClass = findProviderClass(className, cl, doFallback);
 128             Object instance = providerClass.getConstructor().newInstance();
 129             debugPrintln(()->"created new instance of " + providerClass +
 130                              " using ClassLoader: " + cl);
 131             return instance;
 132         } catch (ClassNotFoundException x) {
 133             throw new ConfigurationError(
 134                 "Provider " + className + " not found", x);
 135         } catch (Exception x) {
 136             throw new ConfigurationError(
 137                 "Provider " + className + " could not be instantiated: " + x,
 138                 x);
 139         }
 140     }
 141 
 142     /**
 143      * Find a Class using the same class loader for the ObjectFactory by default
 144      * or boot class loader when Security Manager is in place
 145      */
 146     public static Class<?> findProviderClass(String className, boolean doFallback)
 147         throws ClassNotFoundException, ConfigurationError
 148     {
 149         return findProviderClass (className,
 150                 findClassLoader (), doFallback);
 151     }
 152 
 153     /**
 154      * Find a Class using the specified ClassLoader
 155      */
 156     private static Class<?> findProviderClass(String className, ClassLoader cl,
 157                                            boolean doFallback)
 158         throws ClassNotFoundException, ConfigurationError
 159     {
 160         //throw security exception if the calling thread is not allowed to access the
 161         //class. Restrict the access to the package classes as specified in java.security policy.
 162         SecurityManager security = System.getSecurityManager();
 163         try{
 164             if (security != null){
 165                 if (className.startsWith(JAXP_INTERNAL) ||
 166                     className.startsWith(STAX_INTERNAL)) {
 167                     cl = null;
 168                 } else {
 169                     final int lastDot = className.lastIndexOf(".");
 170                     String packageName = className;
 171                     if (lastDot != -1) packageName = className.substring(0, lastDot);
 172                     security.checkPackageAccess(packageName);
 173                 }
 174              }
 175         }catch(SecurityException e){
 176             throw e;
 177         }
 178 
 179         Class<?> providerClass;
 180         if (cl == null) {
 181             providerClass = Class.forName(className, false, ObjectFactory.class.getClassLoader());
 182         } else {
 183             try {
 184                 providerClass = cl.loadClass(className);
 185             } catch (ClassNotFoundException x) {
 186                 if (doFallback) {
 187                     // Fall back to current classloader
 188                     ClassLoader current = ObjectFactory.class.getClassLoader();
 189                     if (current == null) {
 190                         providerClass = Class.forName(className);
 191                     } else if (cl != current) {
 192                         cl = current;
 193                         providerClass = cl.loadClass(className);
 194                     } else {
 195                         throw x;
 196                     }
 197                 } else {
 198                     throw x;
 199                 }
 200             }
 201         }
 202 
 203         return providerClass;
 204     }
 205 
 206 } // class ObjectFactory