org.apache.logging.log4j.util.LoaderUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pax-logging-api Show documentation
Show all versions of pax-logging-api Show documentation
The Pax Logging API Library is to allow for the Pax Logging Service to be reloaded without stopping the many
dependent bundles. It also contains the OSGi Log Service API and the Knopflerfish Log API.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.util;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Objects;
/**
* Consider this class private. Utility class for ClassLoaders.
*
* @see ClassLoader
* @see RuntimePermission
* @see Thread#getContextClassLoader()
* @see ClassLoader#getSystemClassLoader()
*/
public final class LoaderUtil {
/**
* System property to set to ignore the thread context ClassLoader.
*
* @since 2.1
*/
public static final String IGNORE_TCCL_PROPERTY = "log4j.ignoreTCL";
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 boolean GET_CLASS_LOADER_DISABLED;
private static final PrivilegedAction TCCL_GETTER = new ThreadContextClassLoaderGetter();
static {
if (SECURITY_MANAGER != null) {
boolean getClassLoaderDisabled;
try {
SECURITY_MANAGER.checkPermission(new RuntimePermission("getClassLoader"));
getClassLoaderDisabled = false;
} catch (final SecurityException ignored) {
getClassLoaderDisabled = true;
}
GET_CLASS_LOADER_DISABLED = getClassLoaderDisabled;
} else {
GET_CLASS_LOADER_DISABLED = false;
}
}
private LoaderUtil() {
}
/**
* 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);
}
/**
*
*/
private static class ThreadContextClassLoaderGetter implements PrivilegedAction {
@Override
public ClassLoader run() {
final ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl != null) {
return cl;
}
final ClassLoader ccl = LoaderUtil.class.getClassLoader();
return ccl == null && !GET_CLASS_LOADER_DISABLED ? ClassLoader.getSystemClassLoader() : ccl;
}
}
/**
* Loads a class by name. This method respects the {@link #IGNORE_TCCL_PROPERTY} Log4j property. If this property is
* specified and set to anything besides {@code false}, then the default 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
* @since 2.1
*/
public static Class> loadClass(final String className) throws ClassNotFoundException {
if (isIgnoreTccl()) {
return Class.forName(className);
}
try {
return getThreadContextClassLoader().loadClass(className);
} catch (final Throwable ignored) {
return Class.forName(className);
}
}
/**
* Loads and instantiates a Class using the default constructor.
*
* @param className The class name.
* @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 NoSuchMethodException if there isn't a no-args constructor on the class
* @throws InvocationTargetException if there was an exception whilst constructing the class
* @since 2.1
*/
public static Object newInstanceOf(final String className) throws ClassNotFoundException, IllegalAccessException,
InstantiationException, NoSuchMethodException, InvocationTargetException {
final Class> clazz = loadClass(className);
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();
}
}
/**
* Loads and instantiates a derived class using its default constructor.
*
* @param className The class name.
* @param clazz The class to cast it to.
* @param 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 NoSuchMethodException if there isn't a no-args constructor on 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.1
*/
public static T newCheckedInstanceOf(final String className, final Class clazz)
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException,
IllegalAccessException {
return clazz.cast(newInstanceOf(className));
}
private static boolean isIgnoreTccl() {
// we need to lazily initialize this, but concurrent access is not an issue
if (ignoreTCCL == null) {
final String ignoreTccl = PropertiesUtil.getProperties().getStringProperty(IGNORE_TCCL_PROPERTY, null);
ignoreTCCL = ignoreTccl != null && !"false".equalsIgnoreCase(ignoreTccl.trim());
}
return ignoreTCCL;
}
/**
* Finds classpath {@linkplain URL resources}.
*
* @param resource the name of the resource to find.
* @return a Collection of URLs matching the resource name. If no resources could be found, then this will be empty.
* @since 2.1
*/
public static Collection findResources(final String resource) {
final Collection urlResources = findUrlResources(resource);
final Collection resources = new LinkedHashSet<>(urlResources.size());
for (final UrlResource urlResource : urlResources) {
resources.add(urlResource.getUrl());
}
return resources;
}
static Collection findUrlResources(final String resource) {
final ClassLoader[] candidates = {getThreadContextClassLoader(), LoaderUtil.class.getClassLoader(),
GET_CLASS_LOADER_DISABLED ? null : ClassLoader.getSystemClassLoader()};
final Collection resources = new LinkedHashSet<>();
for (final ClassLoader cl : candidates) {
if (cl != null) {
try {
final Enumeration resourceEnum = cl.getResources(resource);
while (resourceEnum.hasMoreElements()) {
resources.add(new UrlResource(cl, resourceEnum.nextElement()));
}
} catch (final IOException e) {
e.printStackTrace();
}
}
}
return resources;
}
/**
* {@link URL} and {@link ClassLoader} pair.
*/
static class UrlResource {
private final ClassLoader classLoader;
private final URL url;
public UrlResource(final ClassLoader classLoader, final URL url) {
this.classLoader = classLoader;
this.url = url;
}
public ClassLoader getClassLoader() {
return classLoader;
}
public URL getUrl() {
return url;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final UrlResource that = (UrlResource) o;
if (classLoader != null ? !classLoader.equals(that.classLoader) : that.classLoader != null) {
return false;
}
if (url != null ? !url.equals(that.url) : that.url != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
return Objects.hashCode(classLoader) + Objects.hashCode(url);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy