Return-Path: Delivered-To: apmail-struts-commits-archive@minotaur.apache.org Received: (qmail 71118 invoked from network); 3 Aug 2009 23:17:23 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 3 Aug 2009 23:17:23 -0000 Received: (qmail 61373 invoked by uid 500); 3 Aug 2009 23:17:27 -0000 Delivered-To: apmail-struts-commits-archive@struts.apache.org Received: (qmail 61298 invoked by uid 500); 3 Aug 2009 23:17:27 -0000 Mailing-List: contact commits-help@struts.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@struts.apache.org Delivered-To: mailing list commits@struts.apache.org Received: (qmail 61289 invoked by uid 99); 3 Aug 2009 23:17:27 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 03 Aug 2009 23:17:27 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 03 Aug 2009 23:17:18 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 009712388981; Mon, 3 Aug 2009 23:16:58 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r800614 [3/24] - in /struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2: ./ jasper/ jasper/compiler/ jasper/compiler/tagplugin/ jasper/resources/ jasper/runtime/ jasper/security/ jasper/servlet/ jasper/tagplugins/ jasp... Date: Mon, 03 Aug 2009 23:16:53 -0000 To: commits@struts.apache.org From: musachy@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090803231658.009712388981@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELParser.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELParser.java?rev=800614&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELParser.java (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELParser.java Mon Aug 3 23:16:50 2009 @@ -0,0 +1,369 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.struts2.jasper.compiler; + +/** + * This class implements a parser for EL expressions. + * + * It takes strings of the form xxx${..}yyy${..}zzz etc, and turn it into + * a ELNode.Nodes. + * + * Currently, it only handles text outside ${..} and functions in ${ ..}. + * + * @author Kin-man Chung + */ + +public class ELParser { + + private Token curToken; // current token + private ELNode.Nodes expr; + private ELNode.Nodes ELexpr; + private int index; // Current index of the expression + private String expression; // The EL expression + private boolean escapeBS; // is '\' an escape char in text outside EL? + + private static final String reservedWords[] = { + "and", "div", "empty", "eq", "false", + "ge", "gt", "instanceof", "le", "lt", "mod", + "ne", "not", "null", "or", "true"}; + + public ELParser(String expression) { + index = 0; + this.expression = expression; + expr = new ELNode.Nodes(); + } + + /** + * Parse an EL expression + * @param expression The input expression string of the form + * Char* ('${' Char* '}')* Char* + * @return Parsed EL expression in ELNode.Nodes + */ + public static ELNode.Nodes parse(String expression) { + ELParser parser = new ELParser(expression); + while (parser.hasNextChar()) { + String text = parser.skipUntilEL(); + if (text.length() > 0) { + parser.expr.add(new ELNode.Text(text)); + } + ELNode.Nodes elexpr = parser.parseEL(); + if (! elexpr.isEmpty()) { + parser.expr.add(new ELNode.Root(elexpr)); + } + } + return parser.expr; + } + + /** + * Parse an EL expression string '${...}' + *@return An ELNode.Nodes representing the EL expression + * TODO: Currently only parsed into functions and text strings. This + * should be rewritten for a full parser. + */ + private ELNode.Nodes parseEL() { + + StringBuffer buf = new StringBuffer(); + ELexpr = new ELNode.Nodes(); + while (hasNext()) { + curToken = nextToken(); + if (curToken instanceof Char) { + if (curToken.toChar() == '}') { + break; + } + buf.append(curToken.toChar()); + } else { + // Output whatever is in buffer + if (buf.length() > 0) { + ELexpr.add(new ELNode.ELText(buf.toString())); + } + if (!parseFunction()) { + ELexpr.add(new ELNode.ELText(curToken.toString())); + } + } + } + if (buf.length() > 0) { + ELexpr.add(new ELNode.ELText(buf.toString())); + } + + return ELexpr; + } + + /** + * Parse for a function + * FunctionInvokation ::= (identifier ':')? identifier '(' + * (Expression (,Expression)*)? ')' + * Note: currently we don't parse arguments + */ + private boolean parseFunction() { + if (! (curToken instanceof Id) || isELReserved(curToken.toString())) { + return false; + } + String s1 = null; // Function prefix + String s2 = curToken.toString(); // Function name + int mark = getIndex(); + if (hasNext()) { + Token t = nextToken(); + if (t.toChar() == ':') { + if (hasNext()) { + Token t2 = nextToken(); + if (t2 instanceof Id) { + s1 = s2; + s2 = t2.toString(); + if (hasNext()) { + t = nextToken(); + } + } + } + } + if (t.toChar() == '(') { + ELexpr.add(new ELNode.Function(s1, s2)); + return true; + } + } + setIndex(mark); + return false; + } + + /** + * Test if an id is a reserved word in EL + */ + private boolean isELReserved(String id) { + int i = 0; + int j = reservedWords.length; + while (i < j) { + int k = (i+j)/2; + int result = reservedWords[k].compareTo(id); + if (result == 0) { + return true; + } + if (result < 0) { + i = k+1; + } else { + j = k; + } + } + return false; + } + + /** + * Skip until an EL expression ('${') is reached, allowing escape sequences + * '\\' and '\$'. + * @return The text string up to the EL expression + */ + private String skipUntilEL() { + char prev = 0; + StringBuffer buf = new StringBuffer(); + while (hasNextChar()) { + char ch = nextChar(); + if (prev == '\\') { + prev = 0; + if (ch == '\\') { + buf.append('\\'); + if (!escapeBS) + prev = '\\'; + } else if (ch == '$') { + buf.append('$'); + } + // else error! + } else if (prev == '$') { + if (ch == '{') { + prev = 0; + break; + } + buf.append('$'); + buf.append(ch); + prev = 0; + } else if (ch == '\\' || ch == '$') { + prev = ch; + } else { + buf.append(ch); + } + } + if (prev != 0) { + buf.append(prev); + } + return buf.toString(); + } + + /* + * @return true if there is something left in EL expression buffer other + * than white spaces. + */ + private boolean hasNext() { + skipSpaces(); + return hasNextChar(); + } + + /* + * @return The next token in the EL expression buffer. + */ + private Token nextToken() { + skipSpaces(); + if (hasNextChar()) { + char ch = nextChar(); + if (Character.isJavaIdentifierStart(ch)) { + StringBuffer buf = new StringBuffer(); + buf.append(ch); + while ((ch = peekChar()) != -1 && + Character.isJavaIdentifierPart(ch)) { + buf.append(ch); + nextChar(); + } + return new Id(buf.toString()); + } + + if (ch == '\'' || ch == '"') { + return parseQuotedChars(ch); + } else { + // For now... + return new Char(ch); + } + } + return null; + } + + /* + * Parse a string in single or double quotes, allowing for escape sequences + * '\\', and ('\"', or "\'") + */ + private Token parseQuotedChars(char quote) { + StringBuffer buf = new StringBuffer(); + buf.append(quote); + while (hasNextChar()) { + char ch = nextChar(); + if (ch == '\\') { + ch = nextChar(); + if (ch == '\\' || ch == quote) { + buf.append(ch); + } + // else error! + } else if (ch == quote) { + buf.append(ch); + break; + } else { + buf.append(ch); + } + } + return new QuotedString(buf.toString()); + } + + /* + * A collection of low level parse methods dealing with character in + * the EL expression buffer. + */ + + private void skipSpaces() { + while (hasNextChar()) { + if (expression.charAt(index) > ' ') + break; + index++; + } + } + + private boolean hasNextChar() { + return index < expression.length(); + } + + private char nextChar() { + if (index >= expression.length()) { + return (char)-1; + } + return expression.charAt(index++); + } + + private char peekChar() { + if (index >= expression.length()) { + return (char)-1; + } + return expression.charAt(index); + } + + private int getIndex() { + return index; + } + + private void setIndex(int i) { + index = i; + } + + /* + * Represents a token in EL expression string + */ + private static class Token { + + char toChar() { + return 0; + } + + public String toString() { + return ""; + } + } + + /* + * Represents an ID token in EL + */ + private static class Id extends Token { + String id; + + Id(String id) { + this.id = id; + } + + public String toString() { + return id; + } + } + + /* + * Represents a character token in EL + */ + private static class Char extends Token { + + private char ch; + + Char(char ch) { + this.ch = ch; + } + + char toChar() { + return ch; + } + + public String toString() { + return (new Character(ch)).toString(); + } + } + + /* + * Represents a quoted (single or double) string token in EL + */ + private static class QuotedString extends Token { + + private String value; + + QuotedString(String v) { + this.value = v; + } + + public String toString() { + return value; + } + } +} + Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ErrorDispatcher.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ErrorDispatcher.java?rev=800614&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ErrorDispatcher.java (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ErrorDispatcher.java Mon Aug 3 23:16:50 2009 @@ -0,0 +1,614 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.struts2.jasper.compiler; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.Vector; +import java.net.MalformedURLException; + +import org.apache.struts2.jasper.JasperException; +import org.apache.struts2.jasper.JspCompilationContext; +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 { + + // 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 JavacErrorDetail The error details + * @throws JasperException + */ + public static JavacErrorDetail createJavacError(String fname, + Node.Nodes page, + StringBuffer errMsgBuf, int lineNum) throws JasperException { + return createJavacError(fname, page, errMsgBuf, lineNum, null); + } + /** + * @param fname + * @param page + * @param errMsgBuf + * @param lineNum + * @param ctxt + * @return JavacErrorDetail The error details + * @throws JasperException + */ + public static JavacErrorDetail createJavacError(String fname, + Node.Nodes page, + StringBuffer errMsgBuf, int lineNum, JspCompilationContext ctxt) + 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)) { + // If this is a scriplet node then there is a one to one mapping + // between JSP lines and Java lines + if (errVisitor.getJspSourceNode() instanceof Node.Scriptlet) { + javacError = new JavacErrorDetail( + fname, + lineNum, + errNode.getStart().getFile(), + errNode.getStart().getLineNumber() + lineNum - + errVisitor.getJspSourceNode().getBeginJavaLine(), + errMsgBuf, + ctxt); + } else { + javacError = new JavacErrorDetail( + fname, + lineNum, + errNode.getStart().getFile(), + errNode.getStart().getLineNumber(), + errMsgBuf, + ctxt); + } + } 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; + } + } +} Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ErrorHandler.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ErrorHandler.java?rev=800614&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ErrorHandler.java (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ErrorHandler.java Mon Aug 3 23:16:50 2009 @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.struts2.jasper.compiler; + +import org.apache.struts2.jasper.JasperException; + +/** + * Interface for handling JSP parse and javac compilation errors. + * + * An implementation of this interface may be registered with the + * ErrorDispatcher by setting the XXX initialization parameter in the JSP + * page compiler and execution servlet in Catalina's web.xml file to the + * implementation's fully qualified class name. + * + * @author Jan Luehe + * @author Kin-man Chung + */ +public interface ErrorHandler { + + /** + * Processes the given JSP parse error. + * + * @param fname Name of the JSP file in which the parse error occurred + * @param line Parse error line number + * @param column Parse error column number + * @param msg Parse error message + * @param exception Parse exception + */ + public void jspError(String fname, int line, int column, String msg, + Exception exception) throws JasperException; + + /** + * Processes the given JSP parse error. + * + * @param msg Parse error message + * @param exception Parse exception + */ + public void jspError(String msg, Exception exception) + throws JasperException; + + /** + * Processes the given javac compilation errors. + * + * @param details Array of JavacErrorDetail instances corresponding to the + * compilation errors + */ + public void javacError(JavacErrorDetail[] details) + throws JasperException; + + /** + * Processes the given javac error report and exception. + * + * @param errorReport Compilation error report + * @param exception Compilation exception + */ + public void javacError(String errorReport, Exception exception) + throws JasperException; +}