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