You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by bo...@apache.org on 2017/09/16 01:54:20 UTC

svn commit: r1018226 [26/41] - in /websites/production/tapestry/content: ./ cache/ styles/

Modified: websites/production/tapestry/content/overriding-exception-reporting.html
==============================================================================
--- websites/production/tapestry/content/overriding-exception-reporting.html (original)
+++ websites/production/tapestry/content/overriding-exception-reporting.html Sat Sep 16 01:54:19 2017
@@ -27,6 +27,15 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -36,26 +45,13 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div>
-
-</div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div></div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
-<form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html">
-  <input type="text" name="q">
-  <input type="submit" value="Search">
-</form>
-
-</div>
-
-
-<div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div>
-
-
-<div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Overriding Exception Reporting</h1></div>
-
-</div>
+            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html"> 
+ <input type="text" name="q"> 
+ <input type="submit" value="Search"> 
+</form></div><div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div><div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Overriding Exception Reporting</h1></div></div>
       <div class="clearer"></div>
       </div>
 
@@ -67,18 +63,41 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>&#160;</p><parameter ac:name="hidden">true</parameter><parameter ac:name="atlassian-macro-output-type">BLOCK</parameter><rich-text-body><p>Customizing Tapestry's default exception reporting page</p></rich-text-body><p>One of Tapestry's best features is its comprehensive exception reporting. The level of detail is impressive and useful.</p><parameter ac:name="style">float:right</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="class">aui-label</parameter><rich-text-body><parameter ac:name="showLabels">false</parameter><parameter ac:name="showSpace">false</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="cql">label = "errors" and space = currentSpace()</parameter></rich-text-body><p>Of course, one of the first questions anyone asks is "How do I turn it off?" This exception reporting is very helpful for developers but its easy to see it as terrifying for potential user
 s. Catching runtime exceptions can be a very useful way of handling rarely occurring exceptions even in production, and there's no reason to throw away Tapestry's default error reporting just to handle a few specific exceptions. From version 5.4 (for previous versions, the same functionality is available as a <a  class="external-link" href="http://www.tynamo.org/tapestry-exceptionpage+guide/" rel="nofollow">third-party module tapestry-exceptionpage</a>), you can contribute exception handles and/or exception pages for specific exception types. Refer back to <a  href="runtime-exceptions.html">Runtime Exceptions</a> page for more information. Read on if you want to completely replace Tapestry's default exception handling.</p><h2 id="OverridingExceptionReporting-Version1:ReplacingtheExceptionReportPage">Version 1: Replacing the Exception Report Page</h2><p>Let's start with a page that fires an exception from an event handler method.</p><parameter ac:name="language">xml</parameter><param
 eter ac:name="title">ActionFail.tml</parameter><plain-text-body> &lt;html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd" t:type="layout" title="Action Fail"&gt;
+                <div id="ConfluenceContent"><p>&#160;</p><p>One of Tapestry's best features is its comprehensive exception reporting. The level of detail is impressive and useful.</p><div class="aui-label" style="float:right" title="Related Articles"><h3>Related Articles</h3><ul class="content-by-label"><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="error-page-recipe.html">Error Page Recipe</a> 
+  </div> </li><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="specific-errors-faq.html">Specific Errors FAQ</a> 
+  </div> </li><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="overriding-exception-reporting.html">Overriding Exception Reporting</a> 
+  </div> </li></ul></div><p>Of course, one of the first questions anyone asks is "How do I turn it off?" This exception reporting is very helpful for developers but its easy to see it as terrifying for potential users. Catching runtime exceptions can be a very useful way of handling rarely occurring exceptions even in production, and there's no reason to throw away Tapestry's default error reporting just to handle a few specific exceptions. From version 5.4 (for previous versions, the same functionality is available as a <a  class="external-link" href="http://www.tynamo.org/tapestry-exceptionpage+guide/" rel="nofollow">third-party module tapestry-exceptionpage</a>), you can contribute exception handles and/or exception pages for specific exception types. Refer back to <a  href="runtime-exceptions.html">Runtime Exceptions</a> page for more information. Read on if you want to completely replace Tapestry's default exception handling.</p><h2 id="OverridingExceptionReporting-Version1:Rep
 lacingtheExceptionReportPage">Version 1: Replacing the Exception Report Page</h2><p>Let's start with a page that fires an exception from an event handler method.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>ActionFail.tml</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"> &lt;html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd" t:type="layout" title="Action Fail"&gt;
         &lt;p&gt;
             &lt;t:actionlink t:id="fail" class="btn btn-large btn-warning"&gt;Click for Exception&lt;/t:actionlink&gt;
         &lt;/p&gt;
-&lt;/html&gt;</plain-text-body><parameter ac:name="language">java</parameter><parameter ac:name="title">Index.java</parameter><plain-text-body>package com.example.newapp.pages;
+&lt;/html&gt;</pre>
+</div></div><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Index.java</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">package com.example.newapp.pages;
 
 public class ActionFail {
     void onActionFromFail() {
         throw new RuntimeException("Failure inside action event handler.");
     }
 }
-</plain-text-body><p>With production mode disabled, clicking the link displays the default exception report page:</p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image confluence-content-image-border image-center" width="500" src="overriding-exception-reporting.data/actionfail_-_top.png"></span></p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image confluence-content-image-border image-center" width="500" src="overriding-exception-reporting.data/Application_Exception.png"></span></p><p>&#160;</p><p>The easy way to override the exception report is to provide an ExceptionReport page that overrides the one provided with the framework.</p><p>This is as easy as providing a page named "ExceptionReport". It must implement the <a  class="external-link" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/
 tapestry5/services/ExceptionReporter.html">ExceptionReporter</a> interface.</p><parameter ac:name="language">xml</parameter><parameter ac:name="title">ExceptionReport.tml</parameter><plain-text-body>&lt;html t:type="layout" title="Exception"
+</pre>
+</div></div><p>With production mode disabled, clicking the link displays the default exception report page:</p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image confluence-content-image-border image-center" width="500" src="overriding-exception-reporting.data/actionfail_-_top.png"></span></p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image confluence-content-image-border image-center" width="500" src="overriding-exception-reporting.data/Application_Exception.png"></span></p><p>&#160;</p><p>The easy way to override the exception report is to provide an ExceptionReport page that overrides the one provided with the framework.</p><p>This is as easy as providing a page named "ExceptionReport". It must implement the <a  class="external-link" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapest
 ry5/services/ExceptionReporter.html">ExceptionReporter</a> interface.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>ExceptionReport.tml</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;html t:type="layout" title="Exception"
       xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"&gt;
 
 
@@ -95,7 +114,9 @@ public class ActionFail {
 
 
 &lt;/html&gt;
-</plain-text-body><parameter ac:name="language">java</parameter><parameter ac:name="title">ExceptionReport.java</parameter><plain-text-body>package com.example.newapp.pages;
+</pre>
+</div></div><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>ExceptionReport.java</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">package com.example.newapp.pages;
 
 import org.apache.tapestry5.annotations.Property;
 import org.apache.tapestry5.services.ExceptionReporter;
@@ -113,14 +134,18 @@ public class ExceptionReport implements
             message = exception.getClass().getName();
     }
 }
-</plain-text-body><p>The end result is a customized exception report page.</p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image confluence-content-image-border image-center" width="500" src="overriding-exception-reporting.data/customer_exception_report_-_open_1.png"></span></p><h2 id="OverridingExceptionReporting-Version2:OverridingtheRequestExceptionHandler">Version 2: Overriding the RequestExceptionHandler</h2><p>The previous example will display a link back to the Index page of the application. Another alternative is to display the error &lt;on&gt; the Index page. This requires a different approach: overriding the service responsible for reporting request exceptions.</p><p>The service <a  class="external-link" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/services/RequestExceptionHandler.html">RequestExceptionHandler</a> is responsible for this.</p><p>By replacing 
 the default implementation of this service with our own implementation, we can take control over exactly what happens when a request exception occurs.</p><p>We'll do this in two steps. First, we'll extend the Index page to serve as an ExceptionReporter. Second, we'll override the default RequestExceptionHandler to use the Index page instead of the ExceptionReport page. Of course, this is just one approach.</p><parameter ac:name="language">xml</parameter><parameter ac:name="title">Index.tml (partial)</parameter><plain-text-body> &lt;t:if test="message"&gt;
+</pre>
+</div></div><p>The end result is a customized exception report page.</p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image confluence-content-image-border image-center" width="500" src="overriding-exception-reporting.data/customer_exception_report_-_open_1.png"></span></p><h2 id="OverridingExceptionReporting-Version2:OverridingtheRequestExceptionHandler">Version 2: Overriding the RequestExceptionHandler</h2><p>The previous example will display a link back to the Index page of the application. Another alternative is to display the error &lt;on&gt; the Index page. This requires a different approach: overriding the service responsible for reporting request exceptions.</p><p>The service <a  class="external-link" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/services/RequestExceptionHandler.html">RequestExceptionHandler</a> is responsible for this.</p><p>By replacing the de
 fault implementation of this service with our own implementation, we can take control over exactly what happens when a request exception occurs.</p><p>We'll do this in two steps. First, we'll extend the Index page to serve as an ExceptionReporter. Second, we'll override the default RequestExceptionHandler to use the Index page instead of the ExceptionReport page. Of course, this is just one approach.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Index.tml (partial)</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"> &lt;t:if test="message"&gt;
     &lt;div class="panel panel-danger"&gt;
         &lt;div class="panel-heading"&gt;An exception has occurred.&lt;/div&gt;
         &lt;div class="panel-body"&gt;
             ${message}
         &lt;/div&gt;
     &lt;/div&gt;
- &lt;/t:if&gt;</plain-text-body><parameter ac:name="language">java</parameter><parameter ac:name="title">Index.java</parameter><plain-text-body>public class Index implements ExceptionReporter
+ &lt;/t:if&gt;</pre>
+</div></div><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Index.java</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class Index implements ExceptionReporter
 {
 	@Property
 	private String message;
@@ -135,7 +160,9 @@ public class ExceptionReport implements
 	}
 
   ...
-}</plain-text-body><p>The above defines a new property, message, on the Index page. The @Persist annotation indicates that values assigned to the field will persist from one request to another. The use of FLASH for the persistence strategy indicates that the value will be used until the next time the page renders, then the value will be discarded.</p><p>The message property is set from the thrown runtime exception.</p><p>The remaining changes take place inside AppModule.</p><parameter ac:name="language">java</parameter><parameter ac:name="title">AppModule.java (partial)</parameter><plain-text-body>    public RequestExceptionHandler buildAppRequestExceptionHandler(
+}</pre>
+</div></div><p>The above defines a new property, message, on the Index page. The @Persist annotation indicates that values assigned to the field will persist from one request to another. The use of FLASH for the persistence strategy indicates that the value will be used until the next time the page renders, then the value will be discarded.</p><p>The message property is set from the thrown runtime exception.</p><p>The remaining changes take place inside AppModule.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">    public RequestExceptionHandler buildAppRequestExceptionHandler(
             final Logger logger,
             final ResponseRenderer renderer,
             final ComponentSource componentSource)
@@ -163,7 +190,9 @@ public class ExceptionReport implements
     {
         configuration.add(RequestExceptionHandler.class, handler);
     }
-</plain-text-body><p>First we define the new service using a service builder method. This is an alternative to the <code>bind()</code> method; we define the service, its interface type (the return type of the method) and the service id (the part that follows "build" is the method name) and provide the implementation inline. A service builder method must return the service implementation, here implemented as an inner class.</p><p>The Logger resource that is passed into the builder method is the Logger appropriate for the service. ResponseRenderer and ComponentSource are two services defined by Tapestry.</p><p>With this in place, there are now two different services that implement the RequestExceptionHandler interface: the default one built into Tapestry (whose service id is "RequestExceptionHandler") and the new one defined in this module, "AppRequestExceptionHandler"). Without a little more work, Tapestry will be unable to determine which one to use when an exception does occur.</p>
 <p>Tapestry has a pipeline for resolving injected dependencies; the ServiceOverride service is one part of that pipeline. Contributions to it are used to override an existing service, when the injection is exclusively by type.</p><p>Here we inject the AppRequestExceptionHandler service and contribute it as the override for type RequestExceptionHandler. The @Local annotation is used to select the RequestHandler service defined by this module, AppModule. Once contributed into ServiceOverride, it becomes the default service injected throughout the Registry.</p><p>This finally brings us to the point where we can see the result:</p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image confluence-content-image-border image-center" height="375" width="500" src="overriding-exception-reporting.data/index_as_excepton_report.png"></span></p><h2 id="OverridingExceptionReporting-Version3:DecoratingtheRequestEx
 ceptionHandler">Version 3: Decorating the RequestExceptionHandler</h2><p>A third option is available: we don't define a <em>new</em> service, but instead <em>decorate</em> the existing RequestExceptionHandler service. This approach means we don't have to make a contribution to the ServiceOverride service.</p><p>Service decoration is a powerful facility of Tapestry that is generally used to "wrap" an existing service with an interceptor that provides new functionality such as logging, security, transaction management or other cross-cutting concerns. The interceptor is an object that implements the same interface as the service being decorated, and usually delegates method invocations to it.</p><p>However, there's no requirement that an interceptor for a service actually invoke methods on the service; here we contribute a new implementation that <em>replaces</em> the original:</p><parameter ac:name="language">java</parameter><parameter ac:name="title">AppModule.java (partial)</paramet
 er><plain-text-body>    public RequestExceptionHandler decorateRequestExceptionHandler(
+</pre>
+</div></div><p>First we define the new service using a service builder method. This is an alternative to the <code>bind()</code> method; we define the service, its interface type (the return type of the method) and the service id (the part that follows "build" is the method name) and provide the implementation inline. A service builder method must return the service implementation, here implemented as an inner class.</p><p>The Logger resource that is passed into the builder method is the Logger appropriate for the service. ResponseRenderer and ComponentSource are two services defined by Tapestry.</p><p>With this in place, there are now two different services that implement the RequestExceptionHandler interface: the default one built into Tapestry (whose service id is "RequestExceptionHandler") and the new one defined in this module, "AppRequestExceptionHandler"). Without a little more work, Tapestry will be unable to determine which one to use when an exception does occur.</p><p>Tap
 estry has a pipeline for resolving injected dependencies; the ServiceOverride service is one part of that pipeline. Contributions to it are used to override an existing service, when the injection is exclusively by type.</p><p>Here we inject the AppRequestExceptionHandler service and contribute it as the override for type RequestExceptionHandler. The @Local annotation is used to select the RequestHandler service defined by this module, AppModule. Once contributed into ServiceOverride, it becomes the default service injected throughout the Registry.</p><p>This finally brings us to the point where we can see the result:</p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image confluence-content-image-border image-center" height="375" width="500" src="overriding-exception-reporting.data/index_as_excepton_report.png"></span></p><h2 id="OverridingExceptionReporting-Version3:DecoratingtheRequestExceptio
 nHandler">Version 3: Decorating the RequestExceptionHandler</h2><p>A third option is available: we don't define a <em>new</em> service, but instead <em>decorate</em> the existing RequestExceptionHandler service. This approach means we don't have to make a contribution to the ServiceOverride service.</p><p>Service decoration is a powerful facility of Tapestry that is generally used to "wrap" an existing service with an interceptor that provides new functionality such as logging, security, transaction management or other cross-cutting concerns. The interceptor is an object that implements the same interface as the service being decorated, and usually delegates method invocations to it.</p><p>However, there's no requirement that an interceptor for a service actually invoke methods on the service; here we contribute a new implementation that <em>replaces</em> the original:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bot
 tom-width: 1px;"><b>AppModule.java (partial)</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">    public RequestExceptionHandler decorateRequestExceptionHandler(
             final Logger logger,
             final ResponseRenderer renderer,
             final ComponentSource componentSource,
@@ -187,7 +216,8 @@ public class ExceptionReport implements
             }
         };
     }
-</plain-text-body><p>As with service builder methods and service configuration method, decorator methods are recognized by the "decorate" prefix on the method name. As used here, the rest of the method name is used to identify the service to be decorated (there are other options that allow a decorator to be applied to many different services).</p><p>A change in this version is that when in development mode (that is, when <em>not</em> in production mode) we use the normal implementation. Returning null from a service decoration method indicates that the decorator chooses not to decorate.</p><p>The Logger injected here is the Logger for the service being decorated, the default RequestExceptionHandler service.</p><p>Otherwise, we return an interceptor whose implementation is the same as the new service in version #2.</p><p>The end result is that in development mode we get the full exception report, and in production mode we get an abbreviated message on the application's Index page.</p
 ></div>
+</pre>
+</div></div><p>As with service builder methods and service configuration method, decorator methods are recognized by the "decorate" prefix on the method name. As used here, the rest of the method name is used to identify the service to be decorated (there are other options that allow a decorator to be applied to many different services).</p><p>A change in this version is that when in development mode (that is, when <em>not</em> in production mode) we use the normal implementation. Returning null from a service decoration method indicates that the decorator chooses not to decorate.</p><p>The Logger injected here is the Logger for the service being decorated, the default RequestExceptionHandler service.</p><p>Otherwise, we return an interceptor whose implementation is the same as the new service in version #2.</p><p>The end result is that in development mode we get the full exception report, and in production mode we get an abbreviated message on the application's Index page.</p></div
 >
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/page-and-component-classes-faq.html
==============================================================================
--- websites/production/tapestry/content/page-and-component-classes-faq.html (original)
+++ websites/production/tapestry/content/page-and-component-classes-faq.html Sat Sep 16 01:54:19 2017
@@ -27,6 +27,16 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -67,11 +77,14 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><plain-text-body>{scrollbar}</plain-text-body><h2 id="PageAndComponentClassesFAQ-PageAndComponentClasses">Page And Component Classes</h2><p>Main article: <a  href="component-classes.html">Component Classes</a></p><h3 id="PageAndComponentClassesFAQ-What'sthedifferencebetweenapageandacomponent?">What's the difference between a page and a component?</h3><p>There's very little difference between the two. Pages classes must be in the <em>root-package</em>.<code>pages</code> package; components must be in the <em>root-package</em>.<code>components</code>. Pages may provide event handlers for certain page-specific events (such as activate and passivate). Components may have parameters.</p><p>Other than that, they are more equal than they are different. They may have templates or may render themselves in code (pages usually have a template, components are more likely to render only in code).</p><p>The major difference is that Tapestry page templat
 es may be stored in the web context directory, as if they were static files (they can't be accessed from the client however; a specific rule prevents access to files with the <code>.tml</code> extension).</p><rich-text-body><p>It is possible that this feature may be removed in a later release. It is preferred that page templates be stored on the classpath, like component templates.</p></rich-text-body><h3 id="PageAndComponentClassesFAQ-HowdoIstoremypageclassesinadifferentpackage?">How do I store my page classes in a different package?</h3><p>Tapestry is very rigid here; you can't. Page classes must go in <em>root-package</em>.<code>pages</code>, component classes in <em>root-package</em>.<code>components</code>, etc.</p><p>You are allowed to create sub-packages, to help organize your code better and more logically. For example, you might have <em>root-package</em>.<code>pages.account.ViewAccount</code>, which would have the page name "account/viewaccount". (<span style="line-height:
  1.4285715;">Tapestry would also create an alias "account/view", by stripping off the redundant "account" suffix. Either name is equally valid in your code, and Tapestry will use the shorter name, "account/view" in URLs.)</span></p><p>In addition, it is possible to define additional root packages for the application:</p><parameter ac:name="controls">true</parameter><parameter ac:name="linenumbers">true</parameter><plain-text-body>public static void contributeComponentClassResolver(Configuration&lt;LibraryMapping&gt; configuration) {
+                <div id="ConfluenceContent"><h2 id="PageAndComponentClassesFAQ-PageAndComponentClasses">Page And Component Classes</h2><p>Main article: <a  href="component-classes.html">Component Classes</a></p><h3 id="PageAndComponentClassesFAQ-What'sthedifferencebetweenapageandacomponent?">What's the difference between a page and a component?</h3><p>There's very little difference between the two. Pages classes must be in the <em>root-package</em>.<code>pages</code> package; components must be in the <em>root-package</em>.<code>components</code>. Pages may provide event handlers for certain page-specific events (such as activate and passivate). Components may have parameters.</p><p>Other than that, they are more equal than they are different. They may have templates or may render themselves in code (pages usually have a template, components are more likely to render only in code).</p><p>The major difference is that Tapestry page templates may be stored in the web context directory,
  as if they were static files (they can't be accessed from the client however; a specific rule prevents access to files with the <code>.tml</code> extension).</p><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>It is possible that this feature may be removed in a later release. It is preferred that page templates be stored on the classpath, like component templates.</p></div></div><h3 id="PageAndComponentClassesFAQ-HowdoIstoremypageclassesinadifferentpackage?">How do I store my page classes in a different package?</h3><p>Tapestry is very rigid here; you can't. Page classes must go in <em>root-package</em>.<code>pages</code>, component classes in <em>root-package</em>.<code>components</code>, etc.</p><p>You are allowed to create sub-packages, to help organize your code better and more logically. For example, 
 you might have <em>root-package</em>.<code>pages.account.ViewAccount</code>, which would have the page name "account/viewaccount". (<span style="line-height: 1.4285715;">Tapestry would also create an alias "account/view", by stripping off the redundant "account" suffix. Either name is equally valid in your code, and Tapestry will use the shorter name, "account/view" in URLs.)</span></p><p>In addition, it is possible to define additional root packages for the application:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: true; theme: Default" style="font-size:12px;">public static void contributeComponentClassResolver(Configuration&lt;LibraryMapping&gt; configuration) {
        configuration.add(new LibraryMapping("", "com.example.app.tasks"));
        configuration.add(new LibraryMapping("", "com.example.app.chat"));
 }
-</plain-text-body><p>LibraryMappings are used to resolve a library prefix to one or more package names. The empty string represents the application itself; the above example adds two additional root packages; you might see additional pages under <code>com.example.app.tasks.pages</code>, for example.</p><rich-text-body><p>Tapestry doesn't check for name collisions, and the order the packages are searched for pages and components is not defined. In general, if you can get by with a single root package for your application, that is better.</p></rich-text-body><h3 id="PageAndComponentClassesFAQ-Whydomyinstancevariableshavetobeprivate?">Why do my instance variables have to be private?</h3><p><em>In Tapestry 5.3.1 and earlier all instance variables must be private. Starting in version 5.3.2 instance variables can also be protected or package private (that is, not public), or they can even be public if <code>final</code> or annotated with the deprecated @Retain.</em></p><p>Tapestry does a 
 large amount of transformation to your simple POJO classes as it loads them into memory. In many cases, it must locate every read or write of an instance variable and change its behavior; for example, reading a field that is a component parameter will cause a property of the containing page or component to be read.</p><p>Restricting the scope of fields allows Tapestry to do the necessary processing one class at a time, as needed, at runtime. More complex Aspect Orient Programming systems such as AspectJ can perform similar transformations (and much more complex ones), but they require a dedicated build step (or the introduction of a JVM agent).</p><h3 id="PageAndComponentClassesFAQ-Whydon'tmyinformalparametersshowupintherenderedmarkup?">Why don't my informal parameters show up in the rendered markup?</h3><p>Getting informal parameters to work is in two steps. First, you must make a call to the <code>ComponentResources.renderInformalParameters()</code> method, but just as importantly
 , you must tell Tapestry that you want the component to support informal parameters, using the <code>SupportsInformalParameters</code> annotation. Here's a hypothetical component that displays an image based on the value of a <code>Image</code> object (presumably, a database entity):</p><parameter ac:name="controls">true</parameter><parameter ac:name="linenumbers">true</parameter><plain-text-body>@SupportsInformalParameters
+</pre>
+</div></div><p>LibraryMappings are used to resolve a library prefix to one or more package names. The empty string represents the application itself; the above example adds two additional root packages; you might see additional pages under <code>com.example.app.tasks.pages</code>, for example.</p><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Tapestry doesn't check for name collisions, and the order the packages are searched for pages and components is not defined. In general, if you can get by with a single root package for your application, that is better.</p></div></div><h3 id="PageAndComponentClassesFAQ-Whydomyinstancevariableshavetobeprivate?">Why do my instance variables have to be private?</h3><p><em>In Tapestry 5.3.1 and earlier all instance variables must be private. Starting in version 5.3.2 inst
 ance variables can also be protected or package private (that is, not public), or they can even be public if <code>final</code> or annotated with the deprecated @Retain.</em></p><p>Tapestry does a large amount of transformation to your simple POJO classes as it loads them into memory. In many cases, it must locate every read or write of an instance variable and change its behavior; for example, reading a field that is a component parameter will cause a property of the containing page or component to be read.</p><p>Restricting the scope of fields allows Tapestry to do the necessary processing one class at a time, as needed, at runtime. More complex Aspect Orient Programming systems such as AspectJ can perform similar transformations (and much more complex ones), but they require a dedicated build step (or the introduction of a JVM agent).</p><h3 id="PageAndComponentClassesFAQ-Whydon'tmyinformalparametersshowupintherenderedmarkup?">Why don't my informal parameters show up in the rende
 red markup?</h3><p>Getting informal parameters to work is in two steps. First, you must make a call to the <code>ComponentResources.renderInformalParameters()</code> method, but just as importantly, you must tell Tapestry that you want the component to support informal parameters, using the <code>SupportsInformalParameters</code> annotation. Here's a hypothetical component that displays an image based on the value of a <code>Image</code> object (presumably, a database entity):</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: true; theme: Default" style="font-size:12px;">@SupportsInformalParameters
 public class DBImage
 {
   @Parameter(required=true)
@@ -91,12 +104,31 @@ public class DBImage
     return false;
   }
 }
-</plain-text-body><h3 id="PageAndComponentClassesFAQ-WhydoIgetjava.lang.LinkageErrorwhenIinvokepublicmethodsofmypageclasses?">Why do I get java.lang.LinkageError when I invoke public methods of my page classes?</h3><p>In Tapestry, there are always <em>two</em> versions of page (or component) classes. The first version is the version loaded by standard class loader: the simple POJO version that you wrote.</p><p>The second version is much more complicated; it's the transformed version of your code, with lots of extra hooks and changes to allow the class to operate inside Tapestry. This includes implementing new interfaces and methods, adding new constructors, and changing access to existing fields and methods.</p><p>Although these two classes have the same fully qualified class name, they are distinct classes because they are loaded by different class loaders.</p><p><parameter ac:name="size">L</parameter><parameter ac:name="name">Class Loaders</parameter></p><p>In a Tapestry applicati
 on, most application classes are loaded from the middle class loader. Additional class loaders are used<br clear="none"> to support live service reloading, and live component reloading (along with component class transformation).</p><p>When a page or component is passed as a parameter to a service, a failure occurs (how it is reported varies in different JDK releases) because of the class mismatch.</p><p>The solution is to define an interface with the methods that the service will invoke on the page or component instance. The service will expect an object implementing the interface (and doesn't care what class loader loaded the implementing class).</p><p>Just be sure to put the interface class in a non-controlled package, such as your application's <em>root-package</em> (and <strong>not</strong> <em>root-package</em>.<code>pages</code>).</p><h3 id="PageAndComponentClassesFAQ-Whichisbetter,usingmagicmethodnames(i.e.,beginRender())orannotations(i.e.BeginRender)?">Which is better, usin
 g magic method names (i.e., <code>beginRender()</code>) or annotations (i.e. <code>BeginRender</code>)?</h3><p>There is no single best way; this is where your taste may vary. Historically, the annotations came first, and the method naming conventions came later.</p><p>The advantage of using the method naming conventions is that the method names are more concise, which fewer characters to type, and fewer classes to import.</p><p>The main disadvantage of the method naming conventions is that the method names are not meaningful. <code>onSuccessFromLoginForm()</code> is a less meaningful name than <code>storeUserCredentialsAndReturnToProductsPage()</code>, for example.</p><p>The second disadvantage is you are more susceptible to off-by-a-character errors. For example, <code>onSucessFromLoginForm()</code> will <em>never</em> be called because the event name is misspelled; this would not happen using the annotation approach:</p><parameter ac:name="controls">true</parameter><parameter ac:n
 ame="linenumbers">true</parameter><plain-text-body>  @OnEvent(value=EventConstants.SUCCESS, component="loginForm")
+</pre>
+</div></div><h3 id="PageAndComponentClassesFAQ-WhydoIgetjava.lang.LinkageErrorwhenIinvokepublicmethodsofmypageclasses?">Why do I get java.lang.LinkageError when I invoke public methods of my page classes?</h3><p>In Tapestry, there are always <em>two</em> versions of page (or component) classes. The first version is the version loaded by standard class loader: the simple POJO version that you wrote.</p><p>The second version is much more complicated; it's the transformed version of your code, with lots of extra hooks and changes to allow the class to operate inside Tapestry. This includes implementing new interfaces and methods, adding new constructors, and changing access to existing fields and methods.</p><p>Although these two classes have the same fully qualified class name, they are distinct classes because they are loaded by different class loaders.</p><p>    
+
+
+
+
+<span class="gliffy-container" id="gliffy-container-23527573-2405" data-fullwidth="750" data-ceoid="23335008" data-edit="${diagramEditLink.getLinkUrl()}" data-full="${diagramZoomLink.getLinkUrl()}" data-filename="Class Loaders">
+
+    <map id="gliffy-map-23527573-4953" name="gliffy-map-23527573-4953"></map>
+
+    <img class="gliffy-image" id="gliffy-image-23527573-2405" width="750" height="425" data-full-width="750" data-full-height="425" src="https://cwiki.apache.org/confluence/download/attachments/23335008/Class%20Loaders.png?version=4&amp;modificationDate=1283534469000&amp;api=v2" alt="Class Loaders" usemap="#gliffy-map-23527573-4953">
+
+    <map class="gliffy-dynamic" id="gliffy-dynamic-map-23527573-2405" name="gliffy-dynamic-map-23527573-2405"></map>
+</span>
+
+
+</p><p>In a Tapestry application, most application classes are loaded from the middle class loader. Additional class loaders are used<br clear="none"> to support live service reloading, and live component reloading (along with component class transformation).</p><p>When a page or component is passed as a parameter to a service, a failure occurs (how it is reported varies in different JDK releases) because of the class mismatch.</p><p>The solution is to define an interface with the methods that the service will invoke on the page or component instance. The service will expect an object implementing the interface (and doesn't care what class loader loaded the implementing class).</p><p>Just be sure to put the interface class in a non-controlled package, such as your application's <em>root-package</em> (and <strong>not</strong> <em>root-package</em>.<code>pages</code>).</p><h3 id="PageAndComponentClassesFAQ-Whichisbetter,usingmagicmethodnames(i.e.,beginRender())orannotations(i.e.BeginR
 ender)?">Which is better, using magic method names (i.e., <code>beginRender()</code>) or annotations (i.e. <code>BeginRender</code>)?</h3><p>There is no single best way; this is where your taste may vary. Historically, the annotations came first, and the method naming conventions came later.</p><p>The advantage of using the method naming conventions is that the method names are more concise, which fewer characters to type, and fewer classes to import.</p><p>The main disadvantage of the method naming conventions is that the method names are not meaningful. <code>onSuccessFromLoginForm()</code> is a less meaningful name than <code>storeUserCredentialsAndReturnToProductsPage()</code>, for example.</p><p>The second disadvantage is you are more susceptible to off-by-a-character errors. For example, <code>onSucessFromLoginForm()</code> will <em>never</em> be called because the event name is misspelled; this would not happen using the annotation approach:</p><div class="code panel pdl" sty
 le="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: true; theme: Default" style="font-size:12px;">  @OnEvent(value=EventConstants.SUCCESS, component="loginForm")
   Object storeUserCredentialsAndReturnToProductsPage()
   {
     . . .
   }
-</plain-text-body><p>The compiler will catch a misspelling of the constant <code>SUCCESS</code>. Likewise, local constants can be defined for key components, such as "loginForm".</p><rich-text-body><p>Ultimately, it's developer choice. HLS prefers the method naming conventions in nearly all cases, especially prototypes and demos, but can see that in some projects and some teams, an annotation-only approach is best.</p></rich-text-body><h3 id="PageAndComponentClassesFAQ-WhydoIhavetoinjectapage?Whycan'tIjustcreateoneusingnew?">Why do I have to inject a page? Why can't I just create one using new?</h3><p>Tapestry tranforms your class at runtime. It tends to build a large constructor for the class instance. Further, an instance of the class is useless by itself, it must be wired together with its template and its sub-components.</p><p>On top of that, Tapestry keeps just once instance of each page in memory (since 5.2). It reworks the bytecode of the components so that a single instance 
 can be shared across multiple request handling threads.</p><plain-text-body>{scrollbar}</plain-text-body><p>____</p><p>&#160;</p><p>&#160;</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p>&#160;</p><p>&#160;</p></div>
+</pre>
+</div></div><p>The compiler will catch a misspelling of the constant <code>SUCCESS</code>. Likewise, local constants can be defined for key components, such as "loginForm".</p><div class="confluence-information-macro confluence-information-macro-information"><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Ultimately, it's developer choice. HLS prefers the method naming conventions in nearly all cases, especially prototypes and demos, but can see that in some projects and some teams, an annotation-only approach is best.</p></div></div><h3 id="PageAndComponentClassesFAQ-WhydoIhavetoinjectapage?Whycan'tIjustcreateoneusingnew?">Why do I have to inject a page? Why can't I just create one using new?</h3><p>Tapestry tranforms your class at runtime. It tends to build a large constructor for the class instance. Further, an instance of the class is useless by itself, it must be wired together wi
 th its template and its sub-components.</p><p>On top of that, Tapestry keeps just once instance of each page in memory (since 5.2). It reworks the bytecode of the components so that a single instance can be shared across multiple request handling threads.</p><p>____</p><p>&#160;</p><p>&#160;</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><div class="display-footnotes"></div>
+<p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p>&#160;</p><p>&#160;</p></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/page-life-cycle.html
==============================================================================
--- websites/production/tapestry/content/page-life-cycle.html (original)
+++ websites/production/tapestry/content/page-life-cycle.html Sat Sep 16 01:54:19 2017
@@ -36,26 +36,13 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div>
-
-</div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div></div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
-<form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html">
-  <input type="text" name="q">
-  <input type="submit" value="Search">
-</form>
-
-</div>
-
-
-<div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div>
-
-
-<div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Page Life Cycle</h1></div>
-
-</div>
+            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html"> 
+ <input type="text" name="q"> 
+ <input type="submit" value="Search"> 
+</form></div><div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div><div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Page Life Cycle</h1></div></div>
       <div class="clearer"></div>
       </div>
 
@@ -67,7 +54,43 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><parameter ac:name="style">float:right</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="class">aui-label</parameter><rich-text-body><parameter ac:name="showLabels">false</parameter><parameter ac:name="showSpace">false</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="cql">label = "request-processing" and space = currentSpace()</parameter></rich-text-body><rich-text-body><p>This is an advanced topic. Most users won't ever need to know anything about the page life cycle.</p></rich-text-body><p>&#160;</p><p>In Tapestry, you are free to develop your presentation objects, page and components classes, as ordinary objects, complete with instance variables and so forth.</p><p>This is somewhat revolutionary in terms of web development in Java. By comparison, using traditional servlets, or Struts, your presentation objects (Servlets, or Struts Actions, or the equivalent in othe
 r frameworks) are <em>stateless singletons</em>. That is, a <em>single</em> instance is created, and all incoming requests are threaded through that single instance. Because multiple requests are handled by many different threads, this means that the singleton's instance variables are useless ... any value written into an instance variable would immediately be overwritten by a different thread. Thus, it is necessary to use the Servlet API's HttpServletRequest object to store per-request data, and the HttpSession object to store data between requests.</p><p>Tapestry takes a very different approach.</p><p>In Tapestry, each page is a singleton, but with a <em>per thread</em> map of field names &amp; values that Tapestry invisibly manages for you.</p><p>With this approach, all the difficult, ugly issues related to multi-threading go by the wayside. Instead, familiar, simple coding practices (using ordinary methods and fields) can be used.</p><rich-text-body><p>Tapestry 5.0 and 5.1 used 
 page pooling, rather than a singleton page with a per-thread map, to achieve the same effect.</p></rich-text-body><p>The page life cycle is quite simple:</p><ol><li>When first needed, a page is loaded. Loading a page involves instantiating the components of the page and connecting them together.</li><li>Once a page is loaded, it is <em>attached</em> to the current request. Remember that there will be many threads, each handling its own request to the same page.</li><li>At the end of a request, after a response has been sent to the client, the page is <em>detached</em> from the request. This is a chance to perform any cleanup needed for the page.</li></ol><h2 id="PageLifeCycle-PageLifeCycleMethods">Page Life Cycle Methods</h2><p>There are rare occasions where it is useful for a component to perform some operations, usually some kind of initialization or caching, based on the life cycle of the page.</p><p>As with <a  href="component-rendering.html">component rendering</a>, you have th
 e ability to make your components "aware" of these events by telling Tapestry what methods to invoke for each.</p><p>Page life cycle methods should take no parameters and return void.</p><p>You have the choice of attaching an annotation to a method, or simply using the method naming conventions:</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Annotation</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Method Name</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>When Called</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>@<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageLoaded.html">PageLoaded</a></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>pageLoaded()</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>After the page is fully loaded</p></td></tr><tr><td colspan="1" rowspan="1" class
 ="confluenceTd"><p>@<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageAttached.html">PageAttached</a></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>pageAttached()</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>After the page is attached to the request.</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">@<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageReset.html">PageReset</a></td><td colspan="1" rowspan="1" class="confluenceTd">pageReset()</td><td colspan="1" rowspan="1" class="confluenceTd">After the page is <em>activated</em>, except when requesting the same page</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>@<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageDetached.html">PageDetached</a></p></td><td colspan="1" rowspan="1" class="conf
 luenceTd"><p>pageDetached()</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>AFter the page is detached from the request.</p></td></tr></tbody></table></div><p>The @PageReset life cycle (only for Tapestry 5.2 and later) is invoked on a page render request when the page is linked to from some <em>other</em> page of the application (but <em>not</em> on a link to the same page), or upon a reload of the page in the browser. This is to allow the page to reset its state, if any, when a user returns to the page from some other part of the application.</p><h2 id="PageLifeCycle-ComparisontoJavaServerPages">Comparison to JavaServer Pages</h2><p>JSPs also act as singletons. However, the individual JSP tags are pooled.</p><p>This is one of the areas where Tapestry can significantly outperform JSPs. Much of the code inside a compiled JSP class concerns getting tags from a tag pool, configuring the properties of the tag instance, using the tag instance, then cleaning up the tag instanc
 e and putting it back in the pool.</p><p>The operations Tapestry does once per request are instead executed dozens or potentially hundreds of times (depending the complexity of the page, and if any nested loops occur).</p><p>Pooling JSP tags is simply the wrong granularity.</p><p>Tapestry can also take advantage of its more coarse grained caching to optimize how data moves, via parameters, between components. This means that Tapestry pages will actually speed up after they render the first time.</p><h2 id="PageLifeCycle-PagePoolConfiguration">Page Pool Configuration</h2><rich-text-body><p>This related to versions of Tapestry prior to 5.2. Modern Tapestry uses an alternate approach that allows a single page instance to be shared across many request processing threads.</p></rich-text-body><p>In Tapestry 5.0 and 5.1, a page pool is used to store page instances. The pool is "keyed" on the name of the page (such as "start") and the <em>locale</em> for the page (such as "en" or "fr").</p>
 <p>Within each key, Tapestry tracks the number of page instances that have been created, as well as the number that are in use (currently attached to a request).</p><p>When a page is first accessed in a request, it is taken from the pool. Tapestry has some <a  href="configuration.html">configuration values</a> that control the details of how and when page instances are created.</p><ul><li>If a free page instance is available, the page is marked in use and attached to the request.</li><li>If there are fewer page instances than the <em>soft limit</em>, then a new page instance is simply created and attached to the request.</li><li>If the soft limit has been reached, Tapestry will wait for a short period of time for a page instance to become available before creating a new page instance.</li><li>If the hard limit has been reached, Tapestry will throw an exception rather than create a new page instance.</li><li>Otherwise, Tapestry will create a new page instance.<br clear="none"> Thus a
  busy application will initially create pages up-to the soft limit (which defaults to five page instances). If the application continues to be pounded with requests, it will slow its request processing, using the soft wait time in an attempt to reuse an existing page instance.</li></ul><p>A truly busy application will continue to create new page instances as needed until the hard limit is reached.</p><p>Remember that all these configuration values are per key: the combination of page name and locale. Thus even with a hard limit of 20, you may eventually find that Tapestry has created 20 start page instances for locale "en" <em>and</em> 20 start page instances for locale "fr" (if your application is configured to support both English and French). Likewise, you may have 20 instances for the start page, and 20 instances for the newaccount page.</p><p>Tapestry periodically checks its cache for page instances that have not been used recently (within a configurable window). Unused page in
 stances are release to the garbage collector.</p><p>The end result is that you have quite a degree of tuning control over the process. If memory is a limitation and throughput can be sacrificed, try lowering the soft and hard limit and increasing the soft wait.</p><p>If performance is absolute and you have lots of memory, then increase the soft and hard limit and reduce the soft wait. This encourages Tapestry to create more page instances and not wait as long to re-use existing instances.</p></div>
+                <div id="ConfluenceContent"><div class="aui-label" style="float:right" title="Related Articles"><h3>Related Articles</h3><ul class="content-by-label"><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="page-navigation.html">Page Navigation</a> 
+  </div> </li><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="page-life-cycle.html">Page Life Cycle</a> 
+  </div> </li><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="component-rendering.html">Component Rendering</a> 
+  </div> </li><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="component-events.html">Component Events</a> 
+  </div> </li><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="component-events-faq.html">Component Events FAQ</a> 
+  </div> </li><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="request-processing.html">Request Processing</a> 
+  </div> </li></ul></div><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>This is an advanced topic. Most users won't ever need to know anything about the page life cycle.</p></div></div><p>&#160;</p><p>In Tapestry, you are free to develop your presentation objects, page and components classes, as ordinary objects, complete with instance variables and so forth.</p><p>This is somewhat revolutionary in terms of web development in Java. By comparison, using traditional servlets, or Struts, your presentation objects (Servlets, or Struts Actions, or the equivalent in other frameworks) are <em>stateless singletons</em>. That is, a <em>single</em> instance is created, and all incoming requests are threaded through that single instance. Because multiple requests are handled by many different threads, this means that 
 the singleton's instance variables are useless ... any value written into an instance variable would immediately be overwritten by a different thread. Thus, it is necessary to use the Servlet API's HttpServletRequest object to store per-request data, and the HttpSession object to store data between requests.</p><p>Tapestry takes a very different approach.</p><p>In Tapestry, each page is a singleton, but with a <em>per thread</em> map of field names &amp; values that Tapestry invisibly manages for you.</p><p>With this approach, all the difficult, ugly issues related to multi-threading go by the wayside. Instead, familiar, simple coding practices (using ordinary methods and fields) can be used.</p><div class="confluence-information-macro confluence-information-macro-information"><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Tapestry 5.0 and 5.1 used page pooling, rather than a singleto
 n page with a per-thread map, to achieve the same effect.</p></div></div><p>The page life cycle is quite simple:</p><ol><li>When first needed, a page is loaded. Loading a page involves instantiating the components of the page and connecting them together.</li><li>Once a page is loaded, it is <em>attached</em> to the current request. Remember that there will be many threads, each handling its own request to the same page.</li><li>At the end of a request, after a response has been sent to the client, the page is <em>detached</em> from the request. This is a chance to perform any cleanup needed for the page.</li></ol><h2 id="PageLifeCycle-PageLifeCycleMethods">Page Life Cycle Methods</h2><p>There are rare occasions where it is useful for a component to perform some operations, usually some kind of initialization or caching, based on the life cycle of the page.</p><p>As with <a  href="component-rendering.html">component rendering</a>, you have the ability to make your components "aware"
  of these events by telling Tapestry what methods to invoke for each.</p><p>Page life cycle methods should take no parameters and return void.</p><p>You have the choice of attaching an annotation to a method, or simply using the method naming conventions:</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Annotation</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Method Name</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>When Called</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>@<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageLoaded.html">PageLoaded</a></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>pageLoaded()</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>After the page is fully loaded</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>@<a  class="external-l
 ink" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageAttached.html">PageAttached</a></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>pageAttached()</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>After the page is attached to the request.</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">@<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageReset.html">PageReset</a></td><td colspan="1" rowspan="1" class="confluenceTd">pageReset()</td><td colspan="1" rowspan="1" class="confluenceTd">After the page is <em>activated</em>, except when requesting the same page</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>@<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageDetached.html">PageDetached</a></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>pageDetached()</p></td><td c
 olspan="1" rowspan="1" class="confluenceTd"><p>AFter the page is detached from the request.</p></td></tr></tbody></table></div><p>The @PageReset life cycle (only for Tapestry 5.2 and later) is invoked on a page render request when the page is linked to from some <em>other</em> page of the application (but <em>not</em> on a link to the same page), or upon a reload of the page in the browser. This is to allow the page to reset its state, if any, when a user returns to the page from some other part of the application.</p><h2 id="PageLifeCycle-ComparisontoJavaServerPages">Comparison to JavaServer Pages</h2><p>JSPs also act as singletons. However, the individual JSP tags are pooled.</p><p>This is one of the areas where Tapestry can significantly outperform JSPs. Much of the code inside a compiled JSP class concerns getting tags from a tag pool, configuring the properties of the tag instance, using the tag instance, then cleaning up the tag instance and putting it back in the pool.</p><p>
 The operations Tapestry does once per request are instead executed dozens or potentially hundreds of times (depending the complexity of the page, and if any nested loops occur).</p><p>Pooling JSP tags is simply the wrong granularity.</p><p>Tapestry can also take advantage of its more coarse grained caching to optimize how data moves, via parameters, between components. This means that Tapestry pages will actually speed up after they render the first time.</p><h2 id="PageLifeCycle-PagePoolConfiguration">Page Pool Configuration</h2><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>This related to versions of Tapestry prior to 5.2. Modern Tapestry uses an alternate approach that allows a single page instance to be shared across many request processing threads.</p></div></div><p>In Tapestry 5.0 and 5.1, a page poo
 l is used to store page instances. The pool is "keyed" on the name of the page (such as "start") and the <em>locale</em> for the page (such as "en" or "fr").</p><p>Within each key, Tapestry tracks the number of page instances that have been created, as well as the number that are in use (currently attached to a request).</p><p>When a page is first accessed in a request, it is taken from the pool. Tapestry has some <a  href="configuration.html">configuration values</a> that control the details of how and when page instances are created.</p><ul><li>If a free page instance is available, the page is marked in use and attached to the request.</li><li>If there are fewer page instances than the <em>soft limit</em>, then a new page instance is simply created and attached to the request.</li><li>If the soft limit has been reached, Tapestry will wait for a short period of time for a page instance to become available before creating a new page instance.</li><li>If the hard limit has been reach
 ed, Tapestry will throw an exception rather than create a new page instance.</li><li>Otherwise, Tapestry will create a new page instance.<br clear="none"> Thus a busy application will initially create pages up-to the soft limit (which defaults to five page instances). If the application continues to be pounded with requests, it will slow its request processing, using the soft wait time in an attempt to reuse an existing page instance.</li></ul><p>A truly busy application will continue to create new page instances as needed until the hard limit is reached.</p><p>Remember that all these configuration values are per key: the combination of page name and locale. Thus even with a hard limit of 20, you may eventually find that Tapestry has created 20 start page instances for locale "en" <em>and</em> 20 start page instances for locale "fr" (if your application is configured to support both English and French). Likewise, you may have 20 instances for the start page, and 20 instances for the
  newaccount page.</p><p>Tapestry periodically checks its cache for page instances that have not been used recently (within a configurable window). Unused page instances are release to the garbage collector.</p><p>The end result is that you have quite a degree of tuning control over the process. If memory is a limitation and throughput can be sacrificed, try lowering the soft and hard limit and increasing the soft wait.</p><p>If performance is absolute and you have lots of memory, then increase the soft and hard limit and reduce the soft wait. This encourages Tapestry to create more page instances and not wait as long to re-use existing instances.</p></div>
       </div>
 
       <div class="clearer"></div>