1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.util;
18
19
20 import java.io.InputStream;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.ReflectPermission;
23 import java.net.URL;
24 import java.security.AccessController;
25 import java.security.PrivilegedAction;
26
27 import org.apache.logging.log4j.Logger;
28 import org.apache.logging.log4j.status.StatusLogger;
29 import org.apache.logging.log4j.util.PropertiesUtil;
30
31
32
33
34 public final class Loader {
35
36 private static boolean ignoreTCL = false;
37
38 private static final Logger LOGGER = StatusLogger.getLogger();
39
40 private static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
41
42 private static final PrivilegedAction<ClassLoader> THREAD_CONTEXT_CLASS_LOADER_GETTER =
43 new ThreadContextClassLoaderGetter();
44
45 static {
46 final String ignoreTCLProp = PropertiesUtil.getProperties().getStringProperty("log4j.ignoreTCL", null);
47 if (ignoreTCLProp != null) {
48 ignoreTCL = OptionConverter.toBoolean(ignoreTCLProp, true);
49 }
50 final SecurityManager sm = System.getSecurityManager();
51 if (sm != null) {
52 sm.checkPermission(new RuntimePermission("getClassLoader"));
53 sm.checkPermission(new RuntimePermission("getStackTrace"));
54 sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
55 }
56 }
57
58
59
60
61
62 public static ClassLoader getClassLoader() {
63
64 return getClassLoader(Loader.class, null);
65 }
66
67
68
69
70
71
72
73 public static ClassLoader getThreadContextClassLoader() {
74 return getTcl();
75 }
76
77
78 public static ClassLoader getClassLoader(final Class<?> class1, final Class<?> class2) {
79
80 ClassLoader threadContextClassLoader = null;
81 try {
82 threadContextClassLoader = getTcl();
83 } catch (final Exception ex) {
84 LOGGER.warn("Caught exception locating thread ClassLoader {}", ex.getMessage());
85 }
86 final ClassLoader loader1 = class1 == null ? null : class1.getClassLoader();
87 final ClassLoader loader2 = class2 == null ? null : class2.getClassLoader();
88
89 if (isChild(threadContextClassLoader, loader1)) {
90 return isChild(threadContextClassLoader, loader2) ? threadContextClassLoader : loader2;
91 }
92 return isChild(loader1, loader2) ? loader1 : loader2;
93 }
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 public static URL getResource(final String resource, final ClassLoader defaultLoader) {
118 try {
119 ClassLoader classLoader = getTcl();
120 if (classLoader != null) {
121 LOGGER.trace("Trying to find [{}] using context class loader {}.", resource, classLoader);
122 final URL url = classLoader.getResource(resource);
123 if (url != null) {
124 return url;
125 }
126 }
127
128
129 classLoader = Loader.class.getClassLoader();
130 if (classLoader != null) {
131 LOGGER.trace("Trying to find [{}] using {} class loader.", resource, classLoader);
132 final URL url = classLoader.getResource(resource);
133 if (url != null) {
134 return url;
135 }
136 }
137
138 if (defaultLoader != null) {
139 LOGGER.trace("Trying to find [{}] using {} class loader.", resource, defaultLoader);
140 final URL url = defaultLoader.getResource(resource);
141 if (url != null) {
142 return url;
143 }
144 }
145 } catch (final Throwable t) {
146
147
148
149 LOGGER.warn(TSTR, t);
150 }
151
152
153
154
155
156 LOGGER.trace("Trying to find [{}] using ClassLoader.getSystemResource().", resource);
157 return ClassLoader.getSystemResource(resource);
158 }
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182 public static InputStream getResourceAsStream(final String resource, final ClassLoader defaultLoader) {
183 try {
184 ClassLoader classLoader = getTcl();
185 InputStream is;
186 if (classLoader != null) {
187 LOGGER.trace("Trying to find [{}] using context class loader {}.", resource, classLoader);
188 is = classLoader.getResourceAsStream(resource);
189 if (is != null) {
190 return is;
191 }
192 }
193
194
195 classLoader = Loader.class.getClassLoader();
196 if (classLoader != null) {
197 LOGGER.trace("Trying to find [{}] using {} class loader.", resource, classLoader);
198 is = classLoader.getResourceAsStream(resource);
199 if (is != null) {
200 return is;
201 }
202 }
203
204
205 if (defaultLoader != null) {
206 LOGGER.trace("Trying to find [{}] using {} class loader.", resource, defaultLoader);
207 is = defaultLoader.getResourceAsStream(resource);
208 if (is != null) {
209 return is;
210 }
211 }
212 } catch (final Throwable t) {
213
214
215
216 LOGGER.warn(TSTR, t);
217 }
218
219
220
221
222
223 LOGGER.trace("Trying to find [{}] using ClassLoader.getSystemResource().", resource);
224 return ClassLoader.getSystemResourceAsStream(resource);
225 }
226
227 private static ClassLoader getTcl() {
228 return System.getSecurityManager() == null
229 ? THREAD_CONTEXT_CLASS_LOADER_GETTER.run()
230 : AccessController.doPrivileged(THREAD_CONTEXT_CLASS_LOADER_GETTER);
231 }
232
233 private static class ThreadContextClassLoaderGetter implements PrivilegedAction<ClassLoader> {
234 @Override
235 public ClassLoader run() {
236 final ClassLoader cl = Thread.currentThread().getContextClassLoader();
237
238 return cl == null ? ClassLoader.getSystemClassLoader() : cl;
239 }
240 }
241
242
243
244
245
246
247
248
249
250 private static boolean isChild(final ClassLoader loader1, final ClassLoader loader2) {
251 if (loader1 != null && loader2 != null) {
252 ClassLoader parent = loader1.getParent();
253 while (parent != null && parent != loader2) {
254 parent = parent.getParent();
255 }
256
257 return parent != null;
258 }
259 return loader1 != null;
260 }
261
262
263
264
265
266
267
268
269
270
271 public static Class<?> loadClass(final String className) throws ClassNotFoundException {
272
273 if (ignoreTCL) {
274 LOGGER.trace("Ignoring TCCL. Trying Class.forName({}).", className);
275 return loadClassWithDefaultClassLoader(className);
276 }
277 try {
278 LOGGER.trace("Trying TCCL for class {}.", className);
279
280 return Class.forName(className, true, getTcl());
281 } catch (final Throwable e) {
282 LOGGER.trace("TCCL didn't work for class {}: {}.", className, e.toString());
283 return loadClassWithDefaultClassLoader(className);
284 }
285 }
286
287 private static Class<?> loadClassWithDefaultClassLoader(final String className) throws ClassNotFoundException {
288 return Class.forName(className);
289 }
290
291
292
293
294
295
296
297
298
299 public static Class<?> initializeClass(final String className, final ClassLoader loader)
300 throws ClassNotFoundException {
301 return Class.forName(className, true, loader);
302 }
303
304
305
306
307
308
309
310
311
312 public static Class<?> loadSystemClass(final String className) throws ClassNotFoundException {
313 try {
314 return Class.forName(className, true, ClassLoader.getSystemClassLoader());
315 } catch (final Throwable t) {
316 LOGGER.trace("Couldn't use SystemClassLoader. Trying Class.forName({}).", className, t);
317 return Class.forName(className);
318 }
319 }
320
321
322
323
324
325
326
327
328
329
330
331
332 public static Object newInstanceOf(final String className)
333 throws ClassNotFoundException,
334 IllegalAccessException,
335 InstantiationException,
336 NoSuchMethodException,
337 InvocationTargetException {
338 final Class<?> clazz = loadClass(className);
339 try {
340 return clazz.getConstructor().newInstance();
341 } catch (final NoSuchMethodException e) {
342
343
344 return clazz.newInstance();
345 }
346 }
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362 public static <T> T newCheckedInstanceOf(final String className, final Class<T> clazz)
363 throws ClassNotFoundException,
364 NoSuchMethodException,
365 IllegalAccessException,
366 InvocationTargetException,
367 InstantiationException {
368 return clazz.cast(newInstanceOf(className));
369 }
370
371
372
373
374
375
376
377 public static boolean isClassAvailable(final String className) {
378 try {
379 final Class<?> clazz = loadClass(className);
380 return clazz != null;
381 } catch (final ClassNotFoundException e) {
382 return false;
383 } catch (final Throwable e) {
384 LOGGER.trace("Unknown error checking for existence of class [{}].", className, e);
385 return false;
386 }
387 }
388
389 private Loader() {
390 }
391 }