SLING-11299 : JSP source/linenumber is not always shown when an exception occurs
diff --git a/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java b/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java
index 34c49f1..d9b5342 100644
--- a/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java
+++ b/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java
@@ -24,17 +24,14 @@
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.SlingServletException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.observation.ExternalResourceChangeListener;
import org.apache.sling.api.resource.observation.ResourceChange;
@@ -54,7 +51,6 @@
import org.apache.sling.scripting.jsp.jasper.runtime.AnnotationProcessor;
import org.apache.sling.scripting.jsp.jasper.runtime.JspApplicationContextImpl;
import org.apache.sling.scripting.jsp.jasper.servlet.JspServletWrapper;
-import org.apache.sling.scripting.jsp.util.TagUtil;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Activate;
@@ -63,7 +59,6 @@
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
-import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
@@ -585,36 +580,13 @@
if (!contextHasPrecompiledJsp) {
callJsp(slingBindings);
}
- } catch (final SlingServletException e) {
- // ServletExceptions use getRootCause() instead of getCause(),
- // so we have to extract the actual root cause and pass it as
- // cause in our new ScriptException
- if (e.getCause() != null) {
- // SlingServletException always wraps ServletExceptions
- Throwable rootCause = TagUtil.getRootCause((ServletException) e.getCause());
- // the ScriptException unfortunately does not accept a Throwable as cause,
- // but only a Exception, so we have to wrap it with a dummy Exception in Throwable cases
- if (rootCause instanceof Exception) {
- throw new BetterScriptException(rootCause.toString(), (Exception) rootCause);
- }
- throw new BetterScriptException(rootCause.toString(),
- new Exception("Wrapping Throwable: " + rootCause.toString(), rootCause));
- }
-
- // fallback to standard behaviour
- throw new BetterScriptException(e.getMessage(), e);
} catch (final SlingPageException sje) {
try {
callErrorPageJsp(slingBindings, sje.getErrorPage());
} catch (final Exception e) {
-
- throw new BetterScriptException(e.getMessage(), e);
+ throw e;
}
- } catch (final Exception e) {
-
- throw new BetterScriptException(e.getMessage(), e);
-
} finally {
// make sure the context loader is reset after setting up the
@@ -654,29 +626,6 @@
return this.jspRuntimeContext;
}
- /**
- * Fixes {@link ScriptException} that overwrites the
- * {@link ScriptException#getMessage()} method to display its own
- * <code>message</code> instead of the <code>detailMessage</code>
- * defined in {@link Throwable}. Unfortunately using the constructor
- * {@link ScriptException#ScriptException(Exception)} does not set the
- * <code>message</code> member of {@link ScriptException}, which leads to
- * a message of <code>"null"</code>, effectively supressing the detailed
- * information of the cause. This class provides a way to do that explicitly
- * with a new constructor accepting both a message and a causing exception.
- *
- */
- private static class BetterScriptException extends ScriptException {
-
- private static final long serialVersionUID = -6490165487977283019L;
-
- public BetterScriptException(final String message, final Exception cause) {
- super(message);
- this.initCause(cause);
- }
-
- }
-
@Override
public void onChange(final List<ResourceChange> changes) {
for(final ResourceChange change : changes){
diff --git a/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java b/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java
index 616c545..437ecbf 100644
--- a/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java
+++ b/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java
@@ -204,7 +204,15 @@
}
public Compiler getCompiler() {
- return createCompiler();
+ return this.jspCompiler;
+ }
+
+ public Compiler activateCompiler() {
+ if ( jspCompiler == null ) {
+ // create compile and compile
+ this.compile(); // we ignore the exception
+ }
+ return jspCompiler;
}
/** ---------- Access resources in the webapp ---------- */
@@ -495,14 +503,10 @@
// ==================== Compile and reload ====================
public JasperException compile() {
- return compile(false);
- }
-
- public JasperException compile(boolean fromJSPC) {
final Compiler c = createCompiler();
try {
c.removeGeneratedFiles();
- c.compile(true, fromJSPC);
+ c.compile(true, false);
} catch (final JasperException ex) {
return ex;
} catch (final IOException ioe) {
diff --git a/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/TagLibraryInfoImpl.java b/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/TagLibraryInfoImpl.java
index d831ca0..0b9a9af 100644
--- a/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/TagLibraryInfoImpl.java
+++ b/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/TagLibraryInfoImpl.java
@@ -164,7 +164,7 @@
parseTLD(ctxt, location[0], in, null);
// Add TLD to dependency list
- PageInfo pageInfo = ctxt.getCompiler().getPageInfo();
+ PageInfo pageInfo = ctxt.activateCompiler().getPageInfo();
if (pageInfo != null) {
pageInfo.addDependant(location[0]);
}
diff --git a/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java b/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java
index 2dc7480..ca3f8a7 100644
--- a/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java
+++ b/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java
@@ -41,8 +41,6 @@
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.sling.api.SlingException;
-import org.apache.sling.api.SlingIOException;
-import org.apache.sling.api.SlingServletException;
import org.apache.sling.api.scripting.ScriptEvaluationException;
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.commons.classloader.DynamicClassLoader;
@@ -434,29 +432,36 @@
}
/**
- * @param bindings
- * @throws SlingIOException
- * @throws SlingServletException
- * @throws IllegalArgumentException if the Jasper Precompile controller
- * request parameter has an illegal value.
+ * Call the jsp
+ * @param bindings The bindings for the jsp
+ * @throws SlingPageException JSP page exception handler exceptions
+ * @throws SlingException for any non runtime exception
+ * @throws RuntimeException for runtime exceptions
+ *
*/
public void service(final SlingBindings bindings) {
try {
service(bindings.getRequest(), bindings.getResponse());
- } catch (SlingException se) {
- // rethrow as is
+ } catch ( final ServletException se ) {
+ if ( se.getRootCause() != null ) {
+ final Throwable t = se.getRootCause();
+ if( t instanceof Exception ) {
+ handleJspException((Exception)t);
+ }
+ }
+ handleJspException(se);
+ } catch ( final SlingPageException se) {
+ // don't handle SlingPageExceptions, just rethrow
throw se;
- } catch (IOException ioe) {
- throw new SlingIOException(ioe);
- } catch (ServletException se) {
- throw new SlingServletException(se);
+ } catch (final Exception ex) {
+ handleJspException(ex);
}
}
/**
* Process the request.
*/
- public void service(final HttpServletRequest request,
+ private void service(final HttpServletRequest request,
final HttpServletResponse response)
throws ServletException, IOException {
try {
@@ -515,16 +520,6 @@
(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
ex.getMessage());
return;
- } catch (final SlingException ex) {
- throw ex;
- } catch (final ServletException ex) {
- handleJspException(ex);
- } catch (final IOException ex) {
- handleJspException(ex);
- } catch (final IllegalStateException ex) {
- handleJspException(ex);
- }catch (final Exception ex) {
- handleJspException(ex);
}
}
@@ -584,6 +579,15 @@
}
}
+ private RuntimeException wrapException(final Exception e) {
+ if ( e instanceof RuntimeException ) {
+ return (RuntimeException) e;
+ }
+ // wrap in ScriptEvaluationException
+ return new ScriptEvaluationException(this.ctxt.getJspFile(),
+ e.getMessage() == null ? e.toString() : e.getMessage(), e);
+ }
+
/**
* <p>Attempts to construct a JasperException that contains helpful information
* about what went wrong. Uses the JSP compiler system to translate the line
@@ -595,43 +599,13 @@
*</p>
*
* @param ex the exception that was the cause of the problem.
- * @throws a ServletException with more detailed information
+ * @throws a SlingException Wrapping the original exception
*/
- protected void handleJspException(final Exception ex)
- throws ServletException {
- final Exception jspEx = handleJspExceptionInternal(ex);
- if ( jspEx instanceof ServletException ) {
- throw (ServletException)jspEx;
- }
- throw (SlingException)jspEx;
- }
-
- /**
- * Returns only a ServletException or a SlingException
- */
- private Exception handleJspExceptionInternal(final Exception ex)
- throws ServletException {
- Throwable realException = ex;
- String exMessage = realException.getMessage();
- if (ex instanceof ServletException) {
- realException = ((ServletException) ex).getRootCause();
- // root cause might be null (eg. for a JasperException ex)
- if (realException == null) {
- realException = ex;
- } else {
- exMessage = ex.toString();
- }
- }
-
- // avoid nested ScriptEvaluationExceptions (eg. in nested jsp includes)
- while (realException instanceof ScriptEvaluationException) {
- realException = realException.getCause();
- exMessage = realException.getMessage();
- }
-
+ protected void handleJspException(final Exception ex) {
+ RuntimeException result = null;
try {
// First identify the stack frame in the trace that represents the JSP
- StackTraceElement[] frames = realException.getStackTrace();
+ final StackTraceElement[] frames = ex.getStackTrace();
StackTraceElement jspFrame = null;
for (int i=0; i<frames.length; ++i) {
@@ -641,50 +615,43 @@
}
}
- 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
- if ( ex instanceof ServletException ) {
- return ex;
+
+ // If we couldn't find a frame in the stack trace corresponding
+ // to the generated servlet class, we can't really add anything
+ if (jspFrame != null) {
+ final int javaLineNumber = jspFrame.getLineNumber();
+ final JavacErrorDetail detail = ErrorDispatcher.createJavacError(
+ jspFrame.getMethodName(),
+ this.ctxt.activateCompiler().getPageNodes(),
+ null,
+ javaLineNumber,
+ ctxt);
+
+ // If the line number is less than one we couldn't find out
+ // where in the JSP things went wrong
+ final int jspLineNumber = detail.getJspBeginLineNumber();
+ if (jspLineNumber > 0) {
+ final String origMsg = ex.getMessage() == null ? ex.toString() : ex.getMessage();
+ final String message;
+ if (options.getDisplaySourceFragment() && detail.getJspExtract() != null ) {
+ message = Localizer.getMessage("jsp.exception", detail.getJspFileName(), String.valueOf(jspLineNumber))
+ .concat(" : ").concat(origMsg).concat("\n\n").concat(detail.getJspExtract()).concat("\n");
+
+ } else {
+ message = Localizer.getMessage("jsp.exception", detail.getJspFileName(), String.valueOf(jspLineNumber))
+ .concat(" : ").concat(origMsg);
+ }
+ result = new SlingException(message, ex);
}
- return new SlingException(ex.getMessage(), ex);
+
}
- int javaLineNumber = jspFrame.getLineNumber();
- JavacErrorDetail detail = ErrorDispatcher.createJavacError(
- jspFrame.getMethodName(),
- this.ctxt.getCompiler().getPageNodes(),
- null,
- javaLineNumber,
- ctxt);
-
- // 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) {
- if ( realException instanceof ServletException ) {
- return (ServletException)realException;
- }
- return new SlingException(exMessage, realException);
- }
-
- if (options.getDisplaySourceFragment() && detail.getJspExtract() != null ) {
- return new SlingException(Localizer.getMessage
- ("jsp.exception", detail.getJspFileName(),
- "" + jspLineNumber) +
- "\n\n" + detail.getJspExtract() +
- "\n", realException);
-
- }
- return new SlingException(Localizer.getMessage
- ("jsp.exception", detail.getJspFileName(),
- "" + jspLineNumber), realException);
} catch (final Exception je) {
// If anything goes wrong, just revert to the original behaviour
- if (realException instanceof ServletException) {
- return (ServletException)realException;
- }
- return new SlingException(exMessage, realException);
}
+ if ( result == null ) {
+ result = wrapException(ex);
+ }
+ throw result;
}
/**