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