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 (ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
67 try {
68 loadProviders(classLoader);
69 } catch (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 protected static void loadProviders(final ClassLoader cl) {
104 final ServiceLoader<Provider> serviceLoader = ServiceLoader.load(Provider.class, cl);
105 for (final Provider provider : serviceLoader) {
106 if (validVersion(provider.getVersions()) && !PROVIDERS.contains(provider)) {
107 PROVIDERS.add(provider);
108 }
109 }
110 }
111
112
113
114
115 @Deprecated
116 protected static void loadProviders(final Enumeration<URL> urls, final ClassLoader cl) {
117 if (urls != null) {
118 while (urls.hasMoreElements()) {
119 loadProvider(urls.nextElement(), cl);
120 }
121 }
122 }
123
124 public static Iterable<Provider> getProviders() {
125 lazyInit();
126 return PROVIDERS;
127 }
128
129 public static boolean hasProviders() {
130 lazyInit();
131 return !PROVIDERS.isEmpty();
132 }
133
134
135
136
137
138
139 protected static void lazyInit() {
140
141 if (instance == null) {
142 try {
143 STARTUP_LOCK.lockInterruptibly();
144 try {
145 if (instance == null) {
146 instance = new ProviderUtil();
147 }
148 } finally {
149 STARTUP_LOCK.unlock();
150 }
151 } catch (final InterruptedException e) {
152 LOGGER.fatal("Interrupted before Log4j Providers could be loaded.", e);
153 Thread.currentThread().interrupt();
154 }
155 }
156 }
157
158 public static ClassLoader findClassLoader() {
159 return LoaderUtil.getThreadContextClassLoader();
160 }
161
162 private static boolean validVersion(final String version) {
163 for (final String v : COMPATIBLE_API_VERSIONS) {
164 if (version.startsWith(v)) {
165 return true;
166 }
167 }
168 return false;
169 }
170 }