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.spi;
018    
019    import java.net.URL;
020    import java.util.Properties;
021    
022    import org.apache.logging.log4j.Logger;
023    import 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     */
030    public 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    }