1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.util;
18
19 import java.io.IOException;
20 import java.net.URL;
21 import java.util.Collection;
22 import java.util.Enumeration;
23 import java.util.HashSet;
24 import java.util.Properties;
25 import java.util.ServiceLoader;
26 import java.util.concurrent.locks.Lock;
27 import java.util.concurrent.locks.ReentrantLock;
28
29 import org.apache.logging.log4j.Logger;
30 import org.apache.logging.log4j.spi.Provider;
31 import org.apache.logging.log4j.status.StatusLogger;
32
33
34
35
36
37
38 public final class ProviderUtil {
39
40
41
42
43 protected static final String PROVIDER_RESOURCE = "META-INF/log4j-provider.properties";
44
45
46
47
48 protected static final Collection<Provider> PROVIDERS = new HashSet<>();
49
50
51
52
53
54
55 protected static final Lock STARTUP_LOCK = new ReentrantLock();
56
57 private static final String API_VERSION = "Log4jAPIVersion";
58 private static final String[] COMPATIBLE_API_VERSIONS = {"2.6.0"};
59 private static final Logger LOGGER = StatusLogger.getLogger();
60
61
62
63 private static volatile ProviderUtil instance;
64
65 private ProviderUtil() {
66 for (final ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
67 try {
68 loadProviders(classLoader);
69 } catch (final Throwable ex) {
70 LOGGER.debug("Unable to retrieve provider from ClassLoader {}", classLoader, ex);
71 }
72 }
73 for (final LoaderUtil.UrlResource resource : LoaderUtil.findUrlResources(PROVIDER_RESOURCE)) {
74 loadProvider(resource.getUrl(), resource.getClassLoader());
75 }
76 }
77
78 protected static void addProvider(final Provider provider) {
79 PROVIDERS.add(provider);
80 LOGGER.debug("Loaded Provider {}", provider);
81 }
82
83
84
85
86
87
88
89
90 protected static void loadProvider(final URL url, final ClassLoader cl) {
91 try {
92 final Properties props = PropertiesUtil.loadClose(url.openStream(), url);
93 if (validVersion(props.getProperty(API_VERSION))) {
94 final Provider provider = new Provider(props, url, cl);
95 PROVIDERS.add(provider);
96 LOGGER.debug("Loaded Provider {}", provider);
97 }
98 } catch (final IOException e) {
99 LOGGER.error("Unable to open {}", url, e);
100 }
101 }
102
103
104
105
106
107 protected static void loadProviders(final ClassLoader classLoader) {
108 final ServiceLoader<Provider> serviceLoader = ServiceLoader.load(Provider.class, classLoader);
109 for (final Provider provider : serviceLoader) {
110 if (validVersion(provider.getVersions()) && !PROVIDERS.contains(provider)) {
111 PROVIDERS.add(provider);
112 }
113 }
114 }
115
116
117
118
119 @Deprecated
120 protected static void loadProviders(final Enumeration<URL> urls, final ClassLoader cl) {
121 if (urls != null) {
122 while (urls.hasMoreElements()) {
123 loadProvider(urls.nextElement(), cl);
124 }
125 }
126 }
127
128 public static Iterable<Provider> getProviders() {
129 lazyInit();
130 return PROVIDERS;
131 }
132
133 public static boolean hasProviders() {
134 lazyInit();
135 return !PROVIDERS.isEmpty();
136 }
137
138
139
140
141
142
143 protected static void lazyInit() {
144
145 if (instance == null) {
146 try {
147 STARTUP_LOCK.lockInterruptibly();
148 try {
149 if (instance == null) {
150 instance = new ProviderUtil();
151 }
152 } finally {
153 STARTUP_LOCK.unlock();
154 }
155 } catch (final InterruptedException e) {
156 LOGGER.fatal("Interrupted before Log4j Providers could be loaded.", e);
157 Thread.currentThread().interrupt();
158 }
159 }
160 }
161
162 public static ClassLoader findClassLoader() {
163 return LoaderUtil.getThreadContextClassLoader();
164 }
165
166 private static boolean validVersion(final String version) {
167 for (final String v : COMPATIBLE_API_VERSIONS) {
168 if (version.startsWith(v)) {
169 return true;
170 }
171 }
172 return false;
173 }
174 }