1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package org.spf4j.base.avro;
33
34 import java.io.IOException;
35 import java.util.List;
36 import java.util.Objects;
37 import java.util.Set;
38 import javax.annotation.Nullable;
39 import org.spf4j.base.Throwables;
40 import static org.spf4j.base.Throwables.CAUSE_CAPTION;
41 import static org.spf4j.base.Throwables.SUPPRESSED_CAPTION;
42 import static org.spf4j.base.Throwables.writeAbreviatedClassName;
43 import org.spf4j.ds.IdentityHashSet;
44
45
46
47
48
49 public final class AThrowables {
50
51 private AThrowables() { }
52
53 public static void writeTo(final RemoteException t, final Appendable to, final Throwables.PackageDetail detail,
54 final boolean abbreviatedTraceElement, final String prefix) throws IOException {
55 to.append(prefix);
56 writeMessageString(to, t);
57 to.append('\n');
58 writeThrowableDetails(t.getRemoteCause(), to, detail, abbreviatedTraceElement, prefix);
59 }
60
61 public static void writeMessageString(final Appendable to, final RemoteException t) throws IOException {
62 to.append(t.getClass().getName());
63 to.append(':');
64 to.append(t.getRemoteClass());
65 to.append('@');
66 to.append(t.getSource());
67 String message = t.getRemoteCause().getMessage();
68 if (message != null) {
69 to.append(':').append(message);
70 }
71 }
72
73 public static void writeTo(final Throwable t, final Appendable to, final Throwables.PackageDetail detail,
74 final boolean abbreviatedTraceElement, final String prefix) throws IOException {
75 to.append(prefix);
76 writeMessageString(to, t);
77 to.append('\n');
78 writeThrowableDetails(t, to, detail, abbreviatedTraceElement, prefix);
79 }
80
81 public static void writeThrowableDetails(final Throwable t, final Appendable to,
82 final Throwables.PackageDetail detail, final boolean abbreviatedTraceElement, final String prefix)
83 throws IOException {
84 List<StackTraceElement> trace = t.getStackTrace();
85 writeTo(trace, to, detail, abbreviatedTraceElement, prefix);
86
87 Throwable ourCause = t.getCause();
88 List<Throwable> suppressed = t.getSuppressed();
89 if (ourCause == null && suppressed.isEmpty()) {
90 return;
91 }
92 Set<Throwable> dejaVu = new IdentityHashSet<Throwable>();
93 dejaVu.add(t);
94
95 for (Throwable se : suppressed) {
96 printEnclosedStackTrace(se, to, trace, SUPPRESSED_CAPTION, prefix + "\t",
97 dejaVu, detail, abbreviatedTraceElement);
98 }
99
100 if (ourCause != null) {
101 printEnclosedStackTrace(ourCause, to, trace, CAUSE_CAPTION, prefix, dejaVu, detail, abbreviatedTraceElement);
102 }
103 }
104
105 public static void writeTo(final List<StackTraceElement> trace, final Appendable to,
106 final Throwables.PackageDetail detail,
107 final boolean abbreviatedTraceElement, final String prefix)
108 throws IOException {
109 StackTraceElement prevElem = null;
110 for (StackTraceElement traceElement : trace) {
111 to.append(prefix);
112 to.append("\tat ");
113 writeTo(traceElement, prevElem, to, detail, abbreviatedTraceElement);
114 to.append('\n');
115 prevElem = traceElement;
116 }
117 }
118
119
120 public static void writeTo(final StackTraceElement element, @Nullable final StackTraceElement previous,
121 final Appendable to, final Throwables.PackageDetail detail,
122 final boolean abbreviatedTraceElement)
123 throws IOException {
124 Method method = element.getMethod();
125 String currClassName = method.getDeclaringClass();
126 String prevClassName = previous == null ? null : previous.getMethod().getDeclaringClass();
127 if (abbreviatedTraceElement) {
128 if (currClassName.equals(prevClassName)) {
129 to.append('^');
130 } else {
131 writeAbreviatedClassName(currClassName, to);
132 }
133 } else {
134 to.append(currClassName);
135 }
136 to.append('.');
137 to.append(method.getName());
138 FileLocation location = element.getLocation();
139 FileLocation prevLocation = previous == null ? null : previous.getLocation();
140 String currFileName = location != null ? location.getFileName() : "";
141 String prevFileName = prevLocation != null ? prevLocation.getFileName() : "";
142 String fileName = currFileName;
143 if (abbreviatedTraceElement && java.util.Objects.equals(currFileName, prevFileName)) {
144 fileName = "^";
145 }
146 final int lineNumber = location != null ? location.getLineNumber() : -1;
147 if (fileName.isEmpty()) {
148 to.append("(Unknown Source)");
149 } else if (lineNumber >= 0) {
150 to.append('(').append(fileName).append(':')
151 .append(Integer.toString(lineNumber)).append(')');
152 } else {
153 to.append('(').append(fileName).append(')');
154 }
155 if (detail == Throwables.PackageDetail.NONE) {
156 return;
157 }
158 if (abbreviatedTraceElement && currClassName.equals(prevClassName)) {
159 to.append("[^]");
160 return;
161 }
162 PackageInfo presPackageInfo = previous == null ? null : previous.getPackageInfo();
163 org.spf4j.base.avro.PackageInfo pInfo = element.getPackageInfo();
164 if (abbreviatedTraceElement && Objects.equals(pInfo, presPackageInfo)) {
165 to.append("[^]");
166 return;
167 }
168 if (!pInfo.getUrl().isEmpty() || !pInfo.getVersion().isEmpty()) {
169 String jarSourceUrl = pInfo.getUrl();
170 String version = pInfo.getVersion();
171 to.append('[');
172 if (!jarSourceUrl.isEmpty()) {
173 if (detail == Throwables.PackageDetail.SHORT) {
174 String url = jarSourceUrl;
175 int lastIndexOf = url.lastIndexOf('/');
176 if (lastIndexOf >= 0) {
177 int lpos = url.length() - 1;
178 if (lastIndexOf == lpos) {
179 int prevSlPos = url.lastIndexOf('/', lpos - 1);
180 if (prevSlPos < 0) {
181 to.append(url);
182 } else {
183 to.append(url, prevSlPos + 1, url.length());
184 }
185 } else {
186 to.append(url, lastIndexOf + 1, url.length());
187 }
188 } else {
189 to.append(url);
190 }
191 } else {
192 to.append(jarSourceUrl);
193 }
194 } else {
195 to.append("na");
196 }
197 if (!version.isEmpty()) {
198 to.append(':');
199 to.append(version);
200 }
201 to.append(']');
202 }
203 }
204
205 private static void printEnclosedStackTrace(final Throwable t, final Appendable s,
206 final List<StackTraceElement> enclosingTrace,
207 final String caption,
208 final String prefix,
209 final Set<Throwable> dejaVu,
210 final Throwables.PackageDetail detail,
211 final boolean abbreviatedTraceElement) throws IOException {
212 if (dejaVu.contains(t)) {
213 s.append("\t[CIRCULAR REFERENCE:");
214 writeMessageString(s, t);
215 s.append(']');
216 } else {
217 dejaVu.add(t);
218
219 List<StackTraceElement> trace = t.getStackTrace();
220 int framesInCommon = commonFrames(trace, enclosingTrace);
221 int m = trace.size() - framesInCommon;
222
223 s.append(prefix).append(caption);
224 writeMessageString(s, t);
225 s.append('\n');
226 StackTraceElement prev = null;
227 for (int i = 0; i < m; i++) {
228 s.append(prefix).append("\tat ");
229 StackTraceElement ste = trace.get(i);
230 writeTo(ste, prev, s, detail, abbreviatedTraceElement);
231 s.append('\n');
232 prev = ste;
233 }
234 if (framesInCommon != 0) {
235 s.append(prefix).append("\t... ").append(Integer.toString(framesInCommon)).append(" more");
236 s.append('\n');
237 }
238
239
240 for (Throwable se : t.getSuppressed()) {
241 printEnclosedStackTrace(se, s, trace, SUPPRESSED_CAPTION, prefix + '\t',
242 dejaVu, detail, abbreviatedTraceElement);
243 }
244
245
246 Throwable ourCause = t.getCause();
247 if (ourCause != null) {
248 printEnclosedStackTrace(ourCause, s, trace, CAUSE_CAPTION, prefix,
249 dejaVu, detail, abbreviatedTraceElement);
250 }
251 }
252 }
253
254 public static int commonFrames(final List<StackTraceElement> trace,
255 final List<StackTraceElement> enclosingTrace) {
256 int from = trace.size() - 1;
257 int m = from;
258 int n = enclosingTrace.size() - 1;
259 while (m >= 0 && n >= 0 && trace.get(m).equals(enclosingTrace.get(n))) {
260 m--;
261 n--;
262 }
263 return from - m;
264 }
265
266 public static void writeMessageString(final Appendable to, final Throwable t) throws IOException {
267 to.append(t.getClass().getName());
268 String message = t.getMessage();
269 if (message != null) {
270 to.append(':').append(message);
271 }
272 }
273
274 }