You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ma...@apache.org on 2023/10/01 22:38:57 UTC

[logging-log4j2] branch main updated (675fa46629 -> 589dcdaabf)

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

mattsicker pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


    from 675fa46629 Clean up some warnings
     new 9f88fe5884 Clean up more warnings
     new 78f728af51 Add some javadocs
     new 589dcdaabf Clean up and better document LoaderUtil

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../log4j/config/PropertiesConfiguration.java      |   2 +-
 .../apache/logging/log4j/util/LoaderUtilTest.java  |   4 +-
 .../apache/logging/log4j/spi/LoggingSystem.java    |   2 +-
 .../java/org/apache/logging/log4j/util/Cast.java   |  12 +
 .../org/apache/logging/log4j/util/LoaderUtil.java  | 425 +++++++++++++--------
 .../apache/logging/log4j/util/PropertiesUtil.java  |  14 +-
 .../log4j/util/PropertyFilePropertySource.java     |  14 +-
 .../log4j/core/config/AbstractConfiguration.java   |   7 +
 .../logging/log4j/core/config/AppenderControl.java |   2 +-
 .../log4j/core/config/ConfigurationSource.java     |  14 +-
 .../log4j/core/config/CronScheduledFuture.java     |  10 +-
 .../log4j/core/config/DefaultAdvertiser.java       |   2 +-
 .../log4j/core/net/UrlConnectionFactory.java       |   4 +-
 13 files changed, 313 insertions(+), 199 deletions(-)


[logging-log4j2] 01/03: Clean up more warnings

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mattsicker pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 9f88fe588424a95b8add17cc844157f0b7c37f50
Author: Matt Sicker <ma...@apache.org>
AuthorDate: Sun Oct 1 14:29:02 2023 -0500

    Clean up more warnings
    
    Signed-off-by: Matt Sicker <ma...@apache.org>
---
 .../apache/logging/log4j/core/config/AppenderControl.java  |  2 +-
 .../logging/log4j/core/config/ConfigurationSource.java     | 14 +++-----------
 .../logging/log4j/core/config/CronScheduledFuture.java     | 10 +++++-----
 .../logging/log4j/core/config/DefaultAdvertiser.java       |  2 +-
 .../logging/log4j/core/net/UrlConnectionFactory.java       |  4 ++--
 5 files changed, 12 insertions(+), 20 deletions(-)

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControl.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControl.java
index ccf85f291a..8a2b27eb8a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControl.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControl.java
@@ -119,7 +119,7 @@ public class AppenderControl extends AbstractFilterable {
             recursive.set(this);
             callAppender0(event);
         } finally {
-            recursive.set(null);
+            recursive.remove();
         }
     }
 
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 409faaae50..73ee81c508 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
@@ -177,15 +177,15 @@ public class ConfigurationSource {
     }
 
     private boolean isFile() {
-        return source == null ? false : source.getFile() != null;
+        return source != null && source.getFile() != null;
     }
 
     private boolean isURL() {
-        return source == null ? false : source.getURI() != null;
+        return source != null && source.getURI() != null;
     }
 
     private boolean isLocation() {
-        return source == null ? false : source.getLocation() != null;
+        return source != null && source.getLocation() != null;
     }
 
     /**
@@ -198,14 +198,6 @@ public class ConfigurationSource {
         return source == null ? null : source.getURL();
     }
 
-    /**
-     * @deprecated Not used internally, no replacement. TODO remove and make source final.
-     */
-    @Deprecated
-    public void setSource(final Source source) {
-        this.source = source;
-    }
-
     public void setData(final byte[] data) {
         this.data = data;
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CronScheduledFuture.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CronScheduledFuture.java
index 63f060be64..a48b3fa7a8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CronScheduledFuture.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CronScheduledFuture.java
@@ -23,6 +23,8 @@ import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+import org.apache.logging.log4j.util.Cast;
+
 /**
  *
  */
@@ -68,19 +70,17 @@ public class CronScheduledFuture<V> implements ScheduledFuture<V> {
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public V get() throws InterruptedException, ExecutionException {
-        return (V) futureData.scheduledFuture.get();
+        return Cast.cast(futureData.scheduledFuture.get());
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public V get(final long timeout, final TimeUnit unit)
             throws InterruptedException, ExecutionException, TimeoutException {
-        return (V) futureData.scheduledFuture.get(timeout, unit);
+        return Cast.cast(futureData.scheduledFuture.get(timeout, unit));
     }
 
-    private class FutureData {
+    private static class FutureData {
 
         private final ScheduledFuture<?> scheduledFuture;
         private final Date runDate;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultAdvertiser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultAdvertiser.java
index 94951c2338..21e6ec99fb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultAdvertiser.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultAdvertiser.java
@@ -41,7 +41,7 @@ public class DefaultAdvertiser implements Advertiser {
 
     /**
      * Does nothing.
-     * @param advertisedObject
+     * @param advertisedObject ignored
      */
     @Override
     public void unadvertise(final Object advertisedObject) {
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 c37315e784..79e3f5c00a 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
@@ -32,6 +32,7 @@ import org.apache.logging.log4j.core.net.ssl.LaxHostnameVerifier;
 import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
 import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory;
 import org.apache.logging.log4j.core.util.AuthorizationProvider;
+import org.apache.logging.log4j.util.Cast;
 import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.PropertyEnvironment;
 import org.apache.logging.log4j.util.Strings;
@@ -57,7 +58,6 @@ public class UrlConnectionFactory {
     private static final String NO_PROTOCOLS = "_none";
     public static final String ALLOWED_PROTOCOLS = "log4j2.Configuration.allowedProtocols";
 
-    @SuppressWarnings("unchecked")
     public static <T extends URLConnection> T createConnection(final URL url, final long lastModifiedMillis,
             final SslConfiguration sslConfiguration, final AuthorizationProvider authorizationProvider)
         throws IOException {
@@ -110,7 +110,7 @@ public class UrlConnectionFactory {
         } else {
             urlConnection = url.openConnection();
         }
-        return (T) urlConnection;
+        return Cast.cast(urlConnection);
     }
 
     public static URLConnection createConnection(final URL url) throws IOException {


[logging-log4j2] 03/03: Clean up and better document LoaderUtil

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mattsicker pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 589dcdaabf21a6da07d8979cc25ded5ed975d8b4
Author: Matt Sicker <ma...@apache.org>
AuthorDate: Sun Oct 1 17:38:44 2023 -0500

    Clean up and better document LoaderUtil
    
    This makes a few updates here. First, javadoc comments have been updated to properly document all the potential exceptions they throw. Next, unchecked exception variants of methods here have been created. Furthermore, use of SecurityManager has been overhauled to be more consistent. Finally, some unused functionality was removed.
    
    Signed-off-by: Matt Sicker <ma...@apache.org>
---
 .../log4j/config/PropertiesConfiguration.java      |   2 +-
 .../apache/logging/log4j/util/LoaderUtilTest.java  |   4 +-
 .../apache/logging/log4j/spi/LoggingSystem.java    |   2 +-
 .../org/apache/logging/log4j/util/LoaderUtil.java  | 425 +++++++++++++--------
 .../apache/logging/log4j/util/PropertiesUtil.java  |  14 +-
 .../log4j/util/PropertyFilePropertySource.java     |  14 +-
 6 files changed, 282 insertions(+), 179 deletions(-)

diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
index eee359c47e..95ed6f578e 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
@@ -592,7 +592,7 @@ public class PropertiesConfiguration extends Log4j1Configuration {
     private static <T> T newInstanceOf(final String className, final String type) {
         try {
             return LoaderUtil.newInstanceOf(className);
-        } catch (ReflectiveOperationException ex) {
+        } catch (ReflectiveOperationException | LinkageError | RuntimeException ex) {
             LOGGER.error("Unable to create {} {} due to {}:{}", type, className, ex.getClass().getSimpleName(), ex.getMessage(), ex);
             return null;
         }
diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java
index 59db7bf47e..5ae0bc64ae 100644
--- a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java
@@ -49,10 +49,10 @@ public class LoaderUtilTest {
         };
         thread.setContextClassLoader(loader);
         try {
-            assertEquals(0, LoaderUtil.findUrlResources("Log4j-charsets.properties", false).size());
+            assertEquals(0, LoaderUtil.findUrlResources("Log4j-charsets.properties").size());
 
             LoaderUtil.forceTcclOnly = false;
-            assertEquals(1, LoaderUtil.findUrlResources("Log4j-charsets.properties", false).size());
+            assertEquals(1, LoaderUtil.findUrlResources("Log4j-charsets.properties").size());
         } finally {
             thread.setContextClassLoader(tccl);
         }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
index a85dfd514c..b6e3a93922 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
@@ -221,7 +221,7 @@ public class LoggingSystem {
     }
 
     private static List<Provider> loadLegacyProviders() {
-        return LoaderUtil.findUrlResources(PROVIDER_RESOURCE, false)
+        return LoaderUtil.findUrlResources(PROVIDER_RESOURCE)
                 .stream()
                 .map(urlResource -> loadLegacyProvider(urlResource.getUrl(), urlResource.getClassLoader()))
                 .filter(Objects::nonNull)
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java
index 37c4de0784..7a405fdafc 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java
@@ -17,6 +17,7 @@
 package org.apache.logging.log4j.util;
 
 import java.io.IOException;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.security.AccessController;
@@ -41,26 +42,37 @@ public final class LoaderUtil {
 
     private static final ClassLoader[] EMPTY_CLASS_LOADER_ARRAY = {};
 
-    private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager();
-
     // this variable must be lazily loaded; otherwise, we get a nice circular class loading problem where LoaderUtil
     // wants to use PropertiesUtil, but then PropertiesUtil wants to use LoaderUtil.
     private static Boolean ignoreTCCL;
 
+    private static final RuntimePermission GET_CLASS_LOADER = new RuntimePermission("getClassLoader");
     private static final boolean GET_CLASS_LOADER_DISABLED;
 
-    protected static Boolean forceTcclOnly;
+    static Boolean forceTcclOnly;
 
     private static final PrivilegedAction<ClassLoader> TCCL_GETTER = new ThreadContextClassLoaderGetter();
+    private static final PrivilegedAction<ClassLoader[]> CLASSLOADER_ACCUMULATOR = new ClassLoaderAccumulator();
 
     static {
-        if (SECURITY_MANAGER != null) {
+        if (System.getSecurityManager() != null) {
             boolean getClassLoaderDisabled;
             try {
-                SECURITY_MANAGER.checkPermission(new RuntimePermission("getClassLoader"));
+                AccessController.checkPermission(GET_CLASS_LOADER);
+                // seems like we'll be ok
                 getClassLoaderDisabled = false;
             } catch (final SecurityException ignored) {
-                getClassLoaderDisabled = true;
+                try {
+                    // let's see if we can obtain that permission
+                    AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+                        AccessController.checkPermission(GET_CLASS_LOADER);
+                        return null;
+                    }, null, GET_CLASS_LOADER);
+                    getClassLoaderDisabled = false;
+                } catch (final SecurityException ignore) {
+                    // no chance
+                    getClassLoaderDisabled = true;
+                }
             }
             GET_CLASS_LOADER_DISABLED = getClassLoaderDisabled;
         } else {
@@ -73,6 +85,7 @@ public final class LoaderUtil {
 
     /**
      * Returns the ClassLoader to use.
+     *
      * @return the ClassLoader.
      */
     public static ClassLoader getClassLoader() {
@@ -81,31 +94,18 @@ public final class LoaderUtil {
 
     // TODO: this method could use some explanation
     public static ClassLoader getClassLoader(final Class<?> class1, final Class<?> class2) {
-        final ClassLoader threadContextClassLoader = getThreadContextClassLoader();
-        final ClassLoader loader1 = class1 == null ? null : class1.getClassLoader();
-        final ClassLoader loader2 = class2 == null ? null : class2.getClassLoader();
-
-        if (isChild(threadContextClassLoader, loader1)) {
-            return isChild(threadContextClassLoader, loader2) ? threadContextClassLoader : loader2;
-        }
-        return isChild(loader1, loader2) ? loader1 : loader2;
-    }
-
-    /**
-     * Gets the current Thread ClassLoader. Returns the system ClassLoader if the TCCL is {@code null}. If the system
-     * ClassLoader is {@code null} as well, then the ClassLoader for this class is returned. If running with a
-     * {@link SecurityManager} that does not allow access to the Thread ClassLoader or system ClassLoader, then the
-     * ClassLoader for this class is returned.
-     *
-     * @return the current ThreadContextClassLoader.
-     */
-    public static ClassLoader getThreadContextClassLoader() {
-        if (GET_CLASS_LOADER_DISABLED) {
-            // we can at least get this class's ClassLoader regardless of security context
-            // however, if this is null, there's really no option left at this point
-            return LoaderUtil.class.getClassLoader();
-        }
-        return SECURITY_MANAGER == null ? TCCL_GETTER.run() : AccessController.doPrivileged(TCCL_GETTER);
+        PrivilegedAction<ClassLoader> action = () -> {
+            final ClassLoader loader1 = class1 == null ? null : class1.getClassLoader();
+            final ClassLoader loader2 = class2 == null ? null : class2.getClassLoader();
+            final ClassLoader referenceLoader = GET_CLASS_LOADER_DISABLED
+                    ? getThisClassLoader()
+                    : Thread.currentThread().getContextClassLoader();
+            if (isChild(referenceLoader, loader1)) {
+                return isChild(referenceLoader, loader2) ? referenceLoader : loader2;
+            }
+            return isChild(loader1, loader2) ? loader1 : loader2;
+        };
+        return AccessController.doPrivileged(action, null, GET_CLASS_LOADER);
     }
 
     /**
@@ -129,66 +129,101 @@ public final class LoaderUtil {
     }
 
     /**
+     * Looks up the ClassLoader for this current thread. If this class does not have the runtime permission
+     * {@code getClassLoader}, then the only ClassLoader this attempts to look up is the loader behind this
+     * class. When a SecurityManager is installed, this attempts to make a privileged call to get the current
+     * {@linkplain Thread#getContextClassLoader() thread context ClassLoader}, falling back to either the
+     * ClassLoader of this class or the {@linkplain ClassLoader#getSystemClassLoader() system ClassLoader}.
+     * When no SecurityManager is present, the same lookups are performed without use of {@link AccessController}.
+     * If none of these strategies can obtain a ClassLoader, then this returns {@code null}.
      *
+     * @return the current thread's ClassLoader, a fallback loader, or null if no fallback can be determined
      */
+    public static ClassLoader getThreadContextClassLoader() {
+        if (GET_CLASS_LOADER_DISABLED) {
+            // we can at least get this class's ClassLoader regardless of security context
+            // however, if this is null, there's really no option left at this point
+            try {
+                return getThisClassLoader();
+            } catch (final SecurityException ignored) {
+                return null;
+            }
+        }
+        return AccessController.doPrivileged(TCCL_GETTER, null, GET_CLASS_LOADER);
+    }
+
+    public static ClassLoader[] getClassLoaders() {
+        return AccessController.doPrivileged(CLASSLOADER_ACCUMULATOR, null, GET_CLASS_LOADER);
+    }
+
+    private static ClassLoader getThisClassLoader() {
+        return LoaderUtil.class.getClassLoader();
+    }
+
     private static class ThreadContextClassLoaderGetter implements PrivilegedAction<ClassLoader> {
         @Override
         public ClassLoader run() {
-            final ClassLoader cl = Thread.currentThread().getContextClassLoader();
-            if (cl != null) {
-                return cl;
+            final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+            if (contextClassLoader != null) {
+                return contextClassLoader;
+            }
+            final ClassLoader thisClassLoader = getThisClassLoader();
+            if (thisClassLoader != null || GET_CLASS_LOADER_DISABLED) {
+                return thisClassLoader;
             }
-            final ClassLoader ccl = LoaderUtil.class.getClassLoader();
-            return ccl == null && !GET_CLASS_LOADER_DISABLED ? ClassLoader.getSystemClassLoader() : ccl;
+            return ClassLoader.getSystemClassLoader();
         }
     }
 
-    public static ClassLoader[] getClassLoaders() {
-        final Collection<ClassLoader> classLoaders = new LinkedHashSet<>();
-        final ClassLoader tcl = getThreadContextClassLoader();
-        if (tcl != null) {
-            classLoaders.add(tcl);
-        }
-        final ModuleLayer layer = LoaderUtil.class.getModule().getLayer();
-        if (layer == null) {
-            if (!isForceTccl()) {
-                accumulateClassLoaders(LoaderUtil.class.getClassLoader(), classLoaders);
-                accumulateClassLoaders(tcl == null ? null : tcl.getParent(), classLoaders);
-                final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
-                if (systemClassLoader != null) {
-                    classLoaders.add(systemClassLoader);
-                }
+    private static class ClassLoaderAccumulator implements PrivilegedAction<ClassLoader[]> {
+        @Override
+        public ClassLoader[] run() {
+            final Collection<ClassLoader> classLoaders = new LinkedHashSet<>();
+            final ClassLoader tcl = TCCL_GETTER.run();
+            if (tcl != null) {
+                classLoaders.add(tcl);
             }
-        } else {
-            accumulateLayerClassLoaders(layer, classLoaders);
-            if (layer != ModuleLayer.boot()) {
-                for (final Module module : ModuleLayer.boot().modules()) {
-                    accumulateClassLoaders(module.getClassLoader(), classLoaders);
+            final ModuleLayer layer = LoaderUtil.class.getModule().getLayer();
+            if (layer == null) {
+                if (!isForceTccl()) {
+                    accumulateClassLoaders(getThisClassLoader(), classLoaders);
+                    accumulateClassLoaders(tcl == null ? null : tcl.getParent(), classLoaders);
+                    final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+                    if (systemClassLoader != null) {
+                        classLoaders.add(systemClassLoader);
+                    }
+                }
+            } else {
+                accumulateLayerClassLoaders(layer, classLoaders);
+                if (layer != ModuleLayer.boot()) {
+                    for (final Module module : ModuleLayer.boot().modules()) {
+                        accumulateClassLoaders(module.getClassLoader(), classLoaders);
+                    }
                 }
             }
+            return classLoaders.toArray(EMPTY_CLASS_LOADER_ARRAY);
         }
-        return classLoaders.toArray(EMPTY_CLASS_LOADER_ARRAY);
-    }
 
-    private static void accumulateLayerClassLoaders(final ModuleLayer layer, final Collection<ClassLoader> classLoaders) {
-        for (final Module module : layer.modules()) {
-            accumulateClassLoaders(module.getClassLoader(), classLoaders);
-        }
-        if (layer.parents().size() > 0) {
-            for (final ModuleLayer parent : layer.parents()) {
-                accumulateLayerClassLoaders(parent, classLoaders);
+        private static void accumulateLayerClassLoaders(final ModuleLayer layer, final Collection<ClassLoader> classLoaders) {
+            for (final Module module : layer.modules()) {
+                accumulateClassLoaders(module.getClassLoader(), classLoaders);
+            }
+            if (!layer.parents().isEmpty()) {
+                for (final ModuleLayer parent : layer.parents()) {
+                    accumulateLayerClassLoaders(parent, classLoaders);
+                }
             }
         }
-    }
 
-    /**
-     * Adds the provided loader to the loaders collection, and traverses up the tree until either a null
-     * value or a classloader which has already been added is encountered.
-     */
-    private static void accumulateClassLoaders(final ClassLoader loader, final Collection<ClassLoader> loaders) {
-        // Some implementations may use null to represent the bootstrap class loader.
-        if (loader != null && loaders.add(loader)) {
-            accumulateClassLoaders(loader.getParent(), loaders);
+        /**
+         * Adds the provided loader to the loaders collection, and traverses up the tree until either a null
+         * value or a classloader which has already been added is encountered.
+         */
+        private static void accumulateClassLoaders(final ClassLoader loader, final Collection<ClassLoader> loaders) {
+            // Some implementations may use null to represent the bootstrap class loader.
+            if (loader != null && loaders.add(loader)) {
+                accumulateClassLoaders(loader.getParent(), loaders);
+            }
         }
     }
 
@@ -201,8 +236,8 @@ public final class LoaderUtil {
      */
     public static boolean isClassAvailable(final String className) {
         try {
-            final Class<?> clazz = loadClass(className);
-            return clazz != null;
+            loadClass(className);
+            return true;
         } catch (final ClassNotFoundException | LinkageError e) {
             return false;
         } catch (final Throwable e) {
@@ -212,110 +247,192 @@ public final class LoaderUtil {
     }
 
     /**
-     * Loads a class by name. This method respects the {@value LoggingSystemProperty#LOADER_IGNORE_THREAD_CONTEXT_LOADER}
-     * Log4j property. If this property is specified and set to anything besides {@code false}, then this class's
-     * ClassLoader will be used as specified by {@link Class#forName(String)}.
+     * Loads and initializes a class given its fully qualified class name. This method respects the
+     * {@link LoggingSystemProperty#LOADER_IGNORE_THREAD_CONTEXT_LOADER} Log4j property. If this property is specified
+     * and set to anything besides {@code false}, then this class's ClassLoader will be used.
      *
-     * @param className The class name.
-     * @return the Class for the given name.
-     * @throws ClassNotFoundException if the specified class name could not be found
+     * @param className fully qualified class name to load
+     * @return the loaded class
+     * @throws ClassNotFoundException      if the specified class name could not be found
+     * @throws ExceptionInInitializerError if an exception is thrown during class initialization
+     * @throws LinkageError                if the linkage of the class fails for any other reason
      * @since 2.1
      */
     public static Class<?> loadClass(final String className) throws ClassNotFoundException {
-        if (isIgnoreTccl()) {
-            return Class.forName(className);
+        ClassLoader classLoader = isIgnoreTccl() ? getThisClassLoader() : getThreadContextClassLoader();
+        if (classLoader == null) {
+            classLoader = getThisClassLoader();
         }
+        return Class.forName(className, true, classLoader);
+    }
+
+    /**
+     * Loads and initializes a class given its fully qualified class name. All checked reflective operation
+     * exceptions are translated into equivalent {@link LinkageError} classes.
+     *
+     * @param className fully qualified class name to load
+     * @return the loaded class
+     * @throws NoClassDefFoundError        if the specified class name could not be found
+     * @throws ExceptionInInitializerError if an exception is thrown during class initialization
+     * @throws LinkageError                if the linkage of the class fails for any other reason
+     * @see #loadClass(String)
+     * @since 3.0.0
+     */
+    public static Class<?> loadClassUnchecked(final String className) {
         try {
-            final ClassLoader tccl = getThreadContextClassLoader();
-            if (tccl != null) {
-                return tccl.loadClass(className);
-            }
-        } catch (final Throwable ignored) {
+            return loadClass(className);
+        } catch (final ClassNotFoundException e) {
+            final NoClassDefFoundError error = new NoClassDefFoundError(e.getMessage());
+            error.initCause(e);
+            throw error;
         }
-        return Class.forName(className);
     }
 
     /**
      * Loads and instantiates a Class using the default constructor.
      *
-     * @param <T> the type of the class modeled by the {@code Class} object.
+     * @param <T>   the type of the class modeled by the {@code Class} object.
      * @param clazz The class.
      * @return new instance of the class.
-     * @throws IllegalAccessException if the class can't be instantiated through a public constructor
-     * @throws InstantiationException if there was an exception whilst instantiating the class
-     * @throws InvocationTargetException if there was an exception whilst constructing the class
+     * @throws NoSuchMethodException       if no zero-arg constructor exists
+     * @throws SecurityException           if this class is not allowed to access declared members of the provided class
+     * @throws IllegalAccessException      if the class can't be instantiated through a public constructor
+     * @throws InstantiationException      if the provided class is abstract or an interface
+     * @throws InvocationTargetException   if an exception is thrown by the constructor
+     * @throws ExceptionInInitializerError if an exception was thrown while initializing the class
      * @since 2.7
      */
     public static <T> T newInstanceOf(final Class<T> clazz)
-            throws InstantiationException, IllegalAccessException, InvocationTargetException {
+            throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        final Constructor<T> constructor = clazz.getDeclaredConstructor();
+        return constructor.newInstance();
+    }
+
+    /**
+     * Creates an instance of the provided class using the default constructor. All checked reflective operation
+     * exceptions are translated into {@link LinkageError} or {@link InternalException}.
+     *
+     * @param clazz class to instantiate
+     * @param <T>   the type of the object being instantiated
+     * @return instance of the class
+     * @throws NoSuchMethodError  if no zero-arg constructor exists
+     * @throws SecurityException  if this class is not allowed to access declared members of the provided class
+     * @throws InternalException  if an exception is thrown by the constructor
+     * @throws InstantiationError if the provided class is abstract or an interface
+     * @throws IllegalAccessError if the class cannot be accessed
+     * @since 3.0.0
+     */
+    public static <T> T newInstanceOfUnchecked(final Class<T> clazz) {
         try {
-            return clazz.getConstructor().newInstance();
-        } catch (final NoSuchMethodException ignored) {
-            // FIXME: looking at the code for Class.newInstance(), this seems to do the same thing as above
-            return clazz.newInstance();
+            return newInstanceOf(clazz);
+        } catch (final NoSuchMethodException e) {
+            final NoSuchMethodError error = new NoSuchMethodError(e.getMessage());
+            error.initCause(e);
+            throw error;
+        } catch (final InvocationTargetException e) {
+            final Throwable cause = e.getCause();
+            throw new InternalException(cause);
+        } catch (final InstantiationException e) {
+            final InstantiationError error = new InstantiationError(e.getMessage());
+            error.initCause(e);
+            throw error;
+        } catch (final IllegalAccessException e) {
+            final IllegalAccessError error = new IllegalAccessError(e.getMessage());
+            error.initCause(e);
+            throw error;
         }
     }
 
     /**
      * Loads and instantiates a Class using the default constructor.
      *
-     * @param className The class name.
-     * @param <T> The class's type.
-     * @return new instance of the class.
-     * @throws ClassNotFoundException if the class isn't available to the usual ClassLoaders
-     * @throws IllegalAccessException if the class can't be instantiated through a public constructor
-     * @throws InstantiationException if there was an exception whilst instantiating the class
-     * @throws InvocationTargetException if there was an exception whilst constructing the class
+     * @param className fully qualified class name to load, initialize, and construct
+     * @param <T>       type the class must be compatible with
+     * @return new instance of the class
+     * @throws ClassNotFoundException      if the class isn't available to the usual ClassLoaders
+     * @throws ExceptionInInitializerError if an exception was thrown while initializing the class
+     * @throws LinkageError                if the linkage of the class fails for any other reason
+     * @throws ClassCastException          if the class is not compatible with the generic type parameter provided
+     * @throws NoSuchMethodException       if no zero-arg constructor exists
+     * @throws SecurityException           if this class is not allowed to access declared members of the provided class
+     * @throws IllegalAccessException      if the class can't be instantiated through a public constructor
+     * @throws InstantiationException      if the provided class is abstract or an interface
+     * @throws InvocationTargetException   if an exception is thrown by the constructor
      * @since 2.1
      */
-    @SuppressWarnings("unchecked")
     public static <T> T newInstanceOf(final String className) throws ClassNotFoundException, IllegalAccessException,
-            InstantiationException, InvocationTargetException {
-        return newInstanceOf((Class<T>) loadClass(className));
+            InstantiationException, InvocationTargetException, NoSuchMethodException {
+        final Class<T> clazz = Cast.cast(loadClass(className));
+        return newInstanceOf(clazz);
+    }
+
+    /**
+     * Loads and instantiates a class by name using its default constructor. All checked reflective operation
+     * exceptions are translated into corresponding {@link LinkageError} classes.
+     *
+     * @param className fully qualified class name to load, initialize, and construct
+     * @param <T>       type the class must be compatible with
+     * @return new instance of the class
+     * @throws NoClassDefFoundError        if the specified class name could not be found
+     * @throws ExceptionInInitializerError if an exception is thrown during class initialization
+     * @throws ClassCastException          if the class is not compatible with the generic type parameter provided
+     * @throws NoSuchMethodError           if no zero-arg constructor exists
+     * @throws SecurityException           if this class is not allowed to access declared members of the provided class
+     * @throws InternalException           if an exception is thrown by the constructor
+     * @throws InstantiationError          if the provided class is abstract or an interface
+     * @throws IllegalAccessError          if the class cannot be accessed
+     * @throws LinkageError                if the linkage of the class fails for any other reason
+     */
+    public static <T> T newInstanceOfUnchecked(final String className) {
+        final Class<T> clazz = Cast.cast(loadClassUnchecked(className));
+        return newInstanceOfUnchecked(clazz);
     }
 
     /**
      * Loads and instantiates a derived class using its default constructor.
      *
      * @param className The class name.
-     * @param clazz The class to cast it to.
-     * @param <T> The type of the class to check.
+     * @param clazz     The class to cast it to.
+     * @param <T>       The type of the class to check.
      * @return new instance of the class cast to {@code T}
-     * @throws ClassNotFoundException if the class isn't available to the usual ClassLoaders
-     * @throws IllegalAccessException if the class can't be instantiated through a public constructor
-     * @throws InstantiationException if there was an exception whilst instantiating the class
-     * @throws InvocationTargetException if there was an exception whilst constructing the class
-     * @throws ClassCastException if the constructed object isn't type compatible with {@code T}
+     * @throws ClassNotFoundException      if the class isn't available to the usual ClassLoaders
+     * @throws ExceptionInInitializerError if an exception is thrown during class initialization
+     * @throws LinkageError                if the linkage of the class fails for any other reason
+     * @throws ClassCastException          if the constructed object isn't type compatible with {@code T}
+     * @throws NoSuchMethodException       if no zero-arg constructor exists
+     * @throws SecurityException           if this class is not allowed to access declared members of the provided class
+     * @throws IllegalAccessException      if the class can't be instantiated through a public constructor
+     * @throws InstantiationException      if the provided class is abstract or an interface
+     * @throws InvocationTargetException   if there was an exception whilst constructing the class
      * @since 2.1
      */
-    public static <T> T newCheckedInstanceOf(final String className, final Class<T> clazz)
-            throws ClassNotFoundException, InvocationTargetException, InstantiationException,
-            IllegalAccessException {
+    public static <T> T newCheckedInstanceOf(final String className, final Class<T> clazz) throws ClassNotFoundException,
+            InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
         return newInstanceOf(loadClass(className).asSubclass(clazz));
     }
 
     /**
-     * Loads and instantiates a class given by a property name.
+     * Loads the provided class by name as a checked subtype of the given class. All checked reflective operation
+     * exceptions are translated into corresponding {@link LinkageError} classes.
      *
-     * @param propertyName The property name to look up a class name for.
-     * @param clazz        The class to cast it to.
-     * @param <T>          The type to cast it to.
-     * @return new instance of the class given in the property or {@code null} if the property was unset.
-     * @throws ClassNotFoundException    if the class isn't available to the usual ClassLoaders
-     * @throws IllegalAccessException    if the class can't be instantiated through a public constructor
-     * @throws InstantiationException    if there was an exception whilst instantiating the class
-     * @throws InvocationTargetException if there was an exception whilst constructing the class
-     * @throws ClassCastException        if the constructed object isn't type compatible with {@code T}
-     * @since 2.5
+     * @param className fully qualified class name to load
+     * @param supertype supertype of the class being loaded
+     * @param <T>       type of instance to return
+     * @return new instance of the requested class
+     * @throws NoClassDefFoundError        if the provided class name could not be found
+     * @throws ExceptionInInitializerError if an exception is thrown during class initialization
+     * @throws ClassCastException          if the loaded class is not a subtype of the provided class
+     * @throws NoSuchMethodError           if no zero-arg constructor exists
+     * @throws SecurityException           if this class is not allowed to access declared members of the provided class
+     * @throws InternalException           if an exception is thrown by the constructor
+     * @throws InstantiationError          if the provided class is abstract or an interface
+     * @throws IllegalAccessError          if the class cannot be accessed
+     * @throws LinkageError                if the linkage of the class fails for any other reason
+     * @since 3.0.0
      */
-    public static <T> T newCheckedInstanceOfProperty(final String propertyName, final Class<T> clazz)
-        throws ClassNotFoundException, InvocationTargetException, InstantiationException,
-        IllegalAccessException {
-        final String className = PropertiesUtil.getProperties().getStringProperty(propertyName);
-        if (className == null) {
-            return null;
-        }
-        return newCheckedInstanceOf(className, clazz);
+    public static <T> T newInstanceOfUnchecked(final String className, final Class<T> supertype) {
+        final Class<? extends T> clazz = loadClassUnchecked(className).asSubclass(supertype);
+        return newInstanceOfUnchecked(clazz);
     }
 
     private static boolean isIgnoreTccl() {
@@ -330,11 +447,13 @@ public final class LoaderUtil {
     private static boolean isForceTccl() {
         if (forceTcclOnly == null) {
             // PropertiesUtil.getProperties() uses that code path so don't use that!
+            final String key = LoggingSystemProperty.LOADER_FORCE_THREAD_CONTEXT_LOADER.getSystemKey();
+            final SecurityManager securityManager = System.getSecurityManager();
             try {
-                forceTcclOnly = System.getSecurityManager() == null ?
-                    Boolean.getBoolean(LoggingSystemProperty.LOADER_FORCE_THREAD_CONTEXT_LOADER.getSystemKey()) :
-                    AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean(
-                            LoggingSystemProperty.LOADER_FORCE_THREAD_CONTEXT_LOADER.getSystemKey()));
+                if (securityManager != null) {
+                    securityManager.checkPropertyAccess(key);
+                }
+                forceTcclOnly = Boolean.getBoolean(key);
             } catch (final SecurityException se) {
                 forceTcclOnly = false;
             }
@@ -350,11 +469,7 @@ public final class LoaderUtil {
      * @since 2.1
      */
     public static Collection<URL> findResources(final String resource) {
-        return findResources(resource, true);
-    }
-
-    public static Collection<URL> findResources(final String resource, final boolean useTccl) {
-        final Collection<UrlResource> urlResources = findUrlResources(resource, useTccl);
+        final Collection<UrlResource> urlResources = findUrlResources(resource);
         final Collection<URL> resources = new LinkedHashSet<>(urlResources.size());
         for (final UrlResource urlResource : urlResources) {
             resources.add(urlResource.getUrl());
@@ -366,18 +481,13 @@ public final class LoaderUtil {
      * This method will only find resources that follow the JPMS rules for encapsulation. Resources
      * on the class path should be found as normal along with resources with no package name in all
      * modules. Resources within packages in modules must declare those resources open to org.apache.logging.log4j.
+     *
      * @param resource The resource to locate.
      * @return The located resources.
      */
-    public static Collection<UrlResource> findUrlResources(final String resource, final boolean useTccl) {
-        // @formatter:off
-        final ClassLoader[] candidates = {
-                getThreadContextClassLoader(),
-                isForceTccl() ? null : LoaderUtil.class.getClassLoader(),
-                isForceTccl() || GET_CLASS_LOADER_DISABLED ? null : ClassLoader.getSystemClassLoader()};
-        // @formatter:on
+    public static Collection<UrlResource> findUrlResources(final String resource) {
         final Collection<UrlResource> resources = new LinkedHashSet<>();
-        for (final ClassLoader cl : candidates) {
+        for (final ClassLoader cl : getClassLoaders()) {
             if (cl != null) {
                 try {
                     final Enumeration<URL> resourceEnum = cl.getResources(resource);
@@ -423,10 +533,7 @@ public final class LoaderUtil {
 
             final UrlResource that = (UrlResource) o;
 
-            if (classLoader != null ? !classLoader.equals(that.classLoader) : that.classLoader != null) {
-                return false;
-            }
-            return url != null ? url.equals(that.url) : that.url == null;
+            return Objects.equals(classLoader, that.classLoader) && Objects.equals(url, that.url);
         }
 
         @Override
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
index e777f03ef0..58077430f4 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
@@ -112,12 +112,12 @@ public class PropertiesUtil implements PropertyEnvironment {
     private PropertiesUtil(final String contextName, final String propertiesFileName, final boolean useTccl) {
         final List<PropertySource> sources = new ArrayList<>();
         if (propertiesFileName.endsWith(".json") || propertiesFileName.endsWith(".jsn")) {
-            final PropertySource source = getJsonPropertySource(propertiesFileName, useTccl, 50);
+            final PropertySource source = getJsonPropertySource(propertiesFileName, 50);
             if (source != null) {
                 sources.add(source);
             }
         } else {
-            final PropertySource source = new PropertiesPropertySource(PropertyFilePropertySource.loadPropertiesFile(propertiesFileName, useTccl),
+            final PropertySource source = new PropertiesPropertySource(PropertyFilePropertySource.loadPropertiesFile(propertiesFileName),
                 null, 60, true);
             sources.add(source);
         }
@@ -173,10 +173,10 @@ public class PropertiesUtil implements PropertyEnvironment {
     private static Environment getEnvironment(final String namespace, final boolean useTccl) {
         final List<PropertySource> sources = new ArrayList<>();
         final String fileName = String.format("log4j2.%s.properties", namespace);
-        final Properties properties = PropertyFilePropertySource.loadPropertiesFile(fileName, useTccl);
+        final Properties properties = PropertyFilePropertySource.loadPropertiesFile(fileName);
         PropertySource source = new PropertiesPropertySource(properties, 50);
         sources.add(source);
-        source = getJsonPropertySource(String.format("log4j2.%s.json", namespace), useTccl, 60);
+        source = getJsonPropertySource(String.format("log4j2.%s.json", namespace), 60);
         if (source != null) {
             sources.add(source);
         }
@@ -344,7 +344,7 @@ public class PropertiesUtil implements PropertyEnvironment {
         return sources;
     }
 
-    private static PropertySource getJsonPropertySource(final String fileName, final boolean useTccl, int priority) {
+    private static PropertySource getJsonPropertySource(final String fileName, int priority) {
         if (fileName.startsWith("file://")) {
             try {
                 final URL url = new URL(fileName);
@@ -365,7 +365,7 @@ public class PropertiesUtil implements PropertyEnvironment {
                     LowLevelLogUtil.logException("Unable to read " + fileName, ioe);
                 }
             } else {
-                for (final URL url : LoaderUtil.findResources(fileName, useTccl)) {
+                for (final URL url : LoaderUtil.findResources(fileName)) {
                     try (final InputStream in = url.openStream()) {
                         return parseJsonProperties(new String(in.readAllBytes(),
                                 StandardCharsets.UTF_8), PropertySource.SYSTEM_CONTEXT, priority);
@@ -440,7 +440,7 @@ public class PropertiesUtil implements PropertyEnvironment {
 
         private Environment(final String contextName, final List<PropertySource> propertySources) {
             try {
-                final Properties sysProps = PropertyFilePropertySource.loadPropertiesFile(LOG4J_SYSTEM_PROPERTIES_FILE_NAME, false);
+                final Properties sysProps = PropertyFilePropertySource.loadPropertiesFile(LOG4J_SYSTEM_PROPERTIES_FILE_NAME);
                 for (String key : sysProps.stringPropertyNames()) {
                     if (System.getProperty(key) == null) {
                         System.setProperty(key, sysProps.getProperty(key));
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyFilePropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyFilePropertySource.java
index dd08cf5d9d..7c10d4eee2 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyFilePropertySource.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyFilePropertySource.java
@@ -29,20 +29,16 @@ import java.util.Properties;
 public class PropertyFilePropertySource extends PropertiesPropertySource {
 
     public PropertyFilePropertySource(final String fileName) {
-        this(fileName, true, false);
+        this(fileName, false);
     }
 
-    public PropertyFilePropertySource(final String fileName, final boolean useTccl) {
-        this(fileName, useTccl, false);
+    public PropertyFilePropertySource(final String fileName, final boolean includeInvalid) {
+        super(loadPropertiesFile(fileName), SYSTEM_CONTEXT, 20, includeInvalid);
     }
 
-    public PropertyFilePropertySource(final String fileName, final boolean useTccl, final boolean includeInvalid) {
-        super(loadPropertiesFile(fileName, useTccl), SYSTEM_CONTEXT, 20, includeInvalid);
-    }
-
-    static Properties loadPropertiesFile(final String fileName, final boolean useTccl) {
+    static Properties loadPropertiesFile(final String fileName) {
         final Properties props = new Properties();
-        for (final URL url : LoaderUtil.findResources(fileName, useTccl)) {
+        for (final URL url : LoaderUtil.findResources(fileName)) {
             try (final InputStream in = url.openStream()) {
                 props.load(in);
             } catch (final IOException e) {


[logging-log4j2] 02/03: Add some javadocs

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mattsicker pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 78f728af516564031cbcd0d2a6733c3d6dc44ec2
Author: Matt Sicker <ma...@apache.org>
AuthorDate: Sun Oct 1 17:31:21 2023 -0500

    Add some javadocs
    
    Signed-off-by: Matt Sicker <ma...@apache.org>
---
 .../src/main/java/org/apache/logging/log4j/util/Cast.java    | 12 ++++++++++++
 .../logging/log4j/core/config/AbstractConfiguration.java     |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Cast.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Cast.java
index c525bc42d0..8a1dc40975 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Cast.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Cast.java
@@ -18,7 +18,19 @@ package org.apache.logging.log4j.util;
 
 @InternalApi
 public final class Cast {
+
+    /**
+     * Returns the provided object cast to the generic parameter type or null when the argument is null.
+     *
+     * @param o   object to cast
+     * @param <T> the type to cast
+     * @return object after casting or null if the object was null
+     * @throws ClassCastException if the object cannot be cast to the provided type
+     */
     public static <T> T cast(final Object o) {
+        if (o == null) {
+            return null;
+        }
         @SuppressWarnings("unchecked") final T t = (T) o;
         return t;
     }
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 bb434ab654..ebf083b0da 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
@@ -94,8 +94,15 @@ import org.apache.logging.log4j.util.ServiceRegistry;
  */
 public abstract class AbstractConfiguration extends AbstractFilterable implements Configuration {
 
+    /**
+     * The instance factory for this configuration. This may be a child factory to a LoggerContext
+     * in most cases, though this might be a root level factory for null configurations.
+     */
     protected final ConfigurableInstanceFactory instanceFactory;
 
+    /**
+     * The configuration processor for transforming a node tree into plugin instances.
+     */
     protected final ConfigurationProcessor configurationProcessor;
 
     /**