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. */
isDebugEnabled()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. */
debugPrintln(Supplier<String> msgGen)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      */
findClassLoader()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      */
newInstance(String className, boolean doFallback)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      */
newInstance(String className, ClassLoader cl, boolean doFallback)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      */
findProviderClass(String className, boolean doFallback)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      */
findProviderClass(String className, ClassLoader cl, boolean doFallback)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
235