1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.util;
18
19 import java.io.IOException;
20 import java.lang.reflect.InvocationTargetException;
21 import java.net.URL;
22 import java.security.AccessController;
23 import java.security.PrivilegedAction;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Enumeration;
27 import java.util.LinkedHashSet;
28 import java.util.List;
29 import java.util.Objects;
30
31
32
33
34
35
36
37
38
39 public final class LoaderUtil {
40
41
42
43
44
45
46 public static final String IGNORE_TCCL_PROPERTY = "log4j.ignoreTCL";
47
48 private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager();
49
50
51
52 private static Boolean ignoreTCCL;
53
54 private static final boolean GET_CLASS_LOADER_DISABLED;
55
56 private static final PrivilegedAction<ClassLoader> TCCL_GETTER = new ThreadContextClassLoaderGetter();
57
58 static {
59 if (SECURITY_MANAGER != null) {
60 boolean getClassLoaderDisabled;
61 try {
62 SECURITY_MANAGER.checkPermission(new RuntimePermission("getClassLoader"));
63 getClassLoaderDisabled = false;
64 } catch (final SecurityException ignored) {
65 getClassLoaderDisabled = true;
66 }
67 GET_CLASS_LOADER_DISABLED = getClassLoaderDisabled;
68 } else {
69 GET_CLASS_LOADER_DISABLED = false;
70 }
71 }
72
73 private LoaderUtil() {
74 }
75
76
77
78
79
80
81
82
83
84 public static ClassLoader getThreadContextClassLoader() {
85 if (GET_CLASS_LOADER_DISABLED) {
86
87
88 return LoaderUtil.class.getClassLoader();
89 }
90 return SECURITY_MANAGER == null ? TCCL_GETTER.run() : AccessController.doPrivileged(TCCL_GETTER);
91 }
92
93
94
95
96 private static class ThreadContextClassLoaderGetter implements PrivilegedAction<ClassLoader> {
97 @Override
98 public ClassLoader run() {
99 final ClassLoader cl = Thread.currentThread().getContextClassLoader();
100 if (cl != null) {
101 return cl;
102 }
103 final ClassLoader ccl = LoaderUtil.class.getClassLoader();
104 return ccl == null && !GET_CLASS_LOADER_DISABLED ? ClassLoader.getSystemClassLoader() : ccl;
105 }
106 }
107
108 public static ClassLoader[] getClassLoaders() {
109 final List<ClassLoader> classLoaders = new ArrayList<>();
110 final ClassLoader tcl = getThreadContextClassLoader();
111 classLoaders.add(tcl);
112
113 final ClassLoader current = LoaderUtil.class.getClassLoader();
114 if (current != null && current != tcl) {
115 classLoaders.add(current);
116 final ClassLoader parent = current.getParent();
117 while (parent != null && !classLoaders.contains(parent)) {
118 classLoaders.add(parent);
119 }
120 }
121 ClassLoader parent = tcl == null ? null : tcl.getParent();
122 while (parent != null && !classLoaders.contains(parent)) {
123 classLoaders.add(parent);
124 parent = parent.getParent();
125 }
126 final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
127 if (!classLoaders.contains(systemClassLoader)) {
128 classLoaders.add(systemClassLoader);
129 }
130 return classLoaders.toArray(new ClassLoader[classLoaders.size()]);
131 }
132
133
134
135
136
137
138
139
140 public static boolean isClassAvailable(final String className) {
141 try {
142 final Class<?> clazz = loadClass(className);
143 return clazz != null;
144 } catch (final ClassNotFoundException | LinkageError e) {
145 return false;
146 } catch (final Throwable e) {
147 LowLevelLogUtil.logException("Unknown error checking for existence of class: " + className, e);
148 return false;
149 }
150 }
151
152
153
154
155
156
157
158
159
160
161 public static Class<?> loadClass(final String className) throws ClassNotFoundException {
162 if (isIgnoreTccl()) {
163 return Class.forName(className);
164 }
165 try {
166 return getThreadContextClassLoader().loadClass(className);
167 } catch (final Throwable ignored) {
168 return Class.forName(className);
169 }
170 }
171
172
173
174
175
176
177
178
179
180
181
182 public static <T> T newInstanceOf(final Class<T> clazz)
183 throws InstantiationException, IllegalAccessException, InvocationTargetException {
184 try {
185 return clazz.getConstructor().newInstance();
186 } catch (final NoSuchMethodException ignored) {
187
188 return clazz.newInstance();
189 }
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203
204 @SuppressWarnings("unchecked")
205 public static <T> T newInstanceOf(final String className) throws ClassNotFoundException, IllegalAccessException,
206 InstantiationException, NoSuchMethodException, InvocationTargetException {
207 return newInstanceOf((Class<T>) loadClass(className));
208 }
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225 public static <T> T newCheckedInstanceOf(final String className, final Class<T> clazz)
226 throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException,
227 IllegalAccessException {
228 return clazz.cast(newInstanceOf(className));
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246 public static <T> T newCheckedInstanceOfProperty(final String propertyName, final Class<T> clazz)
247 throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException,
248 IllegalAccessException {
249 final String className = PropertiesUtil.getProperties().getStringProperty(propertyName);
250 if (className == null) {
251 return null;
252 }
253 return newCheckedInstanceOf(className, clazz);
254 }
255
256 private static boolean isIgnoreTccl() {
257
258 if (ignoreTCCL == null) {
259 final String ignoreTccl = PropertiesUtil.getProperties().getStringProperty(IGNORE_TCCL_PROPERTY, null);
260 ignoreTCCL = ignoreTccl != null && !"false".equalsIgnoreCase(ignoreTccl.trim());
261 }
262 return ignoreTCCL;
263 }
264
265
266
267
268
269
270
271
272 public static Collection<URL> findResources(final String resource) {
273 final Collection<UrlResource> urlResources = findUrlResources(resource);
274 final Collection<URL> resources = new LinkedHashSet<>(urlResources.size());
275 for (final UrlResource urlResource : urlResources) {
276 resources.add(urlResource.getUrl());
277 }
278 return resources;
279 }
280
281 static Collection<UrlResource> findUrlResources(final String resource) {
282
283 final ClassLoader[] candidates = {
284 getThreadContextClassLoader(),
285 LoaderUtil.class.getClassLoader(),
286 GET_CLASS_LOADER_DISABLED ? null : ClassLoader.getSystemClassLoader()};
287
288 final Collection<UrlResource> resources = new LinkedHashSet<>();
289 for (final ClassLoader cl : candidates) {
290 if (cl != null) {
291 try {
292 final Enumeration<URL> resourceEnum = cl.getResources(resource);
293 while (resourceEnum.hasMoreElements()) {
294 resources.add(new UrlResource(cl, resourceEnum.nextElement()));
295 }
296 } catch (final IOException e) {
297 LowLevelLogUtil.logException(e);
298 }
299 }
300 }
301 return resources;
302 }
303
304
305
306
307 static class UrlResource {
308 private final ClassLoader classLoader;
309 private final URL url;
310
311 UrlResource(final ClassLoader classLoader, final URL url) {
312 this.classLoader = classLoader;
313 this.url = url;
314 }
315
316 public ClassLoader getClassLoader() {
317 return classLoader;
318 }
319
320 public URL getUrl() {
321 return url;
322 }
323
324 @Override
325 public boolean equals(final Object o) {
326 if (this == o) {
327 return true;
328 }
329 if (o == null || getClass() != o.getClass()) {
330 return false;
331 }
332
333 final UrlResource that = (UrlResource) o;
334
335 if (classLoader != null ? !classLoader.equals(that.classLoader) : that.classLoader != null) {
336 return false;
337 }
338 if (url != null ? !url.equals(that.url) : that.url != null) {
339 return false;
340 }
341
342 return true;
343 }
344
345 @Override
346 public int hashCode() {
347 return Objects.hashCode(classLoader) + Objects.hashCode(url);
348 }
349 }
350 }