You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by bu...@apache.org on 2018/02/19 00:22:56 UTC

svn commit: r1025575 - in /websites/production/tapestry/content: cache/main.pageCache default-parameter.html error-page-recipe.html page-navigation.html supporting-informal-parameters.html tapestry-for-jsf-users.html

Author: buildbot
Date: Mon Feb 19 00:22:56 2018
New Revision: 1025575

Log:
Production update by buildbot for tapestry

Modified:
    websites/production/tapestry/content/cache/main.pageCache
    websites/production/tapestry/content/default-parameter.html
    websites/production/tapestry/content/error-page-recipe.html
    websites/production/tapestry/content/page-navigation.html
    websites/production/tapestry/content/supporting-informal-parameters.html
    websites/production/tapestry/content/tapestry-for-jsf-users.html

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

Modified: websites/production/tapestry/content/default-parameter.html
==============================================================================
--- websites/production/tapestry/content/default-parameter.html (original)
+++ websites/production/tapestry/content/default-parameter.html Mon Feb 19 00:22:56 2018
@@ -76,7 +76,7 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>&#160;</p><p>Many of the components provided with Tapestry share a common behavior: if the component's id matches a property of the container, then some parameter of the component (usually value) defaults to that property.</p><div class="aui-label" style="float:right" title="Related Articles">
+                <div id="ConfluenceContent"><p>&#160;</p><p>Many of the components provided with Tapestry share a common behavior: if the component's id matches a property of the container, then some parameter of the component (usually value) defaults to that property.</p><div class="aui-label" style="float:right; margin: 1em" title="Related Articles">
 
 
 

Modified: websites/production/tapestry/content/error-page-recipe.html
==============================================================================
--- websites/production/tapestry/content/error-page-recipe.html (original)
+++ websites/production/tapestry/content/error-page-recipe.html Mon Feb 19 00:22:56 2018
@@ -77,7 +77,7 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><h1 id="ErrorPageRecipe-ServingTapestryPagesasServletErrorPages">Serving Tapestry Pages as Servlet Error Pages</h1><p>Do you want to dress up your site and use a snazzy Tapestry page instead of the default 404 error page? Using modern servlet containers, this is a snap!</p><div class="aui-label" style="float:right" title="Related Articles">
+                <div id="ConfluenceContent"><h1 id="ErrorPageRecipe-ServingTapestryPagesasServletErrorPages">Serving Tapestry Pages as Servlet Error Pages</h1><p>Do you want to dress up your site and use a snazzy Tapestry page instead of the default 404 error page? Using modern servlet containers, this is a snap!</p><div class="aui-label" style="float:right; margin: 1em" title="Related Articles">
 
 
 
@@ -119,7 +119,7 @@
 </div>
 
 
-<p>Simply upgrade your application web.xml to the 2.4 version, and make a couple of changes:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>web.xml</b></div><div class="codeContent panelContent pdl">
+<p>Simply upgrade your application web.xml to the 2.4 version (or newer), and make a couple of changes:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>web.xml</b></div><div class="codeContent panelContent pdl">
 <pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
 
 &lt;web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

Modified: websites/production/tapestry/content/page-navigation.html
==============================================================================
--- websites/production/tapestry/content/page-navigation.html (original)
+++ websites/production/tapestry/content/page-navigation.html Mon Feb 19 00:22:56 2018
@@ -155,7 +155,18 @@
 </div>
 
 
-<p>In essence, a Tapestry application is a number of related pages, working together. To some degree, each page is like an application unto itself.</p><p>Any individual request will be targeted at a single page. Requests come in two forms:&#160;</p><ul><li><em>component event</em> requests target a specific component on a specific page, triggering an event within that component</li><li><em>render</em> requests target a specific page, and stream the HTML markup for that page back to the client</li></ul><p>This dichotomy between component event requests and render requests alleviates a number of problems in traditional web applications related to the browser back button, or to the user hitting the refresh button in their browser.</p><p><br clear="none"><span style="color: rgb(83,145,38);">Logical Page Name Shortening</span></p><p>In certain cases, Tapestry will shorten the the logical name of a page. For example, the page class org.example.pages.address.CreateAddress will be given a l
 ogical name of "address/Create" (the redundant "Address" is removed as a suffix). However, this only affects how the page is referenced in URLs; the template file will still be CreateAddress.tml, whether on the classpath, or as address/CreateAddress.tml (in the web context).</p><p><span>Tapestry actually creates multiple names for the name page: "address/Create" and "address/CreateAddress" are both synonymous. You can user either in Java code that refers to a page by name, or as the page parameter of a PageLink.</span></p><h2 id="PageNavigation-ComponentEventRequests&amp;Responses">Component Event Requests &amp; Responses</h2><p>Main Article: <a  href="page-navigation.html">Page Navigation</a></p><p>Component event requests may take the form of hyperlinks (<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/EventLink.html">EventLink</a> or <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apa
 che/tapestry5/corelib/components/ActionLink.html">ActionLink</a>) or form submissions (<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Form.html">Form</a>).</p><p>The value returned from an <a  href="component-events.html">event handler method</a> controls the response sent to the client web browser.</p><p>The URL for a component event request identifies the name of the page, the nested id of the component, and the name of the event to trigger on the component (specified by the "event" parameter of EventLink, or "action" for an ActionLink). Further, a component event request may contain additional context information, which will be provided to the event handler method.</p><p>These URLs expose a bit of the internal structure of the application. Over time, as an application grows and is maintained, the ids of components may change. This means that component event request URLs should not be bookmarked. Fortunately, user
 s will rarely have the chance to do so (see below).</p><h3 id="PageNavigation-1.Nullresponse">1. Null response</h3><p>If the event handler method returns no value, or returns null, then the current page (the page containing the component) will render the response.</p><p>A page render URL for the current page is created and sent to the client as a client side redirect. The client browser will automatically submit a new request to generate the page.</p><p>The user will see the newly generated content in their browser. In addition, the URL in the browser's address bar will be a render request URL. Render request URLs are shorter and contain less application structure (for instance, they don't include component ids or event types). Render requests URLs are what your users will bookmark. The component event request URLs are transitory, meaningful only while the application is actively engaged, and not meant to be used in later sessions.</p><div class="code panel pdl" style="border-width:
  1px;"><div class="codeContent panelContent pdl">
+<p>In essence, a Tapestry application is a number of related pages, working together. To some degree, each page is like an application unto itself.</p><p>Any individual request will be targeted at a single page. Requests come in two forms:&#160;</p><ul><li><em>component event</em> requests target a specific component on a specific page, triggering an event within that component</li><li><em>render</em> requests target a specific page, and stream the HTML markup for that page back to the client</li></ul><p>This dichotomy between component event requests and render requests alleviates a number of problems in traditional web applications related to the browser back button, or to the user hitting the refresh button in their browser.</p><h3 id="PageNavigation-Contents">Contents</h3><h2 id="PageNavigation-Contents|RelatedArticlesLogicalPageNameShortening"><style type="text/css">/*<![CDATA[*/
+div.rbtoc1518999689641 {padding: 0px;}
+div.rbtoc1518999689641 ul {list-style: disc;margin-left: 0px;}
+div.rbtoc1518999689641 li {margin-left: 0px;padding-left: 0px;}
+
+/*]]>*/</style></h2><div class="toc-macro rbtoc1518999689641">
+<ul class="toc-indentation"><li><a  href="#PageNavigation-Contents|RelatedArticlesLogicalPageNameShortening">Logical Page Name Shortening</a></li><li><a  href="#PageNavigation-ComponentEventRequests&amp;Responses">Component Event Requests &amp; Responses</a>
+<ul class="toc-indentation"><li><a  href="#PageNavigation-1.Nullresponse">1. Null response</a></li><li><a  href="#PageNavigation-2.Stringresponse">2. String response</a></li><li><a  href="#PageNavigation-3.Classresponse">3. Class response</a></li><li><a  href="#PageNavigation-4.Pageresponse">4. Page response</a></li><li><a  href="#PageNavigation-5.HttpError">5. HttpError</a></li><li><a  href="#PageNavigation-6.Linkresponse">6. Link response</a></li><li><a  href="#PageNavigation-7.Streamresponse">7. Stream response</a></li><li><a  href="#PageNavigation-8.URLresponse">8. URL response</a></li><li><a  href="#PageNavigation-9.Objectresponse">9. Object response</a></li></ul>
+</li><li><a  href="#PageNavigation-PageRenderRequests">Page Render Requests</a></li><li><a  href="#PageNavigation-PageActivation">Page Activation</a></li><li><a  href="#PageNavigation-PageNavigationPatterns">Page Navigation Patterns</a>
+<ul class="toc-indentation"><li><a  href="#PageNavigation-Pattern1:Componenteventrequests/PersistentData">Pattern 1: Component event requests / Persistent Data</a></li><li><a  href="#PageNavigation-Pattern2:ComponentEventRequests/NoPersistentData">Pattern 2: Component Event Requests / No Persistent Data</a></li><li><a  href="#PageNavigation-Pattern3:RenderRequestsOnly">Pattern 3: Render Requests Only</a></li><li><a  href="#PageNavigation-Limitations">Limitations</a></li></ul>
+</li></ul>
+</div><br clear="none"><span style="color: rgb(83,145,38);">Logical Page Name Shortening</span><p>In certain cases, Tapestry will shorten the the logical name of a page. For example, the page class org.example.pages.address.CreateAddress will be given a logical name of "address/Create" (the redundant "Address" is removed as a suffix). However, this only affects how the page is referenced in URLs; the template file will still be CreateAddress.tml, whether on the classpath, or as address/CreateAddress.tml (in the web context).</p><p><span>Tapestry actually creates multiple names for the name page: "address/Create" and "address/CreateAddress" are both synonymous. You can user either in Java code that refers to a page by name, or as the page parameter of a PageLink.</span></p><h2 id="PageNavigation-ComponentEventRequests&amp;Responses">Component Event Requests &amp; Responses</h2><p>Main Article:&#160; <a  href="component-events.html">Component Events</a></p><p>Component event requests 
 may take the form of hyperlinks (<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/EventLink.html">EventLink</a> or <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/ActionLink.html">ActionLink</a>) or form submissions (<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Form.html">Form</a>).</p><p>The value returned from an <a  href="component-events.html">event handler method</a> controls the response sent to the client web browser.</p><p>The URL for a component event request identifies the name of the page, the nested id of the component, and the name of the event to trigger on the component (specified by the "event" parameter of EventLink, or "action" for an ActionLink). Further, a component event request may contain additional context information, which will be provided to the event handl
 er method.</p><p>These URLs expose a bit of the internal structure of the application. Over time, as an application grows and is maintained, the ids of components may change. This means that component event request URLs should not be bookmarked. Fortunately, users will rarely have the chance to do so (see below).</p><h3 id="PageNavigation-1.Nullresponse">1. Null response</h3><p>If the event handler method returns no value, or returns null, then the current page (the page containing the component) will render the response.</p><p>A page render URL for the current page is created and sent to the client as a client side redirect. The client browser will automatically submit a new request to generate the page.</p><p>The user will see the newly generated content in their browser. In addition, the URL in the browser's address bar will be a render request URL. Render request URLs are shorter and contain less application structure (for instance, they don't include component ids or event type
 s). Render requests URLs are what your users will bookmark. The component event request URLs are transitory, meaningful only while the application is actively engaged, and not meant to be used in later sessions.</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;">public Object onAction(){
   return null;
 }</pre>
@@ -203,7 +214,7 @@ public Object onAction(){
   long onPassivate() { return product.getId(); }
 }
 </pre>
-</div></div><p>The activation context may consist of a series of values, in which case the return value of the method should be an array or a List.</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>Note: If you are using the <a  href="hibernate-user-guide.html">tapestry-hibernate</a> integration library and your passivate context is a Hibernate entity, then you can just use the entity itself, not its id. Tapestry will automatically extract the entity's id into the URL, and convert it back for the "activate" event handler method.</p></div></div><h2 id="PageNavigation-Pageactivation">Page activation</h2><p>When a page render request arrives, the page is <em>activated</em> before it is rendered.</p><div class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em">
+</div></div><p>The activation context may consist of a series of values, in which case the return value of the method should be an array or a List.</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>Note: If you are using the <a  href="hibernate-user-guide.html">tapestry-hibernate</a> integration library and your passivate context is a Hibernate entity, then you can just use the entity itself, not its id. Tapestry will automatically extract the entity's id into the URL, and convert it back for the "activate" event handler method.</p></div></div><h2 id="PageNavigation-PageActivation">Page Activation</h2><p>When a page render request arrives, the page is <em>activated</em> before it is rendered.</p><div class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demos:</strong><br clear="none">
     <a  class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/navigation/onactivateandonpassivate/3" rel="nofollow">onActivate and onPassivate</a><br clear="none">
     <a  class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/handlingabadcontext/1" rel="nofollow">Handling A Bad Context</a></p></div>Activation serves two purposes:<ul><li>It allows the page to restore its internal state from data encoded into the URL (the activation context discussed above).</li><li>It provides coarse approach to validating access to the page.</li></ul><p>The later case &#8211; validation&#160;&#8211; is generally concerned with user identity and access; if you have pages that may only be accessed by certain users, you may use the page's activate event handler for verifying that access.</p><p>Page activation uses Tapestry's <em>Component Event</em> mechanism. See&#160;<a  href="component-events.html">Component Events</a> for details.</p><p>A page's activate event handler mirrors its passivate handler:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">

Modified: websites/production/tapestry/content/supporting-informal-parameters.html
==============================================================================
--- websites/production/tapestry/content/supporting-informal-parameters.html (original)
+++ websites/production/tapestry/content/supporting-informal-parameters.html Mon Feb 19 00:22:56 2018
@@ -75,7 +75,7 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>&#160;<strong>Informal parameters</strong> are any additional parameters (aka HTML attributes) beyond the those explicitly defined for a component using the <a  class="external-link" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/annotations/Parameter.html">Parameter</a> annotation.</p><div class="aui-label" style="float:right" title="Related Articles">
+                <div id="ConfluenceContent"><p>&#160;<strong>Informal parameters</strong> are any additional parameters (aka HTML attributes) beyond the those explicitly defined for a component using the @<a  class="external-link" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/annotations/Parameter.html">Parameter</a> annotation.</p><div class="aui-label" style="float:right; margin: 1em" title="Related Articles">
 
 
 
@@ -126,7 +126,7 @@
 </div>
 
 
-<p>Any component that closely emulates a particular HTML element <strong><em>should</em></strong> support informal parameters, because it gives users of your component the ability to easily add HTML attributes to the HTML that your component emits. You'll find that most of the built-in Tapestry components, such as Form, Label and TextField, do exactly that.</p><p>To support informal parameters, a component class should use either the @<a  class="external-link" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/annotations/SupportsInformalParameters.html">SupportsInformalParameters</a> annotation or the RenderInformals mixin. Otherwise, providing informal parameters to a component will do nothing: any additional parameters will be ignored.</p><h3 id="SupportingInformalParameters-Approach1:@SupportsInformalParameters">Approach 1: @SupportsInformalParameters</h3><p>In the example below we create an Img component, a custom replacement for the &lt;img&gt; tag. Its sr
 c parameter will be an asset. We'll use the @SupportsInformalParameters annotation to tell Tapestry that the component should support informal parameters.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<p>Any component that closely emulates a particular HTML element <strong><em>should</em></strong> support informal parameters, because it gives users of your component the ability to easily add HTML attributes to the HTML that your component emits. You'll find that most of the built-in Tapestry components, such as Form, Label and TextField, do exactly that.</p><p>To support informal parameters, a component class should use either the @<a  class="external-link" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/annotations/SupportsInformalParameters.html">SupportsInformalParameters</a> annotation or the RenderInformals mixin. Otherwise, providing informal parameters to a component will do nothing: any additional parameters will be ignored.</p><h3 id="SupportingInformalParameters-Approach1:@SupportsInformalParameters">Approach 1: @SupportsInformalParameters</h3><p>In the example below we create an Img component, a custom replacement for the &lt;img&gt; tag. Its sr
 c parameter will be an asset. We'll use the @SupportsInformalParameters annotation to tell Tapestry that the component should support informal parameters.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Img.java</b></div><div class="codeContent panelContent pdl">
 <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@SupportsInformalParameters
 public class Img
 {
@@ -145,7 +145,7 @@ public class Img
     }
 }
 </pre>
-</div></div><p>The call to renderInformalParameters() is what converts and outputs the informal parameters. It should occur <em>after</em> your code has rendered attributes into the element (earlier written attributes will <em>not</em> be overwritten by later written attributes).</p><p>Returning false from beginRender() ensures that the body of the component is not rendered, which makes sense for an &lt;img&gt; tag, which has no body.</p><h3 id="SupportingInformalParameters-Approach2:RenderInformals">Approach 2: RenderInformals</h3><p>Another, equivalent, approach is to use the <a  class="external-link" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/corelib/mixins/RenderInformals.html">RenderInformals</a> mixin:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>The call to renderInformalParameters() is what converts and outputs the informal parameters. It should occur <em>after</em> your code has rendered attributes into the element (earlier written attributes will <em>not</em> be overwritten by later written attributes).</p><p>Returning false from beginRender() ensures that the body of the component is not rendered, which makes sense for an &lt;img&gt; tag, which has no body.</p><h3 id="SupportingInformalParameters-Approach2:RenderInformals">Approach 2: RenderInformals</h3><p>Another, equivalent, approach is to use the <a  class="external-link" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/corelib/mixins/RenderInformals.html">RenderInformals</a> mixin (:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Img.java</b></div><div class="codeContent panelContent pdl">
 <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class Img
 {
     @Parameter(required=true, allowNull=false, defaultPrefix=BindingConstants.ASSET)
@@ -166,7 +166,9 @@ public class Img
     }
 }
 </pre>
-</div></div><p>This variation splits the rendering of the tag in two pieces, so that the RenderInformals mixin can operate (after beginRender() and before beforeRenderBody()).</p></div>
+</div></div><p>This variation splits the rendering of the tag in two pieces, so that the RenderInformals mixin can operate (after beginRender() and before beforeRenderBody()).</p><h3 id="SupportingInformalParameters-Approach3:Extendthe&quot;Any&quot;component">Approach 3: Extend the "Any" component</h3><p>Another approach is to have your component class <em>extend</em> Tapestry's Any component, which already supports informal parameters:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Img.java</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class Img extends Any { ... }</pre>
+</div></div><p>&#160;</p><p>&#160;</p><p>&#160;</p><p>&#160;</p></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/tapestry-for-jsf-users.html
==============================================================================
--- websites/production/tapestry/content/tapestry-for-jsf-users.html (original)
+++ websites/production/tapestry/content/tapestry-for-jsf-users.html Mon Feb 19 00:22:56 2018
@@ -136,7 +136,7 @@
 </div>
 
 
-<p>Since almost all modern JSF applications use Facelets as their view technology, we assume the use of Facelets here when discussing JSF features.</p><p>JSF is a rich, mature web framework specification, and there are lots of smart people who use it productively. This guide isn't intended as a pro-versus-con comparison or as advocacy of any kind. Instead, it just attempts to make transitions between the two frameworks easier, regardless of the reason for doing so.</p><h2 id="TapestryforJSFUsers-Side-by-sideComparison">Side-by-side Comparison</h2><p>JSF and Tapestry have a lot of superficial similarities, so the first steps in that transition are all about relating similar concepts, terms and components in your mind:</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Concepts &amp; Terminology</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><
 p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Java class associated with a page or component</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>"Backing Bean"</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>"<a  href="tapestry-for-jsf-users.html">Component Class</a>"</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Component attributes/parameters</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>"attributes"</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>"<a  href="tapestry-for-jsf-users.html">parameters</a>"</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Common Attributes/Parameters</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>HTML Attribute used for invisible instrumentation</p></td><td colspan="1" rowspan="1
 " class="confluenceTd"><p>jsfc="someComponentType"</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  href="tapestry-for-jsf-users.html">t:type="someComponentType"</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>CSS "class" attribute name</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>styleClass</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>class</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Alternating "zebra" striped rows</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>rowclasses="class1,class2"</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>class="${cycle:class1,class2}" using <a  class="external-link" href="https://wiki.apache.org/tapestry/Tapestry5HowToAddBindingPrefixCycle">cycle binding prefix</a>, or with CSS: .rowClass:nth-child(even) {background-color: #e8e8e8;}</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Output and Messages</p></th><th 
 colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Escaped HTML from property</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:outputText value="myBean.myValue"/&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${myValue}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Raw HTML from property</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{myBean.myValue}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/OutputRaw.html">&lt;t:outputRaw value="myValue"/&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Error messages</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:message&gt; and &lt;h:messages&gt;</p></td><td colsp
 an="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Error.html">&lt;t:error&gt;</a> and <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Errors.html">&lt;t:errors&gt;</a> (for forms) or <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Alerts.html">&lt;t:alerts&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Image display</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:graphicImage&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>use standard &lt;img&gt; tag</em></p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Conditionals and Looping</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry
 </p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Render-time loop</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;ui:repeat&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Loop.html">&lt;t:loop&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Compile-time loop</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;c:forEach&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Loop.html">&lt;t:loop&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Conditional</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;c:if test="#{myBean.myValue}"&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="externa
 l-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/If.html">&lt;t:if test="myValue"&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Conditional</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;ui:fragment rendered="#{myBean.someCondition}"/&gt;...&lt;/ui:fragment&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/If.html">&lt;t:if test="someCondition"&gt;...&lt;/t:if&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Switch</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;c:choose&gt;&lt;c:when ... &gt;&lt;/c:choose&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>See <a  href="tapestry-for-jsf-users.html">Tapestry for JSF Users</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Server-side c
 omment</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;ui:remove&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  href="tapestry-for-jsf-users.html">&lt;t:remove&gt;</a></p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Links and Buttons</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Navigational link</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:link outcome="nextpage.xhtml"/&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/PageLink.html">&lt;t:pagelink page="nextpage"/&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Event-triggering link, without form submission</p></td><td colspan="1" rowspan="1" cl
 ass="confluenceTd"><p><em>not available</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/ActionLink.html">&lt;t:actionLink&gt;</a> or <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/EventLink.html">&lt;t:eventLink&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Form submission link</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:commandLink&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/LinkSubmit.html">&lt;t:linkSubmit&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Form submission button</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:commandButton&gt;</p></td><td 
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Submit.html">&lt;t:submit&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Link to Javascript file</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:outputScript&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>&lt;script&gt; or use @Import in component class</em></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Link to CSS file</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:outputStylesheet&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>&lt;style&gt; or use @Import in component class</em></p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Grids, Tables and Trees</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p
 >Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Tabular data in &lt;table&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:datatable&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Grid.html">&lt;t:grid&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Table used for layout</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:panelGrid&gt; with &lt;h:panelGroup&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>use standard &lt;table&gt; tag</em></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Hierarchical tree</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>depends on component library</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/cu
 rrent/apidocs/org/apache/tapestry5/corelib/components/Tree.html">&lt;t:tree&gt;</a></p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Form Tags/Components</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Form</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:form&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Form.html">&lt;t:form&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Single-line text input field</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:inputText&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/co
 relib/components/TextField.html">&lt;t:textField&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Password field</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:inputSecret&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/PasswordField.html">&lt;t:passwordfield&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Select menu</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:selectOneMenu&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Select.html">&lt;t:select&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Checkbox</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:selectBooleanCheckbox&gt;</p></td
 ><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Checkbox.html">&lt;t:checkbox&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Checkbox list</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:selectManyCheckbox&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Checklist.html">&lt;t:checklist&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Radio button list</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:selectOneRadio&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/RadioGroup.html">&lt;t:radioGroup&gt;</a> with <a  class=
 "external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Radio.html">&lt;t:radio&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Multiple select menu</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:selectManyListbox&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em> (but see Palette and Checklist)</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Hidden field</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:inputHidden&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Hidden.html">&lt;t:hidden&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>textarea tag</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:inputTextarea&gt;</p></td><td colspan="1" rows
 pan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/TextArea.html">&lt;t:textArea&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Label tag</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:outputLabel for="..."&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Label.html">&lt;t:label for="..."&gt;</a></p></td></tr></tbody></table></div><p>Some important notes:</p><ul><li>With Tapestry, you don't use the ${...} syntax with parameters of components. Just use a bare expression within the quotes. For example: &lt;t:textfield value="myProperty"&gt; instead of &lt;t:textfield value="${myProperty}"&gt;, because in the latter case the expression is converted to a read-only string before the textfield component gets it.</li></
 ul><h2 id="TapestryforJSFUsers-HelloWorldComparison">Hello World Comparison</h2><p>Faces templates and Tapestry templates are superficially quite similar.</p><div class="sectionColumnWrapper"><div class="sectionMacro"><div class="sectionMacroRow"><div class="columnMacro"><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>JSF template (helloworld.xhtml)</b></div><div class="codeContent panelContent pdl">
+<p>Since almost all modern JSF applications use Facelets as their view technology, we assume the use of Facelets here when discussing JSF features.</p><p>JSF is a rich, mature web framework specification, and there are lots of smart people who use it productively. This guide isn't intended as a pro-versus-con comparison or as advocacy of any kind. Instead, it just attempts to make transitions between the two frameworks easier, regardless of the reason for doing so.</p><h2 id="TapestryforJSFUsers-Side-by-sideComparison">Side-by-side Comparison</h2><p>JSF and Tapestry have a lot of superficial similarities, so the first steps in that transition are all about relating similar concepts, terms and components in your mind:</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Concepts &amp; Terminology</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><
 p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Java class associated with a page or component</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>"Backing Bean"</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>"<a  href="component-classes.html">Component Class</a>"</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Component attributes/parameters</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>"attributes"</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>"<a  href="component-parameters.html">parameters</a>"</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Common Attributes/Parameters</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>HTML Attribute used for invisible instrumentation</p></td><td colspan="1" rowspan="1" class
 ="confluenceTd"><p>jsfc="someComponentType"</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  href="component-templates.html">t:type="someComponentType"</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>CSS "class" attribute name</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>styleClass</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>class</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Alternating "zebra" striped rows</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>rowclasses="class1,class2"</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>class="${cycle:class1,class2}" using <a  class="external-link" href="https://wiki.apache.org/tapestry/Tapestry5HowToAddBindingPrefixCycle">cycle binding prefix</a>, or with CSS: .rowClass:nth-child(even) {background-color: #e8e8e8;}</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Output and Messages</p></th><th colspan="1
 " rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Escaped HTML from property</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:outputText value="myBean.myValue"/&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${myValue}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Raw HTML from property</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{myBean.myValue}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/OutputRaw.html">&lt;t:outputRaw value="myValue"/&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Error messages</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:message&gt; and &lt;h:messages&gt;</p></td><td colspan="1" row
 span="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Error.html">&lt;t:error&gt;</a> and <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Errors.html">&lt;t:errors&gt;</a> (for forms) or <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Alerts.html">&lt;t:alerts&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Image display</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:graphicImage&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>use standard &lt;img&gt; tag, but see <a  href="assets.html">Assets</a><br clear="none"></em></p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Conditionals and Looping</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspa
 n="1" rowspan="1" class="confluenceTh"><p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Render-time loop</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;ui:repeat&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Loop.html">&lt;t:loop&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Compile-time loop</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;c:forEach&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Loop.html">&lt;t:loop&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Conditional</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;c:if test="#{myBean.myValue}"&gt;</p></td><td colspan="1" rows
 pan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/If.html">&lt;t:if test="myValue"&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Conditional</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;ui:fragment rendered="#{myBean.someCondition}"/&gt;...&lt;/ui:fragment&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/If.html">&lt;t:if test="someCondition"&gt;...&lt;/t:if&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Switch</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;c:choose&gt;&lt;c:when ... &gt;&lt;/c:choose&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>See <a  href="switching-cases.html">Switching Cases</a></p></td></tr><tr><td colspan="1" rowspan="1" c
 lass="confluenceTd"><p>Server-side comment</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;ui:remove&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  href="component-templates.html">&lt;t:remove&gt;</a></p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Links and Buttons</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Navigational link</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:link outcome="nextpage.xhtml"/&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/PageLink.html">&lt;t:pagelink page="nextpage"/&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Event-triggering link, without form submission</p></
 td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/ActionLink.html">&lt;t:actionLink&gt;</a> or <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/EventLink.html">&lt;t:eventLink&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Form submission link</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:commandLink&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/LinkSubmit.html">&lt;t:linkSubmit&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Form submission button</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt
 ;h:commandButton&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Submit.html">&lt;t:submit&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Link to Javascript file</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:outputScript&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>&lt;script&gt; or use @Import in component class</em></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Link to CSS file</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:outputStylesheet&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>&lt;style&gt; or use @Import in component class</em></p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Grids, Tables and Trees</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" ro
 wspan="1" class="confluenceTh"><p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Tabular data in &lt;table&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:datatable&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Grid.html">&lt;t:grid&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Table used for layout</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:panelGrid&gt; with &lt;h:panelGroup&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>use standard &lt;table&gt; tag</em></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Hierarchical tree</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>depends on component library</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" hr
 ef="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Tree.html">&lt;t:tree&gt;</a></p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Form Tags/Components</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Form</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:form&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Form.html">&lt;t:form&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Single-line text input field</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:inputText&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/curren
 t/apidocs/org/apache/tapestry5/corelib/components/TextField.html">&lt;t:textField&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Password field</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:inputSecret&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/PasswordField.html">&lt;t:passwordfield&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Select menu</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:selectOneMenu&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Select.html">&lt;t:select&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Checkbox</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:
 selectBooleanCheckbox&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Checkbox.html">&lt;t:checkbox&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Checkbox list</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:selectManyCheckbox&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Checklist.html">&lt;t:checklist&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Radio button list</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:selectOneRadio&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/RadioGroup.html">&lt;t:r
 adioGroup&gt;</a> with <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Radio.html">&lt;t:radio&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Multiple select menu</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:selectManyListbox&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em> (but see Palette and Checklist)</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Hidden field</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:inputHidden&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Hidden.html">&lt;t:hidden&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>textarea tag</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:inputTextarea
 &gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/TextArea.html">&lt;t:textArea&gt;</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Label tag</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&lt;h:outputLabel for="..."&gt;</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Label.html">&lt;t:label for="..."&gt;</a></p></td></tr></tbody></table></div><p>Some important notes:</p><ul><li>With Tapestry, you don't use the ${...} syntax with parameters of components. Just use a bare expression within the quotes. For example: &lt;t:textfield value="myProperty"&gt; instead of &lt;t:textfield value="${myProperty}"&gt;, because in the latter case the expression is converted to a read-only string before the te
 xtfield component gets it.</li></ul><h2 id="TapestryforJSFUsers-HelloWorldComparison">Hello World Comparison</h2><p>Faces templates and Tapestry templates are superficially quite similar.</p><div class="sectionColumnWrapper"><div class="sectionMacro"><div class="sectionMacroRow"><div class="columnMacro"><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>JSF template (helloworld.xhtml)</b></div><div class="codeContent panelContent pdl">
 <pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;html xmlns="http://www.w3.org/1999/xhtml"
         xmlns:h="http://java.sun.com/jsf/html"&gt;
   &lt;h:body&gt;
@@ -167,13 +167,13 @@ public class HelloWorldBean {
     }
 }
 </pre>
-</div></div></div></div></div></div><h2 id="TapestryforJSFUsers-Expressionsintemplates">Expressions in templates</h2><p>JSF uses the Unified Expression Language with the #{...} or ${...} syntax for accessing Backing Bean properties. For its part, Tapestry uses the ${...} syntax with a similar but intentially limited expression language called <a  href="tapestry-for-jsf-users.html">Tapestry for JSF Users</a>. Both allow easy access to properties via the usual JavaBean conventions, but with Tapestry you don't have to specify which class the expression starts at (because it always starts at the component class corresponding to the template). Some comparisons:</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>&#160;</p></td><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF Syntax</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry Syntax</p></th></tr><tr><td colspan="1" rowspan="1" class="confl
 uenceTd"><p>Property (calls getEmployeeName() or setEmployeeName())</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{employeeBean.employeeName}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${employeeName}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Boolean property (calls isHourly() or setHourly())</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{employeeBean.hourly}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${hourly}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Property chain</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{employeeBean.address.street}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${address.street}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Null-safe property chain</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{employeeBean.address.street}</p></td><td colspan="1" rowspan="1" class="confluence
 Td"><p>${address?.street}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>5th element in a List</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{employeeBean.employees[5].name}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${employees.get(5).name}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Negation</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{! employeeBean.hourly}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${! hourly}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Arithmetic &amp; relational operators</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>+-*/% div mod</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Relational operators</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>== != ne &lt; lt &gt; gt &lt;= le &gt;= ge</p></td><
 td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Ternary operator</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{myBean.foo &lt; 0 ? 'bar' : 'baz'}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Method calling</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{myBean.employees.size()}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${employees.size()}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Iterated Range</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not avaialble</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${1..10}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Iterated Range (calculated)</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not avaia
 lble</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${1..groupList.size()}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>List</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${ [ <a  class="external-link" href="http://user.name" rel="nofollow">user.name</a>, user.email, user.phone ] }</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Map</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${ { 'id':'4039','type':'hourly' } }</p></td></tr></tbody></table></div><p>Features shown as <em>not available</em> above are absent by design, because (in both Tapestry and JSF) it is considered best to keep complex logic in the component class rather than in the template.</p><h2 id="TapestryforJSFUsers-EventHandling&amp;PageNavigation">Event Handling &amp
 ; Page Navigation</h2><h3 id="TapestryforJSFUsers-Eventhandling">Event handling</h3><p>In JSF, you specify the event via the <code>action</code> parameter (for example, &lt;h:commandButton value="Submit" action="employeeBean.saveChanges"&gt;). For Tapestry, event handler methods are found by method naming conventions (onSomeEvent() or by method annotations (@Event), based on a combination of the "t:id" attribute and event name, and the action name used depends on the component. For example, the "&lt;t:actionlink&gt;" component in Tapestry emits an "action" event when clicked, and you handle that event in your "onAction()" method.</p><h2 id="TapestryforJSFUsers-Validation">Validation</h2><p>Tapestry applications can use JSR 303 Bean Validation annotations that JSF users should be familiar with:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div></div></div></div></div><h2 id="TapestryforJSFUsers-Expressionsintemplates">Expressions in templates</h2><p>JSF uses the Unified Expression Language with the #{...} or ${...} syntax for accessing Backing Bean properties. For its part, Tapestry uses the ${...} syntax with a similar but intentionally limited expression language called <a  href="property-expressions.html">Property Expressions</a>. Both allow easy access to properties via the usual JavaBean conventions, but with Tapestry you don't have to specify which class the expression starts at (because it always starts at the component class corresponding to the template). Some comparisons:</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>&#160;</p></td><th colspan="1" rowspan="1" class="confluenceTh"><p>JSF Syntax</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Tapestry Syntax</p></th></tr><tr><td colspan="1" rowspan="1" class="conflue
 nceTd"><p>Property (calls getEmployeeName() or setEmployeeName())</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{employeeBean.employeeName}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${employeeName}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Boolean property (calls isHourly() or setHourly())</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{employeeBean.hourly}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${hourly}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Property chain</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{employeeBean.address.street}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${address.street}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Null-safe property chain</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{employeeBean.address.street}</p></td><td colspan="1" rowspan="1" class="confluenceTd
 "><p>${address?.street}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>5th element in a List</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{employeeBean.employees[5].name}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${employees.get(5).name}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Negation</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{! employeeBean.hourly}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${! hourly}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Arithmetic &amp; relational operators</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>+-*/% div mod</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Relational operators</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>== != ne &lt; lt &gt; gt &lt;= le &gt;= ge</p></td><td
  colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Ternary operator</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{myBean.foo &lt; 0 ? 'bar' : 'baz'}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Method calling</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>#{myBean.employees.size()}</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${employees.size()}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Iterated Range</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not avaialble</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${1..10}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Iterated Range (calculated)</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not avaialb
 le</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${1..groupList.size()}</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>List</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${ [ <a  class="external-link" href="http://user.name" rel="nofollow">user.name</a>, user.email, user.phone ] }</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>Map</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><em>not available</em></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>${ { 'id':'4039','type':'hourly' } }</p></td></tr></tbody></table></div><p>Features shown as <em>not available</em> above are absent by design, because (in both Tapestry and JSF) it is considered best to keep complex logic in the component class rather than in the template.</p><h2 id="TapestryforJSFUsers-EventHandling&amp;PageNavigation">Event Handling &amp; 
 Page Navigation</h2><h3 id="TapestryforJSFUsers-Eventhandling">Event handling</h3><p>In JSF, you specify the event via the <code>action</code> parameter (for example, &lt;h:commandButton value="Submit" action="employeeBean.saveChanges"&gt;). For Tapestry, event handler methods are found by method naming conventions (onSomeEvent() or by method annotations (@Event), based on a combination of the "t:id" attribute and event name, and the action name used depends on the component. For example, the "&lt;t:actionlink&gt;" component in Tapestry emits an "action" event when clicked, and you handle that event in your "onAction()" method.</p><h2 id="TapestryforJSFUsers-Validation">Validation</h2><p>Tapestry applications can use JSR 303 Bean Validation annotations that JSF users should be familiar with:</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;">public class Employee {
     @Validate("required,minlength=2,maxlength=100")
     private String lastName;
     @NotNull @Email private String email;
 </pre>
-</div></div><h3 id="TapestryforJSFUsers-Post-Redirect-GetNavigation">Post-Redirect-Get Navigation</h3><p>By default, most JSF URLs are "one page behind". That is, when you click on an &lt;h:commandLink&gt; link or submit a form, the request goes back to the originating page, and the server returns the contents of the <strong>next</strong> page &#8211; but the URL in the browser shows the previous page's URL. To fix this in JSF you add the "?faces-redirect=true" to the URL you return from event handlers, which causes JSF to send a redirect to the browser to navigate to the next page.</p><p>By contrast, Tapestry implements this Post-Redirect-Get pattern by default. The URL will always reflect the page you're seeing, not the page you just came from.</p><p>Note that by default Tapestry does not save property values across the Post-Redirect-Get cycle. This means that you have to consider how (and whether) to persist property values from one page to the next. The usual solution is to eith
 er make the values part of the page's <a  href="tapestry-for-jsf-users.html">Activation Context</a> (which means the values will be appended to the URL) or <a  href="tapestry-for-jsf-users.html">@Persist the properties</a> the values in the session.</p><h2 id="TapestryforJSFUsers-CustomandCompositeComponents">Custom and Composite Components</h2><p>With JSF, creating custom components is an <a  class="external-link" href="http://jsfcorner.blogspot.com/2011/01/custom-components.html" rel="nofollow">advanced topic</a>. In fact, many JSF developers have <em>never</em> created a custom component. In JSF 1.x, creating each custom component requires a lot of work: creating 3 Java classes (component, component renderer and component tag), registering the component in an XML file, and registering the tag in the .tld file. In JSF 2.x <em>composite components</em> can be created without too much work (if your needs can be met by combining existing components <em>and</em> you don't need any cus
 tom Java), but you still have to use cumbersome &lt;composite:interface&gt; and &lt;composite:implementation&gt; tags in your component templates, and you have to list the composite components in the xml namespace declaration at the top of the pages where you are using them.</p><p>Creating true custom components in JSF 2.0 still requires several steps: create a component class (generally having the @FacesComponent annotation and extending UIComponentBase), create a renderer class (generally extending Renderer), add a &lt;renderer&gt; section to the facesconfig file, and create a *-taglib.xml file in the WEB_INF folder that defines the namespace, tag and component type of the custom component.</p><p>In contrast, with Tapestry, <a  href="tapestry-for-jsf-users.html">creating custom components</a> is a <em>beginner</em> topic: it is expected to be a daily activity for developers, because it is so easy. In fact, the steps are the same as creating a page. All you have to do is create a (
 potentially empty) Java class in a "components" sub-package, and create a template file containing (X)HTML markup in the corresponding "components" sub-folder within your package hierarchy under /src/main/resources. You <em>use</em> a custom component just like you use any built-in Tapestry component: <code>&lt;t:mycomponent&gt;</code>.</p><p>Because they're so easy to create, Tapestry applications tend to have a lot of custom components and much less repetition of HTML than most JSF applications.</p><h2 id="TapestryforJSFUsers-OtherReferences">Other References</h2><ul><li><a  class="external-link" href="http://blog.tapestry5.de/wp-content/uploads/2010/06/JSF-2.0-vs-Tapestry-5.pdf" rel="nofollow">JavaServer Faces 2.0 vs. Tapestry 5: A Head-to-Head Comparison</a> slides by Igor Drobiazko, June 2010.</li><li><a  class="external-link" href="http://docs.oracle.com/javaee/6/tutorial/doc/gkhxa.html" rel="nofollow">Composite Components: Advanced Topics and Example</a> part of <em>The Java 
 EE 6 Tutorial</em> from Oracle</li></ul><p>&#160;</p><p></p></div>
+</div></div><h3 id="TapestryforJSFUsers-Post-Redirect-GetNavigation">Post-Redirect-Get Navigation</h3><p>By default, most JSF URLs are "one page behind". That is, when you click on an &lt;h:commandLink&gt; link or submit a form, the request goes back to the originating page, and the server returns the contents of the <strong>next</strong> page &#8211; but the URL in the browser shows the previous page's URL. To fix this in JSF you add the "?faces-redirect=true" to the URL you return from event handlers, which causes JSF to send a redirect to the browser to navigate to the next page.</p><p>By contrast, Tapestry implements this Post-Redirect-Get pattern by default. The URL will always reflect the page you're seeing, not the page you just came from.</p><p>Note that by default Tapestry does not save property values across the Post-Redirect-Get cycle. This means that you have to consider how (and whether) to persist property values from one page to the next. The usual solution is to eith
 er make the values part of the page's <a  href="page-navigation.html">Activation Context</a> (which means the values will be appended to the URL) or <a  href="persistent-page-data.html">@Persist the properties</a> the values in the session.</p><h2 id="TapestryforJSFUsers-CustomandCompositeComponents">Custom and Composite Components</h2><p>With JSF, creating custom components is an <a  class="external-link" href="http://jsfcorner.blogspot.com/2011/01/custom-components.html" rel="nofollow">advanced topic</a>. In fact, many JSF developers have <em>never</em> created a custom component. In JSF 1.x, creating each custom component requires a lot of work: creating 3 Java classes (component, component renderer and component tag), registering the component in an XML file, and registering the tag in the .tld file. In JSF 2.x <em>composite components</em> can be created without too much work (if your needs can be met by combining existing components <em>and</em> you don't need any custom Java)
 , but you still have to use cumbersome &lt;composite:interface&gt; and &lt;composite:implementation&gt; tags in your component templates, and you have to list the composite components in the xml namespace declaration at the top of the pages where you are using them.</p><p>Creating true custom components in JSF 2.0 still requires several steps: create a component class (generally having the @FacesComponent annotation and extending UIComponentBase), create a renderer class (generally extending Renderer), add a &lt;renderer&gt; section to the facesconfig file, and create a *-taglib.xml file in the WEB_INF folder that defines the namespace, tag and component type of the custom component.</p><p>In contrast, with Tapestry, <a  href="component-classes.html">creating custom components</a> is a <em>beginner</em> topic: it is expected to be a daily activity for developers, because it is so easy. In fact, the steps are the same as creating a page. All you have to do is create a (potentially em
 pty) Java class in a "components" sub-package, and create a template file containing (X)HTML markup in the corresponding "components" sub-folder within your package hierarchy under /src/main/resources. You <em>use</em> a custom component just like you use any built-in Tapestry component: <code>&lt;t:mycomponent&gt;</code>.</p><p>Because they're so easy to create, Tapestry applications tend to have a lot of custom components and much less repetition of HTML than most JSF applications.</p><h2 id="TapestryforJSFUsers-OtherReferences">Other References</h2><ul><li><a  class="external-link" href="http://blog.tapestry5.de/wp-content/uploads/2010/06/JSF-2.0-vs-Tapestry-5.pdf" rel="nofollow">JavaServer Faces 2.0 vs. Tapestry 5: A Head-to-Head Comparison</a> slides by Igor Drobiazko, June 2010.</li><li><a  class="external-link" href="http://docs.oracle.com/javaee/6/tutorial/doc/gkhxa.html" rel="nofollow">Composite Components: Advanced Topics and Example</a> part of <em>The Java EE 6 Tutorial<
 /em> from Oracle</li></ul><p>&#160;</p><p></p></div>
       </div>
 
       <div class="clearer"></div>