1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.web;
18
19 import java.net.URI;
20 import java.util.Map;
21 import java.util.concurrent.ConcurrentHashMap;
22 import javax.servlet.ServletContext;
23 import javax.servlet.UnavailableException;
24
25 import org.apache.logging.log4j.LogManager;
26 import org.apache.logging.log4j.core.LoggerContext;
27 import org.apache.logging.log4j.core.config.Configurator;
28 import org.apache.logging.log4j.core.helpers.FileUtils;
29 import org.apache.logging.log4j.core.helpers.NetUtils;
30 import org.apache.logging.log4j.core.impl.ContextAnchor;
31 import org.apache.logging.log4j.core.impl.Log4jContextFactory;
32 import org.apache.logging.log4j.core.lookup.Interpolator;
33 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
34 import org.apache.logging.log4j.core.selector.ContextSelector;
35 import org.apache.logging.log4j.core.selector.NamedContextSelector;
36 import org.apache.logging.log4j.spi.LoggerContextFactory;
37
38
39
40
41 final class Log4jWebInitializerImpl implements Log4jWebInitializer {
42 private static final Object MUTEX = new Object();
43
44 static {
45 try {
46 Class.forName("org.apache.logging.log4j.core.web.JNDIContextFilter");
47 throw new IllegalStateException("You are using Log4j 2 in a web application with the old, extinct " +
48 "log4j-web artifact. This is not supported and could cause serious runtime problems. Please" +
49 "remove the log4j-web JAR file from your application.");
50 } catch (final ClassNotFoundException ignore) {
51
52 }
53 }
54
55 private final Map<String, String> map = new ConcurrentHashMap<String, String>();
56 private final StrSubstitutor substitutor = new StrSubstitutor(new Interpolator(map));
57 private final ServletContext servletContext;
58
59 private String name;
60 private NamedContextSelector selector;
61 private LoggerContext loggerContext;
62
63 private boolean initialized = false;
64 private boolean deinitialized = false;
65
66 private Log4jWebInitializerImpl(final ServletContext servletContext) {
67 this.servletContext = servletContext;
68 map.put("hostName", NetUtils.getLocalHostname());
69 }
70
71 @Override
72 public synchronized void initialize() throws UnavailableException {
73 if (this.deinitialized) {
74 throw new IllegalStateException("Cannot initialize Log4jWebInitializer after it was destroyed.");
75 }
76
77
78 if (!this.initialized) {
79 this.initialized = true;
80
81 this.name = this.substitutor.replace(this.servletContext.getInitParameter(LOG4J_CONTEXT_NAME));
82 final String location =
83 this.substitutor.replace(this.servletContext.getInitParameter(LOG4J_CONFIG_LOCATION));
84 final boolean isJndi =
85 "true".equalsIgnoreCase(this.servletContext.getInitParameter(IS_LOG4J_CONTEXT_SELECTOR_NAMED));
86
87 if (isJndi) {
88 this.initializeJndi(location);
89 } else {
90 this.initializeNonJndi(location);
91 }
92
93 this.servletContext.setAttribute(CONTEXT_ATTRIBUTE, this.loggerContext);
94 }
95 }
96
97 private void initializeJndi(final String location) throws UnavailableException {
98 URI configLocation = null;
99 if (location != null) {
100 try {
101 configLocation = FileUtils.getCorrectedFilePathUri(location);
102 } catch (final Exception e) {
103 this.servletContext.log("Unable to convert configuration location [" + location + "] to a URI!", e);
104 }
105 }
106
107 if (this.name == null) {
108 throw new UnavailableException("A log4jContextName context parameter is required");
109 }
110
111 LoggerContext loggerContext;
112 final LoggerContextFactory factory = LogManager.getFactory();
113 if (factory instanceof Log4jContextFactory) {
114 final ContextSelector selector = ((Log4jContextFactory) factory).getSelector();
115 if (selector instanceof NamedContextSelector) {
116 this.selector = (NamedContextSelector) selector;
117 loggerContext = this.selector.locateContext(this.name, this.servletContext, configLocation);
118 ContextAnchor.THREAD_CONTEXT.set(loggerContext);
119 if (loggerContext.getStatus() == LoggerContext.Status.INITIALIZED) {
120 loggerContext.start();
121 }
122 ContextAnchor.THREAD_CONTEXT.remove();
123 } else {
124 this.servletContext.log("Potential problem: Selector is not an instance of NamedContextSelector.");
125 return;
126 }
127 } else {
128 this.servletContext.log("Potential problem: Factory is not an instance of Log4jContextFactory.");
129 return;
130 }
131 this.loggerContext = loggerContext;
132 this.servletContext.log("Created logger context for [" + this.name + "] using [" +
133 loggerContext.getClass().getClassLoader() + "].");
134 }
135
136 private void initializeNonJndi(final String location) {
137 if (this.name == null) {
138 this.name = this.servletContext.getServletContextName();
139 }
140
141 if (this.name == null && location == null) {
142 this.servletContext.log("No Log4j context configuration provided. This is very unusual.");
143 return;
144 }
145
146 this.loggerContext = Configurator.initialize(this.name, this.getClassLoader(), location, this.servletContext);
147 }
148
149 @Override
150 public synchronized void deinitialize() {
151 if (!this.initialized) {
152 throw new IllegalStateException("Cannot deinitialize Log4jWebInitializer because it has not initialized.");
153 }
154
155
156 if (!this.deinitialized) {
157 this.deinitialized = true;
158
159 if (this.loggerContext != null) {
160 this.servletContext.log("Removing LoggerContext for [" + this.name + "].");
161 this.servletContext.removeAttribute(CONTEXT_ATTRIBUTE);
162 if (this.selector != null) {
163 this.selector.removeContext(this.name);
164 }
165 this.loggerContext.stop();
166 this.loggerContext.setExternalContext(null);
167 this.loggerContext = null;
168 }
169 }
170 }
171
172 @Override
173 public void setLoggerContext() {
174 if (this.loggerContext != null) {
175 ContextAnchor.THREAD_CONTEXT.set(this.loggerContext);
176 }
177 }
178
179 @Override
180 public void clearLoggerContext() {
181 ContextAnchor.THREAD_CONTEXT.remove();
182 }
183
184 @Override
185 public void wrapExecution(Runnable runnable) {
186 this.setLoggerContext();
187
188 try {
189 runnable.run();
190 } finally {
191 this.clearLoggerContext();
192 }
193 }
194
195 private ClassLoader getClassLoader() {
196 try {
197
198
199
200 return this.servletContext.getClassLoader();
201 } catch (final Throwable ignore) {
202
203 return Log4jWebInitializerImpl.class.getClassLoader();
204 }
205 }
206
207
208
209
210
211
212
213
214 static Log4jWebInitializer getLog4jWebInitializer(final ServletContext servletContext) {
215 synchronized (MUTEX) {
216 Log4jWebInitializer initializer = (Log4jWebInitializer) servletContext.getAttribute(SUPPORT_ATTRIBUTE);
217 if (initializer == null) {
218 initializer = new Log4jWebInitializerImpl(servletContext);
219 servletContext.setAttribute(SUPPORT_ATTRIBUTE, initializer);
220 }
221 return initializer;
222 }
223 }
224 }