1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core;
18
19 import java.beans.PropertyChangeEvent;
20 import java.beans.PropertyChangeListener;
21 import java.io.File;
22 import java.net.URI;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.CopyOnWriteArrayList;
28 import java.util.concurrent.locks.Lock;
29 import java.util.concurrent.locks.ReentrantLock;
30
31 import org.apache.logging.log4j.core.config.Configuration;
32 import org.apache.logging.log4j.core.config.ConfigurationFactory;
33 import org.apache.logging.log4j.core.config.ConfigurationListener;
34 import org.apache.logging.log4j.core.config.DefaultConfiguration;
35 import org.apache.logging.log4j.core.config.NullConfiguration;
36 import org.apache.logging.log4j.core.config.Reconfigurable;
37 import org.apache.logging.log4j.core.helpers.NetUtils;
38 import org.apache.logging.log4j.core.jmx.Assert;
39 import org.apache.logging.log4j.message.MessageFactory;
40 import org.apache.logging.log4j.spi.AbstractLogger;
41 import org.apache.logging.log4j.status.StatusLogger;
42
43
44
45
46
47
48
49
50 public class LoggerContext implements org.apache.logging.log4j.spi.LoggerContext, ConfigurationListener, LifeCycle {
51
52 public static final String PROPERTY_CONFIG = "config";
53 private static final StatusLogger LOGGER = StatusLogger.getLogger();
54
55 private final ConcurrentMap<String, Logger> loggers = new ConcurrentHashMap<String, Logger>();
56 private final CopyOnWriteArrayList<PropertyChangeListener> propertyChangeListeners = new CopyOnWriteArrayList<PropertyChangeListener>();
57
58
59
60
61
62 private volatile Configuration config = new DefaultConfiguration();
63 private Object externalContext;
64 private final String name;
65 private URI configLocation;
66
67 private ShutdownThread shutdownThread = null;
68
69
70
71
72 public enum Status {
73
74 INITIALIZED,
75
76 STARTING,
77
78 STARTED,
79
80 STOPPING,
81
82 STOPPED
83 }
84
85 private volatile Status status = Status.INITIALIZED;
86
87 private final Lock configLock = new ReentrantLock();
88
89
90
91
92
93 public LoggerContext(final String name) {
94 this(name, null, (URI) null);
95 }
96
97
98
99
100
101
102 public LoggerContext(final String name, final Object externalContext) {
103 this(name, externalContext, (URI) null);
104 }
105
106
107
108
109
110
111
112 public LoggerContext(final String name, final Object externalContext, final URI configLocn) {
113 this.name = name;
114 this.externalContext = externalContext;
115 this.configLocation = configLocn;
116 }
117
118
119
120
121
122
123
124
125
126 public LoggerContext(final String name, final Object externalContext, final String configLocn) {
127 this.name = name;
128 this.externalContext = externalContext;
129 if (configLocn != null) {
130 URI uri;
131 try {
132 uri = new File(configLocn).toURI();
133 } catch (final Exception ex) {
134 uri = null;
135 }
136 configLocation = uri;
137 } else {
138 configLocation = null;
139 }
140 }
141
142 public void start() {
143 if (configLock.tryLock()) {
144 try {
145 if (status == Status.INITIALIZED) {
146 status = Status.STARTING;
147 reconfigure();
148 shutdownThread = new ShutdownThread(this);
149 try {
150 Runtime.getRuntime().addShutdownHook(shutdownThread);
151 } catch (SecurityException se) {
152 LOGGER.warn("Unable to register shutdown hook due to security restrictions");
153 shutdownThread = null;
154 }
155 status = Status.STARTED;
156 }
157 } finally {
158 configLock.unlock();
159 }
160 }
161 }
162
163 public void stop() {
164 configLock.lock();
165 try {
166 status = Status.STOPPING;
167 if (shutdownThread != null) {
168 Runtime.getRuntime().removeShutdownHook(shutdownThread);
169 shutdownThread = null;
170 }
171 updateLoggers(new NullConfiguration());
172 config.stop();
173 externalContext = null;
174 status = Status.STOPPED;
175 } finally {
176 configLock.unlock();
177 }
178 }
179
180
181
182
183
184
185 public String getName() {
186 return name;
187 }
188
189 public Status getStatus() {
190 return status;
191 }
192
193 public boolean isStarted() {
194 return status == Status.STARTED;
195 }
196
197
198
199
200
201 public void setExternalContext(final Object context) {
202 this.externalContext = context;
203 }
204
205
206
207
208
209 public Object getExternalContext() {
210 return this.externalContext;
211 }
212
213
214
215
216
217
218 public Logger getLogger(final String name) {
219 return getLogger(name, null);
220 }
221
222
223
224
225
226
227
228
229
230 public Logger getLogger(final String name, final MessageFactory messageFactory) {
231 Logger logger = loggers.get(name);
232 if (logger != null) {
233 AbstractLogger.checkMessageFactory(logger, messageFactory);
234 return logger;
235 }
236
237 logger = newInstance(this, name, messageFactory);
238 final Logger prev = loggers.putIfAbsent(name, logger);
239 return prev == null ? logger : prev;
240 }
241
242
243
244
245
246
247 public boolean hasLogger(final String name) {
248 return loggers.containsKey(name);
249 }
250
251
252
253
254
255
256
257 public Configuration getConfiguration() {
258 return config;
259 }
260
261
262
263
264
265
266 public void addFilter(final Filter filter) {
267 config.addFilter(filter);
268 }
269
270
271
272
273
274 public void removeFilter(final Filter filter) {
275 config.removeFilter(filter);
276 }
277
278
279
280
281
282
283 public synchronized Configuration setConfiguration(final Configuration config) {
284 if (config == null) {
285 throw new NullPointerException("No Configuration was provided");
286 }
287 final Configuration prev = this.config;
288 config.addListener(this);
289 final Map<String, String> map = new HashMap<String, String>();
290 map.put("hostName", NetUtils.getLocalHostname());
291 map.put("contextName", name);
292 config.addComponent(Configuration.CONTEXT_PROPERTIES, map);
293 config.start();
294 this.config = config;
295 updateLoggers();
296 if (prev != null) {
297 prev.removeListener(this);
298 prev.stop();
299 }
300
301
302 PropertyChangeEvent evt = new PropertyChangeEvent(this, PROPERTY_CONFIG, prev, config);
303 for (PropertyChangeListener listener : propertyChangeListeners) {
304 listener.propertyChange(evt);
305 }
306 return prev;
307 }
308
309 public void addPropertyChangeListener(PropertyChangeListener listener) {
310 propertyChangeListeners.add(Assert.isNotNull(listener, "listener"));
311 }
312
313 public void removePropertyChangeListener(PropertyChangeListener listener) {
314 propertyChangeListeners.remove(listener);
315 }
316
317 public synchronized URI getConfigLocation() {
318 return configLocation;
319 }
320
321 public synchronized void setConfigLocation(URI configLocation) {
322 this.configLocation = configLocation;
323 reconfigure();
324 }
325
326
327
328
329 public synchronized void reconfigure() {
330 LOGGER.debug("Reconfiguration started for context " + name);
331 final Configuration instance = ConfigurationFactory.getInstance().getConfiguration(name, configLocation);
332 setConfiguration(instance);
333
334
335
336
337 LOGGER.debug("Reconfiguration completed");
338 }
339
340
341
342
343 public void updateLoggers() {
344 updateLoggers(this.config);
345 }
346
347
348
349
350
351 public void updateLoggers(final Configuration config) {
352 for (final Logger logger : loggers.values()) {
353 logger.updateConfiguration(config);
354 }
355 }
356
357
358
359
360
361
362
363 public synchronized void onChange(final Reconfigurable reconfigurable) {
364 LOGGER.debug("Reconfiguration started for context " + name);
365 final Configuration config = reconfigurable.reconfigure();
366 if (config != null) {
367 setConfiguration(config);
368 LOGGER.debug("Reconfiguration completed");
369 } else {
370 LOGGER.debug("Reconfiguration failed");
371 }
372 }
373
374
375 protected Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) {
376 return new Logger(ctx, name, messageFactory);
377 }
378
379 private class ShutdownThread extends Thread {
380
381 private final LoggerContext context;
382
383 public ShutdownThread(LoggerContext context) {
384 this.context = context;
385 }
386
387 public void run() {
388 context.shutdownThread = null;
389 context.stop();
390 }
391 }
392
393 }