001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.impl; 018 019 import java.net.URI; 020 021 import org.apache.logging.log4j.core.LifeCycle; 022 import org.apache.logging.log4j.core.LoggerContext; 023 import org.apache.logging.log4j.core.config.Configuration; 024 import org.apache.logging.log4j.core.config.ConfigurationFactory; 025 import org.apache.logging.log4j.core.config.ConfigurationSource; 026 import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector; 027 import org.apache.logging.log4j.core.selector.ContextSelector; 028 import org.apache.logging.log4j.core.util.Constants; 029 import org.apache.logging.log4j.core.util.Loader; 030 import org.apache.logging.log4j.spi.LoggerContextFactory; 031 import org.apache.logging.log4j.status.StatusLogger; 032 import org.apache.logging.log4j.util.PropertiesUtil; 033 034 /** 035 * Factory to locate a ContextSelector and then load a LoggerContext. 036 */ 037 public class Log4jContextFactory implements LoggerContextFactory { 038 039 private static final StatusLogger LOGGER = StatusLogger.getLogger(); 040 041 private ContextSelector selector; 042 043 /** 044 * Initializes the ContextSelector. 045 */ 046 public Log4jContextFactory() { 047 final String sel = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_CONTEXT_SELECTOR); 048 if (sel != null) { 049 try { 050 selector = Loader.newCheckedInstanceOf(sel, ContextSelector.class); 051 } catch (final Exception ex) { 052 LOGGER.error("Unable to create context {}", sel, ex); 053 } 054 } 055 if (selector == null) { 056 selector = new ClassLoaderContextSelector(); 057 } 058 } 059 060 /** 061 * Loads the LoggerContext using the ContextSelector. 062 * @param fqcn The fully qualified class name of the caller. 063 * @param loader The ClassLoader to use or null. 064 * @param currentContext If true returns the current Context, if false returns the Context appropriate 065 * for the caller if a more appropriate Context can be determined. 066 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 067 * @return The LoggerContext. 068 */ 069 @Override 070 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, 071 final boolean currentContext) { 072 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext); 073 ctx.setExternalContext(externalContext); 074 if (ctx.getState() == LifeCycle.State.INITIALIZED) { 075 ctx.start(); 076 } 077 return ctx; 078 } 079 080 /** 081 * Loads the LoggerContext using the ContextSelector. 082 * @param fqcn The fully qualified class name of the caller. 083 * @param loader The ClassLoader to use or null. 084 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 085 * @param currentContext If true returns the current Context, if false returns the Context appropriate 086 * for the caller if a more appropriate Context can be determined. 087 * @param source The configuration source. 088 * @return The LoggerContext. 089 */ 090 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, 091 final boolean currentContext, final ConfigurationSource source) { 092 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null); 093 if (externalContext != null && ctx.getExternalContext() == null) { 094 ctx.setExternalContext(externalContext); 095 } 096 if (ctx.getState() == LifeCycle.State.INITIALIZED) { 097 if (source != null) { 098 ContextAnchor.THREAD_CONTEXT.set(ctx); 099 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(source); 100 LOGGER.debug("Starting LoggerContext[name={}] from configuration {}", ctx.getName(), source); 101 ctx.start(config); 102 ContextAnchor.THREAD_CONTEXT.remove(); 103 } else { 104 ctx.start(); 105 } 106 } 107 return ctx; 108 } 109 110 /** 111 * Loads the LoggerContext using the ContextSelector. 112 * @param fqcn The fully qualified class name of the caller. 113 * @param loader The ClassLoader to use or null. 114 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 115 * @param currentContext If true returns the current Context, if false returns the Context appropriate 116 * for the caller if a more appropriate Context can be determined. 117 * @param configLocation The location of the configuration for the LoggerContext. 118 * @return The LoggerContext. 119 */ 120 @Override 121 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, 122 final boolean currentContext, final URI configLocation, final String name) { 123 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, configLocation); 124 if (externalContext != null && ctx.getExternalContext() == null) { 125 ctx.setExternalContext(externalContext); 126 } 127 if (ctx.getState() == LifeCycle.State.INITIALIZED) { 128 if (configLocation != null || name != null) { 129 ContextAnchor.THREAD_CONTEXT.set(ctx); 130 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(name, configLocation); 131 LOGGER.debug("Starting LoggerContext[name={}] from configuration at {}", ctx.getName(), configLocation); 132 ctx.start(config); 133 ContextAnchor.THREAD_CONTEXT.remove(); 134 } else { 135 ctx.start(); 136 } 137 } 138 return ctx; 139 } 140 141 /** 142 * Returns the ContextSelector. 143 * @return The ContextSelector. 144 */ 145 public ContextSelector getSelector() { 146 return selector; 147 } 148 149 /** 150 * Removes knowledge of a LoggerContext. 151 * 152 * @param context The context to remove. 153 */ 154 @Override 155 public void removeContext(final org.apache.logging.log4j.spi.LoggerContext context) { 156 if (context instanceof LoggerContext) { 157 selector.removeContext((LoggerContext) context); 158 } 159 } 160 }