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