1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit;
16
17 import java.io.BufferedReader;
18 import java.io.IOException;
19 import java.io.PrintStream;
20 import java.io.PrintWriter;
21 import java.io.StringReader;
22 import java.io.StringWriter;
23 import java.util.StringTokenizer;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.htmlunit.corejs.javascript.EcmaError;
28 import org.htmlunit.corejs.javascript.JavaScriptException;
29 import org.htmlunit.corejs.javascript.RhinoException;
30 import org.htmlunit.corejs.javascript.WrappedException;
31 import org.htmlunit.html.HtmlPage;
32
33
34
35
36
37
38
39
40
41
42 public class ScriptException extends RuntimeException {
43
44
45 private static final Log LOG = LogFactory.getLog(ScriptException.class);
46
47 private final String scriptSourceCode_;
48 private final HtmlPage page_;
49
50
51
52
53
54
55
56
57
58 public ScriptException(final HtmlPage page, final Throwable throwable,
59 final String scriptSourceCode) {
60 super(getMessageFrom(throwable), throwable);
61 scriptSourceCode_ = scriptSourceCode;
62 page_ = page;
63 }
64
65 private static String getMessageFrom(final Throwable throwable) {
66 if (throwable == null) {
67 return "null";
68 }
69 return throwable.getMessage();
70 }
71
72
73
74
75
76
77 public ScriptException(final HtmlPage page, final Throwable throwable) {
78 this(page, throwable, null);
79 }
80
81
82
83
84
85 @Override
86 public void printStackTrace() {
87 printStackTrace(System.out);
88 }
89
90
91
92
93
94
95
96 @Override
97 public void printStackTrace(final PrintWriter writer) {
98 writer.write(createPrintableStackTrace());
99 }
100
101
102
103
104
105
106
107 @Override
108 public void printStackTrace(final PrintStream stream) {
109 stream.print(createPrintableStackTrace());
110 }
111
112 private String createPrintableStackTrace() {
113 final StringWriter stringWriter = new StringWriter();
114 final PrintWriter printWriter = new PrintWriter(stringWriter);
115
116 printWriter.println("======= EXCEPTION START ========");
117
118 if (getCause() != null) {
119 if (getCause() instanceof EcmaError ecmaError) {
120 printWriter.print("EcmaError: ");
121 printWriter.print("lineNumber=[");
122 printWriter.print(ecmaError.lineNumber());
123 printWriter.print("] column=[");
124 printWriter.print(ecmaError.columnNumber());
125 printWriter.print("] lineSource=[");
126 printWriter.print(getFailingLine());
127 printWriter.print("] name=[");
128 printWriter.print(ecmaError.getName());
129 printWriter.print("] sourceName=[");
130 printWriter.print(ecmaError.sourceName());
131 printWriter.print("] message=[");
132 printWriter.print(ecmaError.getMessage());
133 printWriter.print("]");
134 printWriter.println();
135 }
136 else {
137 printWriter.println("Exception class=[" + getCause().getClass().getName() + "]");
138 }
139 }
140
141 super.printStackTrace(printWriter);
142 if (getCause() instanceof JavaScriptException) {
143 final Object value = ((JavaScriptException) getCause()).getValue();
144
145 printWriter.print("JavaScriptException value = ");
146 if (value instanceof Throwable throwable) {
147 throwable.printStackTrace(printWriter);
148 }
149 else {
150 printWriter.println(value);
151 }
152 }
153 else if (getCause() instanceof WrappedException wrappedException) {
154 printWriter.print("WrappedException: ");
155 wrappedException.printStackTrace(printWriter);
156
157 final Throwable innerException = wrappedException.getWrappedException();
158 if (innerException == null) {
159 printWriter.println("Inside wrapped exception: null");
160 }
161 else {
162 printWriter.println("Inside wrapped exception:");
163 innerException.printStackTrace(printWriter);
164 }
165 }
166 else if (getCause() != null) {
167 printWriter.println("Enclosed exception: ");
168 getCause().printStackTrace(printWriter);
169 }
170
171 if (scriptSourceCode_ != null && !scriptSourceCode_.isEmpty()) {
172 printWriter.println("== CALLING JAVASCRIPT ==");
173 printWriter.println(scriptSourceCode_);
174 }
175 printWriter.println("======= EXCEPTION END ========");
176
177 return stringWriter.toString();
178 }
179
180
181
182
183
184 public String getScriptSourceCode() {
185 return scriptSourceCode_;
186 }
187
188
189
190
191
192
193
194
195 public String getFailingLine() {
196 final int lineNumber = getFailingLineNumber();
197 if (lineNumber == -1 || scriptSourceCode_ == null) {
198 return "<no source>";
199 }
200
201 try (BufferedReader reader = new BufferedReader(new StringReader(scriptSourceCode_))) {
202 for (int i = 0; i < lineNumber - 1; i++) {
203 reader.readLine();
204 }
205 return reader.readLine();
206 }
207 catch (final IOException e) {
208
209 LOG.error("Reading scriptSourceCode failed.", e);
210 }
211
212 return "";
213 }
214
215
216
217
218
219
220
221 public int getFailingLineNumber() {
222 if (getCause() instanceof RhinoException cause) {
223 return cause.lineNumber();
224 }
225
226 return -1;
227 }
228
229
230
231
232
233
234
235 public int getFailingColumnNumber() {
236 if (getCause() instanceof RhinoException cause) {
237 return cause.columnNumber();
238 }
239
240 return -1;
241 }
242
243
244
245
246
247
248
249 public HtmlPage getPage() {
250 return page_;
251 }
252
253
254
255
256
257
258 public void printScriptStackTrace(final PrintWriter writer) {
259 final StringWriter stringWriter = new StringWriter();
260 final PrintWriter printWriter = new PrintWriter(stringWriter);
261
262 getCause().printStackTrace(printWriter);
263
264 writer.print(getCause().getMessage());
265 final StringTokenizer st = new StringTokenizer(stringWriter.toString(), "\r\n");
266 while (st.hasMoreTokens()) {
267 final String line = st.nextToken();
268 if (line.contains("at script")) {
269 writer.println();
270 writer.print(line.replaceFirst("at script\\.?", "at "));
271 }
272 }
273 }
274
275 }