1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.classic.spi;
15
16 import ch.qos.logback.core.CoreConstants;
17 import ch.qos.logback.core.util.OptionHelper;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.IdentityHashMap;
22 import java.util.List;
23 import java.util.Set;
24
25 public class ThrowableProxy implements IThrowableProxy {
26
27 static final StackTraceElementProxy[] EMPTY_STEP = new StackTraceElementProxy[0];
28
29 private Throwable throwable;
30 private String className;
31 private String overridingMessage;
32 private String message;
33
34 StackTraceElementProxy[] stackTraceElementProxyArray;
35
36 int commonFrames;
37 private ThrowableProxy cause;
38 private ThrowableProxy[] suppressed = NO_SUPPRESSED;
39
40
41
42 private transient PackagingDataCalculator packagingDataCalculator;
43 private boolean calculatedPackageData = false;
44
45
46 private boolean cyclic;
47
48 private static final ThrowableProxy[] NO_SUPPRESSED = new ThrowableProxy[0];
49
50 public ThrowableProxy(Throwable throwable) {
51
52 this(throwable, Collections.newSetFromMap(new IdentityHashMap<>()));
53 }
54
55
56 private ThrowableProxy(Throwable circular, boolean isCyclic) {
57 this.throwable = circular;
58 this.className = circular.getClass().getName();
59 this.message = circular.getMessage();
60 this.stackTraceElementProxyArray = EMPTY_STEP;
61 this.cyclic = true;
62 }
63
64 public ThrowableProxy(Throwable throwable, Set<Throwable> alreadyProcessedSet) {
65
66 this.throwable = throwable;
67 this.className = throwable.getClass().getName();
68 this.message = throwable.getMessage();
69 this.overridingMessage = buildOverridingMessage(throwable);
70 this.stackTraceElementProxyArray = ThrowableProxyUtil.steArrayToStepArray(throwable.getStackTrace());
71 this.cyclic = false;
72
73 alreadyProcessedSet.add(throwable);
74
75 Throwable nested = throwable.getCause();
76 if (nested != null) {
77 if (alreadyProcessedSet.contains(nested)) {
78 this.cause = new ThrowableProxy(nested, true);
79 } else {
80 this.cause = new ThrowableProxy(nested, alreadyProcessedSet);
81 this.cause.commonFrames = ThrowableProxyUtil.findNumberOfCommonFrames(nested.getStackTrace(),
82 stackTraceElementProxyArray);
83 }
84 }
85
86 Throwable[] throwableSuppressed = throwable.getSuppressed();
87
88
89 if (OptionHelper.isNotEmtpy(throwableSuppressed)) {
90 List<ThrowableProxy> suppressedList = new ArrayList<>(throwableSuppressed.length);
91 for (Throwable sup : throwableSuppressed) {
92 if (alreadyProcessedSet.contains(sup)) {
93 ThrowableProxy throwableProxy = new ThrowableProxy(sup, true);
94 suppressedList.add(throwableProxy);
95 } else {
96 ThrowableProxy throwableProxy = new ThrowableProxy(sup, alreadyProcessedSet);
97 throwableProxy.commonFrames = ThrowableProxyUtil.findNumberOfCommonFrames(sup.getStackTrace(),
98 stackTraceElementProxyArray);
99 suppressedList.add(throwableProxy);
100 }
101 }
102 this.suppressed = suppressedList.toArray(new ThrowableProxy[suppressedList.size()]);
103 }
104 }
105
106 private String buildOverridingMessage(Throwable throwable) {
107 StringBuilder sb = new StringBuilder();
108 ThrowableProxyUtil.appendNominalFirstLine(sb, throwable.getClass().getName(), throwable.getMessage());
109 String messageFromToString = throwable.toString();
110 String nominalMessage = sb.toString();
111 if (!nominalMessage.equals(messageFromToString)) {
112 return messageFromToString;
113 } else {
114 return null;
115 }
116 }
117
118 public Throwable getThrowable() {
119 return throwable;
120 }
121
122 public String getMessage() {
123 return message;
124 }
125
126
127
128
129
130
131 @Override
132 public String getOverridingMessage() {
133 return overridingMessage;
134 }
135
136
137
138
139
140
141 public String getClassName() {
142 return className;
143 }
144
145 public StackTraceElementProxy[] getStackTraceElementProxyArray() {
146 return stackTraceElementProxyArray;
147 }
148
149 @Override
150 public boolean isCyclic() {
151 return cyclic;
152 }
153
154 public int getCommonFrames() {
155 return commonFrames;
156 }
157
158
159
160
161
162
163 public IThrowableProxy getCause() {
164 return cause;
165 }
166
167 public IThrowableProxy[] getSuppressed() {
168 return suppressed;
169 }
170
171 public PackagingDataCalculator getPackagingDataCalculator() {
172
173
174
175 if (throwable != null && packagingDataCalculator == null) {
176 packagingDataCalculator = new PackagingDataCalculator();
177 }
178 return packagingDataCalculator;
179 }
180
181 public void calculatePackagingData() {
182 if (calculatedPackageData) {
183 return;
184 }
185 PackagingDataCalculator pdc = this.getPackagingDataCalculator();
186 if (pdc != null) {
187 calculatedPackageData = true;
188 pdc.calculate(this);
189 }
190 }
191
192 public void fullDump() {
193 StringBuilder builder = new StringBuilder();
194 for (StackTraceElementProxy step : stackTraceElementProxyArray) {
195 String string = step.toString();
196 builder.append(CoreConstants.TAB).append(string);
197 ThrowableProxyUtil.subjoinPackagingData(builder, step);
198 builder.append(CoreConstants.LINE_SEPARATOR);
199 }
200 System.out.println(builder.toString());
201 }
202
203 }