Index: log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContextFactory.java =================================================================== --- log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContextFactory.java (revision 1449428) +++ log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContextFactory.java (working copy) @@ -19,6 +19,8 @@ import org.apache.logging.log4j.spi.LoggerContext; import org.apache.logging.log4j.spi.LoggerContextFactory; +import java.net.URI; + /** * */ @@ -28,4 +30,9 @@ public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext) { return context; } + + public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext, + URI configLocation) { + return context; + } } Index: core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java (revision 1449428) +++ core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java (working copy) @@ -24,6 +24,7 @@ import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -62,6 +63,11 @@ } public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext) { + return getContext(fqcn, loader, currentContext, null); + } + + public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext, + URI configLocation) { if (currentContext) { final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get(); if (ctx != null) { @@ -69,7 +75,7 @@ } return getDefault(); } else if (loader != null) { - return locateContext(loader, null); + return locateContext(loader, configLocation); } else { if (getCallerClass != null) { try { @@ -90,7 +96,7 @@ } } if (clazz != null) { - return locateContext(clazz.getClassLoader(), null); + return locateContext(clazz.getClassLoader(), configLocation); } } catch (final Exception ex) { // logger.debug("Unable to determine caller class via Sun Reflection", ex); @@ -102,7 +108,7 @@ if (clazz != null) { final ClassLoader ldr = clazz.getClassLoader() != null ? clazz.getClassLoader() : ClassLoader.getSystemClassLoader(); - return locateContext(ldr, null); + return locateContext(ldr, configLocation); } } @@ -121,7 +127,7 @@ } if (name != null) { try { - return locateContext(Loader.loadClass(name).getClassLoader(), null); + return locateContext(Loader.loadClass(name).getClassLoader(), configLocation); } catch (final ClassNotFoundException ex) { //System.out.println("Could not load class " + name); } @@ -155,10 +161,35 @@ return Collections.unmodifiableList(list); } - private LoggerContext locateContext(final ClassLoader loader, final String configLocation) { + private LoggerContext locateContext(final ClassLoader loader, final URI configLocation) { final String name = loader.toString(); - final AtomicReference> ref = CONTEXT_MAP.get(name); + AtomicReference> ref = CONTEXT_MAP.get(name); if (ref == null) { + if (configLocation == null) { + ClassLoader parent = loader.getParent(); + while (parent != null) { + + ref = CONTEXT_MAP.get(parent.toString()); + if (ref != null) { + final WeakReference r = ref.get(); + LoggerContext ctx = r.get(); + if (ctx != null) { + return ctx; + } + } + ClassLoader threadLoader = null; + try { + threadLoader = Thread.currentThread().getContextClassLoader(); + } catch (Exception ex) { + // Ignore SecurityException + } + if (threadLoader != null && threadLoader == parent) { + break; + } else { + parent = parent.getParent(); + } + } + } LoggerContext ctx = new LoggerContext(name, null, configLocation); final AtomicReference> r = new AtomicReference>(); Index: core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java (revision 1449428) +++ core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java (working copy) @@ -18,6 +18,7 @@ import org.apache.logging.log4j.core.LoggerContext; +import java.net.URI; import java.util.List; /** @@ -36,6 +37,17 @@ LoggerContext getContext(String fqcn, ClassLoader loader, boolean currentContext); /** + * Returns the LoggerContext. + * @param fqcn The fully qualified class name of the caller. + * @param loader ClassLoader to use or null. + * @param currentContext If true returns the current Context, if false returns the Context appropriate + * for the caller if a more appropriate Context can be determined. + * @param configLocation The location of the configuration for the LoggerContext. + * @return The LoggerContext. + */ + LoggerContext getContext(String fqcn, ClassLoader loader, boolean currentContext, URI configLocation); + + /** * Returns a List of all the available LoggerContexts. * @return The List of LoggerContexts. */ Index: core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java (revision 1449428) +++ core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java (working copy) @@ -19,6 +19,7 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.impl.ContextAnchor; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -36,6 +37,14 @@ return ctx != null ? ctx : CONTEXT; } + + public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext, + URI configLocation) { + + final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get(); + return ctx != null ? ctx : CONTEXT; + } + public LoggerContext locateContext(final String name, final String configLocation) { return CONTEXT; } Index: core/src/main/java/org/apache/logging/log4j/core/selector/JNDIContextSelector.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/selector/JNDIContextSelector.java (revision 1449428) +++ core/src/main/java/org/apache/logging/log4j/core/selector/JNDIContextSelector.java (working copy) @@ -25,6 +25,7 @@ import javax.naming.InitialContext; import javax.naming.NameNotFoundException; import javax.naming.NamingException; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -94,7 +95,12 @@ private static final StatusLogger LOGGER = StatusLogger.getLogger(); public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext) { + return getContext(fqcn, loader, currentContext, null); + } + public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext, + URI configLocation) { + final LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get(); if (lc != null) { return lc; @@ -109,10 +115,10 @@ LOGGER.error("Unable to lookup " + Constants.JNDI_CONTEXT_NAME, ne); } - return loggingContextName == null ? CONTEXT : locateContext(loggingContextName, null); + return loggingContextName == null ? CONTEXT : locateContext(loggingContextName, configLocation); } - public LoggerContext locateContext(final String name, final String configLocation) { + public LoggerContext locateContext(final String name, final URI configLocation) { if (name == null) { LOGGER.error("A context name is required to locate a LoggerContext"); return null; Index: core/src/main/java/org/apache/logging/log4j/core/selector/NamedContextSelector.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/selector/NamedContextSelector.java (revision 1449428) +++ core/src/main/java/org/apache/logging/log4j/core/selector/NamedContextSelector.java (working copy) @@ -18,6 +18,8 @@ import org.apache.logging.log4j.core.LoggerContext; +import java.net.URI; + /** * ContextSelectors that have a name. */ @@ -29,7 +31,7 @@ * @param configLocation The location of the configuration. * @return A LoggerContext. */ - LoggerContext locateContext(String name, String configLocation); + LoggerContext locateContext(String name, URI configLocation); /** * Locate the LoggerContext with the specified name using the default configuration. Index: core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java (revision 1449428) +++ core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java (working copy) @@ -25,6 +25,8 @@ import org.apache.logging.log4j.spi.LoggerContextFactory; import org.apache.logging.log4j.util.PropertiesUtil; +import java.net.URI; + /** * Factory to locate a ContextSelector and then load a LoggerContext. */ @@ -77,4 +79,23 @@ } return ctx; } + + + /** + * Load the LoggerContext using the ContextSelector. + * @param fqcn The fully qualified class name of the caller. + * @param loader The ClassLoader to use or null. + * @param currentContext If true returns the current Context, if false returns the Context appropriate + * for the caller if a more appropriate Context can be determined. + * @param configLocation The location of the configuration for the LoggerContext. + * @return The LoggerContext. + */ + public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext, + URI configLocation) { + final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, configLocation); + if (ctx.getStatus() == LoggerContext.Status.INITIALIZED) { + ctx.start(); + } + return ctx; + } } Index: core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java (revision 1449428) +++ core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java (working copy) @@ -57,7 +57,7 @@ public static LoggerContext initialize(final String name, final ClassLoader loader, final URI configLocation) { try { - final LoggerContext ctx = (LoggerContext) LogManager.getContext(loader, false); + final LoggerContext ctx = (LoggerContext) LogManager.getContext(loader, false, configLocation); final Configuration config = ConfigurationFactory.getInstance().getConfiguration(name, configLocation); ctx.setConfiguration(config); return ctx; @@ -77,7 +77,13 @@ final ConfigurationFactory.ConfigurationSource source) { try { - final LoggerContext ctx = (LoggerContext) LogManager.getContext(loader, false); + URI configLocation = null; + try { + configLocation = source.getLocation() == null ? null : new URI(source.getLocation()); + } catch (Exception ex) { + // Invalid source location. + } + final LoggerContext ctx = (LoggerContext) LogManager.getContext(loader, false, configLocation); final Configuration config = ConfigurationFactory.getInstance().getConfiguration(source); ctx.setConfiguration(config); return ctx; Index: api/src/test/java/org/apache/logging/log4j/TestLoggerContextFactory.java =================================================================== --- api/src/test/java/org/apache/logging/log4j/TestLoggerContextFactory.java (revision 1449428) +++ api/src/test/java/org/apache/logging/log4j/TestLoggerContextFactory.java (working copy) @@ -19,6 +19,8 @@ import org.apache.logging.log4j.spi.LoggerContext; import org.apache.logging.log4j.spi.LoggerContextFactory; +import java.net.URI; + /** * */ @@ -29,4 +31,9 @@ public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext) { return context; } + + public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext, + URI configLocation) { + return context; + } } Index: api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContextFactory.java =================================================================== --- api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContextFactory.java (revision 1449428) +++ api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContextFactory.java (working copy) @@ -19,6 +19,8 @@ import org.apache.logging.log4j.spi.LoggerContext; import org.apache.logging.log4j.spi.LoggerContextFactory; +import java.net.URI; + /** * */ @@ -29,4 +31,9 @@ public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext) { return context; } + + public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext, + URI configLocation) { + return context; + } } Index: api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java =================================================================== --- api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java (revision 1449428) +++ api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java (working copy) @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.spi; +import java.net.URI; + /** * Implemented by factories that create {@link LoggerContext} objects. */ @@ -31,4 +33,16 @@ * @return The LoggerContext. */ LoggerContext getContext(String fqcn, ClassLoader loader, boolean currentContext); + + /** + * Creates a {@link LoggerContext}. + * + * @param fqcn The fully qualified class name of the caller. + * @param loader The ClassLoader to use or null. + * @param currentContext If true returns the current Context, if false returns the Context appropriate + * for the caller if a more appropriate Context can be determined. + * @param configLocation The location of the configuration for the LoggerContext. + * @return The LoggerContext. + */ + LoggerContext getContext(String fqcn, ClassLoader loader, boolean currentContext, URI configLocation); } Index: api/src/main/java/org/apache/logging/log4j/LogManager.java =================================================================== --- api/src/main/java/org/apache/logging/log4j/LogManager.java (revision 1449428) +++ api/src/main/java/org/apache/logging/log4j/LogManager.java (working copy) @@ -16,12 +16,14 @@ */ package org.apache.logging.log4j; +import java.net.URI; import java.util.Formatter; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; +import com.sun.xml.internal.xsom.impl.UnionSimpleTypeImpl; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.message.StringFormatterMessageFactory; import org.apache.logging.log4j.simple.SimpleLoggerContextFactory; @@ -166,6 +168,22 @@ } /** + * Returns a LoggerContext. + * + * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate + * ClassLoader. + * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For + * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be + * returned and if the caller is a class in the container's classpath then a different LoggerContext may be + * returned. If true then only a single LoggerContext will be returned. + * @return a LoggerContext. + */ + public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext, + URI configLocation) { + return factory.getContext(LogManager.class.getName(), loader, currentContext, configLocation); + } + + /** * Returns a LoggerContext * @param fqcn The fully qualified class name of the Class that this method is a member of. * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For Index: web/src/main/java/org/apache/logging/log4j/core/web/JNDIContextFilter.java =================================================================== --- web/src/main/java/org/apache/logging/log4j/core/web/JNDIContextFilter.java (revision 1449428) +++ web/src/main/java/org/apache/logging/log4j/core/web/JNDIContextFilter.java (working copy) @@ -33,6 +33,7 @@ import javax.servlet.ServletResponse; import javax.servlet.UnavailableException; import java.io.IOException; +import java.net.URI; /** * ServletFilter than may be used to set up a LoggerContext for each web application. @@ -54,7 +55,16 @@ public void init(final FilterConfig filterConfig) throws ServletException { context = filterConfig.getServletContext(); name = filterConfig.getInitParameter(CONTEXT_NAME); - final String configLocn = filterConfig.getInitParameter(CONFIG_LOCATION); + URI configLocation = null; + String configLocn = filterConfig.getInitParameter(CONFIG_LOCATION); + if (configLocn != null) { + try { + configLocation = new URI(configLocn); + } catch (Exception ex) { + context.log("Unable to convert config location " + configLocn + " to a URI: " + ex.getMessage()); + } + } + if (name == null) { throw new UnavailableException("A context-name attribute is required"); } @@ -65,7 +75,7 @@ final ContextSelector sel = ((Log4jContextFactory) factory).getSelector(); if (sel instanceof NamedContextSelector) { selector = (NamedContextSelector) sel; - ctx = selector.locateContext(name, configLocn); + ctx = selector.locateContext(name, configLocation); } else { return; }