Author: buildbot
Date: Sat Feb  3 22:21:02 2018
New Revision: 1024796

Log:
Production update by buildbot for tapestry

Modified:
    websites/production/tapestry/content/cache/main.pageCache
    websites/production/tapestry/content/creating-the-skeleton-application.html
    websites/production/tapestry/content/exploring-the-project.html
    
websites/production/tapestry/content/implementing-the-hi-lo-guessing-game.html
    
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html
    websites/production/tapestry/content/using-tapestry-with-hibernate.html

Modified: websites/production/tapestry/content/cache/main.pageCache
==============================================================================
Binary files - no diff available.

Modified: 
websites/production/tapestry/content/creating-the-skeleton-application.html
==============================================================================
--- websites/production/tapestry/content/creating-the-skeleton-application.html 
(original)
+++ websites/production/tapestry/content/creating-the-skeleton-application.html 
Sat Feb  3 22:21:02 2018
@@ -91,10 +91,10 @@
   
<localRepository>C:/Users/joeuser/.m2/repository</localRepository>
 </settings>
 </pre>
-</div></div><p>Of course, adjust the <code>localRepository</code> element to 
match the correct path for your computer.</p><h3 
id="CreatingTheSkeletonApplication-CreateProject">Create Project</h3><p>Okay, 
let's get started creating our new project.</p><p>In Eclipse, go to 
<strong>File &gt; New &gt;</strong> <strong>Project... &gt; Maven &gt; Maven 
Project</strong></p><p><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/select-a-wizard.png?version=1&amp;modificationDate=1416675284000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/select-a-wizard.png?version=1&amp;modificationDate=1416675284000&amp;api=v2";></span></p><p>Then
 click <strong>Next</strong>, <strong>Next</strong> (again), and then on the 
<strong>Select an Archetype</strong> page click the <strong>Configure</strong> 
button on the Catal
 og line. The <strong>Archetype</strong> preferences dialog should appear. 
Click the <strong>Add Remote Catalog...</strong> button, as shown 
below:</p><p><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/add-archetype-catalog.png?version=1&amp;modificationDate=1416675354000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/add-archetype-catalog.png?version=1&amp;modificationDate=1416675354000&amp;api=v2";></span></p><p>As
 shown above, enter <span class="nolink"><span class="nolink">"<span 
class="nolink">http://tapestry.apache.org</span>"</span></span> in the Catalog 
File field, and "Apache Tapestry" in the Description field.</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>If you want to try an 
unreleased (alpha or beta) version of Tapestry, use <span class="nolink">the 
<strong><a  class="external-link" 
href="https://repository.apache.org/content/repositories/staging";>https://repository.apache.org/content/repositories/staging</a></strong></span>
 archetype catalog file instead.</p></div></div><p>Click <strong>OK</strong>, 
then<strong> OK</strong> again.</p><p>On the Select an Archetype dialog (shown 
below), select the newly-added Apache Tapestry catalog, then select the 
"quickstart" artifact from the list and click 
<strong>Next</strong>.</p><p><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/select-archetype.png?version=1&amp;modificationDate=1416675447000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/sel
 
ect-archetype.png?version=1&amp;modificationDate=1416675447000&amp;api=v2"></span></p><p><em><strong>Note:</strong>
 Screenshots in this tutorial may show different (either newer or older) 
versions of Tapestry than you may see.</em></p><p>Fill in the Group Id, 
Artifact Id, Version and Package&#160; as follows:</p><p><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/specify-archetype-parameters.png?version=1&amp;modificationDate=1416675494000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/specify-archetype-parameters.png?version=1&amp;modificationDate=1416675494000&amp;api=v2";></span></p><p>then
 click Finish.</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 c
 lass="confluence-information-macro-body"><p>The first time you use Maven, 
project creation may take a while as Maven downloads a large number of JAR 
dependencies for Maven, Jetty and Tapestry. These downloaded files are cached 
locally and will not need to be downloaded again, but you do have to be patient 
on first use.</p></div></div><p>After Maven finishes, you'll see a new 
directory, <code>tutorial1, in your Package Explorer view in 
Eclipse.</code></p><h2 
id="CreatingTheSkeletonApplication-RunningtheApplicationusingJetty">Running the 
Application using Jetty</h2><p>One of the first things you can do is use Maven 
to run Jetty directly.</p><p>Right-click on the <code>tutorial1</code> project 
in your Package Explorer view and select <strong>Run As &gt; Maven Build... 
&gt;</strong>, enter a Goal of <strong>"jetty:run"</strong>. This creates a 
"Run Configuration" named "tutorial1" that we'll use throughout this tutorial 
to start the app:</p><p><span class="confluence-embedded-file-wrapp
 er"><img class="confluence-embedded-image confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/run-configuration.png?version=2&amp;modificationDate=1416744425000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/run-configuration.png?version=2&amp;modificationDate=1416744425000&amp;api=v2";></span></p><p>Tapestry
 runs best with a couple of additional options; click the "JRE" tab and enter 
the following VM 
Arguments:</p><pre></pre><p>-XX:MaxPermSize=256M</p><p>-Xmx600m</p><p>-Dtapestry.execution-mode=development</p>
+</div></div><p>Of course, adjust the <code>localRepository</code> element to 
match the correct path for your computer.</p><h3 
id="CreatingTheSkeletonApplication-CreateProject">Create Project</h3><p>Okay, 
let's get started creating our new project.</p><p>In Eclipse, go to 
<strong>File &gt; New &gt;</strong> <strong>Project... &gt; Maven &gt; Maven 
Project</strong></p><p><strong><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="613" 
src="creating-the-skeleton-application.data/select-a-wizard.png"></span><br 
clear="none"></strong></p><p>Then click <strong>Next</strong>, 
<strong>Next</strong> (again), and then on the <strong>Select an 
Archetype</strong> page click the <strong>Configure</strong> button on the 
Catalog line. The <strong>Archetype</strong> preferences dialog should appear. 
Click the <strong>Add Remote Catalog...</strong> button, as shown 
below:</p><p><span class="confluence-embedded-file-wrapper conf
 luence-embedded-manual-size"><img class="confluence-embedded-image" 
width="900" 
src="creating-the-skeleton-application.data/add-archetype-catalog.png"></span></p><p>As
 shown above, enter <span class="nolink"><span class="nolink">"<span 
class="nolink">http://tapestry.apache.org</span>"</span></span> in the Catalog 
File field, and "Apache Tapestry" in the Description field.</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>If you want to try an unreleased 
(alpha or beta) version of Tapestry, use <span class="nolink">the <strong><a  
class="external-link" 
href="https://repository.apache.org/content/repositories/staging";>https://repository.apache.org/content/repositories/staging</a></strong></span>
 archetype catalog file instead.</p></div></div><p>Click <strong>OK</strong>, 
then<strong> OK</strong> again.</p
 ><p>On the Select an Archetype dialog (shown below), select the newly-added 
 >Apache Tapestry catalog, then select the "quickstart" artifact from the list 
 >and click <strong>Next</strong>.</p><p><span 
 >class="confluence-embedded-file-wrapper confluence-embedded-manual-size"><img 
 >class="confluence-embedded-image" width="804" 
 >src="creating-the-skeleton-application.data/select-archetype.png"></span></p><p>&#160;</p><p><em><strong>Note:</strong>
 > Screenshots in this tutorial may show different (either newer or older) 
 >versions of Tapestry than you may see.</em></p><p>Fill in the Group Id, 
 >Artifact Id, Version and Package&#160; as follows:</p><p><span 
 >class="confluence-embedded-file-wrapper confluence-embedded-manual-size"><img 
 >class="confluence-embedded-image" width="530" 
 >src="creating-the-skeleton-application.data/specify-archetype-parameters.png"></span></p><p>then
 > click Finish.</p><div class="confluence-information-macro 
 >confluence-information-macro-information"><span class="aui-icon aui-i
 con-small aui-iconfont-info confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body"><p>The first time you use Maven, 
project creation may take a while as Maven downloads a large number of JAR 
dependencies for Maven, Jetty and Tapestry. These downloaded files are cached 
locally and will not need to be downloaded again, but you do have to be patient 
on first use.</p></div></div><p>After Maven finishes, you'll see a new 
directory, <code>tutorial1, in your Package Explorer view in 
Eclipse.</code></p><h2 
id="CreatingTheSkeletonApplication-RunningtheApplicationusingJetty">Running the 
Application using Jetty</h2><p>One of the first things you can do is use Maven 
to run Jetty directly.</p><p>Right-click on the <code>tutorial1</code> project 
in your Package Explorer view and select <strong>Run As &gt; Maven Build... 
&gt;</strong>, enter a Goal of <strong>"jetty:run"</strong>. This creates a 
"Run Configuration" named "tutorial1" that we'll use throughout this 
 tutorial to start the app:</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="568" 
src="creating-the-skeleton-application.data/run-configuration.png"></span></p><p>Tapestry
 runs best with a couple of additional options; click the "JRE" tab and enter 
the following VM 
Arguments:</p><pre></pre><p>-XX:MaxPermSize=256M</p><p>-Xmx600m</p><p>-Dtapestry.execution-mode=development</p>
 
 
-<p><code><em>(If you're using JDK 1.8 then you should omit the MaxPermSize 
argument.)</em></code></p><p><code>Here's how it looks:<br 
clear="none"></code></p><p><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/run-configuration-jre.png?version=2&amp;modificationDate=1416744425000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/run-configuration-jre.png?version=2&amp;modificationDate=1416744425000&amp;api=v2";></span></p><p>Finally,
 click <strong>Run</strong>.</p><p>Again, the first time, there's a dizzying 
number of downloads, but before you know it, the Jetty servlet container is up 
and running.</p><p>Once Jetty is initialized (which only takes a few seconds 
after the first time), you'll see the following in your console:</p><p><span 
class="confluence-embedded-file-wrapper"><img class="conflue
 nce-embedded-image confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/console-startup.png?version=2&amp;modificationDate=1416797756000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/console-startup.png?version=2&amp;modificationDate=1416797756000&amp;api=v2";></span></p><p><em>Note
 the red square icon above. Later on you'll use that icon to stop Jetty before 
restarting the app.</em></p><p>You can now open a web browser to <a  
class="external-link" href="http://localhost:8080/tutorial1/"; 
rel="nofollow">http://localhost:8080/tutorial1/</a> to see the running 
application:</p><p>&#160;</p><p><span class="confluence-embedded-file-wrapper 
image-left-wrapper"><img class="confluence-embedded-image 
confluence-external-resource confluence-content-image-border image-left" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/startpage.png?version=7&amp;modificationDat
 e=1416798158000&amp;api=v2" 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340356/startpage.png?version=7&amp;modificationDate=1416798158000&amp;api=v2";></span></p><p>&#160;</p><div
 style="clear: both"></div><p style="text-align: left;"><strong><em>NOTE: Your 
screen may look very different depending on the version of Tapestry you are 
using!</em></strong></p><p style="text-align: left;">The date and time in the 
middle of the page shows that this is a live application.</p><p>This is a 
complete little web app; it doesn't do much, but it demonstrate how to create a 
number of pages sharing a common layout, and demonstrates some simple 
navigation and link handling. You can see that it has several different pages 
that share a common layout. (<span><em>Layout</em> is a loose term meaning 
common look and feel and navigation across many or all of the pages of an 
application. Often an application will include a Layout component to provide 
that commonness.)</spa
 n></p><p><span>Next: <a  
href="creating-the-skeleton-application.html">Creating The Skeleton 
Application</a></span></p><p><span><br clear="none"></span></p></div>
+<p><code><em>(If you're using JDK 1.8 then you should omit the MaxPermSize 
argument.)</em></code></p><p><code>Here's how it 
looks:</code></p><p><code><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="666" 
src="creating-the-skeleton-application.data/run-configuration-jre.png"></span><br
 clear="none"></code></p><p>Finally, click <strong>Run</strong>.</p><p>Again, 
the first time, there's a dizzying number of downloads, but before you know it, 
the Jetty servlet container is up and running.</p><p>Once Jetty is initialized 
(which only takes a few seconds after the first time), you'll see the following 
in your console:</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="865" 
src="creating-the-skeleton-application.data/console-startup.png"></span></p><p><em>Note
 the red square icon above. Later on you'll use that icon to stop Jetty before 
 restarting the app.</em></p><p>You can now open a web browser to <a  
class="external-link" href="http://localhost:8080/tutorial1/"; 
rel="nofollow">http://localhost:8080/tutorial1/</a> to see the running 
application:</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="785" 
src="creating-the-skeleton-application.data/startpage.png"></span></p><p>&#160;</p><div
 style="clear: both"></div><p style="text-align: left;"><strong><em>NOTE: Your 
screen may look very different depending on the version of Tapestry you are 
using!</em></strong></p><p style="text-align: left;">The date and time in the 
middle of the page shows that this is a live application.</p><p>This is a 
complete little web app; it doesn't do much, but it demonstrate how to create a 
number of pages sharing a common layout, and demonstrates some simple 
navigation and link handling. You can see that it has several different pages 
that share a common layo
 ut. (<span><em>Layout</em> is a loose term meaning common look and feel and 
navigation across many or all of the pages of an application. Often an 
application will include a Layout component to provide that 
commonness.)</span></p><p><span>Next: <a  
href="creating-the-skeleton-application.html">Creating The Skeleton 
Application</a></span></p><p><span><br clear="none"></span></p></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/exploring-the-project.html
==============================================================================
--- websites/production/tapestry/content/exploring-the-project.html (original)
+++ websites/production/tapestry/content/exploring-the-project.html Sat Feb  3 
22:21:02 2018
@@ -262,13 +262,13 @@ public class Index
 
 
 
-<span class="gliffy-container" id="gliffy-container-24346949-9257" 
data-fullwidth="913" data-ceoid="24188263" 
data-edit="${diagramEditLink.getLinkUrl()}" 
data-full="${diagramZoomLink.getLinkUrl()}" data-filename="Templates and 
Parameters">
+<span class="gliffy-container" id="gliffy-container-24346949-8526" 
data-fullwidth="913" data-ceoid="24188263" 
data-edit="${diagramEditLink.getLinkUrl()}" 
data-full="${diagramZoomLink.getLinkUrl()}" data-filename="Templates and 
Parameters">
 
-    <map id="gliffy-map-24346949-7684" name="gliffy-map-24346949-7684"></map>
+    <map id="gliffy-map-24346949-7884" name="gliffy-map-24346949-7884"></map>
 
-    <img class="gliffy-image gliffy-image-border" 
id="gliffy-image-24346949-9257" width="304" height="300" data-full-width="913" 
data-full-height="901" 
src="https://cwiki.apache.org/confluence/download/attachments/24188263/Templates%20and%20Parameters.png?version=2&amp;modificationDate=1371888025000&amp;api=v2";
 alt="Templates and Parameters" usemap="#gliffy-map-24346949-7684">
+    <img class="gliffy-image gliffy-image-border" 
id="gliffy-image-24346949-8526" width="304" height="300" data-full-width="913" 
data-full-height="901" 
src="https://cwiki.apache.org/confluence/download/attachments/24188263/Templates%20and%20Parameters.png?version=2&amp;modificationDate=1371888025000&amp;api=v2";
 alt="Templates and Parameters" usemap="#gliffy-map-24346949-7884">
 
-    <map class="gliffy-dynamic" id="gliffy-dynamic-map-24346949-9257" 
name="gliffy-dynamic-map-24346949-9257"></map>
+    <map class="gliffy-dynamic" id="gliffy-dynamic-map-24346949-8526" 
name="gliffy-dynamic-map-24346949-8526"></map>
 </span>
 
 
@@ -281,9 +281,9 @@ public class Index
     return "A great day to learn Tapestry";
   }
 </pre>
-</div></div><p>Make sure you save changes; then click the refresh link in the 
web browser:</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image 
confluence-external-resource" width="700" 
src="https://cwiki-test.apache.org/confluence/download/attachments/24188263/app-live-reload.png?version=5&amp;modificationDate=1416707986000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/24188263/app-live-reload.png?version=5&amp;modificationDate=1416707986000&amp;api=v2";></span></p><div
 class="navmenu" style="float:right; width:30%; background:white; margin:3px; 
padding:3px">
+</div></div><p>Make sure you save changes; then click the refresh link in the 
web browser:</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="700" 
src="exploring-the-project.data/app-live-reload.png"></span></p><p>&#160;</p><div
 class="navmenu" style="float:right; width:30%; background:white; margin:3px; 
padding:3px">
 <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>If Live Class Reloading isn't working for you, check the Troubleshooting 
section at <a  href="class-reloading.html" title="Class Reloading">Class 
Reloading</a>.</p></div></div></div>This is one of Tapestry's early <em>wow 
factor</em> features: changes to your component classes are picked up 
immediately (a feature we call Live Class Reloading). No restart. No re-deploy. 
Make the changes and see them <em>now</em>. Nothing should slow you down or get 
in the way of you getting your job done.<p>But ... what if you make a mistake? 
What if you got the name in the template wrong. Give it a try; in the template, 
change ${currentTime} to, say, ${currenTime}, and see what you get:</p><p><span 
class="confluence-embedded-file-wrapper confluence-embedded-manual-size"><img 
class="confluence-embedded-image confluence-external-resource" width="700" 
src="https://cwiki-test.apache.org/confluence/download/attachments/24188263/app-error-1.png?version=3&amp;modificationDate=1416707595000&amp;api=v2";
 d
 
ata-image-src="https://cwiki-test.apache.org/confluence/download/attachments/24188263/app-error-1.png?version=3&amp;modificationDate=1416707595000&amp;api=v2";></span></p><p>This
 is Tapestry's exception report page. It's quite detailed. It clearly 
identifies what Tapestry was doing, and relates the problem to a specific line 
in the template, which is shown in context. Tapestry always expands out the 
entire stack of exceptions, because it is so common for exceptions to be 
thrown, caught, and re-thrown inside other exceptions. In fact, if we scroll 
down just a little bit, we see more detail about this exception, plus a little 
bit of help:</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image 
confluence-external-resource" width="700" 
src="https://cwiki-test.apache.org/confluence/download/attachments/24188263/app-error-2.png?version=4&amp;modificationDate=1416707595000&amp;api=v2";
 data-image-src="https://cwiki-test.apac
 
he.org/confluence/download/attachments/24188263/app-error-2.png?version=4&amp;modificationDate=1416707595000&amp;api=v2"></span></p><p>This
 is part of Tapestry's way: it not only spells out exactly what it was doing 
and what went wrong, but it even helps you find a solution; here it tells you 
the names of properties you could have 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>This level of detail reflects that 
the application has been configured to run in <em>development mode</em> instead 
of <em>production mode</em>. In production mode, the exception report would 
simply be the top level exception message. However, most production 
applications go further and customize how Tapestry handles and reports 
exceptions.</p></div></div><p>Tapestry displays the stack trace of the deepest 
exception, along
  with lots of details about the run-time environment: details about the 
current request, the HttpSession (if one exists), and even a detailed list of 
all JVM system properties. Scroll down to see all this information.</p><p>Next: 
<a  href="exploring-the-project.html">Exploring the 
Project</a></p><p>&#160;</p><p></p></div>
+<p>If Live Class Reloading isn't working for you, check the Troubleshooting 
section at <a  href="class-reloading.html" title="Class Reloading">Class 
Reloading</a>.</p></div></div></div>This is one of Tapestry's early <em>wow 
factor</em> features: changes to your component classes are picked up 
immediately (a feature we call Live Class Reloading). No restart. No re-deploy. 
Make the changes and see them <em>now</em>. Nothing should slow you down or get 
in the way of you getting your job done.<p>But ... what if you make a mistake? 
What if you got the name in the template wrong. Give it a try; in the template, 
change ${currentTime} to, say, ${currenTime}, and see what you get:</p><p><span 
class="confluence-embedded-file-wrapper confluence-embedded-manual-size"><img 
class="confluence-embedded-image" width="700" 
src="exploring-the-project.data/app-error-1.png"></span></p><p>This is 
Tapestry's exception report page. It's quite detailed. It clearly identifies 
what Tapestry was doing, and re
 lates the problem to a specific line in the template, which is shown in 
context. Tapestry always expands out the entire stack of exceptions, because it 
is so common for exceptions to be thrown, caught, and re-thrown inside other 
exceptions. In fact, if we scroll down just a little bit, we see more detail 
about this exception, plus a little bit of help:</p><p><span 
class="confluence-embedded-file-wrapper confluence-embedded-manual-size"><img 
class="confluence-embedded-image" width="700" 
src="exploring-the-project.data/app-error-2.png"></span></p><p>&#160;</p><p>This
 is part of Tapestry's way: it not only spells out exactly what it was doing 
and what went wrong, but it even helps you find a solution; here it tells you 
the names of properties you could have 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-bo
 dy"><p>This level of detail reflects that the application has been configured 
to run in <em>development mode</em> instead of <em>production mode</em>. In 
production mode, the exception report would simply be the top level exception 
message. However, most production applications go further and customize how 
Tapestry handles and reports exceptions.</p></div></div><p>Tapestry displays 
the stack trace of the deepest exception, along with lots of details about the 
run-time environment: details about the current request, the HttpSession (if 
one exists), and even a detailed list of all JVM system properties. Scroll down 
to see all this information.</p><p>Next: <a  
href="implementing-the-hi-lo-guessing-game.html">Implementing the Hi-Lo 
Guessing Game</a></p><p>&#160;</p><p></p></div>
       </div>
 
       <div class="clearer"></div>

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 
Sat Feb  3 22:21:02 2018
@@ -76,7 +76,7 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p><span><br 
clear="none"></span></p><p><span>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 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/hilo
 -flow.png?version=2&amp;modificationDate=1286814202000&amp;api=v2" 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/hilo-flow.png?version=2&amp;modificationDate=1286814202000&amp;api=v2";></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">
+                <div id="ConfluenceContent"><p><span><br 
clear="none"></span></p><p><span>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 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" 
src="implementing-the-hi-lo-guessing-game.data/hilo-flow.png"></span></p><p>Our 
page flow is very simple, con
 sisting 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">
 <pre class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">&lt;html t:type="layout" title="Hi/Lo Guess"
     xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"&gt;
 
@@ -96,12 +96,12 @@ public class Index
 {
 }
 </pre>
-</div></div><p>Running the application gives us our start:</p><p><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/hilo-1.png?version=3&amp;modificationDate=1416879474000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/hilo-1.png?version=3&amp;modificationDate=1416879474000&amp;api=v2";></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 applica
 tion 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"></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 t
 he 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">
 <pre class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">    &lt;p&gt;
         &lt;t:actionlink t:id="start"&gt;start guessing&lt;/t:actionlink&gt;
     &lt;/p&gt;
 </pre>
-</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 
confluence-external-resource image-center" width="500" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/Application_Exception.png?version=1&amp;modificationDate=1428077959000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/Application_Exception.png?version=1&amp;modificationDate=1428077959000&amp;api=v2";></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  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  
href="implementing-the-hi-lo-guessing-game.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 co
 mponent'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 confluence-embedded-manual-size"><img 
class="confluence-embedded-image" width="500" 
src="implementing-the-hi-lo-guessing-game.data/hilo-index-missing-action-error.png"></span></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  
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  
href="implementing-the-hi-lo-guessing-game.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 panelHea
 der 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.tutorial1.pages;
 
 public class Index
@@ -167,7 +167,7 @@ public class Index
     }
 }
 </pre>
-</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 
confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/guess-template-missing.png?version=2&amp;modificationDate=1416710821000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/guess-tem
 
plate-missing.png?version=2&amp;modificationDate=1416710821000&amp;api=v2"></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 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="900" 
src="implementing-the-hi-lo-guessing-game.data/guess-template-missing.png"></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="bo
 rder-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">
 <pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">&lt;html t:type="layout" title="Guess The Number"
     xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"&gt;
 
@@ -177,16 +177,16 @@ public class Index
   
 &lt;/html&gt;
 </pre>
-</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 
confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/guess-no-target-prop.png?version=2&amp;modificationDate=1416711075000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/guess-no-target-prop.png?version=2&amp;modificationDate=1416711075000&amp;api=v2";></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="cod
 e 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 confluence-embedded-manual-size"><img 
class="confluence-embedded-image" width="900" 
src="implementing-the-hi-lo-guessing-game.data/guess-no-target-prop.png"></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">
 <pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">    @Property
     private int target;
 </pre>
-</div></div><p>The @<a  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 
confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/guess-target-zero.png?version=3&amp;modificationDate=1416879255000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/guess-target-zero.png?version=3&amp;modificationDate=1416879255000&amp;api=v2";></span></p><p>What
 gives? We know it was set to at least 1 ... where did the value go?</p><p>As no
 ted 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  
class="external-link" 
href="http://tapestry.apache.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  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"></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 tar
 get <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  class="external-link" 
href="http://tapestry.apache.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">
 <pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">    @Property  
     @Persist
     private int target;
 </pre>
-</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 
confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/guess-target.png?version=3&amp;modificationDate=1416879254000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/guess-target.png?version=3&amp;modificationDate=1416879254000&amp;api=v2";></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"></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">
 <pre class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">&lt;html t:type="layout" title="Guess The Number"
     xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd";
     xmlns:p="tapestry:parameter"&gt;
@@ -238,7 +238,7 @@ public class Guess
 
 }
 </pre>
-</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 
confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/guess-1.png?version=4&amp;modificationDate=1416879255000&amp;api=v2";
 data-image-src="https://cwiki-test.apache.org/confluence/
 
download/attachments/23340505/guess-1.png?version=4&amp;modificationDate=1416879255000&amp;api=v2"></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 panelContent 
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"></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 panelContent 
pdl">
 <pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">    @Property
     @Persist(PersistenceConstants.FLASH)
     private String message;
@@ -306,7 +306,7 @@ public class GameOver
   
 &lt;/html&gt;
 </pre>
-</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 confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/gameover.png?version=4&amp;modificationDate=1416879255000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340505/gameover.png?version=4&amp;modificationDate=1416879255000&amp;api=v2";></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: let's find out how 
Tapestry handles HTML forms and user input.</p><p>Next: <a  
href="implementing-the-hi-lo-guessing-game.html">Implementing the Hi-Lo 
Guessing Game</a></p><p></p><p>&#160;</p><p>&#160;</p></div>
+</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"></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: let's 
find out how Tapestry handles HTML forms and user input.</p><p>Next: <a  
href="using-beaneditform-to-create-user-forms.html">Using BeanEditForm To 
Create User Forms</a></p><p></p><p>&#160;</p><p>&#160;</p></div>
       </div>
 
       <div class="clearer"></div>

Modified: 
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html
==============================================================================
--- 
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html
 (original)
+++ 
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html
 Sat Feb  3 22:21:02 2018
@@ -152,17 +152,17 @@ address/CreateAddress: com.example.tutor
 </div></div><p>When you refresh the page, you may see a warning like the 
following at the top of the page:</p><p><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/hmac-warning.png?version=2&amp;modificationDate=1416883285000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/hmac-warning.png?version=2&amp;modificationDate=1416883285000&amp;api=v2";></span></p><p>If
 you see that, it means you need to invent an HMAC passphrase for your app. 
Just edit your AppModule.java class (in your services package), adding a couple 
of lines to the contributeApplicationDefaults method like the 
following:</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeContent panelContent pdl">
 <pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">        // Set the HMAC pass phrase to secure object 
data serialized to client
         configuration.add(SymbolConstants.HMAC_PASSPHRASE, "");</pre>
-</div></div><p>but, instead of an empty string, insert a long, <strong>random 
string of characters</strong> (like a very long and complex password, at least 
30 characters) that you keep private.</p><p>After you do that, stop the app and 
restart it, and click on the Create new address link again, and you'll see 
something like this:</p><p><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/create-address-initial.png?version=2&amp;modificationDate=1416884366000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/create-address-initial.png?version=2&amp;modificationDate=1416884366000&amp;api=v2";></span></p><p>Tapestry
 has done quite a bit of work here. It has created a form that includes a field 
for each property. Further, it has seen that the honorific property is an 
enumerated type, and presented that 
 as a drop-down list.</p><p>In addition, Tapestry has converted the property 
names ("city", "email", "firstName") to user presentable labels ("City", 
"Email", "First Name"). In fact, these are &lt;label&gt; elements, so clicking 
a label with the mouse will move the input cursor into the corresponding 
field.</p><p>This is an awesome start; it's a presentable interface, quite nice 
in fact for a few minute's work. But it's far from perfect; let's get started 
with some customizations.</p><h1 
id="UsingBeanEditFormToCreateUserForms-ChangingFieldOrder">Changing Field 
Order</h1><p>The BeanEditForm must guess at the right order to present the 
fields; for public fields, they end up in alphabetical order. For standard 
JavaBeans properties, the BeanEditForm default is in the order in which the 
getter methods are defined in the class (it uses line number information, if 
available).</p><p>A better order for these fields is the order in which they 
are defined in the Address class:</p><ul><li>honori
 
fic</li><li>firstName</li><li>lastName</li><li>street1</li><li>street2</li><li>city</li><li>state</li><li>zip</li><li>email</li><li>phone</li></ul><p>We
 can accomplish this by using the <code>reorder</code> parameter of the 
BeanEditForm component, which is a comma separated list of property (or public 
field) names:</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>CreateAddress.tml (partial)</b></div><div class="codeContent 
panelContent pdl">
+</div></div><p>but, instead of an empty string, insert a long, <strong>random 
string of characters</strong> (like a very long and complex password, at least 
30 characters) that you keep private.</p><p>After you do that, stop the app and 
restart it, and click on the Create new address link again, and you'll see 
something like this:</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="485" 
src="using-beaneditform-to-create-user-forms.data/create-address-initial.png"></span></p><p>Tapestry
 has done quite a bit of work here. It has created a form that includes a field 
for each property. Further, it has seen that the honorific property is an 
enumerated type, and presented that as a drop-down list.</p><p>In addition, 
Tapestry has converted the property names ("city", "email", "firstName") to 
user presentable labels ("City", "Email", "First Name"). In fact, these are 
&lt;label&gt; elements, so clicking a label wi
 th the mouse will move the input cursor into the corresponding 
field.</p><p>This is an awesome start; it's a presentable interface, quite nice 
in fact for a few minute's work. But it's far from perfect; let's get started 
with some customizations.</p><h1 
id="UsingBeanEditFormToCreateUserForms-ChangingFieldOrder">Changing Field 
Order</h1><p>The BeanEditForm must guess at the right order to present the 
fields; for public fields, they end up in alphabetical order. For standard 
JavaBeans properties, the BeanEditForm default is in the order in which the 
getter methods are defined in the class (it uses line number information, if 
available).</p><p>A better order for these fields is the order in which they 
are defined in the Address 
class:</p><ul><li>honorific</li><li>firstName</li><li>lastName</li><li>street1</li><li>street2</li><li>city</li><li>state</li><li>zip</li><li>email</li><li>phone</li></ul><p>We
 can accomplish this by using the <code>reorder</code> parameter of the 
BeanEditForm c
 omponent, which is a comma separated list of property (or public field) 
names:</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>CreateAddress.tml (partial)</b></div><div class="codeContent 
panelContent pdl">
 <pre class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">    &lt;t:beaneditform object="address"
         
reorder="honorific,firstName,lastName,street1,street2,city,state,zip,email,phone"
 /&gt;
 </pre>
-</div></div><p><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/create-address-reordered.png?version=2&amp;modificationDate=1416884592000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/create-address-reordered.png?version=2&amp;modificationDate=1416884592000&amp;api=v2";></span></p><h3
 id="UsingBeanEditFormToCreateUserForms-Customizinglabels">Customizing 
labels</h3><p>Tapestry makes it pretty easy to customize the labels used on the 
fields. It's just a matter of creating a <em>message catalog</em> for the 
page.</p><p>In Tapestry, every page and component may have its own message 
catalog. This is a standard Java properties file, and it is named the same as 
the page or component class, with a ".properties" extension. A message catalog 
consists of a series of lines, each line is a message key and
  a message value separated with an equals sign.</p><p>All it takes is to 
create a message entry with a particular name: the name of the property 
suffixed with "-label". As elsewhere, Tapestry is forgiving of case.</p><div 
class="preformatted panel" style="border-width: 1px;"><div 
class="preformattedHeader panelHeader" style="border-bottom-width: 
1px;"><b>src/main/resources/com/example/tutorial/pages/address/CreateAddress.properties</b></div><div
 class="preformattedContent panelContent">
+</div></div><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="492" 
src="using-beaneditform-to-create-user-forms.data/create-address-reordered.png"></span></p><h3
 id="UsingBeanEditFormToCreateUserForms-Customizinglabels">Customizing 
labels</h3><p>Tapestry makes it pretty easy to customize the labels used on the 
fields. It's just a matter of creating a <em>message catalog</em> for the 
page.</p><p>In Tapestry, every page and component may have its own message 
catalog. This is a standard Java properties file, and it is named the same as 
the page or component class, with a ".properties" extension. A message catalog 
consists of a series of lines, each line is a message key and a message value 
separated with an equals sign.</p><p>All it takes is to create a message entry 
with a particular name: the name of the property suffixed with "-label". As 
elsewhere, Tapestry is forgiving of case.</p><div class="preformatte
 d panel" style="border-width: 1px;"><div class="preformattedHeader 
panelHeader" style="border-bottom-width: 
1px;"><b>src/main/resources/com/example/tutorial/pages/address/CreateAddress.properties</b></div><div
 class="preformattedContent panelContent">
 <pre>street1-label=Street 1
 street2-label=Street 2
 email-label=E-Mail
 zip-label=Zip Code
 phone-label=Phone Number</pre>
-</div></div><p>Since this is a <em>new</em> file (and not a change to an 
existing file), you may have to restart Jetty to force Tapestry to pick up the 
change.</p><p><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource 
confluence-content-image-border" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/address-v3.png?version=2&amp;modificationDate=1417055915000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/address-v3.png?version=2&amp;modificationDate=1417055915000&amp;api=v2";></span></p><p>We
 can also customize the options in the drop down list. All we have to do is add 
some more entries to the message catalog matching the enum names to the desired 
labels. Update CreateAddress.properties and add:</p><div class="preformatted 
panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
+</div></div><p>Since this is a <em>new</em> file (and not a change to an 
existing file), you may have to restart Jetty to force Tapestry to pick up the 
change.</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="471" 
src="using-beaneditform-to-create-user-forms.data/address-v3.png"></span></p><p>We
 can also customize the options in the drop down list. All we have to do is add 
some more entries to the message catalog matching the enum names to the desired 
labels. Update CreateAddress.properties and add:</p><div class="preformatted 
panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
 <pre>MR=Mr.
 MRS=Mrs.
 DR=Dr.
@@ -171,7 +171,7 @@ DR=Dr.
 <pre class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">    &lt;t:beaneditform submitlabel="Create Address" 
object="address"
         
reorder="honorific,firstName,lastName,street1,street2,city,state,zip,email,phone"/&gt;
 </pre>
-</div></div><p>The default for the submitlabel parameter is "Create/Update", 
but here we're overriding that default to a specific value.</p><p>The final 
result shows the reformatting and relabelling:</p><p><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource confluence-content-image-border" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/address-v5.png?version=2&amp;modificationDate=1417055915000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/address-v5.png?version=2&amp;modificationDate=1417055915000&amp;api=v2";></span><br
 clear="none">Before continuing on to validation, a side note about message 
catalogs. Message catalogs are not just for re-labeling fields and options; 
we'll see in later chapters how message catalogs are used in the context of 
localization and internationalization.</p><p>Instead of putting the label for 
the submit button dir
 ectly inside the template, we're going to provide a reference to the label; 
the actual label will go in the message catalog.</p><p>In Tapestry, when 
binding a parameter, the value you provide may include a prefix. The prefix 
guides Tapestry in how to interpret the rest of the the parameter value ... is 
it the name of a property? The id of a component? A message key? Most 
parameters have a default prefix, usually "prop:", that is used when you fail 
to provide one (this helps to make the templates as terse as 
possible).</p><p>Here we want to reference a message from the catalog, so we 
use the "message:" prefix:</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeContent panelContent pdl">
+</div></div><p>The default for the submitlabel parameter is "Create/Update", 
but here we're overriding that default to a specific value.</p><p>The final 
result shows the reformatting and relabelling:</p><p><span 
class="confluence-embedded-file-wrapper confluence-embedded-manual-size"><img 
class="confluence-embedded-image" width="453" 
src="using-beaneditform-to-create-user-forms.data/address-v5.png"></span></p><p>Before
 continuing on to validation, a side note about message catalogs. Message 
catalogs are not just for re-labeling fields and options; we'll see in later 
chapters how message catalogs are used in the context of localization and 
internationalization.</p><p>Instead of putting the label for the submit button 
directly inside the template, we're going to provide a reference to the label; 
the actual label will go in the message catalog.</p><p>In Tapestry, when 
binding a parameter, the value you provide may include a prefix. The prefix 
guides Tapestry in how to interpret the res
 t of the the parameter value ... is it the name of a property? The id of a 
component? A message key? Most parameters have a default prefix, usually 
"prop:", that is used when you fail to provide one (this helps to make the 
templates as terse as possible).</p><p>Here we want to reference a message from 
the catalog, so we use the "message:" prefix:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
 <pre class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">    &lt;t:beaneditform object="address" 
submitlabel="message:submit-label"
         
reorder="honorific,firstName,lastName,street1,street2,city,state,zip,email,phone"
 /&gt;
 </pre>
@@ -182,14 +182,14 @@ DR=Dr.
 <pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">    @Validate("required")
     public String firstName;
 </pre>
-</div></div><p>What is that string, "required"? That's how you specify the 
desired validation. It is a series of names that identify what type of 
validation is desired. A number of validators are built in, such as "required", 
"minLength" and "maxLength". As elsewhere, Tapestry is case 
insensitive.</p><p>You can apply multiple validations, by separating the 
validator names with commas. Some validators can be configured (with an equals 
sign). Thus you might say "required,minLength=5" for a field that must be 
specified, and must be at least five characters long.</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>You can easily get confused when 
you make a change to an entity class, such as adding the @Validate annotation, 
and <em>not</em> see the result in the browser. Only component classes, and 
(most) classe
 s in the Tapestry services layer, are live-reloaded. Data and entity objects 
are not reloaded, so this is one area where you need to stop and restart Jetty 
to see the change.</p></div></div><p>Restart the application, and refresh your 
browser, then hit the Create Address button.</p><p><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource confluence-content-image-border" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/address-v6.png?version=3&amp;modificationDate=1417056607000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/address-v6.png?version=3&amp;modificationDate=1417056607000&amp;api=v2";></span></p><p>This
 is a shot just after hitting the Create Address button; all the fields have 
been validated and errors displayed. Each field in error has been highlighted 
in red and had an error message added. Further, the label for each of the 
fields has
  also been highlighted in red, to even more clearly identify what's in error. 
The cursor has also been moved to the first field that's in error. And 
<em>all</em> of this is taking place on the client side, without any 
communication with the application.</p><p>Once all the errors are corrected, 
and the form does submit, all validations are performed on the server side as 
well (just in case the client has JavaScript disabled).</p><p>So ... how about 
some more interesting validation than just "required or not". Tapestry has 
built in support for validating based on field length and several variations of 
field value, including regular expressions. Zip codes are pretty easy to 
express as a regular expression.</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>What is that string, "required"? That's how you specify the 
desired validation. It is a series of names that identify what type of 
validation is desired. A number of validators are built in, such as "required", 
"minLength" and "maxLength". As elsewhere, Tapestry is case 
insensitive.</p><p>You can apply multiple validations, by separating the 
validator names with commas. Some validators can be configured (with an equals 
sign). Thus you might say "required,minLength=5" for a field that must be 
specified, and must be at least five characters long.</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>You can easily get confused when 
you make a change to an entity class, such as adding the @Validate annotation, 
and <em>not</em> see the result in the browser. Only component classes, and 
(most) classe
 s in the Tapestry services layer, are live-reloaded. Data and entity objects 
are not reloaded, so this is one area where you need to stop and restart Jetty 
to see the change.</p></div></div><p>Restart the application, and refresh your 
browser, then hit the Create Address button.</p><p><span 
class="confluence-embedded-file-wrapper confluence-embedded-manual-size"><img 
class="confluence-embedded-image" width="452" 
src="using-beaneditform-to-create-user-forms.data/address-v6.png"></span></p><p>This
 is a shot just after hitting the Create Address button; all the fields have 
been validated and errors displayed. Each field in error has been highlighted 
in red and had an error message added. Further, the label for each of the 
fields has also been highlighted in red, to even more clearly identify what's 
in error. The cursor has also been moved to the first field that's in error. 
And <em>all</em> of this is taking place on the client side, without any 
communication with the application.</p><
 p>Once all the errors are corrected, and the form does submit, all validations 
are performed on the server side as well (just in case the client has 
JavaScript disabled).</p><p>So ... how about some more interesting validation 
than just "required or not". Tapestry has built in support for validating based 
on field length and several variations of field value, including regular 
expressions. Zip codes are pretty easy to express as a regular 
expression.</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeContent panelContent pdl">
 <pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">    @Validate("required,regexp=^\\d{5}(-\\d{4})?$")
     public String zip;
 </pre>
-</div></div><p>Let's give it a try; restart the application and enter an "abc" 
for the zip code.</p><p><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource 
confluence-content-image-border" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/address-v7.png?version=2&amp;modificationDate=1417056608000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/address-v7.png?version=2&amp;modificationDate=1417056608000&amp;api=v2";></span><br
 clear="none">This is what you'll see after typing "abc" and clicking the 
Create Address button.</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>Modern browsers will automatically 
validate a regexp field when the form is submitted, as shown above. O
 lder browsers do not have that automatic support, but will still validate 
input, using the same decorations as for the required fields in the previous 
screenshot.</p></div></div><p>In any case, that's the right validation 
behavior, but it's the wrong message. Your users are not going to know or care 
about regular expressions.</p><p>Fortunately, it's easy to customize validation 
messages. All we need to know is the name of the property ("zip") and the name 
of the validator ("regexp"). We can then put an entry into the CreateAddress 
message catalog:</p><div class="preformatted panel" style="border-width: 
1px;"><div class="preformattedContent panelContent">
+</div></div><p>Let's give it a try; restart the application and enter an "abc" 
for the zip code.</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="448" 
src="using-beaneditform-to-create-user-forms.data/address-v7.png"></span></p><p>This
 is what you'll see after typing "abc" and clicking the Create Address 
button.</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>Modern browsers will automatically 
validate a regexp field when the form is submitted, as shown above. Older 
browsers do not have that automatic support, but will still validate input, 
using the same decorations as for the required fields in the previous 
screenshot.</p></div></div><p>In any case, that's the right validation 
behavior, but it's the wrong message. Your use
 rs are not going to know or care about regular expressions.</p><p>Fortunately, 
it's easy to customize validation messages. All we need to know is the name of 
the property ("zip") and the name of the validator ("regexp"). We can then put 
an entry into the CreateAddress message catalog:</p><div class="preformatted 
panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
 <pre>zip-regexp-message=Zip Codes are five or nine digits.  Example: 02134 or 
90125-1655.
 </pre>
-</div></div><p>Refresh the page and submit again:</p><p><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource confluence-content-image-border" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/address-v8.png?version=2&amp;modificationDate=1417056608000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23340431/address-v8.png?version=2&amp;modificationDate=1417056608000&amp;api=v2";></span></p><p>This
 trick isn't limited to just the regexp validator, it works equally well with 
<em>any</em> validator.</p><p>Let's go one step further. Turns out, we can move 
the regexp pattern to the message catalog as well. If you only provide the name 
of the validator in the @Validate annotation, Tapestry will search the 
containing page's message catalog of the constraint value, as well as the 
validation message. The constraint value for the regexp validator is the 
regular expre
 ssion to match against.</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeContent panelContent pdl">
+</div></div><p>Refresh the page and submit again:</p><p><span 
class="confluence-embedded-file-wrapper confluence-embedded-manual-size"><img 
class="confluence-embedded-image" width="455" 
src="using-beaneditform-to-create-user-forms.data/address-v8.png"></span></p><p>This
 trick isn't limited to just the regexp validator, it works equally well with 
<em>any</em> validator.</p><p>Let's go one step further. Turns out, we can move 
the regexp pattern to the message catalog as well. If you only provide the name 
of the validator in the @Validate annotation, Tapestry will search the 
containing page's message catalog of the constraint value, as well as the 
validation message. The constraint value for the regexp validator is the 
regular expression to match against.</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
 <pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">    @Validate("required,regexp")
     public String zip;
 </pre>
@@ -197,7 +197,7 @@ DR=Dr.
 <pre>zip-regexp=^\\d{5}(-\\d{4})?$
 zip-regexp-message=Zip Codes are five or nine digits.  Example: 02134 or 
90125-1655.
 </pre>
-</div></div><p>After a restart you'll see the ... the same behavior. But when 
we start creating more complicated regular expressions, it'll be much, much 
nicer to put them in the message catalog rather than inside the annotation 
value. And inside the message catalog, you can change and tweak the regular 
expressions without having to restart the application each time.</p><p>We could 
go a bit further here, adding more regular expression validation for phone 
numbers and e-mail addresses. We're also far from done in terms of further 
customizations of the BeanEditForm component.</p><p>By now you are likely 
curious about what happens <em>after</em> the form submits successfully 
(without validation errors), so that's what we'll focus on next.</p><p>Next: <a 
 href="using-beaneditform-to-create-user-forms.html">Using BeanEditForm To 
Create User Forms</a></p><p>&#160;</p><p></p></div>
+</div></div><p>After a restart you'll see the ... the same behavior. But when 
we start creating more complicated regular expressions, it'll be much, much 
nicer to put them in the message catalog rather than inside the annotation 
value. And inside the message catalog, you can change and tweak the regular 
expressions without having to restart the application each time.</p><p>We could 
go a bit further here, adding more regular expression validation for phone 
numbers and e-mail addresses. We're also far from done in terms of further 
customizations of the BeanEditForm component.</p><p>By now you are likely 
curious about what happens <em>after</em> the form submits successfully 
(without validation errors), so that's what we'll focus on next.</p><p>Next: <a 
 href="using-tapestry-with-hibernate.html">Using Tapestry With 
Hibernate</a></p><p>&#160;</p><p></p></div>
       </div>
 
       <div class="clearer"></div>


Reply via email to