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