2
* Copyright 1999,2004 The Apache Software Foundation.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
16
package org.apache.jasper.compiler;
18
import java.io.BufferedReader;
19
import java.io.IOException;
20
import java.io.StringReader;
21
import java.util.Vector;
22
import java.net.MalformedURLException;
24
import org.apache.jasper.JasperException;
25
import org.xml.sax.SAXException;
28
* Class responsible for dispatching JSP parse and javac compilation errors
29
* to the configured error handler.
31
* This class is also responsible for localizing any error codes before they
32
* are passed on to the configured error handler.
34
* In the case of a Java compilation error, the compiler error message is
35
* parsed into an array of JavacErrorDetail instances, which is passed on to
36
* the configured error handler.
39
* @author Kin-man Chung
41
public class ErrorDispatcher {
43
// Custom error handler
44
private ErrorHandler errHandler;
46
// Indicates whether the compilation was initiated by JspServlet or JspC
47
private boolean jspcMode = false;
53
* @param jspcMode true if compilation has been initiated by JspC, false
56
public ErrorDispatcher(boolean jspcMode) {
57
// XXX check web.xml for custom error handler
58
errHandler = new DefaultErrorHandler();
59
this.jspcMode = jspcMode;
63
* Dispatches the given JSP parse error to the configured error handler.
65
* The given error code is localized. If it is not found in the
66
* resource bundle for localized error messages, it is used as the error
69
* @param errCode Error code
71
public void jspError(String errCode) throws JasperException {
72
dispatch(null, errCode, null, null);
76
* Dispatches the given JSP parse error to the configured error handler.
78
* The given error code is localized. If it is not found in the
79
* resource bundle for localized error messages, it is used as the error
82
* @param where Error location
83
* @param errCode Error code
85
public void jspError(Mark where, String errCode) throws JasperException {
86
dispatch(where, errCode, null, null);
90
* Dispatches the given JSP parse error to the configured error handler.
92
* The given error code is localized. If it is not found in the
93
* resource bundle for localized error messages, it is used as the error
96
* @param n Node that caused the error
97
* @param errCode Error code
99
public void jspError(Node n, String errCode) throws JasperException {
100
dispatch(n.getStart(), errCode, null, null);
104
* Dispatches the given JSP parse error to the configured error handler.
106
* The given error code is localized. If it is not found in the
107
* resource bundle for localized error messages, it is used as the error
110
* @param errCode Error code
111
* @param arg Argument for parametric replacement
113
public void jspError(String errCode, String arg) throws JasperException {
114
dispatch(null, errCode, new Object[] {arg}, null);
118
* Dispatches the given JSP parse error to the configured error handler.
120
* The given error code is localized. If it is not found in the
121
* resource bundle for localized error messages, it is used as the error
124
* @param where Error location
125
* @param errCode Error code
126
* @param arg Argument for parametric replacement
128
public void jspError(Mark where, String errCode, String arg)
129
throws JasperException {
130
dispatch(where, errCode, new Object[] {arg}, null);
134
* Dispatches the given JSP parse error to the configured error handler.
136
* The given error code is localized. If it is not found in the
137
* resource bundle for localized error messages, it is used as the error
140
* @param n Node that caused the error
141
* @param errCode Error code
142
* @param arg Argument for parametric replacement
144
public void jspError(Node n, String errCode, String arg)
145
throws JasperException {
146
dispatch(n.getStart(), errCode, new Object[] {arg}, null);
150
* Dispatches the given JSP parse error to the configured error handler.
152
* The given error code is localized. If it is not found in the
153
* resource bundle for localized error messages, it is used as the error
156
* @param errCode Error code
157
* @param arg1 First argument for parametric replacement
158
* @param arg2 Second argument for parametric replacement
160
public void jspError(String errCode, String arg1, String arg2)
161
throws JasperException {
162
dispatch(null, errCode, new Object[] {arg1, arg2}, null);
166
* Dispatches the given JSP parse error to the configured error handler.
168
* The given error code is localized. If it is not found in the
169
* resource bundle for localized error messages, it is used as the error
172
* @param errCode Error code
173
* @param arg1 First argument for parametric replacement
174
* @param arg2 Second argument for parametric replacement
175
* @param arg3 Third argument for parametric replacement
177
public void jspError(String errCode, String arg1, String arg2, String arg3)
178
throws JasperException {
179
dispatch(null, errCode, new Object[] {arg1, arg2, arg3}, null);
183
* Dispatches the given JSP parse error to the configured error handler.
185
* The given error code is localized. If it is not found in the
186
* resource bundle for localized error messages, it is used as the error
189
* @param where Error location
190
* @param errCode Error code
191
* @param arg1 First argument for parametric replacement
192
* @param arg2 Second argument for parametric replacement
194
public void jspError(Mark where, String errCode, String arg1, String arg2)
195
throws JasperException {
196
dispatch(where, errCode, new Object[] {arg1, arg2}, null);
200
* Dispatches the given JSP parse error to the configured error handler.
202
* The given error code is localized. If it is not found in the
203
* resource bundle for localized error messages, it is used as the error
206
* @param where Error location
207
* @param errCode Error code
208
* @param arg1 First argument for parametric replacement
209
* @param arg2 Second argument for parametric replacement
210
* @param arg3 Third argument for parametric replacement
213
public void jspError(Mark where, String errCode, String arg1, String arg2,
215
throws JasperException {
216
dispatch(where, errCode, new Object[] {arg1, arg2, arg3}, null);
220
* Dispatches the given JSP parse error to the configured error handler.
222
* The given error code is localized. If it is not found in the
223
* resource bundle for localized error messages, it is used as the error
226
* @param n Node that caused the error
227
* @param errCode Error code
228
* @param arg1 First argument for parametric replacement
229
* @param arg2 Second argument for parametric replacement
232
public void jspError(Node n, String errCode, String arg1, String arg2)
233
throws JasperException {
234
dispatch(n.getStart(), errCode, new Object[] {arg1, arg2}, null);
238
* Dispatches the given JSP parse error to the configured error handler.
240
* The given error code is localized. If it is not found in the
241
* resource bundle for localized error messages, it is used as the error
244
* @param n Node that caused the error
245
* @param errCode Error code
246
* @param arg1 First argument for parametric replacement
247
* @param arg2 Second argument for parametric replacement
248
* @param arg3 Third argument for parametric replacement
251
public void jspError(Node n, String errCode, String arg1, String arg2,
253
throws JasperException {
254
dispatch(n.getStart(), errCode, new Object[] {arg1, arg2, arg3}, null);
258
* Dispatches the given parsing exception to the configured error handler.
260
* @param e Parsing exception
262
public void jspError(Exception e) throws JasperException {
263
dispatch(null, null, null, e);
267
* Dispatches the given JSP parse error to the configured error handler.
269
* The given error code is localized. If it is not found in the
270
* resource bundle for localized error messages, it is used as the error
273
* @param errCode Error code
274
* @param arg Argument for parametric replacement
275
* @param e Parsing exception
277
public void jspError(String errCode, String arg, Exception e)
278
throws JasperException {
279
dispatch(null, errCode, new Object[] {arg}, e);
283
* Dispatches the given JSP parse error to the configured error handler.
285
* The given error code is localized. If it is not found in the
286
* resource bundle for localized error messages, it is used as the error
289
* @param n Node that caused the error
290
* @param errCode Error code
291
* @param arg Argument for parametric replacement
292
* @param e Parsing exception
294
public void jspError(Node n, String errCode, String arg, Exception e)
295
throws JasperException {
296
dispatch(n.getStart(), errCode, new Object[] {arg}, e);
300
* Parses the given error message into an array of javac compilation error
301
* messages (one per javac compilation error line number).
303
* @param errMsg Error message
304
* @param fname Name of Java source file whose compilation failed
305
* @param page Node representation of JSP page from which the Java source
308
* @return Array of javac compilation errors, or null if the given error
309
* message does not contain any compilation error line numbers
311
public static JavacErrorDetail[] parseJavacErrors(String errMsg,
314
throws JasperException, IOException {
316
return parseJavacMessage(errMsg, fname, page);
320
* Dispatches the given javac compilation errors to the configured error
323
* @param javacErrors Array of javac compilation errors
325
public void javacError(JavacErrorDetail[] javacErrors)
326
throws JasperException {
328
errHandler.javacError(javacErrors);
333
* Dispatches the given compilation error report and exception to the
334
* configured error handler.
336
* @param errorReport Compilation error report
337
* @param e Compilation exception
339
public void javacError(String errorReport, Exception e)
340
throws JasperException {
342
errHandler.javacError(errorReport, e);
346
//*********************************************************************
347
// Private utility methods
350
* Dispatches the given JSP parse error to the configured error handler.
352
* The given error code is localized. If it is not found in the
353
* resource bundle for localized error messages, it is used as the error
356
* @param where Error location
357
* @param errCode Error code
358
* @param args Arguments for parametric replacement
359
* @param e Parsing exception
361
private void dispatch(Mark where, String errCode, Object[] args,
362
Exception e) throws JasperException {
364
String errMsg = null;
367
boolean hasLocation = false;
370
if (errCode != null) {
371
errMsg = Localizer.getMessage(errCode, args);
372
} else if (e != null) {
373
// give a hint about what's wrong
374
errMsg = e.getMessage();
377
// Get error location
380
// Get the full URL of the resource that caused the error
382
file = where.getURL().toString();
383
} catch (MalformedURLException me) {
384
// Fallback to using context-relative path
385
file = where.getFile();
388
// Get the context-relative resource path, so as to not
389
// disclose any local filesystem details
390
file = where.getFile();
392
line = where.getLineNumber();
393
column = where.getColumnNumber();
397
// Get nested exception
398
Exception nestedEx = e;
399
if ((e instanceof SAXException)
400
&& (((SAXException) e).getException() != null)) {
401
nestedEx = ((SAXException) e).getException();
405
errHandler.jspError(file, line, column, errMsg, nestedEx);
407
errHandler.jspError(errMsg, nestedEx);
412
* Parses the given Java compilation error message, which may contain one
413
* or more compilation errors, into an array of JavacErrorDetail instances.
415
* Each JavacErrorDetail instance contains the information about a single
418
* @param errMsg Compilation error message that was generated by the
420
* @param fname Name of Java source file whose compilation failed
421
* @param page Node representation of JSP page from which the Java source
424
* @return Array of JavacErrorDetail instances corresponding to the
427
private static JavacErrorDetail[] parseJavacMessage(
428
String errMsg, String fname, Node.Nodes page)
429
throws IOException, JasperException {
431
Vector errVec = new Vector();
432
StringBuffer errMsgBuf = null;
434
JavacErrorDetail javacError = null;
436
BufferedReader reader = new BufferedReader(new StringReader(errMsg));
439
* Parse compilation errors. Each compilation error consists of a file
440
* path and error line number, followed by a number of lines describing
444
while ((line = reader.readLine()) != null) {
447
* Error line number is delimited by set of colons.
448
* Ignore colon following drive letter on Windows (fromIndex = 2).
449
* XXX Handle deprecation warnings that don't have line info
451
int beginColon = line.indexOf(':', 2);
452
int endColon = line.indexOf(':', beginColon + 1);
453
if ((beginColon >= 0) && (endColon >= 0)) {
454
if (javacError != null) {
455
// add previous error to error vector
456
errVec.add(javacError);
459
String lineNumStr = line.substring(beginColon + 1, endColon);
461
lineNum = Integer.parseInt(lineNumStr);
462
} catch (NumberFormatException e) {
466
errMsgBuf = new StringBuffer();
468
javacError = createJavacError(fname, page, errMsgBuf, lineNum);
471
// Ignore messages preceding first error
472
if (errMsgBuf != null) {
473
errMsgBuf.append(line);
474
errMsgBuf.append("\n");
478
// Add last error to error vector
479
if (javacError != null) {
480
errVec.add(javacError);
485
JavacErrorDetail[] errDetails = null;
486
if (errVec.size() > 0) {
487
errDetails = new JavacErrorDetail[errVec.size()];
488
errVec.copyInto(errDetails);
500
* @return JavacErrorDetail The error details
501
* @throws JasperException
503
public static JavacErrorDetail createJavacError(String fname, Node.Nodes page,
504
StringBuffer errMsgBuf, int lineNum) throws JasperException {
505
JavacErrorDetail javacError;
506
// Attempt to map javac error line number to line in JSP page
507
ErrorVisitor errVisitor = new ErrorVisitor(lineNum);
508
page.visit(errVisitor);
509
Node errNode = errVisitor.getJspSourceNode();
510
if ((errNode != null) && (errNode.getStart() != null)) {
511
javacError = new JavacErrorDetail(
514
errNode.getStart().getFile(),
515
errNode.getStart().getLineNumber(),
519
* javac error line number cannot be mapped to JSP page
520
* line number. For example, this is the case if a
521
* scriptlet is missing a closing brace, which causes
522
* havoc with the try-catch-finally block that the code
523
* generator places around all generated code: As a result
524
* of this, the javac error line numbers will be outside
525
* the range of begin and end java line numbers that were
526
* generated for the scriptlet, and therefore cannot be
527
* mapped to the start line number of the scriptlet in the
529
* Include just the javac error info in the error detail.
531
javacError = new JavacErrorDetail(
541
* Visitor responsible for mapping a line number in the generated servlet
542
* source code to the corresponding JSP node.
544
static class ErrorVisitor extends Node.Visitor {
546
// Java source line number to be mapped
550
* JSP node whose Java source code range in the generated servlet
551
* contains the Java source line number to be mapped
558
* @param lineNum Source line number in the generated servlet code
560
public ErrorVisitor(int lineNum) {
561
this.lineNum = lineNum;
564
public void doVisit(Node n) throws JasperException {
565
if ((lineNum >= n.getBeginJavaLine())
566
&& (lineNum < n.getEndJavaLine())) {
572
* Gets the JSP node to which the source line number in the generated
573
* servlet code was mapped.
575
* @return JSP node to which the source line number in the generated
576
* servlet code was mapped
578
public Node getJspSourceNode() {