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.util.HashMap;
18
19 import sun.reflect.Reflection;
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
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 void populateFrames(StackTraceElementProxy[] stepArray) {
67
68
69 final Throwable t = new Throwable("local stack reference");
70 final StackTraceElement[] localteSTEArray = t.getStackTrace();
71 final int commonFrames = STEUtil.findNumberOfCommonFrames(localteSTEArray,
72 stepArray);
73 final int localFirstCommon = localteSTEArray.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 callerClass = Reflection.getCallerClass(localFirstCommon + i
84 - missfireCount + 1);
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,
107 StackTraceElementProxy[] stepArray, 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,
130 ClassLoader lastExactClassLoader) {
131 String className = step.ste.getClassName();
132 ClassPackagingData cpd = cache.get(className);
133 if (cpd != null) {
134 return cpd;
135 }
136 Class type = bestEffortLoadClass(lastExactClassLoader, className);
137 String version = getImplementationVersion(type);
138 String codeLocation = getCodeLocation(type);
139 cpd = new ClassPackagingData(codeLocation, version, false);
140 cache.put(className, cpd);
141 return cpd;
142 }
143
144 String getImplementationVersion(Class type) {
145 if (type == null) {
146 return "na";
147 }
148 Package aPackage = type.getPackage();
149 if (aPackage != null) {
150 String v = aPackage.getImplementationVersion();
151 if (v == null) {
152 return "na";
153 } else {
154 return v;
155 }
156 }
157 return "na";
158
159 }
160
161 String getCodeLocation(Class type) {
162 try {
163 if (type != null) {
164
165 URL resource = type.getProtectionDomain().getCodeSource().getLocation();
166 if (resource != null) {
167 String locationStr = resource.toString();
168
169 String result = getCodeLocation(locationStr, '/');
170 if (result != null) {
171 return result;
172 }
173 return getCodeLocation(locationStr, '\\');
174 }
175 }
176 } catch (Exception e) {
177
178 }
179 return "na";
180 }
181
182 private String getCodeLocation(String locationStr, char separator) {
183 int idx = locationStr.lastIndexOf(separator);
184 if (isFolder(idx, locationStr)) {
185 idx = locationStr.lastIndexOf(separator, idx - 1);
186 return locationStr.substring(idx + 1);
187 } else if (idx > 0) {
188 return locationStr.substring(idx + 1);
189 }
190 return null;
191 }
192
193 private boolean isFolder(int idx, String text) {
194 return (idx != -1 && idx + 1 == text.length());
195 }
196
197 private Class loadClass(ClassLoader cl, String className) {
198 if (cl == null) {
199 return null;
200 }
201 try {
202 return cl.loadClass(className);
203 } catch (ClassNotFoundException e1) {
204 return null;
205 } catch (NoClassDefFoundError e1) {
206 return null;
207 } catch (Exception e) {
208 e.printStackTrace();
209 return null;
210 }
211
212 }
213
214
215
216
217
218
219 private Class bestEffortLoadClass(ClassLoader lastGuaranteedClassLoader,
220 String className) {
221 Class result = loadClass(lastGuaranteedClassLoader, className);
222 if (result != null) {
223 return result;
224 }
225 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
226 if (tccl != lastGuaranteedClassLoader) {
227 result = loadClass(tccl, className);
228 }
229 if (result != null) {
230 return result;
231 }
232
233 try {
234 return Class.forName(className);
235 } catch (ClassNotFoundException e1) {
236 return null;
237 } catch (NoClassDefFoundError e1) {
238 return null;
239 } catch (Exception e) {
240 e.printStackTrace();
241 return null;
242 }
243 }
244
245 }