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