1 package com.github.triceo.splitlog.splitters.exceptions;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.LinkedHashMap;
8 import java.util.List;
9 import java.util.Map;
10
11 import com.github.triceo.splitlog.api.ExceptionDescriptor;
12
13
14
15
16
17 public class DefaultExceptionDescriptor implements ExceptionDescriptor {
18
19 private static class Builder {
20
21 private final Map<CauseLine, List<StackTraceElement>> causes = new LinkedHashMap<CauseLine, List<StackTraceElement>>();
22 private List<StackTraceElement> currentlyUsedStackTrace;
23
24 public void addLine(final ExceptionLine line) {
25 if (line instanceof CauseLine) {
26
27 this.causes.put((CauseLine) line, new ArrayList<StackTraceElement>());
28 this.currentlyUsedStackTrace = this.causes.get(line);
29 } else if (line instanceof StackTraceLine) {
30
31 final StackTraceLine l = (StackTraceLine) line;
32 final String fqMethodName = l.getMethodName();
33 final int index = fqMethodName.lastIndexOf('.');
34 final StackTraceElement e = new StackTraceElement(fqMethodName.substring(0, index),
35 fqMethodName.substring(index + 1), l.getClassName(), l.getLineInCode());
36 this.currentlyUsedStackTrace.add(e);
37 } else {
38
39 }
40 }
41
42 public ExceptionDescriptor build() {
43 final List<CauseLine> properlyOrdered = new ArrayList<CauseLine>(this.causes.keySet());
44 ExceptionDescriptor previousException = null;
45 for (int i = properlyOrdered.size() - 1; i >= 0; i--) {
46 final CauseLine cause = properlyOrdered.get(i);
47 final List<StackTraceElement> stackTrace = this.causes.get(cause);
48 previousException = new DefaultExceptionDescriptor(cause.getClassName(), cause.getMessage(),
49 stackTrace, previousException);
50 }
51 return previousException;
52 }
53
54 }
55
56
57
58
59
60
61
62
63
64 public static ExceptionDescriptor parseStackTrace(final Collection<String> lines) {
65 if ((lines == null) || lines.isEmpty()) {
66 throw new IllegalArgumentException("No stack trace provided.");
67 }
68 try {
69 final Builder b = new Builder();
70 final Collection<ExceptionLine> parsedLines = new ExceptionParser().parse(lines);
71 for (final ExceptionLine line : parsedLines) {
72 b.addLine(line);
73 }
74 return b.build();
75 } catch (final ExceptionParseException e) {
76
77
78 return null;
79 }
80 }
81
82 private final ExceptionDescriptor cause;
83
84 private final String exceptionClassName, message;
85 private final StackTraceElement[] stackTrace;
86
87 private DefaultExceptionDescriptor(final String className, final String message,
88 final List<StackTraceElement> elements, final ExceptionDescriptor cause) {
89 this.exceptionClassName = className;
90 this.message = message;
91 this.stackTrace = elements.toArray(new StackTraceElement[elements.size()]);
92 this.cause = cause;
93 }
94
95 @Override
96 public boolean equals(final Object obj) {
97 if (this == obj) {
98 return true;
99 }
100 if (obj == null) {
101 return false;
102 }
103 if (this.getClass() != obj.getClass()) {
104 return false;
105 }
106 final DefaultExceptionDescriptor other = (DefaultExceptionDescriptor) obj;
107 if (this.cause == null) {
108 if (other.cause != null) {
109 return false;
110 }
111 } else if (!this.cause.equals(other.cause)) {
112 return false;
113 }
114 if (this.exceptionClassName == null) {
115 if (other.exceptionClassName != null) {
116 return false;
117 }
118 } else if (!this.exceptionClassName.equals(other.exceptionClassName)) {
119 return false;
120 }
121 if (this.message == null) {
122 if (other.message != null) {
123 return false;
124 }
125 } else if (!this.message.equals(other.message)) {
126 return false;
127 }
128 if (!Arrays.equals(this.stackTrace, other.stackTrace)) {
129 return false;
130 }
131 return true;
132 }
133
134 @Override
135 public ExceptionDescriptor getCause() {
136 return this.cause;
137 }
138
139 @Override
140 @SuppressWarnings("unchecked")
141 public Class<? extends Throwable> getExceptionClass() {
142 try {
143 return (Class<? extends Throwable>) Class.forName(this.getExceptionClassName());
144 } catch (final ClassNotFoundException e) {
145
146 return null;
147 }
148 }
149
150 @Override
151 public String getExceptionClassName() {
152 return this.exceptionClassName;
153 }
154
155 @Override
156 public String getMessage() {
157 return this.message;
158 }
159
160 @Override
161 public List<StackTraceElement> getStackTrace() {
162 return Collections.unmodifiableList(Arrays.asList(this.stackTrace));
163 }
164
165 @Override
166 public int hashCode() {
167 final int prime = 31;
168 int result = 1;
169 result = (prime * result) + ((this.cause == null) ? 0 : this.cause.hashCode());
170 result = (prime * result) + ((this.exceptionClassName == null) ? 0 : this.exceptionClassName.hashCode());
171 result = (prime * result) + ((this.message == null) ? 0 : this.message.hashCode());
172 result = (prime * result) + Arrays.hashCode(this.stackTrace);
173 return result;
174 }
175
176 @Override
177 public boolean isRootCause() {
178 return this.cause == null;
179 }
180
181 @Override
182 public String toString() {
183 final StringBuilder builder2 = new StringBuilder();
184 builder2.append("ExceptionDescriptor [");
185 if (this.stackTrace != null) {
186 builder2.append("stackTrace=").append(Arrays.toString(this.stackTrace)).append(", ");
187 }
188 if (this.exceptionClassName != null) {
189 builder2.append("exceptionClassName=").append(this.exceptionClassName).append(", ");
190 }
191 if (this.message != null) {
192 builder2.append("message=").append(this.message).append(", ");
193 }
194 if (this.cause != null) {
195 builder2.append("cause=").append(this.cause);
196 }
197 builder2.append("]");
198 return builder2.toString();
199 }
200
201 }