You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2009/09/28 03:55:35 UTC
svn commit: r819444 [8/27] - in /struts/struts2/trunk/plugins/embeddedjsp:
./ src/main/java/org/apache/struts2/el/
src/main/java/org/apache/struts2/el/lang/
src/main/java/org/apache/struts2/el/parser/
src/main/java/org/apache/struts2/el/util/ src/main/...
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ELNode.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ELNode.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ELNode.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ELNode.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,255 @@
+/*
+ * 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.util.*;
+import javax.servlet.jsp.tagext.FunctionInfo;
+import org.apache.struts2.jasper.JasperException;
+
+/**
+ * This class defines internal representation for an EL Expression
+ *
+ * It currently only defines functions. It can be expanded to define
+ * all the components of an EL expression, if need to.
+ *
+ * @author Kin-man Chung
+ */
+
+abstract class ELNode {
+
+ abstract public void accept(Visitor v) throws JasperException;
+
+ /**
+ * Child classes
+ */
+
+
+ /**
+ * Represents an EL expression: anything in ${ and }.
+ */
+ public static class Root extends ELNode {
+
+ private ELNode.Nodes expr;
+ private char type;
+
+ Root(ELNode.Nodes expr, char type) {
+ this.expr = expr;
+ this.type = type;
+ }
+
+ public void accept(Visitor v) throws JasperException {
+ v.visit(this);
+ }
+
+ public ELNode.Nodes getExpression() {
+ return expr;
+ }
+
+ public char getType() {
+ return type;
+ }
+ }
+
+ /**
+ * Represents text outside of EL expression.
+ */
+ public static class Text extends ELNode {
+
+ private String text;
+
+ Text(String text) {
+ this.text = text;
+ }
+
+ public void accept(Visitor v) throws JasperException {
+ v.visit(this);
+ }
+
+ public String getText() {
+ return text;
+ }
+ }
+
+ /**
+ * Represents anything in EL expression, other than functions, including
+ * function arguments etc
+ */
+ public static class ELText extends ELNode {
+
+ private String text;
+
+ ELText(String text) {
+ this.text = text;
+ }
+
+ public void accept(Visitor v) throws JasperException {
+ v.visit(this);
+ }
+
+ public String getText() {
+ return text;
+ }
+ }
+
+ /**
+ * Represents a function
+ * Currently only include the prefix and function name, but not its
+ * arguments.
+ */
+ public static class Function extends ELNode {
+
+ private String prefix;
+ private String name;
+ private String uri;
+ private FunctionInfo functionInfo;
+ private String methodName;
+ private String[] parameters;
+
+ Function(String prefix, String name) {
+ this.prefix = prefix;
+ this.name = name;
+ }
+
+ public void accept(Visitor v) throws JasperException {
+ v.visit(this);
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+
+ public String getUri() {
+ return uri;
+ }
+
+ public void setFunctionInfo(FunctionInfo f) {
+ this.functionInfo = f;
+ }
+
+ public FunctionInfo getFunctionInfo() {
+ return functionInfo;
+ }
+
+ public void setMethodName(String methodName) {
+ this.methodName = methodName;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public void setParameters(String[] parameters) {
+ this.parameters = parameters;
+ }
+
+ public String[] getParameters() {
+ return parameters;
+ }
+ }
+
+ /**
+ * An ordered list of ELNode.
+ */
+ public static class Nodes {
+
+ /* Name used for creating a map for the functions in this
+ EL expression, for communication to Generator.
+ */
+ String mapName = null; // The function map associated this EL
+ private List<ELNode> list;
+
+ public Nodes() {
+ list = new ArrayList<ELNode>();
+ }
+
+ public void add(ELNode en) {
+ list.add(en);
+ }
+
+ /**
+ * Visit the nodes in the list with the supplied visitor
+ * @param v The visitor used
+ */
+ public void visit(Visitor v) throws JasperException {
+ Iterator<ELNode> iter = list.iterator();
+ while (iter.hasNext()) {
+ ELNode n = iter.next();
+ n.accept(v);
+ }
+ }
+
+ public Iterator<ELNode> iterator() {
+ return list.iterator();
+ }
+
+ public boolean isEmpty() {
+ return list.size() == 0;
+ }
+
+ /**
+ * @return true if the expression contains a ${...}
+ */
+ public boolean containsEL() {
+ Iterator<ELNode> iter = list.iterator();
+ while (iter.hasNext()) {
+ ELNode n = iter.next();
+ if (n instanceof Root) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void setMapName(String name) {
+ this.mapName = name;
+ }
+
+ public String getMapName() {
+ return mapName;
+ }
+
+ }
+
+ /*
+ * A visitor class for traversing ELNodes
+ */
+ public static class Visitor {
+
+ public void visit(Root n) throws JasperException {
+ n.getExpression().visit(this);
+ }
+
+ public void visit(Function n) throws JasperException {
+ }
+
+ public void visit(Text n) throws JasperException {
+ }
+
+ public void visit(ELText n) throws JasperException {
+ }
+ }
+}
+
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ELParser.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ELParser.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ELParser.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ELParser.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,382 @@
+/*
+ * 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 char type;
+
+ 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, parser.type));
+ }
+ }
+ 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 '\$' 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 == '$' || ch == '#') {
+ buf.append(ch);
+ }
+ // else error!
+ } else if (prev == '$' || prev == '#') {
+ if (ch == '{') {
+ this.type = prev;
+ prev = 0;
+ break;
+ }
+ buf.append(prev);
+ prev = 0;
+ }
+ if (ch == '\\' || 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;
+ }
+ }
+
+ public char getType() {
+ return type;
+ }
+}
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ErrorDispatcher.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ErrorDispatcher.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ErrorDispatcher.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ErrorDispatcher.java Mon Sep 28 01:55:26 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.net.MalformedURLException;
+import java.util.ArrayList;
+
+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 {
+
+ ArrayList<JavacErrorDetail> errors = new ArrayList<JavacErrorDetail>();
+ 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
+ errors.add(javacError);
+ }
+
+ String lineNumStr = line.substring(beginColon + 1, endColon);
+ try {
+ lineNum = Integer.parseInt(lineNumStr);
+ } catch (NumberFormatException e) {
+ lineNum = -1;
+ }
+
+ 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) {
+ errors.add(javacError);
+ }
+
+ reader.close();
+
+ JavacErrorDetail[] errDetails = null;
+ if (errors.size() > 0) {
+ errDetails = new JavacErrorDetail[errors.size()];
+ errors.toArray(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/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ErrorHandler.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ErrorHandler.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ErrorHandler.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/compiler/ErrorHandler.java Mon Sep 28 01:55:26 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;
+}