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/07/31 20:12:51 UTC
svn commit: r799681 [3/24] - in /struts/sandbox/trunk/struts2-jsp-plugin: ./
src/main/java/org/apache/struts/ src/main/java/org/apache/struts2/
src/main/java/org/apache/struts2/compiler/
src/main/java/org/apache/struts2/jasper/ src/main/java/org/apache...
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Compiler.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Compiler.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Compiler.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Compiler.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,498 @@
+/*
+ * 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.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.struts2.jasper.JasperException;
+import org.apache.struts2.jasper.JspCompilationContext;
+import org.apache.struts2.jasper.Options;
+import org.apache.struts2.jasper.servlet.JspServletWrapper;
+import org.apache.struts2.jasper.JspCompilationContext;
+
+/**
+ * Main JSP compiler class. This class uses Ant for compiling.
+ *
+ * @author Anil K. Vijendran
+ * @author Mandar Raje
+ * @author Pierre Delisle
+ * @author Kin-man Chung
+ * @author Remy Maucherat
+ * @author Mark Roth
+ */
+public abstract class Compiler {
+ protected org.apache.commons.logging.Log log=
+ org.apache.commons.logging.LogFactory.getLog( Compiler.class );
+
+ // ----------------------------------------------------------------- Static
+
+
+ // Some javac are not thread safe; use a lock to serialize compilation,
+ static Object javacLock = new Object();
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ protected JspCompilationContext ctxt;
+
+ protected ErrorDispatcher errDispatcher;
+ protected PageInfo pageInfo;
+ protected JspServletWrapper jsw;
+ protected TagFileProcessor tfp;
+
+ protected Options options;
+
+ protected Node.Nodes pageNodes;
+ // ------------------------------------------------------------ Constructor
+
+ public void init(JspCompilationContext ctxt, JspServletWrapper jsw) {
+ this.jsw = jsw;
+ this.ctxt = ctxt;
+ this.options = ctxt.getOptions();
+ }
+
+ // --------------------------------------------------------- Public Methods
+
+ /**
+ * <p>Retrieves the parsed nodes of the JSP page, if they are available.
+ * May return null. Used in development mode for generating detailed
+ * error messages. http://issues.apache.org/bugzilla/show_bug.cgi?id=37062.
+ * </p>
+ */
+ public Node.Nodes getPageNodes() {
+ return this.pageNodes;
+ }
+
+ /**
+ * Compile the jsp file into equivalent servlet in .java file
+ * @return a smap for the current JSP page, if one is generated,
+ * null otherwise
+ */
+ protected String[] generateJava() throws Exception {
+
+ String[] smapStr = null;
+
+ long t1, t2, t3, t4;
+
+ t1 = t2 = t3 = t4 = 0;
+
+ if (log.isDebugEnabled()) {
+ t1 = System.currentTimeMillis();
+ }
+
+ // Setup page info area
+ pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader(),
+ errDispatcher),
+ ctxt.getJspFile());
+
+ JspConfig jspConfig = options.getJspConfig();
+ JspConfig.JspProperty jspProperty =
+ jspConfig.findJspProperty(ctxt.getJspFile());
+
+ /*
+ * If the current uri is matched by a pattern specified in
+ * a jsp-property-group in web.xml, initialize pageInfo with
+ * those properties.
+ */
+ pageInfo.setELIgnored(JspUtil.booleanValue(
+ jspProperty.isELIgnored()));
+ pageInfo.setScriptingInvalid(JspUtil.booleanValue(
+ jspProperty.isScriptingInvalid()));
+ if (jspProperty.getIncludePrelude() != null) {
+ pageInfo.setIncludePrelude(jspProperty.getIncludePrelude());
+ }
+ if (jspProperty.getIncludeCoda() != null) {
+ pageInfo.setIncludeCoda(jspProperty.getIncludeCoda());
+ }
+
+ String javaFileName = ctxt.getServletJavaFileName();
+ ServletWriter writer = null;
+
+ try {
+ // Setup the ServletWriter
+ String javaEncoding = ctxt.getOptions().getJavaEncoding();
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
+ OutputStreamWriter osw = null;
+
+ try {
+ osw = new OutputStreamWriter(
+ byteArrayOutputStream, javaEncoding);
+ } catch (UnsupportedEncodingException ex) {
+ errDispatcher.jspError("jsp.error.needAlternateJavaEncoding",
+ javaEncoding);
+ }
+
+ writer = new ServletWriter(new PrintWriter(osw));
+ ctxt.setWriter(writer);
+
+ // Reset the temporary variable counter for the generator.
+ JspUtil.resetTemporaryVariableName();
+
+ // Parse the file
+ ParserController parserCtl = new ParserController(ctxt, this);
+ pageNodes = parserCtl.parse(ctxt.getJspFile());
+
+ if (ctxt.isPrototypeMode()) {
+ // generate prototype .java file for the tag file
+ Generator.generate(writer, this, pageNodes);
+ writer.close();
+ writer = null;
+ return null;
+ }
+
+ // Validate and process attributes
+ Validator.validate(this, pageNodes);
+
+ if (log.isDebugEnabled()) {
+ t2 = System.currentTimeMillis();
+ }
+
+ // Collect page info
+ Collector.collect(this, pageNodes);
+
+ // Compile (if necessary) and load the tag files referenced in
+ // this compilation unit.
+ tfp = new TagFileProcessor();
+ tfp.loadTagFiles(this, pageNodes);
+
+ if (log.isDebugEnabled()) {
+ t3 = System.currentTimeMillis();
+ }
+
+ // Determine which custom tag needs to declare which scripting vars
+ ScriptingVariabler.set(pageNodes, errDispatcher);
+
+ // Optimizations by Tag Plugins
+ TagPluginManager tagPluginManager = options.getTagPluginManager();
+ tagPluginManager.apply(pageNodes, errDispatcher, pageInfo);
+
+ // Optimization: concatenate contiguous template texts.
+ TextOptimizer.concatenate(this, pageNodes);
+
+ // Generate static function mapper codes.
+ ELFunctionMapper.map(this, pageNodes);
+
+ // generate servlet .java file
+ Generator.generate(writer, this, pageNodes);
+ writer.close();
+ writer = null;
+
+ // The writer is only used during the compile, dereference
+ // it in the JspCompilationContext when done to allow it
+ // to be GC'd and save memory.
+ ctxt.setWriter(null);
+ ctxt.setSourceCode(byteArrayOutputStream.toString());
+ if (log.isDebugEnabled()) {
+ t4 = System.currentTimeMillis();
+ log.debug("Generated "+ javaFileName + " total="
+ + (t4-t1) + " generate=" + (t4-t3)
+ + " validate=" + (t2-t1));
+ }
+
+ } catch (Exception e) {
+ if (writer != null) {
+ try {
+ writer.close();
+ writer = null;
+ } catch (Exception e1) {
+ // do nothing
+ }
+ }
+ // Remove the generated .java file
+ new File(javaFileName).delete();
+ throw e;
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (Exception e2) {
+ // do nothing
+ }
+ }
+ }
+
+ // JSR45 Support
+ if (! options.isSmapSuppressed()) {
+ smapStr = SmapUtil.generateSmap(ctxt, pageNodes);
+ }
+
+ // If any proto type .java and .class files was generated,
+ // the prototype .java may have been replaced by the current
+ // compilation (if the tag file is self referencing), but the
+ // .class file need to be removed, to make sure that javac would
+ // generate .class again from the new .java file just generated.
+ tfp.removeProtoTypeFiles(ctxt.getClassFileName());
+
+ return smapStr;
+ }
+
+ /**
+ * Compile the servlet from .java file to .class file
+ */
+ protected abstract void generateClass(String[] smap)
+ throws FileNotFoundException, JasperException, Exception;
+
+
+ /**
+ * Compile the jsp file from the current engine context
+ */
+ public void compile()
+ throws FileNotFoundException, JasperException, Exception
+ {
+ compile(true);
+ }
+
+ /**
+ * Compile the jsp file from the current engine context. As an side-
+ * effect, tag files that are referenced by this page are also compiled.
+ * @param compileClass If true, generate both .java and .class file
+ * If false, generate only .java file
+ */
+ public void compile(boolean compileClass)
+ throws FileNotFoundException, JasperException, Exception
+ {
+ compile(compileClass, false);
+ }
+
+ /**
+ * Compile the jsp file from the current engine context. As an side-
+ * effect, tag files that are referenced by this page are also compiled.
+ *
+ * @param compileClass If true, generate both .java and .class file
+ * If false, generate only .java file
+ * @param jspcMode true if invoked from JspC, false otherwise
+ */
+ public void compile(boolean compileClass, boolean jspcMode)
+ throws FileNotFoundException, JasperException, Exception
+ {
+ if (errDispatcher == null) {
+ this.errDispatcher = new ErrorDispatcher(jspcMode);
+ }
+
+ try {
+ String[] smap = generateJava();
+ if (compileClass) {
+ generateClass(smap);
+ }
+ } finally {
+ if (tfp != null) {
+ tfp.removeProtoTypeFiles(null);
+ }
+ // Make sure these object which are only used during the
+ // generation and compilation of the JSP page get
+ // dereferenced so that they can be GC'd and reduce the
+ // memory footprint.
+ tfp = null;
+ errDispatcher = null;
+ pageInfo = null;
+
+ // Only get rid of the pageNodes if in production.
+ // In development mode, they are used for detailed
+ // error messages.
+ // http://issues.apache.org/bugzilla/show_bug.cgi?id=37062
+ if(!this.options.getDevelopment()) {
+ pageNodes = null;
+ }
+
+ if (ctxt.getWriter() != null) {
+ ctxt.getWriter().close();
+ ctxt.setWriter(null);
+ }
+ }
+ }
+
+ /**
+ * This is a protected method intended to be overridden by
+ * subclasses of Compiler. This is used by the compile method
+ * to do all the compilation.
+ */
+ public boolean isOutDated() {
+ return isOutDated( true );
+ }
+
+ /**
+ * Determine if a compilation is necessary by checking the time stamp
+ * of the JSP page with that of the corresponding .class or .java file.
+ * If the page has dependencies, the check is also extended to its
+ * dependeants, and so on.
+ * This method can by overidden by a subclasses of Compiler.
+ * @param checkClass If true, check against .class file,
+ * if false, check against .java file.
+ */
+ public boolean isOutDated(boolean checkClass) {
+
+ String jsp = ctxt.getJspFile();
+
+ if (jsw != null
+ && (ctxt.getOptions().getModificationTestInterval() > 0)) {
+
+ if (jsw.getLastModificationTest()
+ + (ctxt.getOptions().getModificationTestInterval() * 1000)
+ > System.currentTimeMillis()) {
+ return false;
+ } else {
+ jsw.setLastModificationTest(System.currentTimeMillis());
+ }
+ }
+
+ long jspRealLastModified = 0;
+ try {
+ URL jspUrl = ctxt.getResource(jsp);
+ if (jspUrl == null) {
+ ctxt.incrementRemoved();
+ return false;
+ }
+ URLConnection uc = jspUrl.openConnection();
+ jspRealLastModified = uc.getLastModified();
+ uc.getInputStream().close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return true;
+ }
+
+ long targetLastModified = 0;
+ File targetFile;
+
+ if( checkClass ) {
+ targetFile = new File(ctxt.getClassFileName());
+ } else {
+ targetFile = new File(ctxt.getServletJavaFileName());
+ }
+
+ if (!targetFile.exists()) {
+ return true;
+ }
+
+ targetLastModified = targetFile.lastModified();
+ if (checkClass && jsw != null) {
+ jsw.setServletClassLastModifiedTime(targetLastModified);
+ }
+ if (targetLastModified < jspRealLastModified) {
+ if( log.isDebugEnabled() ) {
+ log.debug("Compiler: outdated: " + targetFile + " " +
+ targetLastModified );
+ }
+ return true;
+ }
+
+ // determine if source dependent files (e.g. includes using include
+ // directives) have been changed.
+ if( jsw==null ) {
+ return false;
+ }
+
+ List depends = jsw.getDependants();
+ if (depends == null) {
+ return false;
+ }
+
+ Iterator it = depends.iterator();
+ while (it.hasNext()) {
+ String include = (String)it.next();
+ try {
+ URL includeUrl = ctxt.getResource(include);
+ if (includeUrl == null) {
+ return true;
+ }
+
+ URLConnection includeUconn = includeUrl.openConnection();
+ long includeLastModified = includeUconn.getLastModified();
+ includeUconn.getInputStream().close();
+
+ if (includeLastModified > targetLastModified) {
+ return true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return true;
+ }
+ }
+
+ return false;
+
+ }
+
+
+ /**
+ * Gets the error dispatcher.
+ */
+ public ErrorDispatcher getErrorDispatcher() {
+ return errDispatcher;
+ }
+
+
+ /**
+ * Gets the info about the page under compilation
+ */
+ public PageInfo getPageInfo() {
+ return pageInfo;
+ }
+
+
+ public JspCompilationContext getCompilationContext() {
+ return ctxt;
+ }
+
+
+ /**
+ * Remove generated files
+ */
+ public void removeGeneratedFiles() {
+ try {
+ String classFileName = ctxt.getClassFileName();
+ if (classFileName != null) {
+ File classFile = new File(classFileName);
+ if( log.isDebugEnabled() )
+ log.debug( "Deleting " + classFile );
+ classFile.delete();
+ }
+ } catch (Exception e) {
+ // Remove as much as possible, ignore possible exceptions
+ }
+ try {
+ String javaFileName = ctxt.getServletJavaFileName();
+ if (javaFileName != null) {
+ File javaFile = new File(javaFileName);
+ if( log.isDebugEnabled() )
+ log.debug( "Deleting " + javaFile );
+ javaFile.delete();
+ }
+ } catch (Exception e) {
+ // Remove as much as possible, ignore possible exceptions
+ }
+ }
+
+ public void removeGeneratedClassFiles() {
+ try {
+ String classFileName = ctxt.getClassFileName();
+ if (classFileName != null) {
+ File classFile = new File(classFileName);
+ if( log.isDebugEnabled() )
+ log.debug( "Deleting " + classFile );
+ classFile.delete();
+ }
+ } catch (Exception e) {
+ // Remove as much as possible, ignore possible exceptions
+ }
+ }
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/DefaultErrorHandler.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/DefaultErrorHandler.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/DefaultErrorHandler.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/DefaultErrorHandler.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,109 @@
+/*
+ * 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;
+
+/**
+ * Default implementation of ErrorHandler interface.
+ *
+ * @author Jan Luehe
+ */
+class DefaultErrorHandler implements 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 errMsg Parse error message
+ * @param exception Parse exception
+ */
+ public void jspError(String fname, int line, int column, String errMsg,
+ Exception ex) throws JasperException {
+ throw new JasperException(fname + "(" + line + "," + column + ")"
+ + " " + errMsg, ex);
+ }
+
+ /*
+ * Processes the given JSP parse error.
+ *
+ * @param errMsg Parse error message
+ * @param exception Parse exception
+ */
+ public void jspError(String errMsg, Exception ex) throws JasperException {
+ throw new JasperException(errMsg, ex);
+ }
+
+ /*
+ * Processes the given javac compilation errors.
+ *
+ * @param details Array of JavacErrorDetail instances corresponding to the
+ * compilation errors
+ */
+ public void javacError(JavacErrorDetail[] details) throws JasperException {
+
+ if (details == null) {
+ return;
+ }
+
+ Object[] args = null;
+ StringBuffer buf = new StringBuffer();
+
+ for (int i=0; i < details.length; i++) {
+ buf.append("\n");
+ if (details[i].getJspBeginLineNumber() >= 0) {
+ args = new Object[] {
+ new Integer(details[i].getJspBeginLineNumber()),
+ details[i].getJspFileName() };
+ buf.append("\n");
+ buf.append(Localizer.getMessage("jsp.error.single.line.number",
+ args));
+ buf.append("\n");
+ buf.append(details[i].getErrorMessage());
+ buf.append("\n");
+ buf.append(details[i].getJspExtract());
+ } else {
+ args = new Object[] {
+ new Integer(details[i].getJavaLineNumber()) };
+ buf.append("\n\n");
+ buf.append(Localizer.getMessage("jsp.error.java.line.number",
+ args));
+ buf.append("\n");
+ buf.append(details[i].getErrorMessage());
+ }
+ }
+ buf.append("\n\nStacktrace:");
+ throw new JasperException(Localizer.getMessage("jsp.error.unable.compile") + ": " + buf);
+ }
+
+ /**
+ * 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 {
+
+ throw new JasperException(
+ Localizer.getMessage("jsp.error.unable.compile"), exception);
+ }
+
+}
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Dumper.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Dumper.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Dumper.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/Dumper.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,207 @@
+/*
+ * 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.xml.sax.Attributes;
+import org.apache.struts2.jasper.JasperException;
+
+class Dumper {
+
+ static class DumpVisitor extends Node.Visitor {
+ private int indent = 0;
+
+ private String getAttributes(Attributes attrs) {
+ if (attrs == null)
+ return "";
+
+ StringBuffer buf = new StringBuffer();
+ for (int i=0; i < attrs.getLength(); i++) {
+ buf.append(" " + attrs.getQName(i) + "=\""
+ + attrs.getValue(i) + "\"");
+ }
+ return buf.toString();
+ }
+
+ private void printString(String str) {
+ printIndent();
+ System.out.print(str);
+ }
+
+ private void printString(String prefix, char[] chars, String suffix) {
+ String str = null;
+ if (chars != null) {
+ str = new String(chars);
+ }
+ printString(prefix, str, suffix);
+ }
+
+ private void printString(String prefix, String str, String suffix) {
+ printIndent();
+ if (str != null) {
+ System.out.print(prefix + str + suffix);
+ } else {
+ System.out.print(prefix + suffix);
+ }
+ }
+
+ private void printAttributes(String prefix, Attributes attrs,
+ String suffix) {
+ printString(prefix, getAttributes(attrs), suffix);
+ }
+
+ private void dumpBody(Node n) throws JasperException {
+ Node.Nodes page = n.getBody();
+ if (page != null) {
+// indent++;
+ page.visit(this);
+// indent--;
+ }
+ }
+
+ public void visit(Node.PageDirective n) throws JasperException {
+ printAttributes("<%@ page", n.getAttributes(), "%>");
+ }
+
+ public void visit(Node.TaglibDirective n) throws JasperException {
+ printAttributes("<%@ taglib", n.getAttributes(), "%>");
+ }
+
+ public void visit(Node.IncludeDirective n) throws JasperException {
+ printAttributes("<%@ include", n.getAttributes(), "%>");
+ dumpBody(n);
+ }
+
+ public void visit(Node.Comment n) throws JasperException {
+ printString("<%--", n.getText(), "--%>");
+ }
+
+ public void visit(Node.Declaration n) throws JasperException {
+ printString("<%!", n.getText(), "%>");
+ }
+
+ public void visit(Node.Expression n) throws JasperException {
+ printString("<%=", n.getText(), "%>");
+ }
+
+ public void visit(Node.Scriptlet n) throws JasperException {
+ printString("<%", n.getText(), "%>");
+ }
+
+ public void visit(Node.IncludeAction n) throws JasperException {
+ printAttributes("<jsp:include", n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</jsp:include>");
+ }
+
+ public void visit(Node.ForwardAction n) throws JasperException {
+ printAttributes("<jsp:forward", n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</jsp:forward>");
+ }
+
+ public void visit(Node.GetProperty n) throws JasperException {
+ printAttributes("<jsp:getProperty", n.getAttributes(), "/>");
+ }
+
+ public void visit(Node.SetProperty n) throws JasperException {
+ printAttributes("<jsp:setProperty", n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</jsp:setProperty>");
+ }
+
+ public void visit(Node.UseBean n) throws JasperException {
+ printAttributes("<jsp:useBean", n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</jsp:useBean>");
+ }
+
+ public void visit(Node.PlugIn n) throws JasperException {
+ printAttributes("<jsp:plugin", n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</jsp:plugin>");
+ }
+
+ public void visit(Node.ParamsAction n) throws JasperException {
+ printAttributes("<jsp:params", n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</jsp:params>");
+ }
+
+ public void visit(Node.ParamAction n) throws JasperException {
+ printAttributes("<jsp:param", n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</jsp:param>");
+ }
+
+ public void visit(Node.NamedAttribute n) throws JasperException {
+ printAttributes("<jsp:attribute", n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</jsp:attribute>");
+ }
+
+ public void visit(Node.JspBody n) throws JasperException {
+ printAttributes("<jsp:body", n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</jsp:body>");
+ }
+
+ public void visit(Node.ELExpression n) throws JasperException {
+ printString( "${" + new String( n.getText() ) + "}" );
+ }
+
+ public void visit(Node.CustomTag n) throws JasperException {
+ printAttributes("<" + n.getQName(), n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</" + n.getQName() + ">");
+ }
+
+ public void visit(Node.UninterpretedTag n) throws JasperException {
+ String tag = n.getQName();
+ printAttributes("<"+tag, n.getAttributes(), ">");
+ dumpBody(n);
+ printString("</" + tag + ">");
+ }
+
+ public void visit(Node.TemplateText n) throws JasperException {
+ printString(new String(n.getText()));
+ }
+
+ private void printIndent() {
+ for (int i=0; i < indent; i++) {
+ System.out.print(" ");
+ }
+ }
+ }
+
+ public static void dump(Node n) {
+ try {
+ n.accept(new DumpVisitor());
+ } catch (JasperException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void dump(Node.Nodes page) {
+ try {
+ page.visit(new DumpVisitor());
+ } catch (JasperException e) {
+ e.printStackTrace();
+ }
+ }
+}
+
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELFunctionMapper.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELFunctionMapper.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELFunctionMapper.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELFunctionMapper.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,280 @@
+/*
+ * 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 generates functions mappers for the EL expressions in the page.
+ * Instead of a global mapper, a mapper is used for each call to EL
+ * evaluator, thus avoiding the prefix overlapping and redefinition
+ * issues.
+ *
+ * @author Kin-man Chung
+ */
+
+public class ELFunctionMapper {
+ private int currFunc = 0;
+ StringBuffer ds; // Contains codes to initialize the functions mappers.
+ StringBuffer ss; // Contains declarations of the functions mappers.
+
+ /**
+ * Creates the functions mappers for all EL expressions in the JSP page.
+ *
+ * @param compiler Current compiler, mainly for accessing error dispatcher.
+ * @param page The current compilation unit.
+ */
+ public static void map(Compiler compiler, Node.Nodes page)
+ throws JasperException {
+
+ ELFunctionMapper map = new ELFunctionMapper();
+ map.ds = new StringBuffer();
+ map.ss = new StringBuffer();
+
+ page.visit(map.new ELFunctionVisitor());
+
+ // Append the declarations to the root node
+ String ds = map.ds.toString();
+ if (ds.length() > 0) {
+ Node root = page.getRoot();
+ new Node.Declaration(map.ss.toString(), null, root);
+ new Node.Declaration("static {\n" + ds + "}\n", null, root);
+ }
+ }
+
+ /**
+ * A visitor for the page. The places where EL is allowed are scanned
+ * for functions, and if found functions mappers are created.
+ */
+ class ELFunctionVisitor extends Node.Visitor {
+
+ /**
+ * Use a global name map to facilitate reuse of function maps.
+ * The key used is prefix:function:uri.
+ */
+ private HashMap gMap = new HashMap();
+
+ public void visit(Node.ParamAction n) throws JasperException {
+ doMap(n.getValue());
+ visitBody(n);
+ }
+
+ public void visit(Node.IncludeAction n) throws JasperException {
+ doMap(n.getPage());
+ visitBody(n);
+ }
+
+ public void visit(Node.ForwardAction n) throws JasperException {
+ doMap(n.getPage());
+ visitBody(n);
+ }
+
+ public void visit(Node.SetProperty n) throws JasperException {
+ doMap(n.getValue());
+ visitBody(n);
+ }
+
+ public void visit(Node.UseBean n) throws JasperException {
+ doMap(n.getBeanName());
+ visitBody(n);
+ }
+
+ public void visit(Node.PlugIn n) throws JasperException {
+ doMap(n.getHeight());
+ doMap(n.getWidth());
+ visitBody(n);
+ }
+
+ public void visit(Node.JspElement n) throws JasperException {
+
+ Node.JspAttribute[] attrs = n.getJspAttributes();
+ for (int i = 0; attrs != null && i < attrs.length; i++) {
+ doMap(attrs[i]);
+ }
+ doMap(n.getNameAttribute());
+ visitBody(n);
+ }
+
+ public void visit(Node.UninterpretedTag n) throws JasperException {
+
+ Node.JspAttribute[] attrs = n.getJspAttributes();
+ for (int i = 0; attrs != null && i < attrs.length; i++) {
+ doMap(attrs[i]);
+ }
+ visitBody(n);
+ }
+
+ public void visit(Node.CustomTag n) throws JasperException {
+ Node.JspAttribute[] attrs = n.getJspAttributes();
+ for (int i = 0; attrs != null && i < attrs.length; i++) {
+ doMap(attrs[i]);
+ }
+ visitBody(n);
+ }
+
+ public void visit(Node.ELExpression n) throws JasperException {
+ doMap(n.getEL());
+ }
+
+ private void doMap(Node.JspAttribute attr)
+ throws JasperException {
+ if (attr != null) {
+ doMap(attr.getEL());
+ }
+ }
+
+ /**
+ * Creates function mappers, if needed, from ELNodes
+ */
+ private void doMap(ELNode.Nodes el)
+ throws JasperException {
+
+ // Only care about functions in ELNode's
+ class Fvisitor extends ELNode.Visitor {
+ ArrayList funcs = new ArrayList();
+ HashMap keyMap = new HashMap();
+ public void visit(ELNode.Function n) throws JasperException {
+ String key = n.getPrefix() + ":" + n.getName();
+ if (! keyMap.containsKey(key)) {
+ keyMap.put(key,"");
+ funcs.add(n);
+ }
+ }
+ }
+
+ if (el == null) {
+ return;
+ }
+
+ // First locate all unique functions in this EL
+ Fvisitor fv = new Fvisitor();
+ el.visit(fv);
+ ArrayList functions = fv.funcs;
+
+ if (functions.size() == 0) {
+ return;
+ }
+
+ // Reuse a previous map if possible
+ String decName = matchMap(functions);
+ if (decName != null) {
+ el.setMapName(decName);
+ return;
+ }
+
+ // Generate declaration for the map statically
+ decName = getMapName();
+ ss.append("static private org.apache.struts2.jasper.runtime.ProtectedFunctionMapper " + decName + ";\n");
+
+ ds.append(" " + decName + "= ");
+ ds.append("org.apache.struts2.jasper.runtime.ProtectedFunctionMapper");
+
+ // Special case if there is only one function in the map
+ String funcMethod = null;
+ if (functions.size() == 1) {
+ funcMethod = ".getMapForFunction";
+ } else {
+ ds.append(".getInstance();\n");
+ funcMethod = " " + decName + ".mapFunction";
+ }
+
+ // Setup arguments for either getMapForFunction or mapFunction
+ for (int i = 0; i < functions.size(); i++) {
+ ELNode.Function f = (ELNode.Function)functions.get(i);
+ FunctionInfo funcInfo = f.getFunctionInfo();
+ String key = f.getPrefix()+ ":" + f.getName();
+ ds.append(funcMethod + "(\"" + key + "\", " +
+ funcInfo.getFunctionClass() + ".class, " +
+ '\"' + f.getMethodName() + "\", " +
+ "new Class[] {");
+ String params[] = f.getParameters();
+ for (int k = 0; k < params.length; k++) {
+ if (k != 0) {
+ ds.append(", ");
+ }
+ int iArray = params[k].indexOf('[');
+ if (iArray < 0) {
+ ds.append(params[k] + ".class");
+ }
+ else {
+ String baseType = params[k].substring(0, iArray);
+ ds.append("java.lang.reflect.Array.newInstance(");
+ ds.append(baseType);
+ ds.append(".class,");
+
+ // Count the number of array dimension
+ int aCount = 0;
+ for (int jj = iArray; jj < params[k].length(); jj++ ) {
+ if (params[k].charAt(jj) == '[') {
+ aCount++;
+ }
+ }
+ if (aCount == 1) {
+ ds.append("0).getClass()");
+ } else {
+ ds.append("new int[" + aCount + "]).getClass()");
+ }
+ }
+ }
+ ds.append("});\n");
+ // Put the current name in the global function map
+ gMap.put(f.getPrefix() + ':' + f.getName() + ':' + f.getUri(),
+ decName);
+ }
+ el.setMapName(decName);
+ }
+
+ /**
+ * Find the name of the function mapper for an EL. Reuse a
+ * previously generated one if possible.
+ * @param functions An ArrayList of ELNode.Function instances that
+ * represents the functions in an EL
+ * @return A previous generated function mapper name that can be used
+ * by this EL; null if none found.
+ */
+ private String matchMap(ArrayList functions) {
+
+ String mapName = null;
+ for (int i = 0; i < functions.size(); i++) {
+ ELNode.Function f = (ELNode.Function)functions.get(i);
+ String temName = (String) gMap.get(f.getPrefix() + ':' +
+ f.getName() + ':' + f.getUri());
+ if (temName == null) {
+ return null;
+ }
+ if (mapName == null) {
+ mapName = temName;
+ } else if (!temName.equals(mapName)) {
+ // If not all in the previous match, then no match.
+ return null;
+ }
+ }
+ return mapName;
+ }
+
+ /*
+ * @return An unique name for a function mapper.
+ */
+ private String getMapName() {
+ return "_jspx_fnmap_" + currFunc++;
+ }
+ }
+}
+
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELNode.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELNode.java?rev=799681&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELNode.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/compiler/ELNode.java Fri Jul 31 18:12:48 2009
@@ -0,0 +1,248 @@
+/*
+ * 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;
+
+ Root(ELNode.Nodes expr) {
+ this.expr = expr;
+ }
+
+ public void accept(Visitor v) throws JasperException {
+ v.visit(this);
+ }
+
+ public ELNode.Nodes getExpression() {
+ return expr;
+ }
+ }
+
+ /**
+ * 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 list;
+
+ public Nodes() {
+ list = new ArrayList();
+ }
+
+ 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 iter = list.iterator();
+ while (iter.hasNext()) {
+ ELNode n = (ELNode) iter.next();
+ n.accept(v);
+ }
+ }
+
+ public Iterator iterator() {
+ return list.iterator();
+ }
+
+ public boolean isEmpty() {
+ return list.size() == 0;
+ }
+
+ /**
+ * @return true if the expression contains a ${...}
+ */
+ public boolean containsEL() {
+ Iterator iter = list.iterator();
+ while (iter.hasNext()) {
+ ELNode n = (ELNode) 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/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=799681&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 Fri Jul 31 18:12:48 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=799681&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 Fri Jul 31 18:12:48 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=799681&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 Fri Jul 31 18:12:48 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;
+}