1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.selector;
18
19 import java.lang.ref.WeakReference;
20 import java.net.URI;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.ConcurrentMap;
28 import java.util.concurrent.atomic.AtomicReference;
29
30 import org.apache.logging.log4j.core.LoggerContext;
31 import org.apache.logging.log4j.core.impl.ContextAnchor;
32 import org.apache.logging.log4j.status.StatusLogger;
33 import org.apache.logging.log4j.util.ReflectionUtil;
34
35
36
37
38
39
40
41
42
43
44
45
46 public class ClassLoaderContextSelector implements ContextSelector {
47
48 private static final AtomicReference<LoggerContext> CONTEXT = new AtomicReference<LoggerContext>();
49
50 protected static final StatusLogger LOGGER = StatusLogger.getLogger();
51
52 protected static final ConcurrentMap<String, AtomicReference<WeakReference<LoggerContext>>> CONTEXT_MAP =
53 new ConcurrentHashMap<String, AtomicReference<WeakReference<LoggerContext>>>();
54
55 @Override
56 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext) {
57 return getContext(fqcn, loader, currentContext, null);
58 }
59
60 @Override
61 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext,
62 final URI configLocation) {
63 if (currentContext) {
64 final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();
65 if (ctx != null) {
66 return ctx;
67 }
68 return getDefault();
69 } else if (loader != null) {
70 return locateContext(loader, configLocation);
71 } else {
72 final Class<?> clazz = ReflectionUtil.getCallerClass(fqcn);
73 if (clazz != null) {
74 return locateContext(clazz.getClassLoader(), configLocation);
75 }
76 final LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get();
77 if (lc != null) {
78 return lc;
79 }
80 return getDefault();
81 }
82 }
83
84 @Override
85 public void removeContext(final LoggerContext context) {
86 for (final Map.Entry<String, AtomicReference<WeakReference<LoggerContext>>> entry : CONTEXT_MAP.entrySet()) {
87 final LoggerContext ctx = entry.getValue().get().get();
88 if (ctx == context) {
89 CONTEXT_MAP.remove(entry.getKey());
90 }
91 }
92 }
93
94 @Override
95 public List<LoggerContext> getLoggerContexts() {
96 final List<LoggerContext> list = new ArrayList<LoggerContext>();
97 final Collection<AtomicReference<WeakReference<LoggerContext>>> coll = CONTEXT_MAP.values();
98 for (final AtomicReference<WeakReference<LoggerContext>> ref : coll) {
99 final LoggerContext ctx = ref.get().get();
100 if (ctx != null) {
101 list.add(ctx);
102 }
103 }
104 return Collections.unmodifiableList(list);
105 }
106
107 private LoggerContext locateContext(final ClassLoader loaderOrNull, final URI configLocation) {
108
109 final ClassLoader loader = loaderOrNull != null ? loaderOrNull : ClassLoader.getSystemClassLoader();
110 final String name = toContextMapKey(loader);
111 AtomicReference<WeakReference<LoggerContext>> ref = CONTEXT_MAP.get(name);
112 if (ref == null) {
113 if (configLocation == null) {
114 ClassLoader parent = loader.getParent();
115 while (parent != null) {
116
117 ref = CONTEXT_MAP.get(toContextMapKey(parent));
118 if (ref != null) {
119 final WeakReference<LoggerContext> r = ref.get();
120 final LoggerContext ctx = r.get();
121 if (ctx != null) {
122 return ctx;
123 }
124 }
125 parent = parent.getParent();
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 }
144 }
145 LoggerContext ctx = new LoggerContext(name, null, configLocation);
146 final AtomicReference<WeakReference<LoggerContext>> r =
147 new AtomicReference<WeakReference<LoggerContext>>();
148 r.set(new WeakReference<LoggerContext>(ctx));
149 CONTEXT_MAP.putIfAbsent(name, r);
150 ctx = CONTEXT_MAP.get(name).get().get();
151 return ctx;
152 }
153 final WeakReference<LoggerContext> weakRef = ref.get();
154 LoggerContext ctx = weakRef.get();
155 if (ctx != null) {
156 if (ctx.getConfigLocation() == null && configLocation != null) {
157 LOGGER.debug("Setting configuration to {}", configLocation);
158 ctx.setConfigLocation(configLocation);
159 } else if (ctx.getConfigLocation() != null && configLocation != null &&
160 !ctx.getConfigLocation().equals(configLocation)) {
161 LOGGER.warn("locateContext called with URI {}. Existing LoggerContext has URI {}", configLocation,
162 ctx.getConfigLocation());
163 }
164 return ctx;
165 }
166 ctx = new LoggerContext(name, null, configLocation);
167 ref.compareAndSet(weakRef, new WeakReference<LoggerContext>(ctx));
168 return ctx;
169 }
170
171 private String toContextMapKey(final ClassLoader loader) {
172 return String.valueOf(System.identityHashCode(loader));
173 }
174
175 protected LoggerContext getDefault() {
176 final LoggerContext ctx = CONTEXT.get();
177 if (ctx != null) {
178 return ctx;
179 }
180 CONTEXT.compareAndSet(null, new LoggerContext("Default"));
181 return CONTEXT.get();
182 }
183
184 }