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;
+}


Reply via email to