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 from system property {@link Constants#LOG4J_CONTEXT_SELECTOR}. 045 */ 046 public Log4jContextFactory() { 047 this(createContextSelector()); 048 } 049 050 /** 051 * Initializes this factory's ContextSelector with the specified selector. 052 * @param selector the selector to use 053 */ 054 public Log4jContextFactory(final ContextSelector selector) { 055 this.selector = selector; 056 } 057 058 private static ContextSelector createContextSelector() { 059 final String sel = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_CONTEXT_SELECTOR); 060 if (sel != null) { 061 try { 062 return Loader.newCheckedInstanceOf(sel, ContextSelector.class); 063 } catch (final Exception ex) { 064 LOGGER.error("Unable to create context {}", sel, ex); 065 } 066 } 067 return new ClassLoaderContextSelector(); 068 } 069 070 /** 071 * Loads the LoggerContext using the ContextSelector. 072 * @param fqcn The fully qualified class name of the caller. 073 * @param loader The ClassLoader to use or null. 074 * @param currentContext If true returns the current Context, if false returns the Context appropriate 075 * for the caller if a more appropriate Context can be determined. 076 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 077 * @return The LoggerContext. 078 */ 079 @Override 080 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, 081 final boolean currentContext) { 082 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext); 083 ctx.setExternalContext(externalContext); 084 if (ctx.getState() == LifeCycle.State.INITIALIZED) { 085 ctx.start(); 086 } 087 return ctx; 088 } 089 090 /** 091 * Loads the LoggerContext using the ContextSelector. 092 * @param fqcn The fully qualified class name of the caller. 093 * @param loader The ClassLoader to use or null. 094 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 095 * @param currentContext If true returns the current Context, if false returns the Context appropriate 096 * for the caller if a more appropriate Context can be determined. 097 * @param source The configuration source. 098 * @return The LoggerContext. 099 */ 100 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, 101 final boolean currentContext, final ConfigurationSource source) { 102 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null); 103 if (externalContext != null && ctx.getExternalContext() == null) { 104 ctx.setExternalContext(externalContext); 105 } 106 if (ctx.getState() == LifeCycle.State.INITIALIZED) { 107 if (source != null) { 108 ContextAnchor.THREAD_CONTEXT.set(ctx); 109 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(source); 110 LOGGER.debug("Starting LoggerContext[name={}] from configuration {}", ctx.getName(), source); 111 ctx.start(config); 112 ContextAnchor.THREAD_CONTEXT.remove(); 113 } else { 114 ctx.start(); 115 } 116 } 117 return ctx; 118 } 119 120 /** 121 * Loads the LoggerContext using the ContextSelector. 122 * @param fqcn The fully qualified class name of the caller. 123 * @param loader The ClassLoader to use or null. 124 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 125 * @param currentContext If true returns the current Context, if false returns the Context appropriate 126 * for the caller if a more appropriate Context can be determined. 127 * @param configLocation The location of the configuration for the LoggerContext. 128 * @return The LoggerContext. 129 */ 130 @Override 131 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, 132 final boolean currentContext, final URI configLocation, final String name) { 133 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, configLocation); 134 if (externalContext != null && ctx.getExternalContext() == null) { 135 ctx.setExternalContext(externalContext); 136 } 137 if (ctx.getState() == LifeCycle.State.INITIALIZED) { 138 if (configLocation != null || name != null) { 139 ContextAnchor.THREAD_CONTEXT.set(ctx); 140 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(name, configLocation); 141 LOGGER.debug("Starting LoggerContext[name={}] from configuration at {}", ctx.getName(), configLocation); 142 ctx.start(config); 143 ContextAnchor.THREAD_CONTEXT.remove(); 144 } else { 145 ctx.start(); 146 } 147 } 148 return ctx; 149 } 150 151 /** 152 * Returns the ContextSelector. 153 * @return The ContextSelector. 154 */ 155 public ContextSelector getSelector() { 156 return selector; 157 } 158 159 /** 160 * Removes knowledge of a LoggerContext. 161 * 162 * @param context The context to remove. 163 */ 164 @Override 165 public void removeContext(final org.apache.logging.log4j.spi.LoggerContext context) { 166 if (context instanceof LoggerContext) { 167 selector.removeContext((LoggerContext) context); 168 } 169 } 170 }