1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.classic.spi;
15
16 import java.net.URL;
17 import java.security.CodeSource;
18 import java.util.HashMap;
19
20
21
22
23
24
25
26 public class PackagingDataCalculator {
27
28 final static StackTraceElementProxy[] STEP_ARRAY_TEMPLATE = new StackTraceElementProxy[0];
29
30 HashMap<String, ClassPackagingData> cache = new HashMap<String, ClassPackagingData>();
31
32 private static boolean GET_CALLER_CLASS_METHOD_AVAILABLE = false;
33
34
35 static {
36
37
38
39
40
41 try {
42
43
44 } catch (NoClassDefFoundError e) {
45 } catch (NoSuchMethodError e) {
46 } catch (UnsupportedOperationException e) {
47 } catch (Throwable e) {
48 System.err.println("Unexpected exception");
49 e.printStackTrace();
50 }
51 }
52
53 public void calculate(IThrowableProxy tp) {
54 while (tp != null) {
55 populateFrames(tp.getStackTraceElementProxyArray());
56 IThrowableProxy[] suppressed = tp.getSuppressed();
57 if (suppressed != null) {
58 for (IThrowableProxy current : suppressed) {
59 populateFrames(current.getStackTraceElementProxyArray());
60 }
61 }
62 tp = tp.getCause();
63 }
64 }
65
66 @SuppressWarnings("unused")
67 void populateFrames(StackTraceElementProxy[] stepArray) {
68
69
70 final Throwable t = new Throwable("local stack reference");
71 final StackTraceElement[] localSTEArray = t.getStackTrace();
72 final int commonFrames = STEUtil.findNumberOfCommonFrames(localSTEArray, stepArray);
73 final int localFirstCommon = localSTEArray.length - commonFrames;
74 final int stepFirstCommon = stepArray.length - commonFrames;
75
76 ClassLoader lastExactClassLoader = null;
77 ClassLoader firsExactClassLoader = null;
78
79 int missfireCount = 0;
80 for (int i = 0; i < commonFrames; i++) {
81 Class<?> callerClass = null;
82 if (GET_CALLER_CLASS_METHOD_AVAILABLE) {
83
84
85 }
86 StackTraceElementProxy step = stepArray[stepFirstCommon + i];
87 String stepClassname = step.ste.getClassName();
88
89 if (callerClass != null && stepClassname.equals(callerClass.getName())) {
90
91 lastExactClassLoader = callerClass.getClassLoader();
92 if (firsExactClassLoader == null) {
93 firsExactClassLoader = lastExactClassLoader;
94 }
95 ClassPackagingData pi = calculateByExactType(callerClass);
96 step.setClassPackagingData(pi);
97 } else {
98 missfireCount++;
99 ClassPackagingData pi = computeBySTEP(step, lastExactClassLoader);
100 step.setClassPackagingData(pi);
101 }
102 }
103 populateUncommonFrames(commonFrames, stepArray, firsExactClassLoader);
104 }
105
106 void populateUncommonFrames(int commonFrames, StackTraceElementProxy[] stepArray,
107 ClassLoader firstExactClassLoader) {
108 int uncommonFrames = stepArray.length - commonFrames;
109 for (int i = 0; i < uncommonFrames; i++) {
110 StackTraceElementProxy step = stepArray[i];
111 ClassPackagingData pi = computeBySTEP(step, firstExactClassLoader);
112 step.setClassPackagingData(pi);
113 }
114 }
115
116 private ClassPackagingData calculateByExactType(Class<?> type) {
117 String className = type.getName();
118 ClassPackagingData cpd = cache.get(className);
119 if (cpd != null) {
120 return cpd;
121 }
122 String version = getImplementationVersion(type);
123 String codeLocation = getCodeLocation(type);
124 cpd = new ClassPackagingData(codeLocation, version);
125 cache.put(className, cpd);
126 return cpd;
127 }
128
129 private ClassPackagingData computeBySTEP(StackTraceElementProxy step, ClassLoader lastExactClassLoader) {
130 String className = step.ste.getClassName();
131 ClassPackagingData cpd = cache.get(className);
132 if (cpd != null) {
133 return cpd;
134 }
135 Class<?> type = bestEffortLoadClass(lastExactClassLoader, className);
136 String version = getImplementationVersion(type);
137 String codeLocation = getCodeLocation(type);
138 cpd = new ClassPackagingData(codeLocation, version, false);
139 cache.put(className, cpd);
140 return cpd;
141 }
142
143 String getImplementationVersion(Class<?> type) {
144 if (type == null) {
145 return "na";
146 }
147 Package aPackage = type.getPackage();
148 if (aPackage != null) {
149 String v = aPackage.getImplementationVersion();
150 if (v == null) {
151 return "na";
152 } else {
153 return v;
154 }
155 }
156 return "na";
157
158 }
159
160 String getCodeLocation(Class<?> type) {
161 try {
162 if (type != null) {
163
164 CodeSource codeSource = type.getProtectionDomain().getCodeSource();
165 if (codeSource != null) {
166 URL resource = codeSource.getLocation();
167 if (resource != null) {
168 String locationStr = resource.toString();
169
170 String result = getCodeLocation(locationStr, '/');
171 if (result != null) {
172 return result;
173 }
174 return getCodeLocation(locationStr, '\\');
175 }
176 }
177 }
178 } catch (Exception e) {
179
180 }
181 return "na";
182 }
183
184 private String getCodeLocation(String locationStr, char separator) {
185 int idx = locationStr.lastIndexOf(separator);
186 if (isFolder(idx, locationStr)) {
187 idx = locationStr.lastIndexOf(separator, idx - 1);
188 return locationStr.substring(idx + 1);
189 } else if (idx > 0) {
190 return locationStr.substring(idx + 1);
191 }
192 return null;
193 }
194
195 private boolean isFolder(int idx, String text) {
196 return (idx != -1 && idx + 1 == text.length());
197 }
198
199 private Class<?> loadClass(ClassLoader cl, String className) {
200 if (cl == null) {
201 return null;
202 }
203 try {
204 return cl.loadClass(className);
205 } catch (ClassNotFoundException e1) {
206 return null;
207 } catch (NoClassDefFoundError e1) {
208 return null;
209 } catch (Exception e) {
210 e.printStackTrace();
211 return null;
212 }
213
214 }
215
216
217
218
219
220
221 private Class<?> bestEffortLoadClass(ClassLoader lastGuaranteedClassLoader, String className) {
222 Class<?> result = loadClass(lastGuaranteedClassLoader, className);
223 if (result != null) {
224 return result;
225 }
226 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
227 if (tccl != lastGuaranteedClassLoader) {
228 result = loadClass(tccl, className);
229 }
230 if (result != null) {
231 return result;
232 }
233
234 try {
235 return Class.forName(className);
236 } catch (ClassNotFoundException e1) {
237 return null;
238 } catch (NoClassDefFoundError e1) {
239 return null;
240 } catch (Exception e) {
241 e.printStackTrace();
242 return null;
243 }
244 }
245
246 }