Exception Report Page

When Tapestry detects an uncaught exception, it displays an "exception report" page. The default page is called ExceptionReport.

To see the current "exception report" page in action, click here: I throw an exception!

ExceptionReport displays a wealth of information when system property tapestry.production-mode=false. This is great for development. When the value is true, which is the default, the page is kept brief to avoid confusing the user and to avoid disclosing details of your application's internals.

Currently, tapestry.production-mode = true.

To try it, stop the server, set the system property, and start the server again. Eg. in Windows:

In tcsh:

Then click on the link above to test it.

However, you may prefer to override the exception report to one of your own. The simplest technique is to create a page called ExceptionReport. Tapestry's exception handler will notice it and use it.

To enable JumpStart's ExceptionReport, find ExceptionReport_parked.java and rename it to ExceptionReport.java, then click on the link above to test it. Like Tapestry's exception report, you will find it displays different things depending on the value of tapestry.production-mode.

To revert back to Tapestry's default exception page, rename our ExceptionReport.java back to ExceptionReport_parked.java and choose Project > Clean... in Eclipse.

References: Overriding Exception Report, How to display your own exception Page.

An exception handling strategy

If you're unsure which exceptions should be handled on your current page and which ones should result in the exception page, then try splitting them according to these 2 categories:

Home


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- We need a doctype to allow us to use special characters like &nbsp; 
     We use a "strict" DTD to make IE follow the alignment rules. -->

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
<body class="container">
    <h3>Exception Report Page</h3>

    <p>When Tapestry detects an uncaught exception, it displays an "exception report" page. The default page is called
        ExceptionReport.</p>

    <div class="eg">
        To see the <strong>current</strong> "exception report" page in action, click here:
        <t:eventlink event="throwexception">I throw an exception!</t:eventlink>
    </div>

    <p>
        ExceptionReport displays a wealth of information when system property <em>tapestry.production-mode=false</em>. This is
        great for development. When the value is <em>true</em>, which is the default, the page is kept brief to avoid
        confusing the user and to avoid disclosing details of your application's internals.
    </p>

    <p>
        Currently, tapestry.production-mode = <em>${productionMode}</em>.
    </p>

    <p>To try it, stop the server, set the system property, and start the server again. Eg. in Windows:</p>
    <ul>
        <li>
            <em>set JAVA_OPTS=-Dtapestry.production-mode=true</em>
        </li>
        <li>
            <em>run.bat</em>
        </li>
    </ul>
    <p>In tcsh:</p>
    <ul>
        <li>
            <em>setenv JAVA_OPTS '-Dtapestry.production-mode=true'</em>
        </li>
        <li>
            <em>run.sh</em>
        </li>
    </ul>
    <p>Then click on the link above to test it.</p>

    <p>
        However, you may prefer to <strong>override the exception report</strong> to one of your own. The simplest technique
        is to create a page called ExceptionReport. Tapestry's exception handler will notice it and use it.
    </p>

    <p>
        <strong>To enable JumpStart's ExceptionReport</strong>, find ExceptionReport_parked.java and rename it to
        ExceptionReport.java, then click on the link above to test it. Like Tapestry's exception report, you will find it
        displays different things depending on the value of <em>tapestry.production-mode</em>.
    </p>

    <p>
        <strong>To revert back to Tapestry's default</strong> exception page, rename our ExceptionReport.java back to
        ExceptionReport_parked.java and choose Project > Clean... in Eclipse.
    </p>

    References:
    <a href="http://tapestry.apache.org/overriding-exception-reporting.html">Overriding Exception Report</a>,
    <a href="http://wiki.apache.org/tapestry/Tapestry5ExceptionPage">How to display your own exception Page</a>.
    <br />

    <h4>An exception handling strategy</h4>
    <p>If you're unsure which exceptions should be handled on your current page and which ones should result in the
        exception page, then try splitting them according to these 2 categories:</p>
    <ul>
        <li>
            <strong>Application exceptions</strong>, such as validation errors. Display application exceptions on the page that
            detects them.
        </li>
        <li>
            <strong>System exceptions</strong>, such as system availability problems (eg. cannot connect to database) and
            irrecoverable errors due to programming bugs (eg. OutOfBoundsException, IllegalStateException). Handle these by
            re-throwing them or not catching them at all, causing the exception page to be shown.
        </li>
    </ul>

    <p>
        <t:pagelink page="Index">Home</t:pagelink>
    </p>

    <t:tabgroup>
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/examples/infrastructure/ExceptionReportPage.tml" />
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/examples/infrastructure/ExceptionReportPage.java" />
        <t:sourcecodetab src="/web/src/main/resources/META-INF/assets/css/examples/plain.css" />
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/ExceptionReport.tml" />
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/ExceptionReport_parked.java" />
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/components/ExceptionAndSessionDisplay.tml"/>
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/components/ExceptionAndSessionDisplay.java"/>
    </t:tabgroup>
</body>
</html>


package jumpstart.web.pages.examples.infrastructure;

import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Symbol;

@Import(stylesheet = "css/examples/plain.css")
public class ExceptionReportPage {

    // Screen fields

    @Inject
    @Symbol(SymbolConstants.PRODUCTION_MODE)
    @Property
    private boolean productionMode;

    // The code

    void onThrowException() {
        throw new RuntimeException(
                "JumpStart threw this exception deliberately to make Tapestry display the current exception report page."
                        + " It's the page that displays exceptions you didn't catch.");
    }
}


.eg {
                margin: 20px 0;
                padding: 14px;
                border: 1px solid #ddd;
                border-radius: 6px;
                -webkit-border-radius: 6px;
                -mox-border-radius: 6px;
}


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- We need a doctype to allow us to use special characters like &nbsp; 
     We use a "strict" DTD to make IE follow the alignment rules. -->
     
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
<head>
    <title>Application Exception</title>
</head>
<body>
    <h1>This is an example custom exception report page</h1>

    <t:if test="productionMode">
        System property <em>tapestry.production-mode</em> is currently <em>true</em>, so I will display a simple non-technical 
        message that doesn't reveal any of the inner workings of the application. For more info about this page, click 
        <a t:type="pagelink" t:page="examples/infrastructure/ExceptionReportPage" href="#">Exception Report Page</a>.<br/><br/><br/>

        <div style="background-color: rgb(204, 190, 153); border: black 2px outset; padding: 20px; font-family: 'Trebuchet MS';">
            <strong>The system is temporarily unavailable.</strong> <br/>
            Please try again later, or <t:pagelink page="Index">click here to return to Start</t:pagelink>.
        </div><br/><br/><br/>
    </t:if>
    <t:if test="!productionMode">
        System property <em>tapestry.production-mode</em> is currently <em>false</em>, so I will display full technical details 
        of the exception - the same exception and session data as Tapestry's default ExceptionReport. 
        The source for this page is at the bottom. For more info about this page, click 
        <a t:type="pagelink" t:page="examples/infrastructure/ExceptionReportPage" href="#">Exception Report Page</a>.<br/><br/><br/>
        
        <t:exceptionandsessiondisplay exception="exception"/>
    </t:if>
    
    <t:tabgroup>
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/ExceptionReport.tml"/>
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/ExceptionReport.java"/>
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/components/ExceptionAndSessionDisplay.tml"/>
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/components/ExceptionAndSessionDisplay.java"/>
    </t:tabgroup>
</body>
</html>


package jumpstart.web.pages;

import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.services.ExceptionReporter;

/**
 * A user-friendly page to display when an uncaught exception occurs. If the system property productionMode=true,
 * it displays a simple non-technical message. If the system property productionMode=false, it displays the 
 * same comprehensive exception and session information as Tapestry's default ExceptionReport page. 
 * For more information see http://wiki.apache.org/tapestry/Tapestry5ExceptionPage.
 */

public class ExceptionReport_parked implements ExceptionReporter {
    
    // Screen fields

    @Property
    private Throwable exception;

    @Property
    @Inject
    @Symbol(SymbolConstants.PRODUCTION_MODE)
    private boolean productionMode;
    
    // The code

    public void reportException(Throwable exception) {
        this.exception = exception;
    }

}


<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">

    <!-- 
        This component is identical to the portion of Tapestry's default ExceptionReport page that
        handles productionMode=false.
     -->

<t:content>
    <h1 class="t-exception-report">An unexpected application exception has occurred.</h1>

    <t:exceptiondisplay exception="exception"/>

    <div class="t-env-data">
        <h2>Request</h2>
        <t:renderobject object="request"/>
        
        <t:if test="hasSession">
            <h2>Session</h2>
            <dl>
                <t:loop source="session.attributeNames" value="attributeName">
                    <dt>${attributeName}</dt>
                    <dd>
                        <t:renderobject object="attributeValue"/>
                    </dd>
                </t:loop>
            </dl>
        </t:if>
    </div>
</t:content>

</html>


package jumpstart.web.components;

import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.Session;

/**
 * This component is identical to the portion of Tapestry's default ExceptionReport page that handles
 * productionMode=false.
 */

public class ExceptionAndSessionDisplay {

    @Parameter(required = true)
    @Property
    private Throwable exception;

    @Inject
    @Property
    private Request request;

    @Property
    private String attributeName;

    public boolean getHasSession() {
        return request.getSession(false) != null;
    }

    public Session getSession() {
        return request.getSession(false);
    }

    public Object getAttributeValue() {
        return getSession().getAttribute(attributeName);
    }

}