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.spi; 018 019import java.util.Map; 020import java.util.WeakHashMap; 021import java.util.concurrent.ConcurrentHashMap; 022import java.util.concurrent.ConcurrentMap; 023 024import org.apache.logging.log4j.LogManager; 025import org.apache.logging.log4j.util.LoaderUtil; 026 027/** 028 * Provides an abstract base class to use for implementing LoggerAdapter. 029 * @param <L> the Logger class to adapt 030 * @since 2.1 031 */ 032public abstract class AbstractLoggerAdapter<L> implements LoggerAdapter<L> { 033 034 /** 035 * A map to store loggers for their given LoggerContexts. 036 */ 037 protected final Map<LoggerContext, ConcurrentMap<String, L>> registry = 038 new WeakHashMap<LoggerContext, ConcurrentMap<String, L>>(); 039 040 @Override 041 public L getLogger(final String name) { 042 final LoggerContext context = getContext(); 043 final ConcurrentMap<String, L> loggers = getLoggersInContext(context); 044 if (loggers.containsKey(name)) { 045 return loggers.get(name); 046 } 047 loggers.putIfAbsent(name, newLogger(name, context)); 048 return loggers.get(name); 049 } 050 051 /** 052 * Gets or creates the ConcurrentMap of named loggers for a given LoggerContext. 053 * 054 * @param context the LoggerContext to get loggers for 055 * @return the map of loggers for the given LoggerContext 056 */ 057 public ConcurrentMap<String, L> getLoggersInContext(final LoggerContext context) { 058 synchronized (registry) { 059 ConcurrentMap<String, L> loggers = registry.get(context); 060 if (loggers == null) { 061 loggers = new ConcurrentHashMap<String, L>(); 062 registry.put(context, loggers); 063 } 064 return loggers; 065 } 066 } 067 068 /** 069 * Creates a new named logger for a given {@link LoggerContext}. 070 * 071 * @param name the name of the logger to create 072 * @param context the LoggerContext this logger will be associated with 073 * @return the new named logger 074 */ 075 protected abstract L newLogger(final String name, final LoggerContext context); 076 077 /** 078 * Gets the {@link LoggerContext} that should be used to look up or create loggers. This is similar in spirit to 079 * the {@code ContextSelector} class in {@code log4j-core}. However, implementations can rely on their own 080 * framework's separation of contexts instead (or simply use a singleton). 081 * 082 * @return the LoggerContext to be used for lookup and creation purposes 083 * @see org.apache.logging.log4j.LogManager#getContext(ClassLoader, boolean) 084 * @see org.apache.logging.log4j.LogManager#getContext(String, boolean) 085 */ 086 protected abstract LoggerContext getContext(); 087 088 /** 089 * Gets the {@link LoggerContext} associated with the given caller class. 090 * 091 * @param callerClass the caller class 092 * @return the LoggerContext for the calling class 093 */ 094 protected LoggerContext getContext(final Class<?> callerClass) { 095 ClassLoader cl = null; 096 if (callerClass != null) { 097 cl = callerClass.getClassLoader(); 098 } 099 if (cl == null) { 100 cl = LoaderUtil.getThreadContextClassLoader(); 101 } 102 return LogManager.getContext(cl, false); 103 } 104 105 @Override 106 public void close() { 107 registry.clear(); 108 } 109}