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 org.apache.logging.log4j.core.LoggerContext;
20 import org.apache.logging.log4j.core.helpers.Loader;
21 import org.apache.logging.log4j.core.impl.ContextAnchor;
22 import org.apache.logging.log4j.status.StatusLogger;
23
24 import java.lang.ref.WeakReference;
25 import java.lang.reflect.Method;
26 import java.lang.reflect.Modifier;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentMap;
34 import java.util.concurrent.atomic.AtomicReference;
35
36
37
38
39
40
41
42
43
44
45
46
47 public class ClassLoaderContextSelector implements ContextSelector {
48
49 private static final AtomicReference<LoggerContext> CONTEXT = new AtomicReference<LoggerContext>();
50
51 private static PrivateSecurityManager securityManager;
52
53 private static Method getCallerClass;
54
55 private static final StatusLogger LOGGER = StatusLogger.getLogger();
56
57 private static final ConcurrentMap<String, AtomicReference<WeakReference<LoggerContext>>> CONTEXT_MAP =
58 new ConcurrentHashMap<String, AtomicReference<WeakReference<LoggerContext>>>();
59
60 static {
61 setupCallerCheck();
62 }
63
64 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext) {
65 if (currentContext) {
66 final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();
67 if (ctx != null) {
68 return ctx;
69 }
70 return getDefault();
71 } else if (loader != null) {
72 return locateContext(loader, null);
73 } else {
74 if (getCallerClass != null) {
75 try {
76 Class clazz = Class.class;
77 boolean next = false;
78 for (int index = 2; clazz != null; ++index) {
79 final Object[] params = new Object[] {index};
80 clazz = (Class) getCallerClass.invoke(null, params);
81 if (clazz == null) {
82 break;
83 }
84 if (clazz.getName().equals(fqcn)) {
85 next = true;
86 continue;
87 }
88 if (next) {
89 break;
90 }
91 }
92 if (clazz != null) {
93 return locateContext(clazz.getClassLoader(), null);
94 }
95 } catch (final Exception ex) {
96
97 }
98 }
99
100 if (securityManager != null) {
101 final Class clazz = securityManager.getCaller(fqcn);
102 if (clazz != null) {
103 final ClassLoader ldr = clazz.getClassLoader() != null ? clazz.getClassLoader() :
104 ClassLoader.getSystemClassLoader();
105 return locateContext(ldr, null);
106 }
107 }
108
109 final Throwable t = new Throwable();
110 boolean next = false;
111 String name = null;
112 for (final StackTraceElement element : t.getStackTrace()) {
113 if (element.getClassName().equals(fqcn)) {
114 next = true;
115 continue;
116 }
117 if (next) {
118 name = element.getClassName();
119 break;
120 }
121 }
122 if (name != null) {
123 try {
124 return locateContext(Loader.loadClass(name).getClassLoader(), null);
125 } catch (final ClassNotFoundException ex) {
126
127 }
128 }
129 final LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get();
130 if (lc != null) {
131 return lc;
132 }
133 return getDefault();
134 }
135 }
136
137 public void removeContext(final LoggerContext context) {
138 for (final Map.Entry<String, AtomicReference<WeakReference<LoggerContext>>> entry : CONTEXT_MAP.entrySet()) {
139 final LoggerContext ctx = entry.getValue().get().get();
140 if (ctx == context) {
141 CONTEXT_MAP.remove(entry.getKey());
142 }
143 }
144 }
145
146 public List<LoggerContext> getLoggerContexts() {
147 final List<LoggerContext> list = new ArrayList<LoggerContext>();
148 final Collection<AtomicReference<WeakReference<LoggerContext>>> coll = CONTEXT_MAP.values();
149 for (final AtomicReference<WeakReference<LoggerContext>> ref : coll) {
150 final LoggerContext ctx = ref.get().get();
151 if (ctx != null) {
152 list.add(ctx);
153 }
154 }
155 return Collections.unmodifiableList(list);
156 }
157
158 private LoggerContext locateContext(final ClassLoader loader, final String configLocation) {
159 final String name = loader.toString();
160 final AtomicReference<WeakReference<LoggerContext>> ref = CONTEXT_MAP.get(name);
161 if (ref == null) {
162 LoggerContext ctx = new LoggerContext(name, null, configLocation);
163 final AtomicReference<WeakReference<LoggerContext>> r =
164 new AtomicReference<WeakReference<LoggerContext>>();
165 r.set(new WeakReference<LoggerContext>(ctx));
166 CONTEXT_MAP.putIfAbsent(loader.toString(), r);
167 ctx = CONTEXT_MAP.get(name).get().get();
168 return ctx;
169 } else {
170 final WeakReference<LoggerContext> r = ref.get();
171 LoggerContext ctx = r.get();
172 if (ctx != null) {
173 return ctx;
174 }
175 ctx = new LoggerContext(name, null, configLocation);
176 ref.compareAndSet(r, new WeakReference<LoggerContext>(ctx));
177 return ctx;
178 }
179 }
180
181 private static void setupCallerCheck() {
182 try {
183 final ClassLoader loader = Loader.getClassLoader();
184 final Class clazz = loader.loadClass("sun.reflect.Reflection");
185 final Method[] methods = clazz.getMethods();
186 for (final Method method : methods) {
187 final int modifier = method.getModifiers();
188 if (method.getName().equals("getCallerClass") && Modifier.isStatic(modifier)) {
189 getCallerClass = method;
190 break;
191 }
192 }
193 } catch (final ClassNotFoundException cnfe) {
194 LOGGER.debug("sun.reflect.Reflection is not installed");
195 }
196 try {
197 securityManager = new PrivateSecurityManager();
198 } catch (final Exception ex) {
199 ex.printStackTrace();
200 LOGGER.debug("Unable to install security manager", ex);
201 }
202 }
203
204 private LoggerContext getDefault() {
205 final LoggerContext ctx = CONTEXT.get();
206 if (ctx != null) {
207 return ctx;
208 }
209 CONTEXT.compareAndSet(null, new LoggerContext("Default"));
210 return CONTEXT.get();
211 }
212
213
214
215
216 private static class PrivateSecurityManager extends SecurityManager {
217
218 public Class getCaller(final String fqcn) {
219 final Class[] classes = getClassContext();
220 boolean next = false;
221 for (final Class clazz : classes) {
222 if (clazz.getName().equals(fqcn)) {
223 next = true;
224 continue;
225 }
226 if (next) {
227 return clazz;
228 }
229 }
230 return null;
231 }
232 }
233
234 }