Author: yoavs Date: Sun Oct 16 15:08:10 2005 New Revision: 322516 URL: http://svn.apache.org/viewcvs?rev=322516&view=rev Log: Bugzilla 37062: http://issues.apache.org/bugzilla/show_bug.cgi?id=37062
Modified: tomcat/jasper/tc5.5.x/jasper2/src/share/org/apache/jasper/compiler/Compiler.java tomcat/jasper/tc5.5.x/jasper2/src/share/org/apache/jasper/servlet/JspServletWrapper.java Modified: tomcat/jasper/tc5.5.x/jasper2/src/share/org/apache/jasper/compiler/Compiler.java URL: http://svn.apache.org/viewcvs/tomcat/jasper/tc5.5.x/jasper2/src/share/org/apache/jasper/compiler/Compiler.java?rev=322516&r1=322515&r2=322516&view=diff ============================================================================== --- tomcat/jasper/tc5.5.x/jasper2/src/share/org/apache/jasper/compiler/Compiler.java (original) +++ tomcat/jasper/tc5.5.x/jasper2/src/share/org/apache/jasper/compiler/Compiler.java Sun Oct 16 15:08:10 2005 @@ -1,5 +1,5 @@ /* - * Copyright 1999,2004 The Apache Software Foundation. + * Copyright 1999,2004-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -76,6 +76,15 @@ // --------------------------------------------------------- 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 @@ -298,7 +307,15 @@ tfp = null; errDispatcher = null; pageInfo = null; - pageNodes = 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); Modified: tomcat/jasper/tc5.5.x/jasper2/src/share/org/apache/jasper/servlet/JspServletWrapper.java URL: http://svn.apache.org/viewcvs/tomcat/jasper/tc5.5.x/jasper2/src/share/org/apache/jasper/servlet/JspServletWrapper.java?rev=322516&r1=322515&r2=322516&view=diff ============================================================================== --- tomcat/jasper/tc5.5.x/jasper2/src/share/org/apache/jasper/servlet/JspServletWrapper.java (original) +++ tomcat/jasper/tc5.5.x/jasper2/src/share/org/apache/jasper/servlet/JspServletWrapper.java Sun Oct 16 15:08:10 2005 @@ -1,5 +1,5 @@ /* - * Copyright 1999,2004 The Apache Software Foundation. + * Copyright 1999,2004-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,16 @@ package org.apache.jasper.servlet; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.IOException; import java.net.URL; +import java.util.ArrayList; +import java.util.List; import javax.servlet.Servlet; import javax.servlet.ServletConfig; @@ -35,6 +42,8 @@ import org.apache.jasper.JasperException; import org.apache.jasper.JspCompilationContext; import org.apache.jasper.Options; +import org.apache.jasper.compiler.ErrorDispatcher; +import org.apache.jasper.compiler.JavacErrorDetail; import org.apache.jasper.compiler.JspRuntimeContext; import org.apache.jasper.compiler.Localizer; import org.apache.jasper.runtime.JspSourceDependent; @@ -54,6 +63,7 @@ * @author Remy Maucherat * @author Kin-man Chung * @author Glenn Nielsen + * @author Tim Fennell */ public class JspServletWrapper { @@ -361,13 +371,29 @@ } } } catch (ServletException ex) { - throw ex; + if(options.getDevelopment()) { + throw handleJspException(ex); + } else { + throw ex; + } } catch (IOException ex) { - throw ex; + if(options.getDevelopment()) { + throw handleJspException(ex); + } else { + throw ex; + } } catch (IllegalStateException ex) { - throw ex; + if(options.getDevelopment()) { + throw handleJspException(ex); + } else { + throw ex; + } } catch (Exception ex) { - throw new JasperException(ex); + if(options.getDevelopment()) { + throw handleJspException(ex); + } else { + throw new JasperException(ex); + } } } @@ -389,5 +415,116 @@ public void setLastModificationTest(long lastModificationTest) { this.lastModificationTest = lastModificationTest; } - + + /** + * <p>Attempts to construct a JasperException that contains helpful information + * about what went wrong. Uses the JSP compiler system to translate the line + * number in the generated servlet that originated the exception to a line + * number in the JSP. Then constructs an exception containing that + * information, and a snippet of the JSP to help debugging. + * Please see http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 and + * http://www.tfenne.com/jasper/ for more details. + *</p> + * + * @param ex the exception that was the cause of the problem. + * @return a JasperException with more detailed information + */ + protected JasperException handleJspException(Exception ex) { + try { + Throwable realException = ex; + if (ex instanceof ServletException) { + realException = ((ServletException) ex).getRootCause(); + } + + // First identify the stack frame in the trace that represents the JSP + StackTraceElement[] frames = realException.getStackTrace(); + StackTraceElement jspFrame = null; + + for (int i=0; i<frames.length; ++i) { + if ( frames[i].getClassName().equals(this.getServlet().getClass().getName()) ) { + jspFrame = frames[i]; + break; + } + } + + if (jspFrame == null) { + // If we couldn't find a frame in the stack trace corresponding + // to the generated servlet class, we can't really add anything + return new JasperException(ex); + } + else { + int javaLineNumber = jspFrame.getLineNumber(); + JavacErrorDetail detail = ErrorDispatcher.createJavacError( + jspFrame.getMethodName(), + this.ctxt.getCompiler().getPageNodes(), + null, + javaLineNumber); + + // If the line number is less than one we couldn't find out + // where in the JSP things went wrong + int jspLineNumber = detail.getJspBeginLineNumber(); + if (jspLineNumber < 1) { + throw new JasperException(ex); + } + + // Read both files in, so we can inspect them + String[] jspLines = readFile + (this.ctxt.getResourceAsStream(this.ctxt.getJspFile())); + + String[] javaLines = readFile + (new FileInputStream(this.ctxt.getServletJavaFileName())); + + // If the line contains the opening of a multi-line scriptlet + // block, then the JSP line number we got back is probably + // faulty. Scan forward to match the java line... + if (jspLines[jspLineNumber-1].lastIndexOf("<%") > + jspLines[jspLineNumber-1].lastIndexOf("%>")) { + String javaLine = javaLines[javaLineNumber-1].trim(); + + for (int i=jspLineNumber-1; i<jspLines.length; i++) { + if (jspLines[i].indexOf(javaLine) != -1) { + jspLineNumber = i+1; + break; + } + } + } + + // copy out a fragment of JSP to display to the user + StringBuffer buffer = new StringBuffer(1024); + int startIndex = Math.max(0, jspLineNumber-1-3); + int endIndex = Math.min(jspLines.length-1, jspLineNumber-1+3); + + for (int i=startIndex;i<=endIndex; ++i) { + buffer.append(i+1); + buffer.append(": "); + buffer.append(jspLines[i]); + buffer.append("\n"); + } + + return new JasperException( + "Exception in JSP: " + detail.getJspFileName() + ":" + + jspLineNumber + "\n\n" + buffer + "\n\nStacktrace:", ex); + } + } catch (Exception je) { + // If anything goes wrong, just revert to the original behaviour + return new JasperException(ex); + } + } + + /** + * Reads a text file from an input stream into a String[]. Used to read in + * the JSP and generated Java file when generating error messages. + */ + private String[] readFile(InputStream s) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(s)); + List lines = new ArrayList(); + String line; + + while ( (line = reader.readLine()) != null ) { + lines.add(line); + } + + return (String[]) lines.toArray( new String[lines.size()] ); + } + } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]