This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch 2.x-site-pro
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/2.x-site-pro by this push:
     new da4420763e fix: synchronize with `2.x`
da4420763e is described below

commit da4420763ee276c8da2f1d31d3a451063702c5d8
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Mon Jun 16 21:54:41 2025 +0200

    fix: synchronize with `2.x`
---
 .../map/UnmodifiableArrayBackedMapTest.java        |  19 --
 .../apache/logging/log4j/message/package-info.java |   2 +-
 .../apache/logging/log4j/spi/AbstractLogger.java   |   4 +
 .../apache/logging/log4j/spi/LoggerContext.java    |   7 +-
 .../org/apache/logging/log4j/spi/package-info.java |   2 +-
 .../log4j/core/appender/AbstractAppender.java      |   6 +-
 .../core/appender/HttpURLConnectionManager.java    |   3 +-
 .../log4j/core/config/AbstractConfiguration.java   |  15 +-
 .../log4j/core/config/ConfigurationSource.java     |   9 +-
 .../apache/logging/log4j/core/net/SmtpManager.java |   3 +-
 .../logging/log4j/core/net/SslSocketManager.java   |  62 +++++-
 .../log4j/core/net/UrlConnectionFactory.java       |   3 +-
 .../net/ssl/AbstractKeyStoreConfiguration.java     |   9 +-
 .../log4j/core/net/ssl/KeyStoreConfiguration.java  |   6 +-
 .../log4j/core/net/ssl/PasswordProvider.java       |   1 +
 .../log4j/core/net/ssl/SslConfiguration.java       | 240 ++++++++-------------
 .../core/net/ssl/SslConfigurationFactory.java      |   3 +-
 .../log4j/core/net/ssl/StoreConfiguration.java     |   2 +-
 .../core/net/ssl/TrustStoreConfiguration.java      |   6 +-
 .../logging/log4j/core/net/ssl/package-info.java   |   2 +-
 .../apache/logging/log4j/core/package-info.java    |   2 +-
 .../org/apache/logging/log4j/core/util/Loader.java |   5 +-
 .../org/apache/logging/log4j/core/util/Source.java |  45 ++--
 .../log4j/core/util/datetime/FastDatePrinter.java  |   2 +-
 .../org/apache/logging/log4j/smtp/SmtpManager.java |   3 +-
 .../log4j/taglib/Log4jTaglibLoggerContext.java     |   7 +-
 .../apache/logging/log4j/taglib/package-info.java  |   2 +-
 .../logging/log4j/tojul/JULLoggerContext.java      |   7 +-
 .../apache/logging/log4j/tojul/package-info.java   |   2 +-
 .../apache/logging/slf4j/SLF4JLoggerContext.java   |   7 +-
 .../org/apache/logging/slf4j/package-info.java     |   2 +-
 31 files changed, 255 insertions(+), 233 deletions(-)

diff --git 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/internal/map/UnmodifiableArrayBackedMapTest.java
 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/internal/map/UnmodifiableArrayBackedMapTest.java
index 48befed7f9..612840bbf5 100644
--- 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/internal/map/UnmodifiableArrayBackedMapTest.java
+++ 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/internal/map/UnmodifiableArrayBackedMapTest.java
@@ -394,23 +394,4 @@ class UnmodifiableArrayBackedMapTest {
         actualMap = actualMap.copyAndRemoveAll(Collections.singleton("inner"));
         Assertions.assertThat(actualMap).isEqualTo(expectedMap);
     }
-
-    @Test
-    void copyAndRemoveAll_should_work() {
-
-        // Create the actual map
-        UnmodifiableArrayBackedMap actualMap = 
UnmodifiableArrayBackedMap.EMPTY_MAP;
-        actualMap = actualMap.copyAndPut("outer", "two");
-        actualMap = actualMap.copyAndPut("inner", "one");
-        actualMap = actualMap.copyAndPut("not-in-closeable", "true");
-
-        // Create the expected map
-        UnmodifiableArrayBackedMap expectedMap = 
UnmodifiableArrayBackedMap.EMPTY_MAP;
-        expectedMap = expectedMap.copyAndPut("outer", "two");
-        expectedMap = expectedMap.copyAndPut("not-in-closeable", "true");
-
-        // Remove the key and verify
-        actualMap = actualMap.copyAndRemoveAll(Collections.singleton("inner"));
-        Assertions.assertThat(actualMap).isEqualTo(expectedMap);
-    }
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/message/package-info.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/message/package-info.java
index dae91264f4..fbec2d82f4 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/package-info.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/package-info.java
@@ -19,7 +19,7 @@
  * Public Message Types used for Log4j 2. Users may implement their own 
Messages.
  */
 @Export
-@Version("2.24.1")
+@Version("2.24.2")
 package org.apache.logging.log4j.message;
 
 import org.osgi.annotation.bundle.Export;
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
index 1ec0a84937..ebe5e5c668 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
@@ -168,7 +168,11 @@ public abstract class AbstractLogger implements 
ExtendedLogger, LocationAwareLog
      *
      * @param logger The logger to check
      * @param messageFactory The message factory to check.
+     * @deprecated As of version {@code 2.25.0}, planned to be removed!
+     * Instead, in {@link LoggerContext#getLogger(String, MessageFactory)} 
implementations, namespace loggers with message factories.
+     * If your implementation uses {@link LoggerRegistry}, you are already 
covered.
      */
+    @Deprecated
     public static void checkMessageFactory(final ExtendedLogger logger, final 
MessageFactory messageFactory) {
         final String name = logger.getName();
         final MessageFactory loggerMessageFactory = logger.getMessageFactory();
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
index 2b6f932d35..d5a9119a1e 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.spi;
 
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.message.MessageFactory;
+import org.jspecify.annotations.Nullable;
 
 /**
  * Anchor point for logging implementations.
@@ -55,7 +56,7 @@ public interface LoggerContext {
      * @return The logger.
      * @since 2.14.0
      */
-    default ExtendedLogger getLogger(Class<?> cls, MessageFactory 
messageFactory) {
+    default ExtendedLogger getLogger(Class<?> cls, @Nullable MessageFactory 
messageFactory) {
         final String canonicalName = cls.getCanonicalName();
         return getLogger(canonicalName != null ? canonicalName : 
cls.getName(), messageFactory);
     }
@@ -74,7 +75,7 @@ public interface LoggerContext {
      *                       the logger but will log a warning if mismatched.
      * @return The logger with the specified name.
      */
-    ExtendedLogger getLogger(String name, MessageFactory messageFactory);
+    ExtendedLogger getLogger(String name, @Nullable MessageFactory 
messageFactory);
 
     /**
      * Gets the LoggerRegistry.
@@ -119,7 +120,7 @@ public interface LoggerContext {
      * @return true if the Logger exists, false otherwise.
      * @since 2.5
      */
-    boolean hasLogger(String name, MessageFactory messageFactory);
+    boolean hasLogger(String name, @Nullable MessageFactory messageFactory);
 
     /**
      * Associates an object into the LoggerContext by name for later use.
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/package-info.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/package-info.java
index 1637d7a3d1..3b6b5c2585 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/package-info.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/package-info.java
@@ -19,7 +19,7 @@
  * API classes.
  */
 @Export
-@Version("2.24.2")
+@Version("2.25.0")
 package org.apache.logging.log4j.spi;
 
 import org.osgi.annotation.bundle.Export;
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
index 83ed7d48f8..beaf5134a0 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
@@ -172,7 +172,7 @@ public abstract class AbstractAppender extends 
AbstractFilterable implements App
     private final boolean ignoreExceptions;
     private final Layout<? extends Serializable> layout;
 
-    private ErrorHandler handler = new DefaultErrorHandler(this);
+    private volatile ErrorHandler handler = new DefaultErrorHandler(this);
 
     @Override
     public boolean requiresLocation() {
@@ -316,10 +316,6 @@ public abstract class AbstractAppender extends 
AbstractFilterable implements App
             LOGGER.error("The handler cannot be set to null");
             return;
         }
-        if (isStarted()) {
-            LOGGER.error("The handler cannot be changed once the appender is 
started");
-            return;
-        }
         this.handler = handler;
     }
 
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java
index 38c9c52b2e..a4e9858431 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java
@@ -100,7 +100,8 @@ public class HttpURLConnectionManager extends HttpManager {
                     header.getName(), 
header.evaluate(getConfiguration().getStrSubstitutor()));
         }
         if (sslConfiguration != null) {
-            ((HttpsURLConnection) 
urlConnection).setSSLSocketFactory(sslConfiguration.getSslSocketFactory());
+            ((HttpsURLConnection) urlConnection)
+                    
.setSSLSocketFactory(sslConfiguration.getSslContext().getSocketFactory());
         }
         if (isHttps && !verifyHostname) {
             ((HttpsURLConnection) 
urlConnection).setHostnameVerifier(LaxHostnameVerifier.INSTANCE);
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index 0f2eebcb70..4c3dde9179 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -17,9 +17,11 @@
 package org.apache.logging.log4j.core.config;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -279,9 +281,10 @@ public abstract class AbstractConfiguration extends 
AbstractFilterable implement
         if (configSource != null && (configSource.getFile() != null || 
configSource.getURL() != null)) {
             if (monitorIntervalSeconds > 0) {
                 watchManager.setIntervalSeconds(monitorIntervalSeconds);
-                if (configSource.getFile() != null) {
-                    final Source cfgSource = new Source(configSource);
-                    final long lastModified = 
configSource.getFile().lastModified();
+                File file = configSource.getFile();
+                if (file != null) {
+                    final Source cfgSource = new Source(file);
+                    final long lastModified = file.lastModified();
                     final ConfigurationFileWatcher watcher =
                             new ConfigurationFileWatcher(this, reconfigurable, 
listeners, lastModified);
                     watchManager.watch(cfgSource, watcher);
@@ -297,8 +300,10 @@ public abstract class AbstractConfiguration extends 
AbstractFilterable implement
     }
 
     private void monitorSource(final Reconfigurable reconfigurable, final 
ConfigurationSource configSource) {
-        if (configSource.getLastModified() > 0) {
-            final Source cfgSource = new Source(configSource);
+        URI uri = configSource.getURI();
+        if (uri != null && configSource.getLastModified() > 0) {
+            File file = configSource.getFile();
+            final Source cfgSource = file != null ? new Source(file) : new 
Source(uri);
             final Watcher watcher = WatcherFactory.getInstance(pluginPackages)
                     .newWatcher(cfgSource, this, reconfigurable, listeners, 
configSource.getLastModified());
             if (watcher != null) {
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
index ff443b08f3..d6143cdc15 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
@@ -142,7 +142,7 @@ public class ConfigurationSource {
      * @param stream the input stream, the caller is responsible for closing 
this resource.
      * @throws IOException if an exception occurred reading from the specified 
stream
      */
-    public ConfigurationSource(final InputStream stream) throws IOException {
+    public ConfigurationSource(InputStream stream) throws IOException {
         this(toByteArray(stream), null, 0);
     }
 
@@ -298,12 +298,13 @@ public class ConfigurationSource {
 
     @Override
     public String toString() {
-        if (isLocation()) {
-            return getLocation();
+        if (source != null) {
+            return source.getLocation();
         }
         if (this == NULL_SOURCE) {
             return "NULL_SOURCE";
         }
+        byte[] data = this.data;
         final int length = data == null ? -1 : data.length;
         return "stream (" + length + " bytes, unknown location)";
     }
@@ -311,7 +312,7 @@ public class ConfigurationSource {
     /**
      * Loads the configuration from a URI.
      * @param configLocation A URI representing the location of the 
configuration.
-     * @return The ConfigurationSource for the configuration.
+     * @return The ConfigurationSource for the configuration or {@code null}.
      */
     public static /*@Nullable*/ ConfigurationSource fromUri(final URI 
configLocation) {
         final File configFile = FileUtils.fileFromUri(configLocation);
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
index 9c362ed045..f129b80fe4 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
@@ -308,7 +308,8 @@ public class SmtpManager extends MailManager {
             if (smtpProtocol.equals("smtps")) {
                 final SslConfiguration sslConfiguration = 
data.getSslConfiguration();
                 if (sslConfiguration != null) {
-                    final SSLSocketFactory sslSocketFactory = 
sslConfiguration.getSslSocketFactory();
+                    final SSLSocketFactory sslSocketFactory =
+                            
sslConfiguration.getSslContext().getSocketFactory();
                     properties.put(prefix + ".ssl.socketFactory", 
sslSocketFactory);
                     properties.setProperty(
                             prefix + ".ssl.checkserveridentity", 
Boolean.toString(sslConfiguration.isVerifyHostName()));
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
index 8326f3ceeb..4f28e57502 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
@@ -22,7 +22,13 @@ import java.io.Serializable;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.security.KeyStoreException;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Enumeration;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 import org.apache.logging.log4j.core.Layout;
@@ -197,6 +203,8 @@ public class SslSocketManager extends TcpSocketManager {
             final Layout<? extends Serializable> layout,
             final int bufferSize,
             final SocketOptions socketOptions) {
+
+        // Check arguments
         if (Strings.isEmpty(host)) {
             throw new IllegalArgumentException("A host name is required");
         }
@@ -206,7 +214,14 @@ public class SslSocketManager extends TcpSocketManager {
         if (reconnectDelayMillis == 0) {
             reconnectDelayMillis = DEFAULT_RECONNECTION_DELAY_MILLIS;
         }
-        final String name = "TLS:" + host + ':' + port;
+
+        // Create an ID associated with the SSL configuration. This is 
necessary to make sure a new `name` is generated
+        // (and consequently a new connection pool is created) upon 
reconfiguration with a different configuration;
+        // e.g., change in the SSL certificate content, even though the 
certificate file locations are still the same.
+        // See #2767 and LOG4J2-2988 for details.
+        final String sslConfigId = createSslConfigurationId(sslConfig);
+        final String name = String.format("%s:%s:%d:%s", 
sslConfig.getProtocol(), host, port, sslConfigId);
+
         return (SslSocketManager) getManager(
                 name,
                 new SslFactoryData(
@@ -222,6 +237,49 @@ public class SslSocketManager extends TcpSocketManager {
                 FACTORY);
     }
 
+    /**
+     * Creates a unique identifier using the certificate issuers and serial 
numbers of the given SSL configuration.
+     *
+     * @param sslConfig an SSL configuration
+     * @return a unique identifier extracted from the given SSL configuration
+     */
+    private static String createSslConfigurationId(final SslConfiguration 
sslConfig) {
+        return String.valueOf(Stream.of(sslConfig.getKeyStoreConfig(), 
sslConfig.getTrustStoreConfig())
+                .flatMap(keyStoreConfig -> {
+                    final Enumeration<String> aliases;
+                    try {
+                        aliases = keyStoreConfig.getKeyStore().aliases();
+                    } catch (final KeyStoreException error) {
+                        LOGGER.error(
+                                "Failed reading the aliases for the key store 
located at `{}`",
+                                keyStoreConfig.getLocation(),
+                                error);
+                        return Stream.empty();
+                    }
+                    return 
Collections.list(aliases).stream().sorted().flatMap(alias -> {
+                        final X509Certificate certificate;
+                        try {
+                            certificate = (X509Certificate)
+                                    
keyStoreConfig.getKeyStore().getCertificate(alias);
+                        } catch (final KeyStoreException error) {
+                            LOGGER.error(
+                                    "Failed reading the certificate of alias 
`{}` for the key store located at `{}`",
+                                    alias,
+                                    keyStoreConfig.getLocation(),
+                                    error);
+                            return Stream.empty();
+                        }
+                        final String issuer =
+                                certificate.getIssuerX500Principal().getName();
+                        final String serialNumber =
+                                certificate.getSerialNumber().toString();
+                        return Stream.of(issuer, serialNumber);
+                    });
+                })
+                .collect(Collectors.toList())
+                .hashCode());
+    }
+
     @Override
     protected Socket createSocket(final InetSocketAddress socketAddress) 
throws IOException {
         final SSLSocketFactory socketFactory = 
createSslSocketFactory(sslConfig);
@@ -234,7 +292,7 @@ public class SslSocketManager extends TcpSocketManager {
         SSLSocketFactory socketFactory;
 
         if (sslConf != null) {
-            socketFactory = sslConf.getSslSocketFactory();
+            socketFactory = sslConf.getSslContext().getSocketFactory();
         } else {
             socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
         }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
index 7c5416210e..e6ba2a1366 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
@@ -102,7 +102,8 @@ public class UrlConnectionFactory {
                 httpURLConnection.setIfModifiedSince(lastModifiedMillis);
             }
             if (url.getProtocol().equals(HTTPS) && sslConfiguration != null) {
-                ((HttpsURLConnection) 
httpURLConnection).setSSLSocketFactory(sslConfiguration.getSslSocketFactory());
+                ((HttpsURLConnection) httpURLConnection)
+                        
.setSSLSocketFactory(sslConfiguration.getSslContext().getSocketFactory());
                 if (!sslConfiguration.isVerifyHostName()) {
                     ((HttpsURLConnection) 
httpURLConnection).setHostnameVerifier(LaxHostnameVerifier.INSTANCE);
                 }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/AbstractKeyStoreConfiguration.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/AbstractKeyStoreConfiguration.java
index ad928482d9..a70b71edd3 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/AbstractKeyStoreConfiguration.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/AbstractKeyStoreConfiguration.java
@@ -33,9 +33,10 @@ import org.apache.logging.log4j.core.util.NetUtils;
  */
 public class AbstractKeyStoreConfiguration extends 
StoreConfiguration<KeyStore> {
 
-    private final KeyStore keyStore;
     private final String keyStoreType;
 
+    private final transient KeyStore keyStore;
+
     public AbstractKeyStoreConfiguration(
             final String location, final PasswordProvider passwordProvider, 
final String keyStoreType)
             throws StoreConfigurationException {
@@ -114,7 +115,7 @@ public class AbstractKeyStoreConfiguration extends 
StoreConfiguration<KeyStore>
         }
     }
 
-    private InputStream openInputStream(final String filePathOrUri) {
+    private static InputStream openInputStream(final String filePathOrUri) {
         return 
ConfigurationSource.fromUri(NetUtils.toURI(filePathOrUri)).getInputStream();
     }
 
@@ -126,7 +127,6 @@ public class AbstractKeyStoreConfiguration extends 
StoreConfiguration<KeyStore>
     public int hashCode() {
         final int prime = 31;
         int result = super.hashCode();
-        result = prime * result + ((keyStore == null) ? 0 : 
keyStore.hashCode());
         result = prime * result + ((keyStoreType == null) ? 0 : 
keyStoreType.hashCode());
         return result;
     }
@@ -143,9 +143,6 @@ public class AbstractKeyStoreConfiguration extends 
StoreConfiguration<KeyStore>
             return false;
         }
         final AbstractKeyStoreConfiguration other = 
(AbstractKeyStoreConfiguration) obj;
-        if (!Objects.equals(keyStore, other.keyStore)) {
-            return false;
-        }
         if (!Objects.equals(keyStoreType, other.keyStoreType)) {
             return false;
         }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
index 6e23d5bb40..205f7b0d9d 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
@@ -161,7 +161,7 @@ public class KeyStoreConfiguration extends 
AbstractKeyStoreConfiguration {
      * Extension Reference Guide for information about these names.
      * @return a new KeyStoreConfiguration
      * @throws StoreConfigurationException Thrown if this call cannot load the 
KeyStore.
-     * @deprecated Use createKeyStoreConfiguration(String, char[], String, 
String)
+     * @deprecated Use {@link #createKeyStoreConfiguration(String, char[], 
String, String, String, String)}
      */
     @Deprecated
     public static KeyStoreConfiguration createKeyStoreConfiguration(
@@ -176,6 +176,10 @@ public class KeyStoreConfiguration extends 
AbstractKeyStoreConfiguration {
                 location, (password == null ? null : password.toCharArray()), 
keyStoreType, keyManagerFactoryAlgorithm);
     }
 
+    /**
+     * @deprecated Planned to be removed in the next major release
+     */
+    @Deprecated
     public KeyManagerFactory initKeyManagerFactory()
             throws NoSuchAlgorithmException, UnrecoverableKeyException, 
KeyStoreException {
         final KeyManagerFactory kmFactory = 
KeyManagerFactory.getInstance(this.keyManagerFactoryAlgorithm);
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/PasswordProvider.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/PasswordProvider.java
index ca61176a30..ec37de3b9e 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/PasswordProvider.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/PasswordProvider.java
@@ -26,6 +26,7 @@ package org.apache.logging.log4j.core.net.ssl;
  * is no longer needed.
  * </p>
  */
+@FunctionalInterface
 public interface PasswordProvider {
 
     /**
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java
index 68ee689b9e..cb24113bd9 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java
@@ -16,10 +16,7 @@
  */
 package org.apache.logging.log4j.core.net.ssl;
 
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
 import java.util.Objects;
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.KeyManagerFactory;
@@ -34,29 +31,42 @@ import 
org.apache.logging.log4j.core.config.plugins.PluginAttribute;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
 import org.apache.logging.log4j.status.StatusLogger;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.NullUnmarked;
+import org.jspecify.annotations.Nullable;
 
 /**
  *  SSL Configuration
  */
+@NullMarked
 @Plugin(name = "Ssl", category = Core.CATEGORY_NAME, printObject = true)
 public class SslConfiguration {
+
     private static final StatusLogger LOGGER = StatusLogger.getLogger();
-    private final KeyStoreConfiguration keyStoreConfig;
-    private final TrustStoreConfiguration trustStoreConfig;
-    private final SSLContext sslContext;
+
     private final String protocol;
+
     private final boolean verifyHostName;
 
+    @Nullable
+    private final KeyStoreConfiguration keyStoreConfig;
+
+    @Nullable
+    private final TrustStoreConfiguration trustStoreConfig;
+
+    private final transient SSLContext sslContext;
+
     private SslConfiguration(
-            final String protocol,
-            final KeyStoreConfiguration keyStoreConfig,
-            final TrustStoreConfiguration trustStoreConfig,
-            final boolean verifyHostName) {
+            @Nullable final String protocol,
+            final boolean verifyHostName,
+            @Nullable final KeyStoreConfiguration keyStoreConfig,
+            @Nullable final TrustStoreConfiguration trustStoreConfig) {
         this.keyStoreConfig = keyStoreConfig;
         this.trustStoreConfig = trustStoreConfig;
-        this.protocol = protocol == null ? SslConfigurationDefaults.PROTOCOL : 
protocol;
-        this.sslContext = this.createSslContext();
+        final String effectiveProtocol = protocol == null ? 
SslConfigurationDefaults.PROTOCOL : protocol;
+        this.protocol = effectiveProtocol;
         this.verifyHostName = verifyHostName;
+        this.sslContext = createSslContext(effectiveProtocol, keyStoreConfig, 
trustStoreConfig);
     }
 
     /**
@@ -71,157 +81,96 @@ public class SslConfiguration {
         }
     }
 
+    /**
+     * Gets the SSL socket factory of the configured SSL context.
+     *
+     * @return the SSL socket factory of the configured SSL context
+     * @deprecated Use {@link SSLContext#getSocketFactory()} on {@link 
#getSslContext()}
+     */
+    @Deprecated
     public SSLSocketFactory getSslSocketFactory() {
         return sslContext.getSocketFactory();
     }
 
+    /**
+     * Gets the SSL server socket factory of the configured SSL context.
+     *
+     * @return the SSL server socket factory of the configured SSL context
+     * @deprecated Use {@link SSLContext#getServerSocketFactory()} on {@link 
#getSslContext()}
+     */
+    @Deprecated
     public SSLServerSocketFactory getSslServerSocketFactory() {
         return sslContext.getServerSocketFactory();
     }
 
-    private SSLContext createSslContext() {
-        SSLContext context = null;
-
-        try {
-            context = createSslContextBasedOnConfiguration();
-            LOGGER.debug("Creating SSLContext with the given parameters");
-        } catch (final TrustStoreConfigurationException e) {
-            context = createSslContextWithTrustStoreFailure();
-        } catch (final KeyStoreConfigurationException e) {
-            context = createSslContextWithKeyStoreFailure();
-        }
-        return context;
-    }
-
-    private SSLContext createSslContextWithTrustStoreFailure() {
-        SSLContext context;
-
-        try {
-            context = createSslContextWithDefaultTrustManagerFactory();
-            LOGGER.debug("Creating SSLContext with default truststore");
-        } catch (final KeyStoreConfigurationException e) {
-            context = createDefaultSslContext();
-            LOGGER.debug("Creating SSLContext with default configuration");
-        }
-        return context;
-    }
-
-    private SSLContext createSslContextWithKeyStoreFailure() {
-        SSLContext context;
-
-        try {
-            context = createSslContextWithDefaultKeyManagerFactory();
-            LOGGER.debug("Creating SSLContext with default keystore");
-        } catch (final TrustStoreConfigurationException e) {
-            context = createDefaultSslContext();
-            LOGGER.debug("Creating SSLContext with default configuration");
-        }
-        return context;
-    }
-
-    private SSLContext createSslContextBasedOnConfiguration()
-            throws KeyStoreConfigurationException, 
TrustStoreConfigurationException {
-        return createSslContext(false, false);
-    }
-
-    private SSLContext createSslContextWithDefaultKeyManagerFactory() throws 
TrustStoreConfigurationException {
-        try {
-            return createSslContext(true, false);
-        } catch (final KeyStoreConfigurationException dummy) {
-            LOGGER.debug("Exception occurred while using default keystore. 
This should be a BUG");
-            return null;
-        }
-    }
-
-    private SSLContext createSslContextWithDefaultTrustManagerFactory() throws 
KeyStoreConfigurationException {
-        try {
-            return createSslContext(false, true);
-        } catch (final TrustStoreConfigurationException dummy) {
-            LOGGER.debug("Exception occurred while using default truststore. 
This should be a BUG");
-            return null;
-        }
-    }
-
-    private SSLContext createDefaultSslContext() {
+    private static SSLContext createDefaultSslContext(final String protocol) {
         try {
             return SSLContext.getDefault();
-        } catch (final NoSuchAlgorithmException e) {
-            LOGGER.error("Failed to create an SSLContext with default 
configuration", e);
-            return null;
+        } catch (final NoSuchAlgorithmException defaultContextError) {
+            LOGGER.error(
+                    "Failed to create an `SSLContext` using the default 
configuration, falling back to creating an empty one",
+                    defaultContextError);
+            try {
+                final SSLContext emptyContext = 
SSLContext.getInstance(protocol);
+                emptyContext.init(new KeyManager[0], new TrustManager[0], 
null);
+                return emptyContext;
+            } catch (final Exception emptyContextError) {
+                LOGGER.error("Failed to create an empty `SSLContext`", 
emptyContextError);
+                return null;
+            }
         }
     }
 
-    private SSLContext createSslContext(
-            final boolean loadDefaultKeyManagerFactory, final boolean 
loadDefaultTrustManagerFactory)
-            throws KeyStoreConfigurationException, 
TrustStoreConfigurationException {
+    private static SSLContext createSslContext(
+            final String protocol,
+            @Nullable final KeyStoreConfiguration keyStoreConfig,
+            @Nullable final TrustStoreConfiguration trustStoreConfig) {
         try {
-            KeyManager[] kManagers = null;
-            TrustManager[] tManagers = null;
-
-            final SSLContext newSslContext = 
SSLContext.getInstance(this.protocol);
-            if (!loadDefaultKeyManagerFactory) {
-                final KeyManagerFactory kmFactory = loadKeyManagerFactory();
-                kManagers = kmFactory.getKeyManagers();
-            }
-            if (!loadDefaultTrustManagerFactory) {
-                final TrustManagerFactory tmFactory = 
loadTrustManagerFactory();
-                tManagers = tmFactory.getTrustManagers();
-            }
-
-            newSslContext.init(kManagers, tManagers, null);
-            return newSslContext;
-        } catch (final NoSuchAlgorithmException e) {
-            LOGGER.error("No Provider supports a TrustManagerFactorySpi 
implementation for the specified protocol", e);
-            throw new TrustStoreConfigurationException(e);
-        } catch (final KeyManagementException e) {
-            LOGGER.error("Failed to initialize the SSLContext", e);
-            throw new KeyStoreConfigurationException(e);
+            final SSLContext sslContext = SSLContext.getInstance(protocol);
+            final KeyManager[] keyManagers = loadKeyManagers(keyStoreConfig);
+            final TrustManager[] trustManagers = 
loadTrustManagers(trustStoreConfig);
+            sslContext.init(keyManagers, trustManagers, null);
+            return sslContext;
+        } catch (final Exception error) {
+            LOGGER.error(
+                    "Failed to create an `SSLContext` using the provided 
configuration, falling back to a default instance",
+                    error);
+            return createDefaultSslContext(protocol);
         }
     }
 
-    private TrustManagerFactory loadTrustManagerFactory() throws 
TrustStoreConfigurationException {
-        if (trustStoreConfig == null) {
-            throw new TrustStoreConfigurationException(new Exception("The 
trustStoreConfiguration is null"));
+    private static KeyManager[] loadKeyManagers(@Nullable final 
KeyStoreConfiguration config) throws Exception {
+        if (config == null) {
+            return new KeyManager[0];
         }
-
+        final KeyManagerFactory factory = 
KeyManagerFactory.getInstance(config.getKeyManagerFactoryAlgorithm());
+        final char[] password = config.getPasswordAsCharArray();
         try {
-            return trustStoreConfig.initTrustManagerFactory();
-        } catch (final NoSuchAlgorithmException e) {
-            LOGGER.error("The specified algorithm is not available from the 
specified provider", e);
-            throw new TrustStoreConfigurationException(e);
-        } catch (final KeyStoreException e) {
-            LOGGER.error("Failed to initialize the TrustManagerFactory", e);
-            throw new TrustStoreConfigurationException(e);
+            factory.init(config.getKeyStore(), password);
+        } finally {
+            config.clearSecrets();
         }
+        return factory.getKeyManagers();
     }
 
-    private KeyManagerFactory loadKeyManagerFactory() throws 
KeyStoreConfigurationException {
-        if (keyStoreConfig == null) {
-            throw new KeyStoreConfigurationException(new Exception("The 
keyStoreConfiguration is null"));
-        }
-
-        try {
-            return keyStoreConfig.initKeyManagerFactory();
-        } catch (final NoSuchAlgorithmException e) {
-            LOGGER.error("The specified algorithm is not available from the 
specified provider", e);
-            throw new KeyStoreConfigurationException(e);
-        } catch (final KeyStoreException e) {
-            LOGGER.error("Failed to initialize the TrustManagerFactory", e);
-            throw new KeyStoreConfigurationException(e);
-        } catch (final UnrecoverableKeyException e) {
-            LOGGER.error("The key cannot be recovered (e.g. the given password 
is wrong)", e);
-            throw new KeyStoreConfigurationException(e);
+    private static TrustManager[] loadTrustManagers(@Nullable final 
TrustStoreConfiguration config) throws Exception {
+        if (config == null) {
+            return new TrustManager[0];
         }
+        final TrustManagerFactory factory = 
TrustManagerFactory.getInstance(config.getTrustManagerFactoryAlgorithm());
+        factory.init(config.getKeyStore());
+        return factory.getTrustManagers();
     }
 
     /**
      * Creates an SslConfiguration from a KeyStoreConfiguration and a 
TrustStoreConfiguration.
      *
-     * @param protocol The protocol, see <a 
href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext";>SSLContext
 Algorithms</a>
-     * @param keyStoreConfig The KeyStoreConfiguration.
+     * @param protocol         The protocol, see <a 
href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext";>SSLContext
 Algorithms</a>
+     * @param keyStoreConfig   The KeyStoreConfiguration.
      * @param trustStoreConfig The TrustStoreConfiguration.
      * @return a new SslConfiguration
      */
+    @NullUnmarked
     @PluginFactory
     public static SslConfiguration createSSLConfiguration(
             // @formatter:off
@@ -229,7 +178,7 @@ public class SslConfiguration {
             @PluginElement("KeyStore") final KeyStoreConfiguration 
keyStoreConfig,
             @PluginElement("TrustStore") final TrustStoreConfiguration 
trustStoreConfig) {
         // @formatter:on
-        return new SslConfiguration(protocol, keyStoreConfig, 
trustStoreConfig, false);
+        return new SslConfiguration(protocol, false, keyStoreConfig, 
trustStoreConfig);
     }
 
     /**
@@ -242,6 +191,7 @@ public class SslConfiguration {
      * @return a new SslConfiguration
      * @since 2.12
      */
+    @NullUnmarked
     public static SslConfiguration createSSLConfiguration(
             // @formatter:off
             @PluginAttribute("protocol") final String protocol,
@@ -249,7 +199,7 @@ public class SslConfiguration {
             @PluginElement("TrustStore") final TrustStoreConfiguration 
trustStoreConfig,
             @PluginAttribute("verifyHostName") final boolean verifyHostName) {
         // @formatter:on
-        return new SslConfiguration(protocol, keyStoreConfig, 
trustStoreConfig, verifyHostName);
+        return new SslConfiguration(protocol, verifyHostName, keyStoreConfig, 
trustStoreConfig);
     }
 
     @Override
@@ -269,13 +219,13 @@ public class SslConfiguration {
             return false;
         }
         final SslConfiguration other = (SslConfiguration) obj;
-        if (!Objects.equals(keyStoreConfig, other.keyStoreConfig)) {
+        if (!Objects.equals(protocol, other.protocol)) {
             return false;
         }
-        if (!Objects.equals(protocol, other.protocol)) {
+        if (!Objects.equals(verifyHostName, other.verifyHostName)) {
             return false;
         }
-        if (!Objects.equals(sslContext, other.sslContext)) {
+        if (!Objects.equals(keyStoreConfig, other.keyStoreConfig)) {
             return false;
         }
         if (!Objects.equals(trustStoreConfig, other.trustStoreConfig)) {
@@ -284,6 +234,14 @@ public class SslConfiguration {
         return true;
     }
 
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public boolean isVerifyHostName() {
+        return verifyHostName;
+    }
+
     public KeyStoreConfiguration getKeyStoreConfig() {
         return keyStoreConfig;
     }
@@ -295,12 +253,4 @@ public class SslConfiguration {
     public SSLContext getSslContext() {
         return sslContext;
     }
-
-    public String getProtocol() {
-        return protocol;
-    }
-
-    public boolean isVerifyHostName() {
-        return verifyHostName;
-    }
 }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactory.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactory.java
index 6c09ad2c09..2da16b886d 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactory.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfigurationFactory.java
@@ -27,7 +27,6 @@ import org.apache.logging.log4j.util.Strings;
 public class SslConfigurationFactory {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
-    private static final SslConfiguration sslConfiguration = 
createSslConfiguration(PropertiesUtil.getProperties());
 
     private static final String trustStorelocation = 
"log4j2.trustStoreLocation";
     private static final String trustStorePassword = 
"log4j2.trustStorePassword";
@@ -111,6 +110,6 @@ public class SslConfigurationFactory {
     }
 
     public static SslConfiguration getSslConfiguration() {
-        return sslConfiguration;
+        return createSslConfiguration(PropertiesUtil.getProperties());
     }
 }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/StoreConfiguration.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/StoreConfiguration.java
index e50a4a377e..0c4393bc19 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/StoreConfiguration.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/StoreConfiguration.java
@@ -58,7 +58,7 @@ public class StoreConfiguration<T> {
      */
     public void clearSecrets() {
         this.location = null;
-        this.passwordProvider = null;
+        this.passwordProvider = new MemoryPasswordProvider(new char[0]);
     }
 
     public String getLocation() {
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
index 6dc212303d..5b27b883b0 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
@@ -152,7 +152,7 @@ public class TrustStoreConfiguration extends 
AbstractKeyStoreConfiguration {
      * Secure Socket Extension Reference Guide for information these names.
      * @return a new TrustStoreConfiguration
      * @throws StoreConfigurationException Thrown if this instance cannot load 
the KeyStore.
-     * @deprecated Use createKeyStoreConfiguration(String, char[], String, 
String)
+     * @deprecated Use {@link #createKeyStoreConfiguration(String, char[], 
String, String, String, String)}
      */
     @Deprecated
     public static TrustStoreConfiguration createKeyStoreConfiguration(
@@ -172,6 +172,10 @@ public class TrustStoreConfiguration extends 
AbstractKeyStoreConfiguration {
                 trustManagerFactoryAlgorithm);
     }
 
+    /**
+     * @deprecated Planned to be removed in the next major release
+     */
+    @Deprecated
     public TrustManagerFactory initTrustManagerFactory() throws 
NoSuchAlgorithmException, KeyStoreException {
         final TrustManagerFactory tmFactory = 
TrustManagerFactory.getInstance(this.trustManagerFactoryAlgorithm);
         tmFactory.init(this.getKeyStore());
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/package-info.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/package-info.java
index db4860c1ff..7f7b26c282 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/package-info.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/package-info.java
@@ -18,7 +18,7 @@
  * Log4j 2 SSL support
  */
 @Export
-@Version("2.20.2")
+@Version("2.20.3")
 package org.apache.logging.log4j.core.net.ssl;
 
 import org.osgi.annotation.bundle.Export;
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java
index 7c02b12fe6..00552976b7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java
@@ -18,7 +18,7 @@
  * Implementation of Log4j 2.
  */
 @Export
-@Version("2.24.1")
+@Version("2.24.2")
 package org.apache.logging.log4j.core;
 
 import org.osgi.annotation.bundle.Export;
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java
index a0464fde4f..4ae5d46335 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java
@@ -23,6 +23,7 @@ import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.LoaderUtil;
 import org.apache.logging.log4j.util.PropertiesUtil;
+import org.jspecify.annotations.Nullable;
 
 /**
  * Load resources (or images) from various sources.
@@ -84,9 +85,9 @@ public final class Loader {
      * </ol>
      * @param resource The resource to load.
      * @param defaultLoader The default ClassLoader.
-     * @return A URL to the resource.
+     * @return A URL to the resource or {@code null}.
      */
-    public static URL getResource(final String resource, final ClassLoader 
defaultLoader) {
+    public static @Nullable URL getResource(final String resource, final 
ClassLoader defaultLoader) {
         try {
             ClassLoader classLoader = getThreadContextClassLoader();
             if (classLoader != null) {
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Source.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Source.java
index 580d3b73d4..5a79ab8b9a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Source.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Source.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.core.util;
 
+import static java.util.Objects.requireNonNull;
+
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.io.File;
 import java.io.IOException;
@@ -30,10 +32,13 @@ import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.ConfigurationSource;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.Strings;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
 
 /**
  * Represents the source for the logging configuration as an immutable object.
  */
+@NullMarked
 public class Source {
     private static final Logger LOGGER = StatusLogger.getLogger();
 
@@ -45,9 +50,9 @@ public class Source {
         }
     }
 
-    private static File toFile(final Path path) {
+    private static @Nullable File toFile(Path path) {
         try {
-            return Objects.requireNonNull(path, "path").toFile();
+            return requireNonNull(path, "path").toFile();
         } catch (final UnsupportedOperationException e) {
             return null;
         }
@@ -57,9 +62,9 @@ public class Source {
     @SuppressFBWarnings(
             value = "PATH_TRAVERSAL_IN",
             justification = "The URI should be specified in a configuration 
file.")
-    private static File toFile(final URI uri) {
+    private static @Nullable File toFile(URI uri) {
         try {
-            final String scheme = Objects.requireNonNull(uri, 
"uri").getScheme();
+            final String scheme = requireNonNull(uri, "uri").getScheme();
             if (Strings.isBlank(scheme) || scheme.equals("file")) {
                 return new File(uri.getPath());
             } else {
@@ -67,20 +72,20 @@ public class Source {
                 return null;
             }
         } catch (final Exception e) {
-            LOGGER.debug("uri is malformed: " + uri.toString());
+            LOGGER.debug("uri is malformed: " + uri);
             return null;
         }
     }
 
     private static URI toURI(final URL url) {
         try {
-            return Objects.requireNonNull(url, "url").toURI();
+            return requireNonNull(url, "url").toURI();
         } catch (final URISyntaxException e) {
             throw new IllegalArgumentException(e);
         }
     }
 
-    private final File file;
+    private final @Nullable File file;
     private final URI uri;
     private final String location;
 
@@ -88,21 +93,23 @@ public class Source {
      * Constructs a Source from a ConfigurationSource.
      *
      * @param source The ConfigurationSource.
+     * @throws NullPointerException if {@code source} is {@code null}.
      */
     public Source(final ConfigurationSource source) {
         this.file = source.getFile();
-        this.uri = source.getURI();
-        this.location = source.getLocation();
+        this.uri = requireNonNull(source.getURI());
+        this.location = requireNonNull(source.getLocation());
     }
 
     /**
      * Constructs a new {@code Source} with the specified file.
      * file.
      *
-     * @param file the file where the input stream originated
+     * @param file the file where the input stream originated.
+     * @throws NullPointerException if {@code file} is {@code null}.
      */
     public Source(final File file) {
-        this.file = Objects.requireNonNull(file, "file");
+        this.file = requireNonNull(file, "file");
         this.location = normalize(file);
         this.uri = file.toURI();
     }
@@ -111,9 +118,10 @@ public class Source {
      * Constructs a new {@code Source} from the specified Path.
      *
      * @param path the Path where the input stream originated
+     * @throws NullPointerException if {@code path} is {@code null}.
      */
     public Source(final Path path) {
-        final Path normPath = Objects.requireNonNull(path, "path").normalize();
+        final Path normPath = requireNonNull(path, "path").normalize();
         this.file = toFile(normPath);
         this.uri = normPath.toUri();
         this.location = normPath.toString();
@@ -123,9 +131,10 @@ public class Source {
      * Constructs a new {@code Source} from the specified URI.
      *
      * @param uri the URI where the input stream originated
+     * @throws NullPointerException if {@code uri} is {@code null}.
      */
     public Source(final URI uri) {
-        final URI normUri = Objects.requireNonNull(uri, "uri").normalize();
+        final URI normUri = requireNonNull(uri, "uri").normalize();
         this.uri = normUri;
         this.location = normUri.toString();
         this.file = toFile(normUri);
@@ -135,11 +144,12 @@ public class Source {
      * Constructs a new {@code Source} from the specified URI.
      *
      * @param uri the URI where the input stream originated
-     * @param lastModified Not used.
+     * @param ignored Not used.
      * @deprecated Use {@link Source#Source(URI)}.
+     * @throws NullPointerException if {@code uri} is {@code null}.
      */
     @Deprecated
-    public Source(final URI uri, final long lastModified) {
+    public Source(URI uri, long ignored) {
         this(uri);
     }
 
@@ -147,6 +157,7 @@ public class Source {
      * Constructs a new {@code Source} from the specified URL.
      *
      * @param url the URL where the input stream originated
+     * @throws NullPointerException if this URL is {@code null}.
      * @throws IllegalArgumentException if this URL is not formatted strictly 
according to RFC2396 and cannot be
      *         converted to a URI.
      */
@@ -174,7 +185,7 @@ public class Source {
      *
      * @return the configuration source file, or {@code null}
      */
-    public File getFile() {
+    public @Nullable File getFile() {
         return file;
     }
 
@@ -197,7 +208,7 @@ public class Source {
             value = "PATH_TRAVERSAL_IN",
             justification = "The `file`, `uri` and `location` fields come from 
Log4j properties.")
     public Path getPath() {
-        return file != null ? file.toPath() : uri != null ? Paths.get(uri) : 
Paths.get(location);
+        return file != null ? file.toPath() : Paths.get(uri);
     }
 
     /**
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java
index f2e50816d3..f4df3ebfa0 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java
@@ -459,7 +459,7 @@ public class FastDatePrinter implements DatePrinter, 
Serializable {
     }
 
     /**
-     * Creation method for new calender instances.
+     * Creation method for new calendar instances.
      * @return a new Calendar instance.
      */
     private Calendar newCalendar() {
diff --git 
a/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java
 
b/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java
index afa401341c..ab1963ea23 100644
--- 
a/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java
+++ 
b/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java
@@ -262,7 +262,8 @@ public class SmtpManager extends MailManager {
             if (smtpProtocol.equals("smtps")) {
                 final SslConfiguration sslConfiguration = 
data.getSslConfiguration();
                 if (sslConfiguration != null) {
-                    final SSLSocketFactory sslSocketFactory = 
sslConfiguration.getSslSocketFactory();
+                    final SSLSocketFactory sslSocketFactory =
+                            
sslConfiguration.getSslContext().getSocketFactory();
                     properties.put(prefix + ".ssl.socketFactory", 
sslSocketFactory);
                     properties.setProperty(
                             prefix + ".ssl.checkserveridentity", 
Boolean.toString(sslConfiguration.isVerifyHostName()));
diff --git 
a/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/Log4jTaglibLoggerContext.java
 
b/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/Log4jTaglibLoggerContext.java
index 46fb56f3de..97a7ab28bb 100644
--- 
a/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/Log4jTaglibLoggerContext.java
+++ 
b/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/Log4jTaglibLoggerContext.java
@@ -28,6 +28,8 @@ import 
org.apache.logging.log4j.message.ParameterizedMessageFactory;
 import org.apache.logging.log4j.spi.ExtendedLogger;
 import org.apache.logging.log4j.spi.LoggerContext;
 import org.apache.logging.log4j.spi.LoggerRegistry;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
 
 /**
  * This bridge between the tag library and the Log4j API ensures that 
instances of {@link Log4jTaglibLogger} are
@@ -35,6 +37,7 @@ import org.apache.logging.log4j.spi.LoggerRegistry;
  *
  * @since 2.0
  */
+@NullMarked
 final class Log4jTaglibLoggerContext implements LoggerContext {
 
     private static final ReadWriteLock LOCK = new ReentrantReadWriteLock();
@@ -67,7 +70,7 @@ final class Log4jTaglibLoggerContext implements LoggerContext 
{
     }
 
     @Override
-    public Log4jTaglibLogger getLogger(final String name, final MessageFactory 
messageFactory) {
+    public Log4jTaglibLogger getLogger(final String name, @Nullable final 
MessageFactory messageFactory) {
         final MessageFactory effectiveMessageFactory =
                 messageFactory != null ? messageFactory : 
DEFAULT_MESSAGE_FACTORY;
         final Log4jTaglibLogger oldLogger = loggerRegistry.getLogger(name, 
effectiveMessageFactory);
@@ -91,7 +94,7 @@ final class Log4jTaglibLoggerContext implements LoggerContext 
{
     }
 
     @Override
-    public boolean hasLogger(final String name, final MessageFactory 
messageFactory) {
+    public boolean hasLogger(final String name, @Nullable final MessageFactory 
messageFactory) {
         final MessageFactory effectiveMessageFactory =
                 messageFactory != null ? messageFactory : 
DEFAULT_MESSAGE_FACTORY;
         return loggerRegistry.hasLogger(name, effectiveMessageFactory);
diff --git 
a/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/package-info.java 
b/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/package-info.java
index ac85ecafea..9f8d273e7d 100644
--- 
a/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/package-info.java
+++ 
b/log4j-taglib/src/main/java/org/apache/logging/log4j/taglib/package-info.java
@@ -20,7 +20,7 @@
  * @since 2.0
  */
 @Export
-@Version("2.24.1")
+@Version("2.25.0")
 package org.apache.logging.log4j.taglib;
 
 import org.osgi.annotation.bundle.Export;
diff --git 
a/log4j-to-jul/src/main/java/org/apache/logging/log4j/tojul/JULLoggerContext.java
 
b/log4j-to-jul/src/main/java/org/apache/logging/log4j/tojul/JULLoggerContext.java
index ae6697fd98..6c18a83d48 100644
--- 
a/log4j-to-jul/src/main/java/org/apache/logging/log4j/tojul/JULLoggerContext.java
+++ 
b/log4j-to-jul/src/main/java/org/apache/logging/log4j/tojul/JULLoggerContext.java
@@ -22,6 +22,7 @@ import 
org.apache.logging.log4j.message.ParameterizedMessageFactory;
 import org.apache.logging.log4j.spi.ExtendedLogger;
 import org.apache.logging.log4j.spi.LoggerContext;
 import org.apache.logging.log4j.spi.LoggerRegistry;
+import org.jspecify.annotations.Nullable;
 
 /**
  * Implementation of Log4j {@link LoggerContext} SPI.
@@ -48,7 +49,7 @@ class JULLoggerContext implements LoggerContext {
     }
 
     @Override
-    public ExtendedLogger getLogger(final String name, final MessageFactory 
messageFactory) {
+    public ExtendedLogger getLogger(final String name, @Nullable final 
MessageFactory messageFactory) {
         final MessageFactory effectiveMessageFactory =
                 messageFactory != null ? messageFactory : 
DEFAULT_MESSAGE_FACTORY;
         final ExtendedLogger oldLogger = loggerRegistry.getLogger(name, 
effectiveMessageFactory);
@@ -60,7 +61,7 @@ class JULLoggerContext implements LoggerContext {
         return loggerRegistry.getLogger(name, effectiveMessageFactory);
     }
 
-    private static ExtendedLogger createLogger(final String name, final 
MessageFactory messageFactory) {
+    private static ExtendedLogger createLogger(final String name, @Nullable 
final MessageFactory messageFactory) {
         final Logger logger = Logger.getLogger(name);
         return new JULLogger(name, messageFactory, logger);
     }
@@ -71,7 +72,7 @@ class JULLoggerContext implements LoggerContext {
     }
 
     @Override
-    public boolean hasLogger(final String name, final MessageFactory 
messageFactory) {
+    public boolean hasLogger(final String name, @Nullable final MessageFactory 
messageFactory) {
         final MessageFactory effectiveMessageFactory =
                 messageFactory != null ? messageFactory : 
DEFAULT_MESSAGE_FACTORY;
         return loggerRegistry.hasLogger(name, effectiveMessageFactory);
diff --git 
a/log4j-to-jul/src/main/java/org/apache/logging/log4j/tojul/package-info.java 
b/log4j-to-jul/src/main/java/org/apache/logging/log4j/tojul/package-info.java
index 8308d5c2fa..68812bb248 100644
--- 
a/log4j-to-jul/src/main/java/org/apache/logging/log4j/tojul/package-info.java
+++ 
b/log4j-to-jul/src/main/java/org/apache/logging/log4j/tojul/package-info.java
@@ -21,7 +21,7 @@
  * @author <a href="http://www.vorburger.ch";>Michael Vorburger.ch</a> for 
Google
  */
 @Export
-@Version("2.24.1")
+@Version("2.25.0")
 package org.apache.logging.log4j.tojul;
 
 import org.osgi.annotation.bundle.Export;
diff --git 
a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java 
b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java
index 407a9636f0..50160e9063 100644
--- 
a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java
+++ 
b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java
@@ -21,6 +21,7 @@ import 
org.apache.logging.log4j.message.ParameterizedMessageFactory;
 import org.apache.logging.log4j.spi.ExtendedLogger;
 import org.apache.logging.log4j.spi.LoggerContext;
 import org.apache.logging.log4j.spi.LoggerRegistry;
+import org.jspecify.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,7 +42,7 @@ public class SLF4JLoggerContext implements LoggerContext {
     }
 
     @Override
-    public ExtendedLogger getLogger(final String name, final MessageFactory 
messageFactory) {
+    public ExtendedLogger getLogger(final String name, @Nullable final 
MessageFactory messageFactory) {
         final MessageFactory effectiveMessageFactory =
                 messageFactory != null ? messageFactory : 
DEFAULT_MESSAGE_FACTORY;
         final ExtendedLogger oldLogger = loggerRegistry.getLogger(name, 
effectiveMessageFactory);
@@ -53,7 +54,7 @@ public class SLF4JLoggerContext implements LoggerContext {
         return loggerRegistry.getLogger(name, effectiveMessageFactory);
     }
 
-    private static ExtendedLogger createLogger(final String name, final 
MessageFactory messageFactory) {
+    private static ExtendedLogger createLogger(final String name, @Nullable 
final MessageFactory messageFactory) {
         final Logger logger = LoggerFactory.getLogger(name);
         return new SLF4JLogger(name, messageFactory, logger);
     }
@@ -64,7 +65,7 @@ public class SLF4JLoggerContext implements LoggerContext {
     }
 
     @Override
-    public boolean hasLogger(final String name, final MessageFactory 
messageFactory) {
+    public boolean hasLogger(final String name, @Nullable final MessageFactory 
messageFactory) {
         final MessageFactory effectiveMessageFactory =
                 messageFactory != null ? messageFactory : 
DEFAULT_MESSAGE_FACTORY;
         return loggerRegistry.hasLogger(name, effectiveMessageFactory);
diff --git 
a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/package-info.java 
b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/package-info.java
index 12e4bedba2..8e6a1c3ac8 100644
--- a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/package-info.java
+++ b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/package-info.java
@@ -18,7 +18,7 @@
  * SLF4J support.
  */
 @Export
-@Version("2.24.1")
+@Version("2.25.0")
 package org.apache.logging.slf4j;
 
 import org.osgi.annotation.bundle.Export;

Reply via email to