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.net.URL;
020import java.util.Properties;
021
022import org.apache.logging.log4j.Logger;
023import org.apache.logging.log4j.status.StatusLogger;
024
025/**
026 * Model class for a Log4j 2 provider. The properties in this class correspond to the properties used in a
027 * {@code META-INF/log4j-provider.properties} file. Note that this class is automatically created by Log4j and should
028 * not be used by providers.
029 */
030public class Provider {
031    private static final Integer DEFAULT_PRIORITY = Integer.valueOf(-1);
032    /**
033     * Property name to set for a Log4j 2 provider to specify the priority of this implementation.
034     */
035    public static final String FACTORY_PRIORITY = "FactoryPriority";
036    /**
037     * Property name to set to the implementation of {@link org.apache.logging.log4j.spi.ThreadContextMap}.
038     */
039    public static final String THREAD_CONTEXT_MAP = "ThreadContextMap";
040    /**
041     * Property name to set to the implementation of {@link org.apache.logging.log4j.spi.LoggerContextFactory}.
042     */
043    public static final String LOGGER_CONTEXT_FACTORY = "LoggerContextFactory";
044
045    private static final Logger LOGGER = StatusLogger.getLogger();
046
047    private final Integer priority;
048    private final String className;
049    private final String threadContextMap;
050    private final URL url;
051    private final ClassLoader classLoader;
052
053    public Provider(final Properties props, final URL url, final ClassLoader classLoader) {
054        this.url = url;
055        this.classLoader = classLoader;
056        final String weight = props.getProperty(FACTORY_PRIORITY);
057        priority = weight == null ? DEFAULT_PRIORITY : Integer.valueOf(weight);
058        className = props.getProperty(LOGGER_CONTEXT_FACTORY);
059        threadContextMap = props.getProperty(THREAD_CONTEXT_MAP);
060    }
061
062    /**
063     * Gets the priority (natural ordering) of this Provider.
064     *
065     * @return the priority of this Provider
066     */
067    public Integer getPriority() {
068        return priority;
069    }
070
071    /**
072     * Gets the class name of the {@link org.apache.logging.log4j.spi.LoggerContextFactory} implementation of this
073     * Provider.
074     *
075     * @return the class name of a LoggerContextFactory implementation
076     */
077    public String getClassName() {
078        return className;
079    }
080
081    /**
082     * Loads the {@link org.apache.logging.log4j.spi.LoggerContextFactory} class specified by this Provider.
083     *
084     * @return the LoggerContextFactory implementation class or {@code null} if there was an error loading it
085     */
086    public Class<? extends LoggerContextFactory> loadLoggerContextFactory() {
087        if (className == null) {
088            return null;
089        }
090        try {
091            final Class<?> clazz = classLoader.loadClass(className);
092            if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
093                return clazz.asSubclass(LoggerContextFactory.class);
094            }
095        } catch (final Exception e) {
096            LOGGER.error("Unable to create class {} specified in {}", className, url.toString(), e);
097        }
098        return null;
099    }
100
101    /**
102     * Gets the class name of the {@link org.apache.logging.log4j.spi.ThreadContextMap} implementation of this
103     * Provider.
104     *
105     * @return the class name of a ThreadContextMap implementation
106     */
107    public String getThreadContextMap() {
108        return threadContextMap;
109    }
110
111    /**
112     * Loads the {@link org.apache.logging.log4j.spi.ThreadContextMap} class specified by this Provider.
113     *
114     * @return the ThreadContextMap implementation class or {@code null} if there was an error loading it
115     */
116    public Class<? extends ThreadContextMap> loadThreadContextMap() {
117        if (threadContextMap == null) {
118            return null;
119        }
120        try {
121            final Class<?> clazz = classLoader.loadClass(threadContextMap);
122            if (ThreadContextMap.class.isAssignableFrom(clazz)) {
123                return clazz.asSubclass(ThreadContextMap.class);
124            }
125        } catch (final Exception e) {
126            LOGGER.error("Unable to create class {} specified in {}", threadContextMap, url.toString(), e);
127        }
128        return null;
129    }
130
131    /**
132     * Gets the URL containing this Provider's Log4j details.
133     *
134     * @return the URL corresponding to the Provider {@code META-INF/log4j-provider.properties} file
135     */
136    public URL getUrl() {
137        return url;
138    }
139}