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.jcl;
018
019import java.util.Map;
020import java.util.WeakHashMap;
021import java.util.concurrent.ConcurrentHashMap;
022import java.util.concurrent.ConcurrentMap;
023
024import org.apache.commons.logging.Log;
025import org.apache.commons.logging.LogConfigurationException;
026import org.apache.commons.logging.LogFactory;
027import org.apache.logging.log4j.LogManager;
028import org.apache.logging.log4j.spi.AbstractLogger;
029import org.apache.logging.log4j.spi.LoggerContext;
030
031/**
032 *
033 */
034public class LogFactoryImpl extends LogFactory {
035
036    private final Map<LoggerContext, ConcurrentMap<String, Log>> contextMap =
037        new WeakHashMap<LoggerContext, ConcurrentMap<String, Log>>();
038
039    private final ConcurrentMap<String, Object> attributes = new ConcurrentHashMap<String, Object>();
040
041    @Override
042    public Log getInstance(final String name) throws LogConfigurationException {
043        final ConcurrentMap<String, Log> loggers = getLoggersMap();
044        if (loggers.containsKey(name)) {
045            return loggers.get(name);
046        }
047        final org.apache.logging.log4j.Logger logger = PrivateManager.getLogger(name);
048        if (logger instanceof AbstractLogger) {
049            loggers.putIfAbsent(name, new Log4jLog((AbstractLogger) logger, name));
050            return loggers.get(name);
051        }
052        throw new LogConfigurationException(
053            "Commons Logging Adapter requires base logging system to extend Log4j AbstractLogger");
054    }
055
056    private ConcurrentMap<String, Log> getLoggersMap() {
057        final LoggerContext context = PrivateManager.getContext();
058        synchronized (contextMap) {
059            ConcurrentMap<String, Log> map = contextMap.get(context);
060            if (map == null) {
061                map = new ConcurrentHashMap<String, Log>();
062                contextMap.put(context, map);
063            }
064            return map;
065        }
066    }
067
068    @Override
069    public Object getAttribute(final String name) {
070        return attributes.get(name);
071    }
072
073    @Override
074    public String[] getAttributeNames() {
075        return attributes.keySet().toArray(new String[attributes.size()]);
076    }
077
078    @Override
079    public Log getInstance(@SuppressWarnings("rawtypes") final Class clazz) throws LogConfigurationException {
080        return getInstance(clazz.getName());
081    }
082
083    /**
084     * This method is supposed to clear all loggers. In this implementation it will clear all the logger
085     * wrappers but the loggers managed by the underlying logger context will not be.
086     */
087    @Override
088    public void release() {
089        getLoggersMap().clear();
090    }
091
092    @Override
093    public void removeAttribute(final String name) {
094        attributes.remove(name);
095    }
096
097    @Override
098    public void setAttribute(final String name, final Object value) {
099        if (value != null) {
100            attributes.put(name, value);
101        } else {
102            removeAttribute(name);
103        }
104    }
105
106    /**
107     * The real bridge between commons logging and Log4j.
108     */
109    private static class PrivateManager extends LogManager {
110        private static final String FQCN = LogFactory.class.getName();
111
112        public static LoggerContext getContext() {
113            return getContext(FQCN, false);
114        }
115
116        public static org.apache.logging.log4j.Logger getLogger(final String name) {
117            return getLogger(FQCN, name);
118        }
119    }
120
121}