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>>> contextMap =
58 new ConcurrentHashMap<String, AtomicReference<WeakReference<LoggerContext>>>();
59
60 static {
61 setupCallerCheck();
62 }
63
64 public LoggerContext getContext(String fqcn, ClassLoader loader, boolean currentContext) {
65 if (currentContext) {
66 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 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 (Exception ex) {
96
97 }
98 }
99
100 if (securityManager != null) {
101 Class clazz = securityManager.getCaller(fqcn);
102 if (clazz != null) {
103 return locateContext(clazz.getClassLoader(), null);
104 }
105 }
106
107 Throwable t = new Throwable();
108 boolean next = false;
109 String name = null;
110 for (StackTraceElement element : t.getStackTrace()) {
111 if (element.getClassName().equals(fqcn)) {
112 next = true;
113 continue;
114 }
115 if (next) {
116 name = element.getClassName();
117 break;
118 }
119 }
120 if (name != null) {
121 try {
122 return locateContext(Loader.loadClass(name).getClassLoader(), null);
123 } catch (ClassNotFoundException ex) {
124
125 }
126 }
127 LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get();
128 if (lc != null) {
129 return lc;
130 }
131 return getDefault();
132 }
133 }
134
135 public void removeContext(LoggerContext context) {
136 for (Map.Entry<String, AtomicReference<WeakReference<LoggerContext>>> entry : contextMap.entrySet()) {
137 LoggerContext ctx = entry.getValue().get().get();
138 if (ctx == context) {
139 contextMap.remove(entry.getKey());
140 }
141 }
142 }
143
144 public List<LoggerContext> getLoggerContexts() {
145 List<LoggerContext> list = new ArrayList<LoggerContext>();
146 Collection<AtomicReference<WeakReference<LoggerContext>>> coll = contextMap.values();
147 for (AtomicReference<WeakReference<LoggerContext>> ref : coll) {
148 LoggerContext ctx = ref.get().get();
149 if (ctx != null) {
150 list.add(ctx);
151 }
152 }
153 return Collections.unmodifiableList(list);
154 }
155
156 private LoggerContext locateContext(ClassLoader loader, String configLocation) {
157 String name = loader.toString();
158 AtomicReference<WeakReference<LoggerContext>> ref = contextMap.get(name);
159 if (ref == null) {
160 LoggerContext ctx = new LoggerContext(name, null, configLocation);
161 AtomicReference<WeakReference<LoggerContext>> r =
162 new AtomicReference<WeakReference<LoggerContext>>();
163 r.set(new WeakReference<LoggerContext>(ctx));
164 contextMap.putIfAbsent(loader.toString(), r);
165 ctx = contextMap.get(name).get().get();
166 return ctx;
167 } else {
168 WeakReference<LoggerContext> r = ref.get();
169 LoggerContext ctx = r.get();
170 if (ctx != null) {
171 return ctx;
172 }
173 ctx = new LoggerContext(name, null, configLocation);
174 ref.compareAndSet(r, new WeakReference<LoggerContext>(ctx));
175 return ctx;
176 }
177 }
178
179 private static void setupCallerCheck() {
180 try {
181 ClassLoader loader = Loader.getClassLoader();
182 Class clazz = loader.loadClass("sun.reflect.Reflection");
183 Method[] methods = clazz.getMethods();
184 for (Method method : methods) {
185 int modifier = method.getModifiers();
186 if (method.getName().equals("getCallerClass") && Modifier.isStatic(modifier)) {
187 getCallerClass = method;
188 break;
189 }
190 }
191 } catch (ClassNotFoundException cnfe) {
192 logger.debug("sun.reflect.Reflection is not installed");
193 }
194 try {
195 securityManager = new PrivateSecurityManager();
196 } catch (Exception ex) {
197 ex.printStackTrace();
198 logger.debug("Unable to install security manager", ex);
199 }
200 }
201
202 private LoggerContext getDefault() {
203 LoggerContext ctx = context.get();
204 if (ctx != null) {
205 return ctx;
206 }
207 context.compareAndSet(null, new LoggerContext("Default"));
208 return context.get();
209 }
210
211
212
213
214 private static class PrivateSecurityManager extends SecurityManager {
215
216 public Class getCaller(String fqcn) {
217 Class[] classes = getClassContext();
218 boolean next = false;
219 for (Class clazz : classes) {
220 if (clazz.getName().equals(fqcn)) {
221 next = true;
222 continue;
223 }
224 if (next) {
225 return clazz;
226 }
227 }
228 return null;
229 }
230 }
231
232 }