All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.logging.log4j.spi.LoggerRegistry Maven / Gradle / Ivy

There is a newer version: 3.0.0-beta2
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.logging.log4j.spi;

import static java.util.Objects.requireNonNull;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.message.ParameterizedMessageFactory;

/**
 * Convenience class to be used as an {@link ExtendedLogger} registry by {@code LoggerContext} implementations.
 */
public class LoggerRegistry {

    private final Map>> loggerRefByMessageFactoryByName = new HashMap<>();

    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    private final Lock readLock = lock.readLock();

    private final Lock writeLock = lock.writeLock();

    /**
     * Data structure contract for the internal storage of admitted loggers.
     *
     * @param  subtype of {@code ExtendedLogger}
     */
    public interface MapFactory {

        Map createInnerMap();

        Map> createOuterMap();

        void putIfAbsent(Map innerMap, String name, T logger);
    }

    /**
     * {@link MapFactory} implementation using {@link ConcurrentHashMap}.
     *
     * @param  subtype of {@code ExtendedLogger}
     */
    public static class ConcurrentMapFactory implements MapFactory {

        @Override
        public Map createInnerMap() {
            return new ConcurrentHashMap<>();
        }

        @Override
        public Map> createOuterMap() {
            return new ConcurrentHashMap<>();
        }

        @Override
        public void putIfAbsent(final Map innerMap, final String name, final T logger) {
            innerMap.putIfAbsent(name, logger);
        }
    }

    /**
     * {@link MapFactory} implementation using {@link WeakHashMap}.
     *
     * @param  subtype of {@code ExtendedLogger}
     */
    public static class WeakMapFactory implements MapFactory {

        @Override
        public Map createInnerMap() {
            return new WeakHashMap<>();
        }

        @Override
        public Map> createOuterMap() {
            return new WeakHashMap<>();
        }

        @Override
        public void putIfAbsent(final Map innerMap, final String name, final T logger) {
            innerMap.put(name, logger);
        }
    }

    public LoggerRegistry() {}

    /**
     * Constructs an instance ignoring the given the map factory.
     *
     * @param mapFactory a map factory
     */
    public LoggerRegistry(final MapFactory mapFactory) {
        this();
    }

    /**
     * Returns the logger associated with the given name.
     * 

* There can be made no assumptions on the message factory of the returned logger. * Callers are strongly advised to switch to {@link #getLogger(String, MessageFactory)} and provide a message factory parameter! *

* * @param name a logger name * @return the logger associated with the name */ public T getLogger(final String name) { requireNonNull(name, "name"); return getLogger(name, null); } /** * Returns the logger associated with the given name and message factory. *

* In the absence of a message factory, there can be made no assumptions on the message factory of the returned logger. * This lenient behaviour is only kept for backward compatibility. * Callers are strongly advised to provide a message factory parameter to the method! *

* * @param name a logger name * @param messageFactory a message factory * @return the logger associated with the given name and message factory */ public T getLogger(final String name, final MessageFactory messageFactory) { requireNonNull(name, "name"); readLock.lock(); try { final Map> loggerRefByMessageFactory = loggerRefByMessageFactoryByName.get(name); if (loggerRefByMessageFactory == null) { return null; } final MessageFactory effectiveMessageFactory = messageFactory != null ? messageFactory : ParameterizedMessageFactory.INSTANCE; final WeakReference loggerRef = loggerRefByMessageFactory.get(effectiveMessageFactory); if (loggerRef == null) { return null; } return loggerRef.get(); } finally { readLock.unlock(); } } public Collection getLoggers() { return getLoggers(new ArrayList()); } public Collection getLoggers(final Collection destination) { requireNonNull(destination, "destination"); readLock.lock(); try { loggerRefByMessageFactoryByName.values().stream() .flatMap(loggerRefByMessageFactory -> loggerRefByMessageFactory.values().stream().map(WeakReference::get)) .filter(Objects::nonNull) .forEach(destination::add); } finally { readLock.unlock(); } return destination; } /** * Checks if a logger associated with the given name exists. *

* There can be made no assumptions on the message factory of the found logger. * Callers are strongly advised to switch to {@link #hasLogger(String, MessageFactory)} and provide a message factory parameter! *

* * @param name a logger name * @return {@code true}, if the logger exists; {@code false} otherwise. */ public boolean hasLogger(final String name) { requireNonNull(name, "name"); final T logger = getLogger(name); return logger != null; } /** * Checks if a logger associated with the given name and message factory exists. *

* In the absence of a message factory, there can be made no assumptions on the message factory of the found logger. * This lenient behaviour is only kept for backward compatibility. * Callers are strongly advised to provide a message factory parameter to the method! *

* * @param name a logger name * @param messageFactory a message factory * @return {@code true}, if the logger exists; {@code false} otherwise. * @since 2.5 */ public boolean hasLogger(final String name, final MessageFactory messageFactory) { requireNonNull(name, "name"); final T logger = getLogger(name, messageFactory); return logger != null; } /** * Checks if a logger associated with the given name and message factory type exists. * * @param name a logger name * @param messageFactoryClass a message factory class * @return {@code true}, if the logger exists; {@code false} otherwise. * @since 2.5 */ public boolean hasLogger(final String name, final Class messageFactoryClass) { requireNonNull(name, "name"); requireNonNull(messageFactoryClass, "messageFactoryClass"); readLock.lock(); try { return loggerRefByMessageFactoryByName.getOrDefault(name, Collections.emptyMap()).keySet().stream() .anyMatch(messageFactory -> messageFactoryClass.equals(messageFactory.getClass())); } finally { readLock.unlock(); } } /** * Registers the provided logger. * Logger name and message factory parameters are ignored, those will be obtained from the logger instead. * * @param name ignored – kept for backward compatibility * @param messageFactory ignored – kept for backward compatibility * @param logger a logger instance */ public void putIfAbsent(final String name, final MessageFactory messageFactory, final T logger) { // Check arguments requireNonNull(logger, "logger"); // Insert the logger writeLock.lock(); try { final Map> loggerRefByMessageFactory = loggerRefByMessageFactoryByName.computeIfAbsent( logger.getName(), this::createLoggerRefByMessageFactoryMap); final MessageFactory loggerMessageFactory = logger.getMessageFactory(); final WeakReference loggerRef = loggerRefByMessageFactory.get(loggerMessageFactory); if (loggerRef == null || loggerRef.get() == null) { loggerRefByMessageFactory.put(loggerMessageFactory, new WeakReference<>(logger)); } } finally { writeLock.unlock(); } } private Map> createLoggerRefByMessageFactoryMap(final String ignored) { return new WeakHashMap<>(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy