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 */ 017package org.apache.logging.log4j.core.impl; 018 019import java.net.URI; 020 021import org.apache.logging.log4j.core.LoggerContext; 022import org.apache.logging.log4j.core.config.Configuration; 023import org.apache.logging.log4j.core.config.ConfigurationFactory; 024import org.apache.logging.log4j.core.helpers.Constants; 025import org.apache.logging.log4j.core.helpers.Loader; 026import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector; 027import org.apache.logging.log4j.core.selector.ContextSelector; 028import org.apache.logging.log4j.spi.LoggerContextFactory; 029import org.apache.logging.log4j.status.StatusLogger; 030import org.apache.logging.log4j.util.PropertiesUtil; 031 032/** 033 * Factory to locate a ContextSelector and then load a LoggerContext. 034 */ 035public class Log4jContextFactory implements LoggerContextFactory { 036 037 private static final StatusLogger LOGGER = StatusLogger.getLogger(); 038 039 private ContextSelector selector; 040 041 /** 042 * Constructor that initializes the ContextSelector. 043 */ 044 public Log4jContextFactory() { 045 final String sel = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_CONTEXT_SELECTOR); 046 if (sel != null) { 047 try { 048 final Class<?> clazz = Loader.loadClass(sel); 049 if (clazz != null && ContextSelector.class.isAssignableFrom(clazz)) { 050 selector = (ContextSelector) clazz.newInstance(); 051 } 052 } catch (final Exception ex) { 053 LOGGER.error("Unable to create context " + sel, ex); 054 } 055 } 056 if (selector == null) { 057 selector = new ClassLoaderContextSelector(); 058 } 059 } 060 061 /** 062 * Returns the ContextSelector. 063 * @return The ContextSelector. 064 */ 065 public ContextSelector getSelector() { 066 return selector; 067 } 068 069 /** 070 * Load the LoggerContext using the ContextSelector. 071 * @param fqcn The fully qualified class name of the caller. 072 * @param loader The ClassLoader to use or null. 073 * @param currentContext If true returns the current Context, if false returns the Context appropriate 074 * for the caller if a more appropriate Context can be determined. 075 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 076 * @return The LoggerContext. 077 */ 078 @Override 079 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, 080 final boolean currentContext) { 081 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext); 082 ctx.setExternalContext(externalContext); 083 if (ctx.getStatus() == LoggerContext.Status.INITIALIZED) { 084 ctx.start(); 085 } 086 return ctx; 087 } 088 089 /** 090 * Load the LoggerContext using the ContextSelector. 091 * @param fqcn The fully qualified class name of the caller. 092 * @param loader The ClassLoader to use or null. 093 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 094 * @param currentContext If true returns the current Context, if false returns the Context appropriate 095 * for the caller if a more appropriate Context can be determined. 096 * @param configLocation The location of the configuration for the LoggerContext. 097 * @return The LoggerContext. 098 */ 099 @Override 100 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, 101 final boolean currentContext, final URI configLocation, final String name) { 102 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, configLocation); 103 if (externalContext != null && ctx.getExternalContext() == null) { 104 ctx.setExternalContext(externalContext); 105 } 106 if (ctx.getStatus() == LoggerContext.Status.INITIALIZED) { 107 if (configLocation != null || name != null) { 108 ContextAnchor.THREAD_CONTEXT.set(ctx); 109 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(name, configLocation); 110 ctx.start(config); 111 ContextAnchor.THREAD_CONTEXT.remove(); 112 } else { 113 ctx.start(); 114 } 115 } 116 return ctx; 117 } 118 119 /** 120 * Load the LoggerContext using the ContextSelector. 121 * @param fqcn The fully qualified class name of the caller. 122 * @param loader The ClassLoader to use or null. 123 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 124 * @param currentContext If true returns the current Context, if false returns the Context appropriate 125 * for the caller if a more appropriate Context can be determined. 126 * @param source The configuration source. 127 * @return The LoggerContext. 128 */ 129 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, 130 final boolean currentContext, final ConfigurationFactory.ConfigurationSource source) { 131 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null); 132 if (externalContext != null && ctx.getExternalContext() == null) { 133 ctx.setExternalContext(externalContext); 134 } 135 if (ctx.getStatus() == LoggerContext.Status.INITIALIZED) { 136 if (source != null) { 137 ContextAnchor.THREAD_CONTEXT.set(ctx); 138 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(source); 139 ctx.start(config); 140 ContextAnchor.THREAD_CONTEXT.remove(); 141 } else { 142 ctx.start(); 143 } 144 } 145 return ctx; 146 } 147 148 149 150 /** 151 * Removes knowledge of a LoggerContext. 152 * 153 * @param context The context to remove. 154 */ 155 @Override 156 public void removeContext(final org.apache.logging.log4j.spi.LoggerContext context) { 157 if (context instanceof LoggerContext) { 158 selector.removeContext((LoggerContext) context); 159 } 160 } 161}