| /* |
| * Copyright 1999,2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.jasper.compiler; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.util.ResourceBundle; |
| import java.util.Vector; |
| import java.net.MalformedURLException; |
| |
| import org.apache.jasper.JasperException; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * Class responsible for dispatching JSP parse and javac compilation errors |
| * to the configured error handler. |
| * |
| * This class is also responsible for localizing any error codes before they |
| * are passed on to the configured error handler. |
| * |
| * In the case of a Java compilation error, the compiler error message is |
| * parsed into an array of JavacErrorDetail instances, which is passed on to |
| * the configured error handler. |
| * |
| * @author Jan Luehe |
| * @author Kin-man Chung |
| */ |
| public class ErrorDispatcher { |
| |
| private static final ResourceBundle bundle = ResourceBundle.getBundle( |
| "org.apache.jasper.resources.messages"); |
| |
| // Custom error handler |
| private ErrorHandler errHandler; |
| |
| // Indicates whether the compilation was initiated by JspServlet or JspC |
| private boolean jspcMode = false; |
| |
| |
| /* |
| * Constructor. |
| * |
| * @param jspcMode true if compilation has been initiated by JspC, false |
| * otherwise |
| */ |
| public ErrorDispatcher(boolean jspcMode) { |
| // XXX check web.xml for custom error handler |
| errHandler = new DefaultErrorHandler(); |
| this.jspcMode = jspcMode; |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param errCode Error code |
| */ |
| public void jspError(String errCode) throws JasperException { |
| dispatch(null, errCode, null, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param where Error location |
| * @param errCode Error code |
| */ |
| public void jspError(Mark where, String errCode) throws JasperException { |
| dispatch(where, errCode, null, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param n Node that caused the error |
| * @param errCode Error code |
| */ |
| public void jspError(Node n, String errCode) throws JasperException { |
| dispatch(n.getStart(), errCode, null, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param errCode Error code |
| * @param arg Argument for parametric replacement |
| */ |
| public void jspError(String errCode, String arg) throws JasperException { |
| dispatch(null, errCode, new Object[] {arg}, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param where Error location |
| * @param errCode Error code |
| * @param arg Argument for parametric replacement |
| */ |
| public void jspError(Mark where, String errCode, String arg) |
| throws JasperException { |
| dispatch(where, errCode, new Object[] {arg}, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param n Node that caused the error |
| * @param errCode Error code |
| * @param arg Argument for parametric replacement |
| */ |
| public void jspError(Node n, String errCode, String arg) |
| throws JasperException { |
| dispatch(n.getStart(), errCode, new Object[] {arg}, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param errCode Error code |
| * @param arg1 First argument for parametric replacement |
| * @param arg2 Second argument for parametric replacement |
| */ |
| public void jspError(String errCode, String arg1, String arg2) |
| throws JasperException { |
| dispatch(null, errCode, new Object[] {arg1, arg2}, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param errCode Error code |
| * @param arg1 First argument for parametric replacement |
| * @param arg2 Second argument for parametric replacement |
| * @param arg3 Third argument for parametric replacement |
| */ |
| public void jspError(String errCode, String arg1, String arg2, String arg3) |
| throws JasperException { |
| dispatch(null, errCode, new Object[] {arg1, arg2, arg3}, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param where Error location |
| * @param errCode Error code |
| * @param arg1 First argument for parametric replacement |
| * @param arg2 Second argument for parametric replacement |
| */ |
| public void jspError(Mark where, String errCode, String arg1, String arg2) |
| throws JasperException { |
| dispatch(where, errCode, new Object[] {arg1, arg2}, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param where Error location |
| * @param errCode Error code |
| * @param arg1 First argument for parametric replacement |
| * @param arg2 Second argument for parametric replacement |
| * @param arg3 Third argument for parametric replacement |
| */ |
| |
| public void jspError(Mark where, String errCode, String arg1, String arg2, |
| String arg3) |
| throws JasperException { |
| dispatch(where, errCode, new Object[] {arg1, arg2, arg3}, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param n Node that caused the error |
| * @param errCode Error code |
| * @param arg1 First argument for parametric replacement |
| * @param arg2 Second argument for parametric replacement |
| */ |
| |
| public void jspError(Node n, String errCode, String arg1, String arg2) |
| throws JasperException { |
| dispatch(n.getStart(), errCode, new Object[] {arg1, arg2}, null); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param n Node that caused the error |
| * @param errCode Error code |
| * @param arg1 First argument for parametric replacement |
| * @param arg2 Second argument for parametric replacement |
| * @param arg3 Third argument for parametric replacement |
| */ |
| |
| public void jspError(Node n, String errCode, String arg1, String arg2, |
| String arg3) |
| throws JasperException { |
| dispatch(n.getStart(), errCode, new Object[] {arg1, arg2, arg3}, null); |
| } |
| |
| /* |
| * Dispatches the given parsing exception to the configured error handler. |
| * |
| * @param e Parsing exception |
| */ |
| public void jspError(Exception e) throws JasperException { |
| dispatch(null, null, null, e); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param errCode Error code |
| * @param arg Argument for parametric replacement |
| * @param e Parsing exception |
| */ |
| public void jspError(String errCode, String arg, Exception e) |
| throws JasperException { |
| dispatch(null, errCode, new Object[] {arg}, e); |
| } |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param n Node that caused the error |
| * @param errCode Error code |
| * @param arg Argument for parametric replacement |
| * @param e Parsing exception |
| */ |
| public void jspError(Node n, String errCode, String arg, Exception e) |
| throws JasperException { |
| dispatch(n.getStart(), errCode, new Object[] {arg}, e); |
| } |
| |
| /** |
| * Parses the given error message into an array of javac compilation error |
| * messages (one per javac compilation error line number). |
| * |
| * @param errMsg Error message |
| * @param fname Name of Java source file whose compilation failed |
| * @param page Node representation of JSP page from which the Java source |
| * file was generated |
| * |
| * @return Array of javac compilation errors, or null if the given error |
| * message does not contain any compilation error line numbers |
| */ |
| public static JavacErrorDetail[] parseJavacErrors(String errMsg, |
| String fname, |
| Node.Nodes page) |
| throws JasperException, IOException { |
| |
| return parseJavacMessage(errMsg, fname, page); |
| } |
| |
| /* |
| * Dispatches the given javac compilation errors to the configured error |
| * handler. |
| * |
| * @param javacErrors Array of javac compilation errors |
| */ |
| public void javacError(JavacErrorDetail[] javacErrors) |
| throws JasperException { |
| |
| errHandler.javacError(javacErrors); |
| } |
| |
| |
| /* |
| * Dispatches the given compilation error report and exception to the |
| * configured error handler. |
| * |
| * @param errorReport Compilation error report |
| * @param e Compilation exception |
| */ |
| public void javacError(String errorReport, Exception e) |
| throws JasperException { |
| |
| errHandler.javacError(errorReport, e); |
| } |
| |
| |
| //********************************************************************* |
| // Private utility methods |
| |
| /* |
| * Dispatches the given JSP parse error to the configured error handler. |
| * |
| * The given error code is localized. If it is not found in the |
| * resource bundle for localized error messages, it is used as the error |
| * message. |
| * |
| * @param where Error location |
| * @param errCode Error code |
| * @param args Arguments for parametric replacement |
| * @param e Parsing exception |
| */ |
| private void dispatch(Mark where, String errCode, Object[] args, |
| Exception e) throws JasperException { |
| String file = null; |
| String errMsg = null; |
| int line = -1; |
| int column = -1; |
| boolean hasLocation = false; |
| |
| // Localize |
| if (errCode != null) { |
| errMsg = Localizer.getMessage(errCode, args); |
| } else if (e != null) { |
| // give a hint about what's wrong |
| errMsg = e.getMessage(); |
| } |
| |
| // Get error location |
| if (where != null) { |
| if (jspcMode) { |
| // Get the full URL of the resource that caused the error |
| try { |
| file = where.getURL().toString(); |
| } catch (MalformedURLException me) { |
| // Fallback to using context-relative path |
| file = where.getFile(); |
| } |
| } else { |
| // Get the context-relative resource path, so as to not |
| // disclose any local filesystem details |
| file = where.getFile(); |
| } |
| line = where.getLineNumber(); |
| column = where.getColumnNumber(); |
| hasLocation = true; |
| } |
| |
| // Get nested exception |
| Exception nestedEx = e; |
| if ((e instanceof SAXException) |
| && (((SAXException) e).getException() != null)) { |
| nestedEx = ((SAXException) e).getException(); |
| } |
| |
| if (hasLocation) { |
| errHandler.jspError(file, line, column, errMsg, nestedEx); |
| } else { |
| errHandler.jspError(errMsg, nestedEx); |
| } |
| } |
| |
| /* |
| * Parses the given Java compilation error message, which may contain one |
| * or more compilation errors, into an array of JavacErrorDetail instances. |
| * |
| * Each JavacErrorDetail instance contains the information about a single |
| * compilation error. |
| * |
| * @param errMsg Compilation error message that was generated by the |
| * javac compiler |
| * @param fname Name of Java source file whose compilation failed |
| * @param page Node representation of JSP page from which the Java source |
| * file was generated |
| * |
| * @return Array of JavacErrorDetail instances corresponding to the |
| * compilation errors |
| */ |
| private static JavacErrorDetail[] parseJavacMessage( |
| String errMsg, String fname, Node.Nodes page) |
| throws IOException, JasperException { |
| |
| Vector errVec = new Vector(); |
| StringBuffer errMsgBuf = null; |
| int lineNum = -1; |
| JavacErrorDetail javacError = null; |
| |
| BufferedReader reader = new BufferedReader(new StringReader(errMsg)); |
| |
| /* |
| * Parse compilation errors. Each compilation error consists of a file |
| * path and error line number, followed by a number of lines describing |
| * the error. |
| */ |
| String line = null; |
| while ((line = reader.readLine()) != null) { |
| |
| /* |
| * Error line number is delimited by set of colons. |
| * Ignore colon following drive letter on Windows (fromIndex = 2). |
| * XXX Handle deprecation warnings that don't have line info |
| */ |
| int beginColon = line.indexOf(':', 2); |
| int endColon = line.indexOf(':', beginColon + 1); |
| if ((beginColon >= 0) && (endColon >= 0)) { |
| if (javacError != null) { |
| // add previous error to error vector |
| errVec.add(javacError); |
| } |
| |
| String lineNumStr = line.substring(beginColon + 1, endColon); |
| try { |
| lineNum = Integer.parseInt(lineNumStr); |
| } catch (NumberFormatException e) { |
| // XXX |
| } |
| |
| errMsgBuf = new StringBuffer(); |
| |
| javacError = createJavacError(fname, page, errMsgBuf, lineNum); |
| } |
| |
| // Ignore messages preceding first error |
| if (errMsgBuf != null) { |
| errMsgBuf.append(line); |
| errMsgBuf.append("\n"); |
| } |
| } |
| |
| // Add last error to error vector |
| if (javacError != null) { |
| errVec.add(javacError); |
| } |
| |
| reader.close(); |
| |
| JavacErrorDetail[] errDetails = null; |
| if (errVec.size() > 0) { |
| errDetails = new JavacErrorDetail[errVec.size()]; |
| errVec.copyInto(errDetails); |
| } |
| |
| return errDetails; |
| } |
| |
| |
| /** |
| * @param fname |
| * @param page |
| * @param errMsgBuf |
| * @param lineNum |
| * @return |
| * @throws JasperException |
| */ |
| public static JavacErrorDetail createJavacError(String fname, Node.Nodes page, |
| StringBuffer errMsgBuf, int lineNum) throws JasperException { |
| JavacErrorDetail javacError; |
| // Attempt to map javac error line number to line in JSP page |
| ErrorVisitor errVisitor = new ErrorVisitor(lineNum); |
| page.visit(errVisitor); |
| Node errNode = errVisitor.getJspSourceNode(); |
| if ((errNode != null) && (errNode.getStart() != null)) { |
| javacError = new JavacErrorDetail( |
| fname, |
| lineNum, |
| errNode.getStart().getFile(), |
| errNode.getStart().getLineNumber(), |
| errMsgBuf); |
| } else { |
| /* |
| * javac error line number cannot be mapped to JSP page |
| * line number. For example, this is the case if a |
| * scriptlet is missing a closing brace, which causes |
| * havoc with the try-catch-finally block that the code |
| * generator places around all generated code: As a result |
| * of this, the javac error line numbers will be outside |
| * the range of begin and end java line numbers that were |
| * generated for the scriptlet, and therefore cannot be |
| * mapped to the start line number of the scriptlet in the |
| * JSP page. |
| * Include just the javac error info in the error detail. |
| */ |
| javacError = new JavacErrorDetail( |
| fname, |
| lineNum, |
| errMsgBuf); |
| } |
| return javacError; |
| } |
| |
| |
| /* |
| * Visitor responsible for mapping a line number in the generated servlet |
| * source code to the corresponding JSP node. |
| */ |
| static class ErrorVisitor extends Node.Visitor { |
| |
| // Java source line number to be mapped |
| private int lineNum; |
| |
| /* |
| * JSP node whose Java source code range in the generated servlet |
| * contains the Java source line number to be mapped |
| */ |
| Node found; |
| |
| /* |
| * Constructor. |
| * |
| * @param lineNum Source line number in the generated servlet code |
| */ |
| public ErrorVisitor(int lineNum) { |
| this.lineNum = lineNum; |
| } |
| |
| public void doVisit(Node n) throws JasperException { |
| if ((lineNum >= n.getBeginJavaLine()) |
| && (lineNum < n.getEndJavaLine())) { |
| found = n; |
| } |
| } |
| |
| /* |
| * Gets the JSP node to which the source line number in the generated |
| * servlet code was mapped. |
| * |
| * @return JSP node to which the source line number in the generated |
| * servlet code was mapped |
| */ |
| public Node getJspSourceNode() { |
| return found; |
| } |
| } |
| } |