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 message;
32
33 StackTraceElementProxy[] stackTraceElementProxyArray;
34
35 int commonFrames;
36 private ThrowableProxy cause;
37 private ThrowableProxy[] suppressed = NO_SUPPRESSED;
38
39
40
41 private transient PackagingDataCalculator packagingDataCalculator;
42 private boolean calculatedPackageData = false;
43
44 private boolean circular;
45
46 private static final ThrowableProxy[] NO_SUPPRESSED = new ThrowableProxy[0];
47
48 public ThrowableProxy(Throwable throwable) {
49
50 this(throwable, Collections.newSetFromMap(new IdentityHashMap<>()));
51 }
52
53
54 private ThrowableProxy(Throwable circular, boolean isCircular) {
55 this.throwable = circular;
56 this.className = circular.getClass().getName();
57 this.message = circular.getMessage();
58 this.stackTraceElementProxyArray = EMPTY_STEP;
59 this.circular = true;
60 }
61
62 public ThrowableProxy(Throwable throwable, Set<Throwable> alreadyProcessedSet) {
63
64 this.throwable = throwable;
65 this.className = throwable.getClass().getName();
66 this.message = throwable.getMessage();
67 this.stackTraceElementProxyArray = ThrowableProxyUtil.steArrayToStepArray(throwable.getStackTrace());
68 this.circular = false;
69
70 alreadyProcessedSet.add(throwable);
71
72 Throwable nested = throwable.getCause();
73 if (nested != null) {
74 if (alreadyProcessedSet.contains(nested)) {
75 this.cause = new ThrowableProxy(nested, true);
76 } else {
77 this.cause = new ThrowableProxy(nested, alreadyProcessedSet);
78 this.cause.commonFrames = ThrowableProxyUtil.findNumberOfCommonFrames(nested.getStackTrace(),
79 stackTraceElementProxyArray);
80 }
81 }
82
83 Throwable[] throwableSuppressed = throwable.getSuppressed();
84
85
86 if (OptionHelper.isNotEmtpy(throwableSuppressed)) {
87 List<ThrowableProxy> suppressedList = new ArrayList<>(throwableSuppressed.length);
88 for (Throwable sup : throwableSuppressed) {
89 if (alreadyProcessedSet.contains(sup)) {
90 ThrowableProxy throwableProxy = new ThrowableProxy(sup, true);
91 suppressedList.add(throwableProxy);
92 } else {
93 ThrowableProxy throwableProxy = new ThrowableProxy(sup, alreadyProcessedSet);
94 throwableProxy.commonFrames = ThrowableProxyUtil.findNumberOfCommonFrames(sup.getStackTrace(),
95 stackTraceElementProxyArray);
96 suppressedList.add(throwableProxy);
97 }
98 }
99 this.suppressed = suppressedList.toArray(new ThrowableProxy[suppressedList.size()]);
100 }
101 }
102
103 public Throwable getThrowable() {
104 return throwable;
105 }
106
107 public String getMessage() {
108 return message;
109 }
110
111
112
113
114
115
116 public String getClassName() {
117 return className;
118 }
119
120 public StackTraceElementProxy[] getStackTraceElementProxyArray() {
121 return stackTraceElementProxyArray;
122 }
123
124 @Override
125 public boolean isCyclic() {
126 return circular;
127 }
128
129 public int getCommonFrames() {
130 return commonFrames;
131 }
132
133
134
135
136
137
138 public IThrowableProxy getCause() {
139 return cause;
140 }
141
142 public IThrowableProxy[] getSuppressed() {
143 return suppressed;
144 }
145
146 public PackagingDataCalculator getPackagingDataCalculator() {
147
148
149
150 if (throwable != null && packagingDataCalculator == null) {
151 packagingDataCalculator = new PackagingDataCalculator();
152 }
153 return packagingDataCalculator;
154 }
155
156 public void calculatePackagingData() {
157 if (calculatedPackageData) {
158 return;
159 }
160 PackagingDataCalculator pdc = this.getPackagingDataCalculator();
161 if (pdc != null) {
162 calculatedPackageData = true;
163 pdc.calculate(this);
164 }
165 }
166
167 public void fullDump() {
168 StringBuilder builder = new StringBuilder();
169 for (StackTraceElementProxy step : stackTraceElementProxyArray) {
170 String string = step.toString();
171 builder.append(CoreConstants.TAB).append(string);
172 ThrowableProxyUtil.subjoinPackagingData(builder, step);
173 builder.append(CoreConstants.LINE_SEPARATOR);
174 }
175 System.out.println(builder.toString());
176 }
177
178 }