Skip to content

Commit fbde9cd

Browse files
committed
adding log4j2.forceTCLOnly option
1 parent ffd4ab6 commit fbde9cd

File tree

2 files changed

+93
-15
lines changed

2 files changed

+93
-15
lines changed

log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java

+35-15
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public final class LoaderUtil {
4444
* @since 2.1
4545
*/
4646
public static final String IGNORE_TCCL_PROPERTY = "log4j.ignoreTCL";
47+
public static final String FORCE_TCL_ONLY_PROPERTY = "log4j.forceTCLOnly";
4748

4849
private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager();
4950

@@ -53,6 +54,8 @@ public final class LoaderUtil {
5354

5455
private static final boolean GET_CLASS_LOADER_DISABLED;
5556

57+
protected static Boolean forceTcclOnly;
58+
5659
private static final PrivilegedAction<ClassLoader> TCCL_GETTER = new ThreadContextClassLoaderGetter();
5760

5861
static {
@@ -109,21 +112,23 @@ public static ClassLoader[] getClassLoaders() {
109112
List<ClassLoader> classLoaders = new ArrayList<>();
110113
ClassLoader tcl = getThreadContextClassLoader();
111114
classLoaders.add(tcl);
112-
ClassLoader current = LoaderUtil.class.getClassLoader();
113-
if (current != tcl) {
114-
classLoaders.add(current);
115-
ClassLoader parent = current.getParent();
115+
if (!isForceTccl()) {
116+
ClassLoader current = LoaderUtil.class.getClassLoader();
117+
if (current != tcl) {
118+
classLoaders.add(current);
119+
ClassLoader parent = current.getParent();
120+
while (parent != null && !classLoaders.contains(parent)) {
121+
classLoaders.add(parent);
122+
}
123+
}
124+
ClassLoader parent = tcl.getParent();
116125
while (parent != null && !classLoaders.contains(parent)) {
117126
classLoaders.add(parent);
127+
parent = parent.getParent();
128+
}
129+
if (!classLoaders.contains(ClassLoader.getSystemClassLoader())) {
130+
classLoaders.add(ClassLoader.getSystemClassLoader());
118131
}
119-
}
120-
ClassLoader parent = tcl.getParent();
121-
while (parent != null && !classLoaders.contains(parent)) {
122-
classLoaders.add(parent);
123-
parent = parent.getParent();
124-
}
125-
if (!classLoaders.contains(ClassLoader.getSystemClassLoader())) {
126-
classLoaders.add(ClassLoader.getSystemClassLoader());
127132
}
128133
return classLoaders.toArray(new ClassLoader[classLoaders.size()]);
129134
}
@@ -260,6 +265,21 @@ private static boolean isIgnoreTccl() {
260265
return ignoreTCCL;
261266
}
262267

268+
private static boolean isForceTccl() {
269+
if (forceTcclOnly == null) {
270+
// PropertiesUtil.getProperties() uses that code path so don't use that!
271+
forceTcclOnly = System.getSecurityManager() == null ?
272+
Boolean.getBoolean(FORCE_TCL_ONLY_PROPERTY) :
273+
AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
274+
@Override
275+
public Boolean run() {
276+
return Boolean.getBoolean(FORCE_TCL_ONLY_PROPERTY);
277+
}
278+
});
279+
}
280+
return forceTcclOnly;
281+
}
282+
263283
/**
264284
* Finds classpath {@linkplain URL resources}.
265285
*
@@ -279,9 +299,9 @@ public static Collection<URL> findResources(final String resource) {
279299
static Collection<UrlResource> findUrlResources(final String resource) {
280300
// @formatter:off
281301
final ClassLoader[] candidates = {
282-
getThreadContextClassLoader(),
283-
LoaderUtil.class.getClassLoader(),
284-
GET_CLASS_LOADER_DISABLED ? null : ClassLoader.getSystemClassLoader()};
302+
getThreadContextClassLoader(),
303+
isForceTccl() ? null : LoaderUtil.class.getClassLoader(),
304+
isForceTccl() || GET_CLASS_LOADER_DISABLED ? null : ClassLoader.getSystemClassLoader()};
285305
// @formatter:on
286306
final Collection<UrlResource> resources = new LinkedHashSet<>();
287307
for (final ClassLoader cl : candidates) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache license, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the license for the specific language governing permissions and
15+
* limitations under the license.
16+
*/
17+
package org.apache.logging.log4j.util;
18+
19+
import static org.junit.Assert.assertEquals;
20+
21+
import java.net.URL;
22+
import java.util.Collections;
23+
import java.util.Enumeration;
24+
25+
import org.junit.After;
26+
import org.junit.Before;
27+
import org.junit.Test;
28+
29+
public class LoaderUtilTest {
30+
@Before
31+
@After
32+
public void reset() {
33+
LoaderUtil.forceTcclOnly = null;
34+
}
35+
36+
@Test
37+
public void systemClassLoader() {
38+
final Thread thread = Thread.currentThread();
39+
final ClassLoader tccl = thread.getContextClassLoader();
40+
41+
LoaderUtil.forceTcclOnly = true;
42+
final ClassLoader loader = new ClassLoader(tccl) {
43+
@Override
44+
public Enumeration<URL> getResources(final String name) {
45+
return Collections.emptyEnumeration();
46+
}
47+
};
48+
thread.setContextClassLoader(loader);
49+
try {
50+
assertEquals(0, LoaderUtil.findUrlResources("Log4j-charsets.properties").size());
51+
52+
LoaderUtil.forceTcclOnly = false;
53+
assertEquals(1, LoaderUtil.findUrlResources("Log4j-charsets.properties").size());
54+
} finally {
55+
thread.setContextClassLoader(tccl);
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)