Skip to content

Commit 19d64c3

Browse files
authored
1799 - Spring shutdown fails due to ClassCastException. Spring 33450 - Spring shutdown fails due to IllegalStateException (#2062)
1 parent 1a2d8b1 commit 19d64c3

File tree

12 files changed

+608
-110
lines changed

12 files changed

+608
-110
lines changed

log4j-api-test/src/test/java/org/apache/logging/log4j/util/PropertiesUtilTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,23 @@ public void testPublish() {
140140
assertEquals("Log4j", value);
141141
}
142142

143+
@Test
144+
@ResourceLock(Resources.SYSTEM_PROPERTIES)
145+
public void testBadPropertysource() {
146+
final String key1 = "testKey";
147+
System.getProperties().put(key1, "test");
148+
final PropertiesUtil util = new PropertiesUtil(new Properties());
149+
ErrorPropertySource source = new ErrorPropertySource();
150+
util.addPropertySource(source);
151+
try {
152+
assertEquals("test", util.getStringProperty(key1));
153+
assertTrue(source.exceptionThrown);
154+
} finally {
155+
util.removePropertySource(source);
156+
System.getProperties().remove(key1);
157+
}
158+
}
159+
143160
private static final String[][] data = {
144161
{null, "org.apache.logging.log4j.level"},
145162
{null, "Log4jAnotherProperty"},
@@ -184,4 +201,25 @@ public void testLog4jProperty() {
184201
final PropertiesUtil util = new PropertiesUtil(props);
185202
assertNull(util.getStringProperty(correct));
186203
}
204+
205+
private class ErrorPropertySource implements PropertySource {
206+
public boolean exceptionThrown = false;
207+
208+
@Override
209+
public int getPriority() {
210+
return Integer.MIN_VALUE;
211+
}
212+
213+
@Override
214+
public String getProperty(String key) {
215+
exceptionThrown = true;
216+
throw new InstantiationError("Test");
217+
}
218+
219+
@Override
220+
public boolean containsProperty(String key) {
221+
exceptionThrown = true;
222+
throw new InstantiationError("Test");
223+
}
224+
}
187225
}

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

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,13 @@ public void addPropertySource(final PropertySource propertySource) {
199199
}
200200
}
201201

202+
@Override
203+
public void removePropertySource(final PropertySource propertySource) {
204+
if (environment != null) {
205+
environment.removePropertySource(propertySource);
206+
}
207+
}
208+
202209
/**
203210
* Returns {@code true} if the specified property is defined, regardless of its value (it may not have a value).
204211
*
@@ -683,6 +690,11 @@ public void addPropertySource(final PropertySource propertySource) {
683690
sources.add(propertySource);
684691
}
685692

693+
@Override
694+
public void removePropertySource(final PropertySource propertySource) {
695+
sources.remove(propertySource);
696+
}
697+
686698
private void reload() {
687699
literal.clear();
688700
sources.forEach((s) -> {
@@ -700,14 +712,14 @@ private void reload() {
700712
sources.forEach(source -> {
701713
if (source instanceof ContextAwarePropertySource) {
702714
final ContextAwarePropertySource src = Cast.cast(source);
703-
if (src.containsProperty(contextName, contextKey)) {
715+
if (sourceContainsProperty(src, contextName, contextKey)) {
704716
literal.putIfAbsent(key, src.getProperty(contextName, contextKey));
705717
}
706718
}
707719
});
708720
}
709721
sources.forEach(source -> {
710-
if (source.containsProperty(contextKey)) {
722+
if (sourceContainsProperty(source, contextKey)) {
711723
literal.putIfAbsent(key, source.getProperty(contextKey));
712724
}
713725
});
@@ -727,7 +739,7 @@ public String getStringProperty(final String key) {
727739
while (source != null) {
728740
if (source instanceof ContextAwarePropertySource) {
729741
final ContextAwarePropertySource src = Cast.cast(source);
730-
result = src.getProperty(contextName, contextKey);
742+
result = sourceGetProperty(src, contextName, contextKey);
731743
}
732744
if (result != null) {
733745
return result;
@@ -737,7 +749,7 @@ public String getStringProperty(final String key) {
737749
}
738750
PropertySource source = sources.first();
739751
while (source != null) {
740-
result = source.getProperty(contextKey);
752+
result = sourceGetProperty(source, contextKey);
741753
if (result != null) {
742754
return result;
743755
}
@@ -746,6 +758,22 @@ public String getStringProperty(final String key) {
746758
return result;
747759
}
748760

761+
private String sourceGetProperty(ContextAwarePropertySource source, String contextName, String key) {
762+
try {
763+
return source.getProperty(contextName, key);
764+
} catch (Throwable ex) {
765+
return null;
766+
}
767+
}
768+
769+
private String sourceGetProperty(PropertySource source, String key) {
770+
try {
771+
return source.getProperty(key);
772+
} catch (Throwable ex) {
773+
return null;
774+
}
775+
}
776+
749777
@Override
750778
public boolean hasProperty(final String key) {
751779
if (literal.containsKey(key)) {
@@ -758,7 +786,7 @@ public boolean hasProperty(final String key) {
758786
while (source != null) {
759787
if (source instanceof ContextAwarePropertySource) {
760788
final ContextAwarePropertySource src = Cast.cast(source);
761-
if (src.containsProperty(contextName, contextKey)) {
789+
if (sourceContainsProperty(src, contextName, contextKey)) {
762790
return true;
763791
}
764792
}
@@ -769,9 +797,9 @@ public boolean hasProperty(final String key) {
769797
while (source != null) {
770798
if (source instanceof ContextAwarePropertySource) {
771799
final ContextAwarePropertySource src = Cast.cast(source);
772-
if (src.containsProperty(contextName, contextKey)
800+
if (sourceContainsProperty(src, contextName, contextKey)
773801
|| (!contextName.equals(PropertySource.SYSTEM_CONTEXT)
774-
&& src.containsProperty(PropertySource.SYSTEM_CONTEXT, contextKey))) {
802+
&& sourceContainsProperty(src, PropertySource.SYSTEM_CONTEXT, contextKey))) {
775803
return true;
776804
}
777805
} else {
@@ -784,6 +812,22 @@ public boolean hasProperty(final String key) {
784812
return false;
785813
}
786814

815+
private boolean sourceContainsProperty(ContextAwarePropertySource source, String contextName, String key) {
816+
try {
817+
return source.containsProperty(contextName, key);
818+
} catch (Throwable ex) {
819+
return false;
820+
}
821+
}
822+
823+
private boolean sourceContainsProperty(PropertySource source, String key) {
824+
try {
825+
return source.containsProperty(key);
826+
} catch (Throwable ex) {
827+
return false;
828+
}
829+
}
830+
787831
private String getContextKey(final String key) {
788832
String keyToCheck = key;
789833
if (keyToCheck.startsWith(PropertySource.PREFIX)) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ public interface PropertyEnvironment {
2828
*/
2929
void addPropertySource(PropertySource propertySource);
3030

31+
/**
32+
* Allows a PropertySource that was added to be removed.
33+
* @param propertySource the PropertySource to remove.
34+
*/
35+
void removePropertySource(PropertySource propertySource);
36+
3137
/**
3238
* Returns {@code true} if the specified property is defined, regardless of its value (it may not have a value).
3339
*
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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.core;
18+
19+
import static org.junit.jupiter.api.Assertions.assertTrue;
20+
21+
import org.apache.logging.log4j.LogManager;
22+
import org.apache.logging.log4j.core.impl.Log4jContextFactory;
23+
import org.apache.logging.log4j.core.impl.internal.InternalLoggerContext;
24+
import org.apache.logging.log4j.core.util.DefaultShutdownCallbackRegistry;
25+
import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
26+
import org.apache.logging.log4j.spi.LoggerContextFactory;
27+
import org.junit.jupiter.api.Test;
28+
29+
/**
30+
* Validate Logging after Shutdown.
31+
*/
32+
public class LoggerContextTest {
33+
34+
@Test
35+
public void shutdownTest() {
36+
LoggerContextFactory contextFactory = LogManager.getFactory();
37+
assertTrue(contextFactory instanceof Log4jContextFactory);
38+
Log4jContextFactory factory = (Log4jContextFactory) contextFactory;
39+
ShutdownCallbackRegistry registry = factory.getShutdownCallbackRegistry();
40+
assertTrue(registry instanceof DefaultShutdownCallbackRegistry);
41+
((DefaultShutdownCallbackRegistry) registry).start();
42+
((DefaultShutdownCallbackRegistry) registry).stop();
43+
LoggerContext loggerContext = factory.getContext(LoggerContextTest.class.getName(), null, null, false);
44+
assertTrue(loggerContext instanceof InternalLoggerContext);
45+
}
46+
}

log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/MissingRootLoggerTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static org.hamcrest.Matchers.hasKey;
2222
import static org.hamcrest.Matchers.instanceOf;
2323
import static org.hamcrest.Matchers.is;
24+
import static org.hamcrest.Matchers.startsWith;
2425
import static org.junit.jupiter.api.Assertions.*;
2526

2627
import java.util.Map;
@@ -48,7 +49,7 @@ public void testMissingRootLogger(final LoggerContext ctx) throws Exception {
4849
assertNotNull(map, "Appenders not null");
4950
assertThat("There should only be two appenders", map, hasSize(2));
5051
assertThat(map, hasKey("List"));
51-
assertThat(map, hasKey("DefaultConsole-2"));
52+
assertThat(map, hasKey(startsWith("DefaultConsole-")));
5253

5354
final Map<String, LoggerConfig> loggerMap = config.getLoggers();
5455
assertNotNull(loggerMap, "loggerMap not null");
@@ -67,7 +68,8 @@ public void testMissingRootLogger(final LoggerContext ctx) throws Exception {
6768
final Map<String, Appender> rootAppenders = root.getAppenders();
6869
assertThat("The root logger should only have one appender", rootAppenders, hasSize(1));
6970
// root only has Console appender!
70-
assertThat("The root appender should be a ConsoleAppender", rootAppenders, hasKey("DefaultConsole-2"));
71+
assertThat(
72+
"The root appender should be a ConsoleAppender", rootAppenders, hasKey(startsWith("DefaultConsole-")));
7173
assertEquals(Level.ERROR, root.getLevel());
7274
}
7375
}

log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ protected Logger(final LoggerContext context, final String name, final MessageFa
6666
privateConfig = new PrivateConfig(context.getConfiguration(), this);
6767
}
6868

69+
/**
70+
* This is used to construct an InternalLoggerContext, which makes SimpleLoggerContext conmpatible with core.
71+
* @param context the InternalLoggerContext.
72+
* @param name the Logger name.
73+
*/
74+
protected Logger(final LoggerContext context, final String name) {
75+
super(name);
76+
this.context = context;
77+
privateConfig = null;
78+
}
79+
6980
/**
7081
* This method is only used for 1.x compatibility. Returns the parent of this Logger. If it doesn't already exist
7182
* return a temporary Logger.

log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ public class LoggerContext extends AbstractLifeCycle
9999

100100
private final Lock configLock = new ReentrantLock();
101101

102+
/**
103+
* Constructor used to create an InternalLoggerContext.
104+
*/
105+
protected LoggerContext() {
106+
setStarted();
107+
instanceFactory = null;
108+
this.nullConfiguration = null;
109+
}
110+
102111
/**
103112
* Constructor taking only a name.
104113
*
@@ -428,6 +437,7 @@ public boolean stop(final long timeout, final TimeUnit timeUnit) {
428437
}
429438

430439
this.setStopping();
440+
String name = getName();
431441
try {
432442
Server.unregisterLoggerContext(getName()); // LOG4J2-406, LOG4J2-500
433443
} catch (final LinkageError | Exception e) {

log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@
2121
import org.apache.logging.log4j.core.LoggerContext;
2222
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
2323
import org.apache.logging.log4j.core.impl.Log4jPropertyKey;
24+
import org.apache.logging.log4j.core.util.AuthorizationProvider;
2425
import org.apache.logging.log4j.plugins.Namespace;
2526
import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
2627
import org.apache.logging.log4j.plugins.di.Key;
2728
import org.apache.logging.log4j.plugins.model.PluginNamespace;
2829
import org.apache.logging.log4j.status.StatusLogger;
2930
import org.apache.logging.log4j.util.LoaderUtil;
31+
import org.apache.logging.log4j.util.PropertiesUtil;
32+
import org.apache.logging.log4j.util.PropertyEnvironment;
3033
import org.apache.logging.log4j.util.PropertyKey;
3134

3235
/**
@@ -118,6 +121,15 @@ protected boolean isActive() {
118121
return true;
119122
}
120123

124+
/**
125+
* Required for Spring Boot.
126+
* @param props PropertiesUtil.
127+
* @return the AuthorizationProvider, if any.
128+
*/
129+
public static AuthorizationProvider authorizationProvider(final PropertiesUtil props) {
130+
return AuthorizationProvider.getAuthorizationProvider((PropertyEnvironment) props);
131+
}
132+
121133
public abstract Configuration getConfiguration(final LoggerContext loggerContext, ConfigurationSource source);
122134

123135
/**

0 commit comments

Comments
 (0)