You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by bu...@apache.org on 2015/07/15 11:20:20 UTC

svn commit: r958386 [2/4] - in /websites/production/tapestry/content: ./ cache/

Modified: websites/production/tapestry/content/implementing-the-hi-lo-guessing-game.html
==============================================================================
--- websites/production/tapestry/content/implementing-the-hi-lo-guessing-game.html (original)
+++ websites/production/tapestry/content/implementing-the-hi-lo-guessing-game.html Wed Jul 15 09:20:19 2015
@@ -65,7 +65,7 @@ table.ScrollbarTable td.ScrollbarParent
 table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
 table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}
 
-/*]]>*/</style><div class="Scrollbar"><table class="ScrollbarTable"><tr><td colspan="1" rowspan="1" class="ScrollbarPrevIcon"><a shape="rect" href="exploring-the-project.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/back_16.gif" width="16" height="16"></a></td><td colspan="1" rowspan="1" class="ScrollbarPrevName" width="33%"><a shape="rect" href="exploring-the-project.html">Exploring the Project</a>&#160;</td><td colspan="1" rowspan="1" class="ScrollbarParent" width="33%"><sup><a shape="rect" href="tapestry-tutorial.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/up_16.gif" width="8" height="8"></a></sup><a shape="rect" href="tapestry-tutorial.html">Tapestry Tutorial</a></td><td colspan="1" rowspan="1" class="ScrollbarNextName" width="33%">&#160;<a shape="rect" href="using-beaneditform-to-create-user-forms.html">Using BeanEditForm To Create User Forms</a></td><td colspan="1" rowspan="1" class="Sc
 rollbarNextIcon"><a shape="rect" href="using-beaneditform-to-create-user-forms.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/forwd_16.gif" width="16" height="16"></a></td></tr></table></div><p><span style="line-height: 1.4285715;">Let's start building a basic Hi-Lo Guessing game.</span></p><p>In the game, the computer selects a number between 1 and 10. You try and guess the number, clicking links. At the end, the computer tells you how many guesses you required to identify the target number. Even a simple example like this will demonstrate several important concepts in Tapestry:</p><ul><li>Breaking an application into individual pages</li><li>Transferring information from one page to another</li><li>Responding to user interactions</li><li>Storing client information in the server-side session</li></ul><p>We'll build this little application in small pieces, using the kind of iterative development that Tapestry makes so easy.</p><p><span cla
 ss="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/hilo-flow.png" data-image-src="/confluence/download/attachments/23340505/hilo-flow.png?version=2&amp;modificationDate=1286814202000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="23527744" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="hilo-flow.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="46"></span></p><p>Our page flow is very simple, consisting of three pages: Index (the starting page), Guess and GameOver. The Index page introduces the application and includes a link to start guessing. The Guess page presents the user with ten links, plus feedback such as "too low" or "too high". The GameOver page tells the user how many guesses they 
 took before finding the target number.</p><h1 id="ImplementingtheHi-LoGuessingGame-IndexPage">Index Page</h1><p>Let's get to work on the Index page and template. Make Index.tml look like this:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Index.tml</b></div><div class="codeContent panelContent pdl">
+/*]]>*/</style><div class="Scrollbar"><table class="ScrollbarTable"><tr><td colspan="1" rowspan="1" class="ScrollbarPrevIcon"><a shape="rect" href="exploring-the-project.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/back_16.gif" width="16" height="16"></a></td><td colspan="1" rowspan="1" class="ScrollbarPrevName" width="33%"><a shape="rect" href="exploring-the-project.html">Exploring the Project</a>&#160;</td><td colspan="1" rowspan="1" class="ScrollbarParent" width="33%"><sup><a shape="rect" href="tapestry-tutorial.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/up_16.gif" width="8" height="8"></a></sup><a shape="rect" href="tapestry-tutorial.html">Tapestry Tutorial</a></td><td colspan="1" rowspan="1" class="ScrollbarNextName" width="33%">&#160;<a shape="rect" href="using-beaneditform-to-create-user-forms.html">Using BeanEditForm To Create User Forms</a></td><td colspan="1" rowspan="1" class="Sc
 rollbarNextIcon"><a shape="rect" href="using-beaneditform-to-create-user-forms.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/forwd_16.gif" width="16" height="16"></a></td></tr></table></div><p><span style="line-height: 1.4285715;">Let's start building a basic Hi-Lo Guessing game.</span></p><p>In the game, the computer selects a number between 1 and 10. You try and guess the number, clicking links. At the end, the computer tells you how many guesses you required to identify the target number. Even a simple example like this will demonstrate several important concepts in Tapestry:</p><ul><li>Breaking an application into individual pages</li><li>Transferring information from one page to another</li><li>Responding to user interactions</li><li>Storing client information in the server-side session</li></ul><p>We'll build this little application in small pieces, using the kind of iterative development that Tapestry makes so easy.</p><p><span cla
 ss="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/hilo-flow.png" data-image-src="/confluence/download/attachments/23340505/hilo-flow.png?version=2&amp;modificationDate=1286814202000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="23527744" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="hilo-flow.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="47"></span></p><p>Our page flow is very simple, consisting of three pages: Index (the starting page), Guess and GameOver. The Index page introduces the application and includes a link to start guessing. The Guess page presents the user with ten links, plus feedback such as "too low" or "too high". The GameOver page tells the user how many guesses they 
 took before finding the target number.</p><h1 id="ImplementingtheHi-LoGuessingGame-IndexPage">Index Page</h1><p>Let's get to work on the Index page and template. Make Index.tml look like this:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Index.tml</b></div><div class="codeContent panelContent pdl">
 <script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[&lt;html t:type=&quot;layout&quot; title=&quot;Hi/Lo Guess&quot;
     xmlns:t=&quot;http://tapestry.apache.org/schema/tapestry_5_4.xsd&quot;&gt;
 
@@ -83,12 +83,12 @@ table.ScrollbarTable td.ScrollbarNextIco
 {
 }
 ]]></script>
-</div></div><p>Running the application gives us our start:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/hilo-1.png" data-image-src="/confluence/download/attachments/23340505/hilo-1.png?version=3&amp;modificationDate=1416879474000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24346889" data-linked-resource-version="3" data-linked-resource-type="attachment" data-linked-resource-default-alias="hilo-1.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="46"></span></p><p>However, clicking the link doesn't do anything yet, as its just a placeholder &lt;a&gt; tag, not an actual Tapestry component. Let's think about what should happen when the user clicks that link:</p><ul><li>A random target number between 1 and 10 should be selected</li><
 li>The number of guesses taken should be reset to 0</li><li>The user should be sent to the Guess page to make a guess</li></ul><p>Our first step is to find out when the user clicks that "start guessing" link. In a typical web application framework, we might start thinking about URLs and handlers and maybe some sort of XML configuration file. But this is Tapestry, so we're going to work with components and methods on our classes.</p><p>First, the component. We want to perform an action (selecting the number) before continuing on to the Guess page. The ActionLink component is just what we need; it creates a link with a URL that will trigger an action event in our code ... but that's getting ahead of ourselves. First up, convert the &lt;a&gt; tag to an ActionLink component:</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">
+</div></div><p>Running the application gives us our start:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/hilo-1.png" data-image-src="/confluence/download/attachments/23340505/hilo-1.png?version=3&amp;modificationDate=1416879474000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24346889" data-linked-resource-version="3" data-linked-resource-type="attachment" data-linked-resource-default-alias="hilo-1.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="47"></span></p><p>However, clicking the link doesn't do anything yet, as its just a placeholder &lt;a&gt; tag, not an actual Tapestry component. Let's think about what should happen when the user clicks that link:</p><ul><li>A random target number between 1 and 10 should be selected</li><
 li>The number of guesses taken should be reset to 0</li><li>The user should be sent to the Guess page to make a guess</li></ul><p>Our first step is to find out when the user clicks that "start guessing" link. In a typical web application framework, we might start thinking about URLs and handlers and maybe some sort of XML configuration file. But this is Tapestry, so we're going to work with components and methods on our classes.</p><p>First, the component. We want to perform an action (selecting the number) before continuing on to the Guess page. The ActionLink component is just what we need; it creates a link with a URL that will trigger an action event in our code ... but that's getting ahead of ourselves. First up, convert the &lt;a&gt; tag to an ActionLink component:</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">
 <script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    &lt;p&gt;
         &lt;t:actionlink t:id=&quot;start&quot;&gt;start guessing&lt;/t:actionlink&gt;
     &lt;/p&gt;
 ]]></script>
-</div></div><p>If you refresh the browser and hover your mouse over the "start guessing" link, you'll see that its URL is now /tutorial1/index.start, which identifies the name of the page ("index") and the id of the component ("start").</p><p>If you click the link now, you'll get an error:</p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image image-center" width="500" src="implementing-the-hi-lo-guessing-game.data/Application_Exception.png" data-image-src="/confluence/download/attachments/23340505/Application_Exception.png?version=1&amp;modificationDate=1428077959000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="55476323" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Application_Exception.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resourc
 e-container-id="23340505" data-linked-resource-container-version="46"></span></p><p>&#160;</p><p>Tapestry is telling us that we need to provide some kind of event handler for that event. What does that look like?</p><p>An event handler is a method of the Java class with a special name. The name is <code>on</code><strong><em>Eventname</em></strong><code>From</code><strong><em>Component-id</em></strong> ... here we want a method named <code>onActionFromStart()</code>. How do we know that "action" is the right event name? Because that's what ActionLink does, that's why its named <strong><em>Action</em></strong>Link.</p><p>Once again, Tapestry gives us options; if you don't like naming conventions, there's an @<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/OnEvent.html">OnEvent</a> annotation you can place on the method instead, which restores the freedom to name the method as you like. Details about this approach 
 are in the <a shape="rect" href="component-events.html">Tapestry Users' Guide</a>. We'll be sticking with the naming convention approach for the tutorial.</p><p>When handling a component event request (the kind of request triggered by the ActionLink component's URL), Tapestry will find the component and trigger a component event on it. This is the callback our server-side code needs to figure out what the user is doing on the client side. Let's start with an empty event handler:</p><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">
+</div></div><p>If you refresh the browser and hover your mouse over the "start guessing" link, you'll see that its URL is now /tutorial1/index.start, which identifies the name of the page ("index") and the id of the component ("start").</p><p>If you click the link now, you'll get an error:</p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image image-center" width="500" src="implementing-the-hi-lo-guessing-game.data/Application_Exception.png" data-image-src="/confluence/download/attachments/23340505/Application_Exception.png?version=1&amp;modificationDate=1428077959000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="55476323" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Application_Exception.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resourc
 e-container-id="23340505" data-linked-resource-container-version="47"></span></p><p>&#160;</p><p>Tapestry is telling us that we need to provide some kind of event handler for that event. What does that look like?</p><p>An event handler is a method of the Java class with a special name. The name is <code>on</code><strong><em>Eventname</em></strong><code>From</code><strong><em>Component-id</em></strong> ... here we want a method named <code>onActionFromStart()</code>. How do we know that "action" is the right event name? Because that's what ActionLink does, that's why its named <strong><em>Action</em></strong>Link.</p><p>Once again, Tapestry gives us options; if you don't like naming conventions, there's an @<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/OnEvent.html">OnEvent</a> annotation you can place on the method instead, which restores the freedom to name the method as you like. Details about this approach 
 are in the <a shape="rect" href="component-events.html">Tapestry Users' Guide</a>. We'll be sticking with the naming convention approach for the tutorial.</p><p>When handling a component event request (the kind of request triggered by the ActionLink component's URL), Tapestry will find the component and trigger a component event on it. This is the callback our server-side code needs to figure out what the user is doing on the client side. Let's start with an empty event handler:</p><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">
 <script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[package com.example.tutorial.pages;
 
 public class Index
@@ -154,7 +154,7 @@ public class Index
     }
 }
 ]]></script>
-</div></div><p>The new event handler method now chooses the target number, and tells the Guess page about it. Because Tapestry is a managed environment, we don't just create an instance of Guess ... it is Tapestry's responsibility to manage the life cycle of the Guess page. Instead, we ask Tapestry for the Guess page, using the @InjectPage annotation.</p><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>All fields in a Tapestry page or component class must be <strong>non-public</strong>.</p></div></div><p>Once we have that Guess page instance, we can invoke methods on it normally.</p><p>Returning a page instance from an event handler method directs Tapestry to send a client-side redirect to the returned page, rather than sending a redirect for the active page. Thus once the user clicks the "start guessing" lin
 k, they'll see the Guess page.</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>When creating your own applications, make sure that the objects stored in final variables are thread safe. It seems counter-intuitive, but final variables are shared across many threads. Ordinary instance variables are not. Fortunately, the implementation of Random is, in fact, thread safe.</p></div></div><p>So ... let's click the link and see what we get:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/guess-template-missing.png" data-image-src="/confluence/download/attachments/23340505/guess-template-missing.png?version=2&amp;modificationDate=1416710821000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24346891"
  data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="guess-template-missing.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="46"></span></p><p>Ah! We didn't create a Guess page template. Tapestry was really expecting us to create one, so we better do so.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>src/main/resources/com/example/tutorial/pages/Guess.tml</b></div><div class="codeContent panelContent pdl">
+</div></div><p>The new event handler method now chooses the target number, and tells the Guess page about it. Because Tapestry is a managed environment, we don't just create an instance of Guess ... it is Tapestry's responsibility to manage the life cycle of the Guess page. Instead, we ask Tapestry for the Guess page, using the @InjectPage annotation.</p><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>All fields in a Tapestry page or component class must be <strong>non-public</strong>.</p></div></div><p>Once we have that Guess page instance, we can invoke methods on it normally.</p><p>Returning a page instance from an event handler method directs Tapestry to send a client-side redirect to the returned page, rather than sending a redirect for the active page. Thus once the user clicks the "start guessing" lin
 k, they'll see the Guess page.</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>When creating your own applications, make sure that the objects stored in final variables are thread safe. It seems counter-intuitive, but final variables are shared across many threads. Ordinary instance variables are not. Fortunately, the implementation of Random is, in fact, thread safe.</p></div></div><p>So ... let's click the link and see what we get:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/guess-template-missing.png" data-image-src="/confluence/download/attachments/23340505/guess-template-missing.png?version=2&amp;modificationDate=1416710821000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24346891"
  data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="guess-template-missing.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="47"></span></p><p>Ah! We didn't create a Guess page template. Tapestry was really expecting us to create one, so we better do so.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>src/main/resources/com/example/tutorial/pages/Guess.tml</b></div><div class="codeContent panelContent pdl">
 <script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[&lt;html t:type=&quot;layout&quot; title=&quot;Guess The Number&quot;
     xmlns:t=&quot;http://tapestry.apache.org/schema/tapestry_5_4.xsd&quot;&gt;
 
@@ -164,16 +164,16 @@ public class Index
   
 &lt;/html&gt;
 ]]></script>
-</div></div><p>Hit the browser's back button, then click the "start guessing" link again. We're getting closer:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/guess-no-target-prop.png" data-image-src="/confluence/download/attachments/23340505/guess-no-target-prop.png?version=2&amp;modificationDate=1416711075000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24346892" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="guess-no-target-prop.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="46"></span></p><p>If you scroll down, you'll see the line of the Guess.tml template that has the error. We have a field named target, but it is private and there's no corresponding property, so 
 Tapestry was unable to access it.</p><p>We just need to write the missing JavaBeans accessor methods <code>getTarget()</code> (and <code>setTarget()</code> for good measure). Or we could let Tapestry write those methods instead:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>Hit the browser's back button, then click the "start guessing" link again. We're getting closer:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/guess-no-target-prop.png" data-image-src="/confluence/download/attachments/23340505/guess-no-target-prop.png?version=2&amp;modificationDate=1416711075000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24346892" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="guess-no-target-prop.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="47"></span></p><p>If you scroll down, you'll see the line of the Guess.tml template that has the error. We have a field named target, but it is private and there's no corresponding property, so 
 Tapestry was unable to access it.</p><p>We just need to write the missing JavaBeans accessor methods <code>getTarget()</code> (and <code>setTarget()</code> for good measure). Or we could let Tapestry write those methods instead:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
 <script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    @Property
     private int target;
 ]]></script>
-</div></div><p>The @<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Property.html">Property</a> annotation very simply directs Tapestry to write the getter and setter method for you. You only need to do this if you are going to reference the field from the template.</p><p>We are getting very close but there's one last big oddity to handle. Once you refresh the page you'll see that target is 0!</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/guess-target-zero.png" data-image-src="/confluence/download/attachments/23340505/guess-target-zero.png?version=3&amp;modificationDate=1416879255000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24346893" data-linked-resource-version="3" data-linked-resource-type="attachment" data-linked-resource-default-alias="guess-target-zero.png" data-base-url="https://cwiki.
 apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="46"></span></p><p>What gives? We know it was set to at least 1 ... where did the value go?</p><p>As noted above, Tapestry sends a redirect to the client after handling the event request. That means that the rendering of the page happens in an entirely new request. Meanwhile, at the end of each request, Tapestry wipes out the value in each instance variable. So that means that target <em>was</em> a non-zero number during the component event request ... but by the time the new page render request comes up from the web browser to render the Guess page, the value of the target field has reverted back to its default, zero.</p><p>The solution here is to mark which fields have values that should persist from one request to the next (and next, and next ...). That's what the @<a shape="rect" class="external-link" href="http://tapestry.apach
 e.org/current/apidocs/org/apache/tapestry5/annotations/Persist.html">Persist</a> annotation is for:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>The @<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Property.html">Property</a> annotation very simply directs Tapestry to write the getter and setter method for you. You only need to do this if you are going to reference the field from the template.</p><p>We are getting very close but there's one last big oddity to handle. Once you refresh the page you'll see that target is 0!</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/guess-target-zero.png" data-image-src="/confluence/download/attachments/23340505/guess-target-zero.png?version=3&amp;modificationDate=1416879255000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24346893" data-linked-resource-version="3" data-linked-resource-type="attachment" data-linked-resource-default-alias="guess-target-zero.png" data-base-url="https://cwiki.
 apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="47"></span></p><p>What gives? We know it was set to at least 1 ... where did the value go?</p><p>As noted above, Tapestry sends a redirect to the client after handling the event request. That means that the rendering of the page happens in an entirely new request. Meanwhile, at the end of each request, Tapestry wipes out the value in each instance variable. So that means that target <em>was</em> a non-zero number during the component event request ... but by the time the new page render request comes up from the web browser to render the Guess page, the value of the target field has reverted back to its default, zero.</p><p>The solution here is to mark which fields have values that should persist from one request to the next (and next, and next ...). That's what the @<a shape="rect" class="external-link" href="http://tapestry.apach
 e.org/current/apidocs/org/apache/tapestry5/annotations/Persist.html">Persist</a> annotation is for:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
 <script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    @Property  
     @Persist
     private int target;
 ]]></script>
-</div></div><p>This doesn't have anything to do with database persistence (that's coming up in a later chapter). It means that the value is stored in the HttpSession between requests.</p><p>Go back to the Index page and click the link again. Finally, we have a target number:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/guess-target.png" data-image-src="/confluence/download/attachments/23340505/guess-target.png?version=3&amp;modificationDate=1416879254000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24346894" data-linked-resource-version="3" data-linked-resource-type="attachment" data-linked-resource-default-alias="guess-target.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="46"></span></p><p>That's enough for us to get started.
  Let's build out the Guess page, and get ready to let the user make guesses. We'll show the count of guesses, and increment that count when they make them. We'll worry about high and low and actually selecting the correct value later.</p><p>When building Tapestry pages, you sometimes start with the Java code and build the template to match, and sometime start with the template and build the Java code to match. Both approaches are valid. Here, lets start with the markup in the template, then figure out what we need in the Java code to make it work.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Guess.tml (revised)</b></div><div class="codeContent panelContent pdl">
+</div></div><p>This doesn't have anything to do with database persistence (that's coming up in a later chapter). It means that the value is stored in the HttpSession between requests.</p><p>Go back to the Index page and click the link again. Finally, we have a target number:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/guess-target.png" data-image-src="/confluence/download/attachments/23340505/guess-target.png?version=3&amp;modificationDate=1416879254000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24346894" data-linked-resource-version="3" data-linked-resource-type="attachment" data-linked-resource-default-alias="guess-target.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="47"></span></p><p>That's enough for us to get started.
  Let's build out the Guess page, and get ready to let the user make guesses. We'll show the count of guesses, and increment that count when they make them. We'll worry about high and low and actually selecting the correct value later.</p><p>When building Tapestry pages, you sometimes start with the Java code and build the template to match, and sometime start with the template and build the Java code to match. Both approaches are valid. Here, lets start with the markup in the template, then figure out what we need in the Java code to make it work.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Guess.tml (revised)</b></div><div class="codeContent panelContent pdl">
 <script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[&lt;html t:type=&quot;layout&quot; title=&quot;Guess The Number&quot;
     xmlns:t=&quot;http://tapestry.apache.org/schema/tapestry_5_4.xsd&quot;
     xmlns:p=&quot;tapestry:parameter&quot;&gt;
@@ -225,7 +225,7 @@ public class Guess
 
 }
 ]]></script>
-</div></div><p>The revised version of Guess includes two new properties: <code>current</code> and <code>guessCount</code>. There's also a handler for the action event from the makeGuess ActionLink component; currently it just increments the count.</p><p>Notice that the <code>onActionFromMakeGuess()</code> method now has a parameter: the context value that was encoded into the URL by the ActionLink. When then user clicks the link, Tapestry will automatically extract the string from the URL, convert it to an int and pass that int value into the event handler method. More boilerplate code you don't have to write.</p><p>At this point, the page is partially operational:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/guess-1.png" data-image-src="/confluence/download/attachments/23340505/guess-1.png?version=4&amp;modificationDate=1416879255000&amp;api=v2" data-unresolved-comment-count="0" data-linke
 d-resource-id="24346895" data-linked-resource-version="4" data-linked-resource-type="attachment" data-linked-resource-default-alias="guess-1.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="46"></span></p><p>Our next step is to actually check the value provided by the user against the target and provide feedback: either they guessed too high, or too low, or just right. If they get it just right, we'll switch to the GameOver page with a message such as "You guessed the number 5 in 2 guesses".</p><p>Let's start with the Guess page; it now needs a new property to store the message to be displayed to the user, and needs a field for the injected GameOver page:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Guess.java (partial)</b></div><div class="codeContent panel
 Content pdl">
+</div></div><p>The revised version of Guess includes two new properties: <code>current</code> and <code>guessCount</code>. There's also a handler for the action event from the makeGuess ActionLink component; currently it just increments the count.</p><p>Notice that the <code>onActionFromMakeGuess()</code> method now has a parameter: the context value that was encoded into the URL by the ActionLink. When then user clicks the link, Tapestry will automatically extract the string from the URL, convert it to an int and pass that int value into the event handler method. More boilerplate code you don't have to write.</p><p>At this point, the page is partially operational:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/guess-1.png" data-image-src="/confluence/download/attachments/23340505/guess-1.png?version=4&amp;modificationDate=1416879255000&amp;api=v2" data-unresolved-comment-count="0" data-linke
 d-resource-id="24346895" data-linked-resource-version="4" data-linked-resource-type="attachment" data-linked-resource-default-alias="guess-1.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="47"></span></p><p>Our next step is to actually check the value provided by the user against the target and provide feedback: either they guessed too high, or too low, or just right. If they get it just right, we'll switch to the GameOver page with a message such as "You guessed the number 5 in 2 guesses".</p><p>Let's start with the Guess page; it now needs a new property to store the message to be displayed to the user, and needs a field for the injected GameOver page:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Guess.java (partial)</b></div><div class="codeContent panel
 Content pdl">
 <script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    @Property
     @Persist(PersistenceConstants.FLASH)
     private String message;
@@ -293,7 +293,7 @@ public class GameOver
   
 &lt;/html&gt;
 ]]></script>
-</div></div><p>The result, when you guess correctly, should be this:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/gameover.png" data-image-src="/confluence/download/attachments/23340505/gameover.png?version=4&amp;modificationDate=1416879255000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24347015" data-linked-resource-version="4" data-linked-resource-type="attachment" data-linked-resource-default-alias="gameover.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="46"></span></p><p>That wraps up the basics of Tapestry; we've demonstrated the basics of linking pages together and passing information from page to page in code as well as incorporating data inside URLs.</p><p>There's still more room to refactor this toy application; for 
 example, making it possible to start a new game from the GameOver page (and doing it in a way that doesn't duplicate code). In addition, later we'll see other ways of sharing information between pages that are less cumbersome than the setup-and-persist approach shown here.</p><p>Next up, we'll start delving into how Tapestry handles HTML forms and user input.&#160;</p><style type="text/css">/*<![CDATA[*/
+</div></div><p>The result, when you guess correctly, should be this:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="implementing-the-hi-lo-guessing-game.data/gameover.png" data-image-src="/confluence/download/attachments/23340505/gameover.png?version=4&amp;modificationDate=1416879255000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24347015" data-linked-resource-version="4" data-linked-resource-type="attachment" data-linked-resource-default-alias="gameover.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340505" data-linked-resource-container-version="47"></span></p><p>That wraps up the basics of Tapestry; we've demonstrated the basics of linking pages together and passing information from page to page in code as well as incorporating data inside URLs.</p><p>There's still more room to refactor this toy application; for 
 example, making it possible to start a new game from the GameOver page (and doing it in a way that doesn't duplicate code). In addition, later we'll see other ways of sharing information between pages that are less cumbersome than the setup-and-persist approach shown here.</p><p>Next up, we'll start delving into how Tapestry handles HTML forms and user input.&#160;</p><style type="text/css">/*<![CDATA[*/
 table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color: #f0f0f0}
 table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
 table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}

Modified: websites/production/tapestry/content/javascript-modules.html
==============================================================================
--- websites/production/tapestry/content/javascript-modules.html (original)
+++ websites/production/tapestry/content/javascript-modules.html Wed Jul 15 09:20:19 2015
@@ -109,7 +109,7 @@ public class Confirm
   ...
 
   javaScriptSupport.require(&quot;my-module&quot;).invoke(&quot;setup&quot;).with(clientId, actionUrl);]]></script>
-</div></div><p>In the first example, <code>my-module</code> exports a single function of two parameters. In the second example, <code>my-module</code> exports an object and the <code>setup</code> key is the function that is invoked.</p><h2 id="JavaScriptModules-DevelopmentMode">Development Mode</h2><p>In development mode, Tapestry will write details into the client-side console.</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="javascript-modules.data/Tapestry_Integration_Test_Application_and_JavaScriptSupport__Tapestry_API_Documentation_.png" data-image-src="/confluence/download/attachments/41813130/Tapestry_Integration_Test_Application_and_JavaScriptSupport__Tapestry_API_Documentation_.png?version=1&amp;modificationDate=1401727827000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="42041399" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Tapestry_Integr
 ation_Test_Application_and_JavaScriptSupport__Tapestry_API_Documentation_.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="41813130" data-linked-resource-container-version="11"></span></p><p>This lists modules&#160;<em>explicitly</em> loaded (for initialization), but does not include modules loaded only as dependencies. You can see more details about what was actually loaded using&#160;<em>view source</em>; RequireJS adds <code>&lt;script&gt;</code> tags to the document to load libraries and modules.</p><h2 id="JavaScriptModules-LibrariesversusModules">Libraries versus Modules</h2><p>Tapestry still supports JavaScript libraries. &#160;When the page is loading, all libraries are loaded before any modules.</p><p>Libraries are loaded sequentially, so if you can avoid using libraries, so much the better in terms of page load time.</p><p>Libraries work in both normal page rendering, and Ajax partial 
 page updates. Even in partial page updates, the libraries will be loaded sequentially before modules are loaded or exported functions invoked.</p><h2 id="JavaScriptModules-AggregatingModules">Aggregating Modules</h2><p>An important part of performance for production applications is JavaScript aggregation.</p><p>In development mode, you want your modules and other assets to load individually. For both CSS and JavaScript, smaller files that align with corresponding server-side files makes it much easier to debug problems.</p><p>Unlike assets, modules can't be fingerprinted, so on each page load, the client browser must ask the server for the module's contents frequently (typically getting a 304 Not Modified response).</p><p><span>This is acceptable in development mode, but quite undesirable in production.</span></p><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></s
 pan><div class="confluence-information-macro-body"><p>By default, Tapestry sets a max age of 60 (seconds) on modules, so you won't see module requests on every page load. This is configurable and you may want a much higher value in production. If you are rapidly iterating on the source of a module, you may need to force the browser to reload after clearing local cache. Chrome has an option to disable the client-side cache when its developer tools are open.</p></div></div><p>With JavaScript aggregation, the module can be included in the single virtual JavaScript library that represents a <a shape="rect" class="external-link" href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/javascript/JavaScriptStack.html">JavaScript stack</a>. This significantly cuts down on both the number of requests from the client to the server, and the overall number of bytes transferred.</p><p>Adding a module to the stack is not the same as <code>require</code>-ing it. In fact, you mus
 t still use <code>JavaScriptSupport.require()</code> regardless.</p><p>What adding a module to a stack accomplishes is that the module's code is downloaded in the first, initial JavaScript download; the download of the stack's virtual library. When (and if) the module is required as a dependency, the code will already be present in the browser and ready to execute.</p><p>Tapestry&#160;<strong>does not</strong> attempt to do dependency analysis; that is left as a manual exercise. Typically, if you aggregate a module, your should look at its dependencies, and aggregate those as well. Failure to do so will cause unwanted requests back to the Tapestry server for the dependency modules, even though the aggregated module's code is present.</p><p>Because Tapestry is open, it is possible to contribute modules even into the&#160;<strong>core</strong> JavaScript stack. &#160;This is done using your application's module:</p><div class="code panel pdl" style="border-width: 1px;"><div class="cod
 eContent panelContent pdl">
+</div></div><p>In the first example, <code>my-module</code> exports a single function of two parameters. In the second example, <code>my-module</code> exports an object and the <code>setup</code> key is the function that is invoked.</p><h2 id="JavaScriptModules-DevelopmentMode">Development Mode</h2><p>In development mode, Tapestry will write details into the client-side console.</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="javascript-modules.data/Tapestry_Integration_Test_Application_and_JavaScriptSupport__Tapestry_API_Documentation_.png" data-image-src="/confluence/download/attachments/41813130/Tapestry_Integration_Test_Application_and_JavaScriptSupport__Tapestry_API_Documentation_.png?version=1&amp;modificationDate=1401727827000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="42041399" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Tapestry_Integr
 ation_Test_Application_and_JavaScriptSupport__Tapestry_API_Documentation_.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="41813130" data-linked-resource-container-version="12"></span></p><p>This lists modules&#160;<em>explicitly</em> loaded (for initialization), but does not include modules loaded only as dependencies. You can see more details about what was actually loaded using&#160;<em>view source</em>; RequireJS adds <code>&lt;script&gt;</code> tags to the document to load libraries and modules.</p><h2 id="JavaScriptModules-LibrariesversusModules">Libraries versus Modules</h2><p>Tapestry still supports JavaScript libraries. &#160;When the page is loading, all libraries are loaded before any modules.</p><p>Libraries are loaded sequentially, so if you can avoid using libraries, so much the better in terms of page load time.</p><p>Libraries work in both normal page rendering, and Ajax partial 
 page updates. Even in partial page updates, the libraries will be loaded sequentially before modules are loaded or exported functions invoked.</p><h2 id="JavaScriptModules-AggregatingModules">Aggregating Modules</h2><p>An important part of performance for production applications is JavaScript aggregation.</p><p>In development mode, you want your modules and other assets to load individually. For both CSS and JavaScript, smaller files that align with corresponding server-side files makes it much easier to debug problems.</p><p>Unlike assets, modules can't be fingerprinted, so on each page load, the client browser must ask the server for the module's contents frequently (typically getting a 304 Not Modified response).</p><p><span>This is acceptable in development mode, but quite undesirable in production.</span></p><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></s
 pan><div class="confluence-information-macro-body"><p>By default, Tapestry sets a max age of 60 (seconds) on modules, so you won't see module requests on every page load. This is configurable and you may want a much higher value in production. If you are rapidly iterating on the source of a module, you may need to force the browser to reload after clearing local cache. Chrome has an option to disable the client-side cache when its developer tools are open.</p></div></div><p>With JavaScript aggregation, the module can be included in the single virtual JavaScript library that represents a <a shape="rect" class="external-link" href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/javascript/JavaScriptStack.html">JavaScript stack</a>. This significantly cuts down on both the number of requests from the client to the server, and the overall number of bytes transferred.</p><p>Adding a module to the stack is not the same as <code>require</code>-ing it. In fact, you mus
 t still use <code>JavaScriptSupport.require()</code> regardless.</p><p>What adding a module to a stack accomplishes is that the module's code is downloaded in the first, initial JavaScript download; the download of the stack's virtual library. When (and if) the module is required as a dependency, the code will already be present in the browser and ready to execute.</p><p>Tapestry&#160;<strong>does not</strong> attempt to do dependency analysis; that is left as a manual exercise. Typically, if you aggregate a module, your should look at its dependencies, and aggregate those as well. Failure to do so will cause unwanted requests back to the Tapestry server for the dependency modules, even though the aggregated module's code is present.</p><p>Because Tapestry is open, it is possible to contribute modules even into the&#160;<strong>core</strong> JavaScript stack. &#160;This is done using your application's module:</p><div class="code panel pdl" style="border-width: 1px;"><div class="cod
 eContent panelContent pdl">
 <script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    @Contribute(JavaScriptStack.class)
     @Core
     public static void addAppModules(OrderedConfiguration&lt;StackExtension&gt; configuration) {

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 Jul 15 09:20:19 2015
@@ -81,7 +81,7 @@ public class ActionFail {
     }
 }
 ]]></script>
-</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" data-image-src="/confluence/download/attachments/20645557/actionfail_-_top.png?version=1&amp;modificationDate=1428096039000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="55476331" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="actionfail_-_top.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="20645557" data-linked-resource-container-version="24"></span></p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-m
 anual-size"><img class="confluence-embedded-image confluence-content-image-border image-center" width="500" src="overriding-exception-reporting.data/Application_Exception.png" data-image-src="/confluence/download/attachments/20645557/Application_Exception.png?version=1&amp;modificationDate=1428096098000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="55476332" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Application_Exception.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="20645557" data-linked-resource-container-version="24"></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 shape="rect" class="external-link"
  href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/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">
+</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" data-image-src="/confluence/download/attachments/20645557/actionfail_-_top.png?version=1&amp;modificationDate=1428096039000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="55476331" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="actionfail_-_top.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="20645557" data-linked-resource-container-version="25"></span></p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-m
 anual-size"><img class="confluence-embedded-image confluence-content-image-border image-center" width="500" src="overriding-exception-reporting.data/Application_Exception.png" data-image-src="/confluence/download/attachments/20645557/Application_Exception.png?version=1&amp;modificationDate=1428096098000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="55476332" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Application_Exception.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="20645557" data-linked-resource-container-version="25"></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 shape="rect" class="external-link"
  href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/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">
 <script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[&lt;html t:type=&quot;layout&quot; title=&quot;Exception&quot;
       xmlns:t=&quot;http://tapestry.apache.org/schema/tapestry_5_4.xsd&quot;&gt;
 
@@ -120,7 +120,7 @@ public class ExceptionReport implements
     }
 }
 ]]></script>
-</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" data-image-src="/confluence/download/attachments/20645557/customer_exception_report_-_open_1.png?version=1&amp;modificationDate=1428096581000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="55476333" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="customer_exception_report_-_open_1.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="20645557" data-linked-resource-container-version="24"></span></p><h2 id="OverridingExceptionReporting-Version2:OverridingtheRequestExceptionH
 andler">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 shape="rect" 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><div class="code pan
 el 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">
+</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" data-image-src="/confluence/download/attachments/20645557/customer_exception_report_-_open_1.png?version=1&amp;modificationDate=1428096581000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="55476333" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="customer_exception_report_-_open_1.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="20645557" data-linked-resource-container-version="25"></span></p><h2 id="OverridingExceptionReporting-Version2:OverridingtheRequestExceptionH
 andler">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 shape="rect" 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><div class="code pan
 el 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">
 <script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[ &lt;t:if test=&quot;message&quot;&gt;
     &lt;div class=&quot;panel panel-danger&quot;&gt;
         &lt;div class=&quot;panel-heading&quot;&gt;An exception has occurred.&lt;/div&gt;
@@ -176,7 +176,7 @@ public class ExceptionReport implements
         configuration.add(RequestExceptionHandler.class, handler);
     }
 ]]></script>
-</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" data-image-src="/confluence/download/attachments/20645557/index_as_excepton_report.pn
 g?version=1&amp;modificationDate=1428096947000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="55476334" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="index_as_excepton_report.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="20645557" data-linked-resource-container-version="24"></span></p><h2 id="OverridingExceptionReporting-Version3:DecoratingtheRequestExceptionHandler">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 functio
 nality 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-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div class="codeContent panelContent pdl">
+</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" data-image-src="/confluence/download/attachments/20645557/index_as_excepton_report.pn
 g?version=1&amp;modificationDate=1428096947000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="55476334" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="index_as_excepton_report.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="20645557" data-linked-resource-container-version="25"></span></p><h2 id="OverridingExceptionReporting-Version3:DecoratingtheRequestExceptionHandler">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 functio
 nality 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-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div class="codeContent panelContent pdl">
 <script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    public RequestExceptionHandler decorateRequestExceptionHandler(
             final Logger logger,
             final ResponseRenderer renderer,

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 Jul 15 09:20:19 2015
@@ -98,13 +98,13 @@ public class DBImage
 
 
 
-<span class="gliffy-container" id="gliffy-container-23527573-8966" data-fullwidth="750" data-ceoid="23335008" data-edit="${diagramEditLink.getLinkUrl()}" data-full="/confluence/plugins/gliffy/viewer.action?inline=false&amp;pageId=23335008&amp;attachmentId=23527573&amp;name=Class%20Loaders&amp;lastPage=%2Fpages%2Fviewpage.action%3FpageId%3D23335008" data-pageid="23335008" data-filename="Class Loaders">
+<span class="gliffy-container" id="gliffy-container-23527573-7461" data-fullwidth="750" data-ceoid="23335008" data-edit="${diagramEditLink.getLinkUrl()}" data-full="/confluence/plugins/gliffy/viewer.action?inline=false&amp;pageId=23335008&amp;attachmentId=23527573&amp;name=Class%20Loaders&amp;lastPage=%2Fpages%2Fviewpage.action%3FpageId%3D23335008" data-pageid="23335008" data-filename="Class Loaders">
 
-    <map id="gliffy-map-23527573-501" name="gliffy-map-23527573-501"></map>
+    <map id="gliffy-map-23527573-1039" name="gliffy-map-23527573-1039"></map>
 
-    <img class="gliffy-image" id="gliffy-image-23527573-8966" 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-501">
+    <img class="gliffy-image" id="gliffy-image-23527573-7461" 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-1039">
 
-    <map class="gliffy-dynamic" id="gliffy-dynamic-map-23527573-8966" name="gliffy-dynamic-map-23527573-8966"></map>
+    <map class="gliffy-dynamic" id="gliffy-dynamic-map-23527573-7461" name="gliffy-dynamic-map-23527573-7461"></map>
 </span>
 
 
@@ -123,7 +123,7 @@ table.ScrollbarTable td.ScrollbarParent
 table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
 table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}
 
-/*]]>*/</style><div class="Scrollbar"><table class="ScrollbarTable"><tr><td colspan="1" rowspan="1" class="ScrollbarPrevIcon"><a shape="rect" href="templating-and-markup-faq.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/back_16.gif" width="16" height="16"></a></td><td colspan="1" rowspan="1" class="ScrollbarPrevName" width="33%"><a shape="rect" href="templating-and-markup-faq.html">Templating and Markup FAQ</a>&#160;</td><td colspan="1" rowspan="1" class="ScrollbarParent" width="33%"><sup><a shape="rect" href="frequently-asked-questions.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/up_16.gif" width="8" height="8"></a></sup><a shape="rect" href="frequently-asked-questions.html">Frequently Asked Questions</a></td><td colspan="1" rowspan="1" class="ScrollbarNextName" width="33%">&#160;<a shape="rect" href="forms-and-form-components-faq.html">Forms and Form Components FAQ</a></td><td colspan="1" ro
 wspan="1" class="ScrollbarNextIcon"><a shape="rect" href="forms-and-form-components-faq.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/forwd_16.gif" width="16" height="16"></a></td></tr></table></div><p>____</p><p>&#160;</p><p>&#160;</p><p></p><p></p><p></p><p></p><p></p><p></p><p><table class="Footnotes" style="width: 100%; border:none;" cellspacing="0" cellpadding="0" summary="This table contains one or more notes for references made elsewhere on the page."><caption class="accessibility">Footnotes</caption><thead class="accessibility"><tr class="accessibility"><th colspan="1" rowspan="1" class="accessibility" id="footnote-th1">Reference</th><th colspan="1" rowspan="1" class="accessibility" id="footnote-th2">Notes</th></tr></thead><tbody></tbody></table></p><p></p><p></p><p></p><p></p><p></p><p></p><p>&#160;</p><p>&#160;</p></div>
+/*]]>*/</style><div class="Scrollbar"><table class="ScrollbarTable"><tr><td colspan="1" rowspan="1" class="ScrollbarPrevIcon"><a shape="rect" href="templating-and-markup-faq.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/back_16.gif" width="16" height="16"></a></td><td colspan="1" rowspan="1" class="ScrollbarPrevName" width="33%"><a shape="rect" href="templating-and-markup-faq.html">Templating and Markup FAQ</a>&#160;</td><td colspan="1" rowspan="1" class="ScrollbarParent" width="33%"><sup><a shape="rect" href="frequently-asked-questions.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/up_16.gif" width="8" height="8"></a></sup><a shape="rect" href="frequently-asked-questions.html">Frequently Asked Questions</a></td><td colspan="1" rowspan="1" class="ScrollbarNextName" width="33%">&#160;<a shape="rect" href="forms-and-form-components-faq.html">Forms and Form Components FAQ</a></td><td colspan="1" ro
 wspan="1" class="ScrollbarNextIcon"><a shape="rect" href="forms-and-form-components-faq.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/forwd_16.gif" width="16" height="16"></a></td></tr></table></div><p>____</p><p>&#160;</p><p>&#160;</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><table class="Footnotes" style="width: 100%; border:none;" cellspacing="0" cellpadding="0" summary="This table contains one or more notes for references made elsewhere on the page."><caption class="accessibility">Footnotes</caption><thead class="accessibility"><tr class="accessibility"><th colspan="1" rowspan="1" class="accessibility" id="footnote-th1">Reference</th><th colspan="1" rowspan="1" class="accessibility" id="footnote-th2">Notes</th></tr></thead><tbody></tbody></table></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/pipelinebuilder-service.html
==============================================================================
--- websites/production/tapestry/content/pipelinebuilder-service.html (original)
+++ websites/production/tapestry/content/pipelinebuilder-service.html Wed Jul 15 09:20:19 2015
@@ -121,7 +121,7 @@ public class UpcasePostFilter implements
 
 <p>What the builder accomplishes is to represent each <em>filter</em> in the pipeline as an instance of the <em>service</em> interface.</p>
 
-<p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="pipelinebuilder-service.data/PipelineCallingSequence.png" data-image-src="/confluence/download/attachments/23338488/PipelineCallingSequence.png?version=1&amp;modificationDate=1293052796000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24347111" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="PipelineCallingSequence.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23338488" data-linked-resource-container-version="21"></span><br clear="none">
+<p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="pipelinebuilder-service.data/PipelineCallingSequence.png" data-image-src="/confluence/download/attachments/23338488/PipelineCallingSequence.png?version=1&amp;modificationDate=1293052796000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24347111" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="PipelineCallingSequence.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23338488" data-linked-resource-container-version="22"></span><br clear="none">
 Pipeline Calling Sequence</p>
 
 <p>The bridges are created by the PipelineBuilder service. The terminator must be provided. The bridges and the terminator implement the service interface.</p>