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 
Wed Sep 20 12:29:16 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 
Wed Sep 20 12:29:16 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 Wed Sep 20 
12:29:16 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>


Reply via email to