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