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> </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> </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;"><?xml version="1.0" encoding="UTF-8"?>
<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: </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&Responses">Component Event
Requests & 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: </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&Responses">Component Event
Requests & 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&Responses">Component Event
Requests & Responses</h2><p>Main Article:  <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 – validation – 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 <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> <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> <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 <img> 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 <img> 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 <img> 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 <img> 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"Any"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> </p><p> </p><p> </p><p> </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 & 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><h:outputText
value="myBean.myValue"/></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"><t:outputRaw
value="myValue"/></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><h:message> and <h:messages></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"><t:error></a>
and <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Errors.html"><t:errors></a>
(for forms) or <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Alerts.html"><t:alerts></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><h:graphicImage></p></td><td colspan="1"
rowspan="1" class="confluenceTd"><p><em>use standard <img>
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><ui:repeat></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"><t:loop></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><c:forEach></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"><t:loop></a></p></td></tr><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p>Conditional</p></td><td
colspan="1" rowspan="1" class="confluenceTd"><p><c:if
test="#{myBean.myValue}"></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"><t:if
test="myValue"></a></p></td></tr><tr><td colspan="1" rowspan="1"
class="confluenceTd"><p>Conditional</p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><ui:fragment
rendered="#{myBean.someCondition}"/>...</ui:fragment></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"><t:if
test="someCondition">...</t:if></a></p></td></tr><tr><td colspan="1"
rowspan="1" class="confluenceTd"><p>Switch</p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><c:choose><c:when ...
></c:choose></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><ui:remove></p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><a
href="tapestry-for-jsf-users.html"><t:remove></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><h:link
outcome="nextpage.xhtml"/></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"><t:pagelink
page="nextpage"/></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"><t:actionLink></a>
or <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/EventLink.html"><t:eventLink></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><h:commandLink></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"><t:linkSubmit></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><h:commandButton></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"><t:submit></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><h:outputScript></p></td><td colspan="1"
rowspan="1" class="confluenceTd"><p><em><script> 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><h:outputStylesheet></p></td><td colspan="1"
rowspan="1" class="confluenceTd"><p><em><style> 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 <table></p></td><td colspan="1"
>rowspan="1" class="confluenceTd"><p><h:datatable></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"><t:grid></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><h:panelGrid> with
><h:panelGroup></p></td><td colspan="1" rowspan="1"
>class="confluenceTd"><p><em>use standard <table>
>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"><t:tree></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><h:form></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"><t:form></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><h:inputText></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"><t:textField></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><h:inputSecret></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"><t:passwordfield></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><h:selectOneMenu></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"><t:select></a></p></td></tr><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p>Checkbox</p></td><td
colspan="1" rowspan="1"
class="confluenceTd"><p><h:selectBooleanCheckbox></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"><t:checkbox></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><h:selectManyCheckbox></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"><t:checklist></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><h:selectOneRadio></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"><t:radioGroup></a>
> with <a class=
"external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Radio.html"><t:radio></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><h:selectManyListbox></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><h:inputHidden></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"><t:hidden></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><h:inputTextarea></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"><t:textArea></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><h:outputLabel
for="..."></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"><t:label
for="..."></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: <t:textfield value="myProperty"> instead of <t:textfield
value="${myProperty}">, 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 & 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><h:outputText
value="myBean.myValue"/></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"><t:outputRaw
value="myValue"/></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><h:message> and <h:messages></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"><t:error></a>
and <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Errors.html"><t:errors></a>
(for forms) or <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Alerts.html"><t:alerts></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><h:graphicImage></p></td><td colspan="1"
rowspan="1" class="confluenceTd"><p><em>use standard <img> 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><ui:repeat></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"><t:loop></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><c:forEach></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"><t:loop></a></p></td></tr><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p>Conditional</p></td><td
colspan="1" rowspan="1" class="confluenceTd"><p><c:if
test="#{myBean.myValue}"></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"><t:if
test="myValue"></a></p></td></tr><tr><td colspan="1" rowspan="1"
class="confluenceTd"><p>Conditional</p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><ui:fragment
rendered="#{myBean.someCondition}"/>...</ui:fragment></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"><t:if
test="someCondition">...</t:if></a></p></td></tr><tr><td colspan="1"
rowspan="1" class="confluenceTd"><p>Switch</p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><c:choose><c:when ...
></c:choose></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><ui:remove></p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><a
href="component-templates.html"><t:remove></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><h:link
outcome="nextpage.xhtml"/></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"><t:pagelink
page="nextpage"/></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"><t:actionLink></a>
or <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/EventLink.html"><t:eventLink></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><h:commandLink></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"><t:linkSubmit></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><
;h:commandButton></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"><t:submit></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><h:outputScript></p></td><td colspan="1"
rowspan="1" class="confluenceTd"><p><em><script> 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><h:outputStylesheet></p></td><td colspan="1"
rowspan="1" class="confluenceTd"><p><em><style> 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 <table></p></td><td
colspan="1" rowspan="1" class="confluenceTd"><p><h:datatable></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"><t:grid></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><h:panelGrid> with
<h:panelGroup></p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><em>use standard <table>
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"><t:tree></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><h:form></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"><t:form></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><h:inputText></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"><t:textField></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><h:inputSecret></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"><t:passwordfield></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><h:selectOneMenu></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"><t:select></a></p></td></tr><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p>Checkbox</p></td><td
colspan="1" rowspan="1" class="confluenceTd"><p><h:
selectBooleanCheckbox></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"><t:checkbox></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><h:selectManyCheckbox></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"><t:checklist></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><h:selectOneRadio></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"><t:r
adioGroup></a> with <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Radio.html"><t:radio></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><h:selectManyListbox></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><h:inputHidden></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"><t:hidden></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><h:inputTextarea
></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"><t:textArea></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><h:outputLabel
for="..."></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"><t:label
for="..."></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: <t:textfield value="myProperty"> instead of <t:textfield
value="${myProperty}">, 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;"><html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
@@ -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> </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 & 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 > gt <= le >=
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 < 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&PageNavigation">Event Handling &
; 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, <h:commandButton value="Submit"
action="employeeBean.saveChanges">). 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
"<t:actionlink>" 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> </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 & 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 > gt <= le >=
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 < 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&PageNavigation">Event Handling &
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, <h:commandButton value="Submit"
action="employeeBean.saveChanges">). 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
"<t:actionlink>" 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 <h:commandLink> 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 – 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 <composite:interface>
and <composite:implementation> 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
<renderer> 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><t:mycomponent></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> </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 <h:commandLink> 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 – 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 <composite:interface> and
<composite:implementation> 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 <renderer> 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><t:mycomponent></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> </p><p></p></div>
</div>
<div class="clearer"></div>