View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.spi;
18  
19  import java.lang.ref.WeakReference;
20  import java.net.URL;
21  import java.util.Properties;
22  
23  import org.apache.logging.log4j.Logger;
24  import org.apache.logging.log4j.status.StatusLogger;
25  
26  /**
27   * Model class for a Log4j 2 provider. The properties in this class correspond to the properties used in a
28   * {@code META-INF/log4j-provider.properties} file. Note that this class is automatically created by Log4j and should
29   * not be used by providers.
30   */
31  public class Provider {
32      /**
33       * Property name to set for a Log4j 2 provider to specify the priority of this implementation.
34       */
35      public static final String FACTORY_PRIORITY = "FactoryPriority";
36      /**
37       * Property name to set to the implementation of {@link org.apache.logging.log4j.spi.ThreadContextMap}.
38       */
39      public static final String THREAD_CONTEXT_MAP = "ThreadContextMap";
40      /**
41       * Property name to set to the implementation of {@link org.apache.logging.log4j.spi.LoggerContextFactory}.
42       */
43      public static final String LOGGER_CONTEXT_FACTORY = "LoggerContextFactory";
44  
45      private static final Integer DEFAULT_PRIORITY = Integer.valueOf(-1);
46      private static final Logger LOGGER = StatusLogger.getLogger();
47  
48      private final Integer priority;
49      private final String className;
50      private final String threadContextMap;
51      private final URL url;
52      private final WeakReference<ClassLoader> classLoader;
53  
54      public Provider(final Properties props, final URL url, final ClassLoader classLoader) {
55          this.url = url;
56          this.classLoader = new WeakReference<>(classLoader);
57          final String weight = props.getProperty(FACTORY_PRIORITY);
58          priority = weight == null ? DEFAULT_PRIORITY : Integer.valueOf(weight);
59          className = props.getProperty(LOGGER_CONTEXT_FACTORY);
60          threadContextMap = props.getProperty(THREAD_CONTEXT_MAP);
61      }
62  
63      /**
64       * Gets the priority (natural ordering) of this Provider.
65       *
66       * @return the priority of this Provider
67       */
68      public Integer getPriority() {
69          return priority;
70      }
71  
72      /**
73       * Gets the class name of the {@link org.apache.logging.log4j.spi.LoggerContextFactory} implementation of this
74       * Provider.
75       *
76       * @return the class name of a LoggerContextFactory implementation
77       */
78      public String getClassName() {
79          return className;
80      }
81  
82      /**
83       * Loads the {@link org.apache.logging.log4j.spi.LoggerContextFactory} class specified by this Provider.
84       *
85       * @return the LoggerContextFactory implementation class or {@code null} if there was an error loading it
86       */
87      public Class<? extends LoggerContextFactory> loadLoggerContextFactory() {
88          if (className == null) {
89              return null;
90          }
91          final ClassLoader loader = classLoader.get();
92          if (loader == null) {
93              return null;
94          }
95          try {
96              final Class<?> clazz = loader.loadClass(className);
97              if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
98                  return clazz.asSubclass(LoggerContextFactory.class);
99              }
100         } catch (final Exception e) {
101             LOGGER.error("Unable to create class {} specified in {}", className, url.toString(), e);
102         }
103         return null;
104     }
105 
106     /**
107      * Gets the class name of the {@link org.apache.logging.log4j.spi.ThreadContextMap} implementation of this Provider.
108      *
109      * @return the class name of a ThreadContextMap implementation
110      */
111     public String getThreadContextMap() {
112         return threadContextMap;
113     }
114 
115     /**
116      * Loads the {@link org.apache.logging.log4j.spi.ThreadContextMap} class specified by this Provider.
117      *
118      * @return the ThreadContextMap implementation class or {@code null} if there was an error loading it
119      */
120     public Class<? extends ThreadContextMap> loadThreadContextMap() {
121         if (threadContextMap == null) {
122             return null;
123         }
124         final ClassLoader loader = classLoader.get();
125         if (loader == null) {
126             return null;
127         }
128         try {
129             final Class<?> clazz = loader.loadClass(threadContextMap);
130             if (ThreadContextMap.class.isAssignableFrom(clazz)) {
131                 return clazz.asSubclass(ThreadContextMap.class);
132             }
133         } catch (final Exception e) {
134             LOGGER.error("Unable to create class {} specified in {}", threadContextMap, url.toString(), e);
135         }
136         return null;
137     }
138 
139     /**
140      * Gets the URL containing this Provider's Log4j details.
141      *
142      * @return the URL corresponding to the Provider {@code META-INF/log4j-provider.properties} file
143      */
144     public URL getUrl() {
145         return url;
146     }
147     
148     @Override
149     public String toString() {
150         String result = "Provider[";
151         if (priority != DEFAULT_PRIORITY) {
152             result += "priority=" + priority + ", ";
153         }
154         if (threadContextMap != null) {
155             result += "threadContextMap=" + threadContextMap + ", ";
156         }
157         if (className != null) {
158             result += "className=" + className + ", ";
159         }
160         result += "url=" + url;
161         final ClassLoader loader = classLoader.get();
162         if (loader == null) {
163             result += ", classLoader=null(not reachable)";
164         } else {
165             result += ", classLoader=" + loader;
166         }
167         result += "]";
168         return result;
169     }
170 }