Modified: websites/production/tapestry/content/persistent-page-data.html
==============================================================================
--- websites/production/tapestry/content/persistent-page-data.html (original)
+++ websites/production/tapestry/content/persistent-page-data.html Mon Jul 11 
07:12:07 2022
@@ -160,7 +160,7 @@
                 <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a href="session-storage.html">Session Storage</a>
+                        <a href="performance-and-clustering.html">Performance 
and Clustering</a>
                 
                         
                     </div>
@@ -169,7 +169,7 @@
                 <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a href="performance-and-clustering.html">Performance 
and Clustering</a>
+                        <a href="session-storage.html">Session Storage</a>
                 
                         
                     </div>
@@ -190,10 +190,10 @@
 <pre><code class="language-java">  @Persist
   private int value;
 </code></pre>
-</div></div><p>Such annotated fields will retain their state between requests. 
Generally, speaking, this means that the value is stored into the session (but 
other approaches are possible).</p><p>Whenever you make a change to a 
persistent field, its value is saved. On later requests to the same page, the 
value for the field is restored.</p><h2 
id="PersistentPageData-PersistenceStrategies">Persistence Strategies</h2><p>The 
value for each field is the <em>strategy</em> used to store the field between 
requests.</p><h3 id="PersistentPageData-SessionStrategy">Session 
Strategy</h3><div class="navmenu" style="float:right; background:#eee; 
margin:3px; padding:0 1em">
+</div></div><p>Such annotated fields will retain their state between requests. 
Generally, speaking, this means that the value is stored into the session (but 
other approaches are possible).</p><p>Whenever you make a change to a 
persistent field, its value is saved. On later requests to the same page, the 
value for the field is restored.</p><h2 
id="PersistentPageData-PersistenceStrategies">Persistence Strategies</h2><p>The 
value for each field is the <em>strategy</em> used to store the field between 
requests.</p><h3 id="PersistentPageData-SessionStrategy">Session 
Strategy</h3><p></p><div class="navmenu" style="float:right; background:#eee; 
margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demo:</strong>
-    <span class="nobr"><a class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/state/storingdatainapage";
 rel="nofollow">Storing Data in a Page<sup><img align="middle" 
class="rendericon" src="/images/confluence/icons/linkext7.gif" height="7" 
width="7" alt="" border="0"></sup></a></span>
-    <span class="nobr"><a class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/state/passingdatabetweenpages";
 rel="nofollow">Passing Data Between Pages<sup><img align="middle" 
class="rendericon" src="/images/confluence/icons/linkext7.gif" height="7" 
width="7" alt="" border="0"></sup></a></span></p></div>The session strategy 
stores field changes into the session; the session is created as necessary. 
Session strategy is the default strategy used unless otherwise overridden.<p>A 
suitably long session attribute name is used; it incorporates the name of the 
page, the nested component id, and the name of the field.</p><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>Example: Session Strategy</b></div><div 
class="codeContent panelContent pdl">
+    <span class="nobr"><a class="external-link" 
href="https://tapestry-jumpstart.org/jumpstart/examples/state/storingdatainapage";
 rel="nofollow">Storing Data in a Page<sup><img align="middle" 
class="rendericon" src="/images/confluence/icons/linkext7.gif" height="7" 
width="7" alt="" border="0"></sup></a></span>
+    <span class="nobr"><a class="external-link" 
href="https://tapestry-jumpstart.org/jumpstart/examples/state/passingdatabetweenpages";
 rel="nofollow">Passing Data Between Pages<sup><img align="middle" 
class="rendericon" src="/images/confluence/icons/linkext7.gif" height="7" 
width="7" alt="" border="0"></sup></a></span></p></div>The session strategy 
stores field changes into the session; the session is created as necessary. 
Session strategy is the default strategy used unless otherwise 
overridden.<p></p><p>A suitably long session attribute name is used; it 
incorporates the name of the page, the nested component id, and the name of the 
field.</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>Example: Session Strategy</b></div><div class="codeContent 
panelContent pdl">
 <pre><code class="language-java">  @Persist
   private int value;
 </code></pre>
@@ -208,7 +208,7 @@
 </div></div><h3 id="PersistentPageData-HibernateEntityStrategy">Hibernate 
Entity Strategy</h3><p><span>Entity persistence is provided by the 
tapestry-hibernate module (which extends Tapestry with new 
features).</span></p><p>In Entity persistence, the field should store a 
Hibernate entity instance.</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>"Hibernate Entity Strategy"</b></div><div class="codeContent 
panelContent pdl">
 <pre><code class="language-java">  
@Persist(HibernatePersistenceConstants.ENTITY)
   private User user;</code></pre>
-</div></div><p>The value stored in the HttpSession is a&#160;<em>token</em> 
for the entity: its Java class name and primary key. When the field is restored 
in a later request, the entity is re-instantiated using that data.</p><p>What 
is&#160;<em>not</em> stored is any changes to the persistent entity that are 
not committed to the external datastore (the database).</p><p>Starting in 
Tapestry 5.4, it is possible to store a non-persistent entity (a transient 
entity). A transient entity is stored directly into the HttpSession, and should 
be Serializable if the application is clustered.</p><h3 
id="PersistentPageData-JPAEntityStrategy">JPA Entity Strategy</h3><p>The 
tapestry-jpa module uses a similar strategy. However, at the current time it 
can only store a persisted entity (one that has been saved to the database and 
has a primary key).</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>"Example: JPA Ent
 ity Strategy"</b></div><div class="codeContent panelContent pdl">
+</div></div><p></p><p>The value stored in the HttpSession is 
a&#160;<em>token</em> for the entity: its Java class name and primary key. When 
the field is restored in a later request, the entity is re-instantiated using 
that data.</p><p>What is&#160;<em>not</em> stored is any changes to the 
persistent entity that are not committed to the external datastore (the 
database).</p><p>Starting in Tapestry 5.4, it is possible to store a 
non-persistent entity (a transient entity). A transient entity is stored 
directly into the HttpSession, and should be Serializable if the application is 
clustered.</p><h3 id="PersistentPageData-JPAEntityStrategy">JPA Entity 
Strategy</h3><p>The tapestry-jpa module uses a similar strategy. However, at 
the current time it can only store a persisted entity (one that has been saved 
to the database and has a primary key).</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>"Example: 
 JPA Entity Strategy"</b></div><div class="codeContent panelContent pdl">
 <pre><code class="language-java">  @Persist(JpaPersistenceConstants.ENTITY)
   private Account account;</code></pre>
 </div></div><h3 id="PersistentPageData-PersistenceStrategyInheritance"><span 
style="color: rgb(83,145,38);">Persistence Strategy 
Inheritance</span></h3><p>By default the value for the Persist annotation is 
the empty string. When this is true, then the actual strategy to be used is 
determined by a search up the component hierarchy.</p><p>For each component, 
the meta-data property <code>tapestry.persistence-strategy</code> is checked. 
This can be specified using the @<a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Meta.html";>Meta</a>
 annotation.</p><p>If the value is non-blank, then that strategy is used. This 
allows a component to control the persistence strategy used inside any 
sub-components (that don't explicitly use a different strategy).</p><p>In any 
case, if no component provides the meta data, then the ultimate default, 
"session", is used.</p><h2 id="PersistentPageData-DefaultValues">Default 
Values</h2><p>Fields marked
  with @Persist may not have default values (whether set inline, or inside a 
constructor).</p><h2 id="PersistentPageData-ClearingPersistentFields">Clearing 
Persistent Fields</h2><p>If you reach a point where you know that all data for 
a page can be discarded, you can do exactly that.</p><p>The method 
<code>discardPersistentFieldChanges()</code> of ComponentResources will discard 
all persistent fields for the page, regardless of which strategy is used to 
store the property. This will not affect the page in memory, but takes effect 
for subsequent requests.</p><h2 
id="PersistentPageData-ClusteringIssues">Clustering Issues</h2><p>The Servlet 
API was designed with the intention that there would be only a modest amount of 
server-side state, and that the stored values would be individual numbers and 
strings, and thus, immutable.</p><p>However, many web applications do not use 
the HttpSession this way, instead storing large, mutable objects in the 
session. This is not a problem for single se
 rvers, but in a cluster, anything stored in the session must be serialized to 
a bytestream and distributed to other servers within the cluster, and restored 
there.</p><p>Most application servers perform that serialization and 
distribution whenever HttpSession.setAttribute() is called. This creates a data 
consistency problem for mutable objects, because if you read a mutable session 
object, change its state, but <em>don't</em> invoke setAttribute(), the changes 
will be isolated to just a single server in the cluster.</p><p>Tapestry 
attempts to solve this: any session-persisted object that is read during a 
request will be re-stored back into the HttpSession at the end of the request. 
This ensures that changed internal state of those mutable objects is properly 
replicated around the cluster.</p><p>But while this solution solves the data 
consistency problem, it does so at the expense of performance, since all of 
those calls to setAttribute() result in extra session data being replicated
  needlessly if the internal state of the mutable object hasn't 
changed.</p><p>Tapestry has solutions to this, too:</p><h3 
id="PersistentPageData-@ImmutableSessionPersistedObjectAnnotation">@ImmutableSessionPersistedObject
 Annotation</h3><p>Tapestry knows that Java's String, Number and Boolean 
classes are immutable. Immutable objects do not require a re-store into the 
session.</p><p>You can mark your own session objects as immutable (and thus not 
requiring session replication) using the <a class="external-link" 
href="https://tapestry.apache.org/current/apidocs/org/apache/tapestry5/http/annotations/ImmutableSessionPersistedObject.html";>ImmutableSessionPersistedObject</a>
 annotation.</p><h3 
id="PersistentPageData-OptimizedSessionPersistedObjectInterface">OptimizedSessionPersistedObject
 Interface</h3><p>The <a class="external-link" 
href="https://tapestry.apache.org/current/apidocs/org/apache/tapestry5/http/OptimizedSessionPersistedObject.html";>OptimizedSessionPersistedObject</a>
 interfa
 ce allows an object to control this behavior. An object with this interface 
can track when its mutable state changes. Typically, you should extend from the 
<a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/BaseOptimizedSessionPersistedObject.html";>BaseOptimizedSessionPersistedObject</a>
 base class.</p><h3 
id="PersistentPageData-SessionPersistedObjectAnalyzerService">SessionPersistedObjectAnalyzer
 Service</h3><p>The <a class="external-link" 
href="https://tapestry.apache.org/current/apidocs/org/apache/tapestry5/http/services/SessionPersistedObjectAnalyzer.html";>SessionPersistedObjectAnalyzer</a>
 service is ultimately responsible for determining whether a session persisted 
object is dirty or not (dirty meaning in need of a restore into the session). 
This is an extensible service where new strategies, for new classes, can be 
introduced.</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="bo
 rder-bottom-width: 1px;"><b>Example: Entity Session Strategy</b></div><div 
class="codeContent panelContent pdl">

Modified: websites/production/tapestry/content/security.html
==============================================================================
--- websites/production/tapestry/content/security.html (original)
+++ websites/production/tapestry/content/security.html Mon Jul 11 07:12:07 2022
@@ -197,7 +197,7 @@
 
 <p></p><h2 id="Security-HTTPS-onlyPages">HTTPS-only Pages</h2><p>Main Article: 
<a href="https.html">HTTPS</a></p><p>Tapestry provides several annotations and 
configuration settings that you can use to&#160;<span>ensure that all access to 
certain pages (or all pages) occurs only via the encrypted HTTPS 
protocol</span><span>. See&#160;<a href="https.html">HTTPS</a> for 
details.</span></p><h2 id="Security-ControllingPageAccess"><span>Controlling 
Page Access</span></h2><p></p><div class="navmenu" style="float:right; 
background:#eee; margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demo:</strong>
-    <span class="nobr"><a class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/protectingpages";
 rel="nofollow">Protecting Pages<sup><img align="middle" class="rendericon" 
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt="" 
border="0"></sup></a></span></p></div><p><span>For simple access control needs, 
you can contribute a&#160;<span><a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ComponentRequestFilter.html";>ComponentRequestFilter</a>
 with your custom logic that decides which pages should be accessed by which 
users. The <a class="external-link" 
href="https://tapestry-app.apache.org/hotels/";>Tapestry Hotel Booking </a>app 
demonstrates this approach with an <code>@AnonymousAccess</code> annotation 
along with a ComponentRequestFilter 
named&#160;<code>AuthenticationFilter.java</code>. The filter enforces security 
by intercepting all requests to pages that don't hav
 e that annotation, and it redirects those requests to the login page. <a 
class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/protectingpages";
 rel="nofollow">JumpStart</a> has a similar 
demo.</span></span></p><p></p><p><span>For more advanced needs see the Security 
Framework Integration section below.</span></p><h2 
id="Security-White-listedPages">White-listed Pages</h2><p>Pages whose component 
classes are annotated with&#160;@<a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/WhitelistAccessOnly.html";>WhitelistAccessOnly</a>&#160;will
 only be displayed to users (clients) that are on the&#160;<em>whitelist</em>. 
By default the whitelist consists only of clients whose fully-qualified domain 
name is "localhost" (or the IP address equivalent, 127.0.0.1 or 
0:0:0:0:0:0:0:1),&#160;but you can customize this by contributing to the 
ClientWhitelist service&#160;in your application's module 
 class (usually AppModule.java):</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>AppModule.java (partial) &#8211; simple 
inline example</b></div><div class="codeContent panelContent pdl">
+    <span class="nobr"><a class="external-link" 
href="https://tapestry-jumpstart.org/jumpstart/examples/infrastructure/protectingpages";
 rel="nofollow">Protecting Pages<sup><img align="middle" class="rendericon" 
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt="" 
border="0"></sup></a></span></p></div><span>For simple access control needs, 
you can contribute a&#160;<span><a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ComponentRequestFilter.html";>ComponentRequestFilter</a>
 with your custom logic that decides which pages should be accessed by which 
users. The <a class="external-link" 
href="https://tapestry-app.apache.org/hotels/";>Tapestry Hotel Booking </a>app 
demonstrates this approach with an <code>@AnonymousAccess</code> annotation 
along with a ComponentRequestFilter 
named&#160;<code>AuthenticationFilter.java</code>. The filter enforces security 
by intercepting all requests to pages that don't have that anno
 tation, and it redirects those requests to the login page. <a 
class="external-link" 
href="https://tapestry-jumpstart.org/jumpstart/examples/infrastructure/protectingpages";
 rel="nofollow">JumpStart</a> has a similar 
demo.</span></span><p></p><p><span>For more advanced needs see the Security 
Framework Integration section below.</span></p><h2 
id="Security-White-listedPages">White-listed Pages</h2><p>Pages whose component 
classes are annotated with&#160;@<a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/WhitelistAccessOnly.html";>WhitelistAccessOnly</a>&#160;will
 only be displayed to users (clients) that are on the&#160;<em>whitelist</em>. 
By default the whitelist consists only of clients whose fully-qualified domain 
name is "localhost" (or the IP address equivalent, 127.0.0.1 or 
0:0:0:0:0:0:0:1),&#160;but you can customize this by contributing to the 
ClientWhitelist service&#160;in your application's module class (usually 
AppModul
 e.java):</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>AppModule.java (partial) &#8211; simple inline example</b></div><div 
class="codeContent panelContent pdl">
 <pre><code class="language-java">    @Contribute(ClientWhitelist.class)
     public static void 
provideWhitelistAnalyzer(OrderedConfiguration&lt;WhitelistAnalyzer&gt; 
configuration)
     {
@@ -210,7 +210,7 @@
             }
         }, "before:*");
     }</code></pre>
-</div></div><p></p><p>Sometimes, in production, a firewall or proxy may make 
it look like the client web browser originates from localhost, with the 
consequence that whitelisted pages may be visible to all users. See the&#160;<a 
href="security-faq.html">Security FAQ</a> for how to deal with this.</p><h2 
id="Security-AssetSecurity">Asset Security</h2><p>Main Article:&#160;<a 
href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=85462227";>Security</a></p><p
 class="confluence-link">Tapestry serves assets (static content such as CSS 
files, images, and JavaScript, many of which are on the classpath alongside 
your compiled class files) to the client.&#160;Because of this, great care has 
gone into ensuring that certain file types cannot be served to the client. By 
default, file ending with ".class', ".tml" and ".properties" can be served to 
the client only if the request includes the file's MD5 checksum. As you would 
expect, that blacklist can be extended. See <a href="ass
 ets.html">Assets</a> for more information.</p><h2 
id="Security-ProtectingSerializedObjectDataontheClient">Protecting Serialized 
Object Data on the Client</h2><p><span style="color: rgb(0,0,0);">As of version 
5.3.6, Tapestry integrates a&#160;</span><a class="external-link" 
style="text-decoration: underline;text-align: justify;" 
href="http://en.wikipedia.org/wiki/HMAC"; rel="nofollow">hash-based message 
authentication code</a><span style="color: rgb(0,0,0);">&#160;(HMAC) into 
serialized Java object data that it sends to the client (generally, this means 
the&#160;</span><code style="text-align: justify;">t:formdata</code><span 
style="color: rgb(0,0,0);">&#160;hidden field used by the Form component). This 
ensures that the hidden binary object data is guaranteed to be unaltered when 
it returns to the server upon form (or AJAX) submission. The HMAC pass phrase 
is set using the&#160;<a href="configuration.html">tapestry.hmac-passphrase</a> 
configuration symbol. If you don't set that value
 , you'll see a warning message in the browser, like this:&#160;</span></p><div 
class="preformatted panel" style="border-width: 1px;"><div 
class="preformattedContent panelContent">
+</div></div><p></p><p>Sometimes, in production, a firewall or proxy may make 
it look like the client web browser originates from localhost, with the 
consequence that whitelisted pages may be visible to all users. See the&#160;<a 
href="security-faq.html">Security FAQ</a> for how to deal with this.</p><h2 
id="Security-AssetSecurity">Asset Security</h2><p>Main Article:&#160;<a 
href="security.html">Security</a></p><p class="confluence-link">Tapestry serves 
assets (static content such as CSS files, images, and JavaScript, many of which 
are on the classpath alongside your compiled class files) to the 
client.&#160;Because of this, great care has gone into ensuring that certain 
file types cannot be served to the client. By default, file ending with 
".class', ".tml" and ".properties" can be served to the client only if the 
request includes the file's MD5 checksum. As you would expect, that blacklist 
can be extended. See <a href="assets.html">Assets</a> for more 
information.</p><h2 id="Securi
 ty-ProtectingSerializedObjectDataontheClient">Protecting Serialized Object 
Data on the Client</h2><p><span style="color: rgb(0,0,0);">As of version 5.3.6, 
Tapestry integrates a&#160;</span><a class="external-link" 
style="text-decoration: underline;text-align: justify;" 
href="http://en.wikipedia.org/wiki/HMAC"; rel="nofollow">hash-based message 
authentication code</a><span style="color: rgb(0,0,0);">&#160;(HMAC) into 
serialized Java object data that it sends to the client (generally, this means 
the&#160;</span><code style="text-align: justify;">t:formdata</code><span 
style="color: rgb(0,0,0);">&#160;hidden field used by the Form component). This 
ensures that the hidden binary object data is guaranteed to be unaltered when 
it returns to the server upon form (or AJAX) submission. The HMAC pass phrase 
is set using the&#160;<a href="configuration.html">tapestry.hmac-passphrase</a> 
configuration symbol. If you don't set that value, you'll see a warning message 
in the browser, like this:&#1
 60;</span></p><div class="preformatted panel" style="border-width: 1px;"><div 
class="preformattedContent panelContent">
 <pre>The symbol 'tapestry.hmac-passphrase' has not been configured. This is 
used to configure hash-based message authentication of Tapestry data stored in 
forms, or in the URL. You application is less secure, and more vulnerable to 
denial-of-service attacks, when this symbol is not configured.</pre>
 </div></div><p><span style="color: rgb(0,0,0);">The solution is to set the 
tapestry.hmac-passphrase to some value (any fixed, private string, such as 30 
to 40 random-looking characters, will do) in your application's module class 
(usually AppModule.java).</span></p><h2 
id="Security-CrossSiteRequestForgery(CSRF)"><span style="color: 
rgb(83,145,38);">Cross Site Request Forgery (CSRF)</span></h2><p>Cross Site 
Request Forgery is a type of security vulnerability in which legitimate, 
authorized users may be made to unwittingly submit malicious requests to your 
web application.</p><p><a class="external-link" 
href="https://github.com/porscheinformatik/tapestry-csrf-protection"; 
rel="nofollow">Tapestry-csrf-protection</a>&#160;is a 3rd party module that has 
several features for preventing CSRF attacks. It protects 
all&#160;<span>component event handlers (event links, forms, etc.) by adding 
a&#160;</span><span>CSRF token to event links and adds a CSRF token as a hidden 
field to all forms.&#160
 ;</span><span>Tokens are generated on a per-session basis.</span></p><h2 
id="Security-SecurityFrameworkIntegration"><span>Security Framework 
Integration</span></h2><p>Tapestry does not lock you into a specific 
authentication/authorization implementation. There are integration modules 
available for the more popular open source Java security frameworks. A popular 
choice among Tapestry users is <a class="external-link" 
href="http://www.tynamo.org/tapestry-security+guide/"; 
rel="nofollow">tapestry-security (based on Apache Shiro) from Tynamo.org</a>. 
It is always kept up-to-date with the latest Tapestry versions and offers 
several supporting security modules (e.g. <a class="external-link" 
href="http://www.tynamo.org/tapestry-security-jpa+guide/"; 
rel="nofollow">tapestry-security-jpa</a>, <a class="external-link" 
href="http://www.tynamo.org/tynamo-federatedaccounts+guide/"; 
rel="nofollow">tynamo-federatedaccounts</a>). There's also an <a 
class="external-link" href="http://www.localhost.nu/j
 ava/tapestry-spring-security" rel="nofollow">integration module available for 
Spring Security</a> but lately, it hasn't kept up with the latest versions of 
Tapestry 5.</p><p>Additional information:</p><ul><li><a class="external-link" 
href="http://www.tynamo.org/tynamo-federatedaccounts+guide/"; 
rel="nofollow">Tynamo-federatedaccounts</a>&#160;<span style="color: 
rgb(0,0,0);">is an add-on to the&#160;</span><a class="external-link" 
href="http://www.tynamo.org/tapestry-security+guide/"; 
rel="nofollow">tapestry-security</a><span style="color: 
rgb(0,0,0);">&#160;module, providing federated (third-party) authentication 
with Facebook, Twitter or Google.</span></li></ul><ul><li><span>To include 
OpenID with Spring Security in your application, see the following Wiki 
entry:&#160;</span><a class="external-link" 
href="http://wiki.apache.org/tapestry/Tapestry5HowToSpringSecurityAndOpenId";>http://wiki.apache.org/tapestry/Tapestry5HowToSpringSecurityAndOpenId</a></li></ul><h2
 id="Security-Vulnerabi
 lityDisclosures">Vulnerability Disclosures</h2><h3 
id="Security-CVE-2019-0195:FilereadingLeadstoJavaDeserializationVulnerability.">CVE-2019-0195:
 File reading Leads to Java Deserialization Vulnerability.</h3><p>Disclosure 
date:&#160;<a class="external-link" 
href="https://lists.apache.org/thread.html/5173c4eed06e2fca6fd5576ed723ff6bb1711738ec515cb51a04ab24@%3Cusers.tapestry.apache.org%3E";>September
 13th, 2019</a></p><p>Versions affected: all Apache Tapestry versions from 
5.4.0 (including its betas) through 5.4.3</p><p>Description:&#160;Manipulating 
classpath asset file URLs, an attacker could guess the path to&#160;a known 
file in the classpath and have it downloaded. If the attacker&#160;found the 
file with the value of the tapestry.hmac-passphrase configuration&#160;symbol, 
most probably the webapp's AppModule class, the value of this&#160;symbol could 
be used to craft a Java deserialization attack, thus running&#160;malicious 
injected Java code. The vector would be the t:formdata 
 parameter&#160;from the Form component.</p><p>Mitigation: Upgrade to Tapestry 
5.4.5, which is a drop-in replacement for any 5.4.x version.</p><p>Credit: 
Ricter Zheng</p><h3 
id="Security-CVE-2019-0207:ApacheTapestry5.4.2PathTraversalvulnerability">CVE-2019-0207:
 Apache Tapestry 5.4.2 Path Traversal vulnerability</h3><p>Disclosure 
date:&#160;<a class="external-link" 
href="https://lists.apache.org/thread.html/765be3606d865de513f6df9288842c3cf58b09a987c617a535f2b99d@%3Cusers.tapestry.apache.org%3E";>September
 13th, 2019</a></p><p>Versions affected: all Apache Tapestry versions from 
5.4.0 (including its betas) through 5.4.4.</p><p>Description: Tapestry 
processes assets `/assets/ctx` using classes chain `StaticFilesFilter -&gt; 
AssetDispatcher -&gt; ContextResource`, which doesn't filter the character `\`, 
so attacker can perform a path traversal attack to read any files on Windows 
platform.</p><p>Mitigation: Upgrade to Tapestry 5.4.5, which is a drop-in 
replacement for any 5.4.x version.<
 /p><p>Credit: Ricter Zheng</p><h3 
id="Security-CVE-2019-10071:NewIssueinFixforCVE-2014-1972">CVE-2019-10071: New 
Issue in Fix for CVE-2014-1972</h3><p>Disclosure date: <a 
rel="nofollow">September 13th, 2019</a></p><p>Versions affected: all Apache 
Tapestry versions from 5.4.0 (including its&#160;betas) through 
5.4.3</p><p>Description: The code which checks HMAC in form submissions 
usedString.equals() for comparisons, which results in a timing side channel 
vulnerability inthe comparison of the HMAC signatures. This could lead to 
remote codeexecution if an attacker is able to determine the correct signature 
fortheir payload. The comparison should have been done with a constant time 
algorithm instead.</p><p>Mitigation: Upgrade to Tapestry 5.4.5, which is a 
drop-in replacement for any 5.4.xversion.</p><p>Credit:&#160;</p><pre>David 
Tomaschik of the Google Security Team</pre><h3 
id="Security-CVE-2019-10071:BypassofthefixforCVE-2019-0195">CVE-2019-10071:&#160;Bypass
 of the fix for CVE-2019
 -0195</h3><p>Disclosure date: <a rel="nofollow">March 14th, 
2021</a></p><p>Versions affected: all Apache Tapestry versions from 5.4.0 
(including its&#160;betas) through 5.6.1, plus 5.7.0.</p><p>Description: A 
critical unauthenticated remote code execution vulnerability was found&#160;all 
recent versions of Apache Tapestry.&#160;The affected versions include 5.4.5, 
5.5.0, 5.6.2 and 5.7.0.</p><p>The vulnerability I have found is a bypass of the 
fix for CVE-2019-0195.&#160;</p><p>Recap:</p><p>Before the fix of CVE-2019-0195 
it was possible to download arbitrary class files from the classpath by 
providing a crafted asset file URL.&#160;An attacker was able to download the 
file `AppModule.class` by&#160;requesting the URL&#160;`<span 
class="nolink">http://localhost:8080/assets/something/services/AppModule.class</span>`
 which contains a HMAC secret key.&#160;The fix for that bug was a blacklist 
filter that checks if the URL&#160;ends with `.class`, `.properties` or 
`.xml`.</p><p>Bypass:</
 p><p>Unfortunately, the blacklist solution can simply be bypassed by appending 
a `/` at the end of the URL: 
`http://localhost:8080/assets/something/services/AppModule.class/`</p><p>The 
slash is stripped after the blacklist check and the file `AppModule.class` is 
loaded into the response.&#160;This class usually contains the HMAC secret key 
which is used to sign</p><p>serialized Java objects.&#160;With the knowledge of 
that key an attacker can sign a Java gadget&#160;chain that leads to RCE (e.g. 
CommonsBeanUtils1 from ysoserial).&#160;</p><p>Solution for this 
vulnerability:</p><p>* For Apache Tapestry 5.4.0 to 5.6.1, upgrade to 5.6.2 or 
later.</p><p>* For Apache Tapestry 5.7.0, upgrade to 5.7.1 or later.</p><p>This 
issue is being tracked as TAP5-2663</p><p>Credit:</p><p>Apache Tapestry would 
like to thank Johannes Moritz for finding and notifying this 
vulnerability</p><p></p><pre></pre></div>
             </div>

Modified: websites/production/tapestry/content/uploading-files.html
==============================================================================
--- websites/production/tapestry/content/uploading-files.html (original)
+++ websites/production/tapestry/content/uploading-files.html Mon Jul 11 
07:12:07 2022
@@ -151,7 +151,7 @@
 </code></pre>
 </div></div><p>If you aren't using Maven, you'll have to download the jar and 
its dependencies yourself.</p><h1 id="UploadingFiles-Usage">Usage</h1><p>The 
upload component supports default value binding (based on id) and 
validation.</p><div class="navmenu" style="float:right; background:#eee; 
margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demo:</strong>
-    <span class="nobr"><a class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/javascript/fileupload";
 rel="nofollow">File Upload<sup><img align="middle" class="rendericon" 
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt="" 
border="0"></sup></a></span></p></div><h2 
id="UploadingFiles-ComponentTemplate">Component Template</h2><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+    <span class="nobr"><a class="external-link" 
href="https://tapestry-jumpstart.org/jumpstart/examples/javascript/fileupload"; 
rel="nofollow">File Upload<sup><img align="middle" class="rendericon" 
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt="" 
border="0"></sup></a></span></p></div><h2 
id="UploadingFiles-ComponentTemplate">Component Template</h2><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
 <pre><code class="language-java">    &lt;t:form&gt;
         &lt;t:errors/&gt;
         &lt;input t:type="upload" t:id="file" t:value="file" 
validate="required"/&gt;

Modified: websites/production/tapestry/content/using-select-with-a-list.html
==============================================================================
--- websites/production/tapestry/content/using-select-with-a-list.html 
(original)
+++ websites/production/tapestry/content/using-select-with-a-list.html Mon Jul 
11 07:12:07 2022
@@ -168,11 +168,11 @@
 </div><h1 id="UsingSelectWithaList-UsingSelectWithaList">Using Select With a 
List</h1><p>The documentation for the <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Select.html";>Select
 Component</a> and the <a href="tapestry-tutorial.html">Tapestry Tutorial</a> 
provide simplistic examples of populating a drop-down menu (as the (X)HTML 
<em>Select</em> element) using comma-delimited strings and enums. However, most 
real-world Tapestry applications need to populate such menus using values from 
a database, commonly in the form of java.util.List objects. Doing so generally 
requires a <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/SelectModel.html";>SelectModel</a>
 and a <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html";>ValueEncoder</a>
 bound to the Select component with its "model" and "encoder" 
parameters:</p><div 
 class="code panel pdl" style="border-width: 1px;"><div class="codeContent 
panelContent pdl">
 <pre><code class="language-java">&lt;t:select t:id="colorMenu" 
value="selectedColor" model="ColorSelectModel" encoder="colorEncoder" /&gt;
 </code></pre>
-</div></div><p>In the above example, ColorSelectModel must be of type 
SelectModel, or anything that Tapestry knows how to <a 
href="parameter-type-coercion.html">coerce</a> into a SelectModel, such as a 
List or a Map or a "value=label,value=label,..." delimited string, or anything 
Tapestry knows how to coerce into a List or Map, such as an Array or a 
comma-delimited String.</p><h2 
id="UsingSelectWithaList-SelectModel">SelectModel</h2><div class="navmenu" 
style="float:right; background:#eee; margin:3px; padding:0 1em">
+</div></div><p>In the above example, ColorSelectModel must be of type 
SelectModel, or anything that Tapestry knows how to <a 
href="parameter-type-coercion.html">coerce</a> into a SelectModel, such as a 
List or a Map or a "value=label,value=label,..." delimited string, or anything 
Tapestry knows how to coerce into a List or Map, such as an Array or a 
comma-delimited String.</p><h2 
id="UsingSelectWithaList-SelectModel">SelectModel</h2><p></p><div 
class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demos:</strong>
-    <span class="nobr"><a class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/totalcontrolobject";
 rel="nofollow">Total Control Object Select<sup><img align="middle" 
class="rendericon" src="/images/confluence/icons/linkext7.gif" height="7" 
width="7" alt="" border="0"></sup></a></span>
-    <span class="nobr"><a class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/id"; 
rel="nofollow">ID Select<sup><img align="middle" class="rendericon" 
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt="" 
border="0"></sup></a></span>
-    <span class="nobr"><a class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyid"; 
rel="nofollow">Easy ID Select<sup><img align="middle" class="rendericon" 
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt="" 
border="0"></sup></a></span></p></div>A SelectModel is a collection of options 
(specifically <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/OptionModel.html";>OptionModel</a>
 objects) for a drop-down menu. Basically, each option is a value (an object) 
and a label (presented to the user).<p>If you provide a property of type List 
for the "model" parameter, Tapestry automatically builds a SelectModel that 
uses each object's toString() for both the select option value and the select 
option label. For database-derrived lists this is rarely useful, however, since 
after form submission you would then have to look up the selected object using 
that label.</p><p>If you provide a 
 Map, Tapestry builds a SelectModel that uses each item's key as the encoded 
value and its value as the user-visible label. This is more useful, but if you 
are going to build a copy of the list as a map just for this purpose, you may 
as well let Tapestry do it for you, using SelectModelFactory.</p><h2 
id="UsingSelectWithaList-SelectModelFactory">SelectModelFactory</h2><p>To have 
Tapestry create a SelectModel for you, use the <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/SelectModelFactory.html";>SelectModelFactory</a>
 service. SelectModelFactory creates a SelectModel from a List of objects (of 
whatever type) and a label property name that you choose:</p><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (a page 
class)</b></div><div class="codeContent panelContent pdl">
+    <span class="nobr"><a class="external-link" 
href="https://tapestry-jumpstart.org/jumpstart/examples/select/totalcontrolobject";
 rel="nofollow">Total Control Object Select<sup><img align="middle" 
class="rendericon" src="/images/confluence/icons/linkext7.gif" height="7" 
width="7" alt="" border="0"></sup></a></span>
+    <span class="nobr"><a class="external-link" 
href="https://tapestry-jumpstart.org/jumpstart/examples/select/id"; 
rel="nofollow">ID Select<sup><img align="middle" class="rendericon" 
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt="" 
border="0"></sup></a></span>
+    <span class="nobr"><a class="external-link" 
href="https://tapestry-jumpstart.org/jumpstart/examples/select/easyid"; 
rel="nofollow">Easy ID Select<sup><img align="middle" class="rendericon" 
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt="" 
border="0"></sup></a></span></p></div>A SelectModel is a collection of options 
(specifically <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/OptionModel.html";>OptionModel</a>
 objects) for a drop-down menu. Basically, each option is a value (an object) 
and a label (presented to the user).<p></p><p>If you provide a property of type 
List for the "model" parameter, Tapestry automatically builds a SelectModel 
that uses each object's toString() for both the select option value and the 
select option label. For database-derrived lists this is rarely useful, 
however, since after form submission you would then have to look up the 
selected object using that label.</p><p>If you provide a M
 ap, Tapestry builds a SelectModel that uses each item's key as the encoded 
value and its value as the user-visible label. This is more useful, but if you 
are going to build a copy of the list as a map just for this purpose, you may 
as well let Tapestry do it for you, using SelectModelFactory.</p><h2 
id="UsingSelectWithaList-SelectModelFactory">SelectModelFactory</h2><p>To have 
Tapestry create a SelectModel for you, use the <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/SelectModelFactory.html";>SelectModelFactory</a>
 service. SelectModelFactory creates a SelectModel from a List of objects (of 
whatever type) and a label property name that you choose:</p><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (a page 
class)</b></div><div class="codeContent panelContent pdl">
 <pre><code class="language-java">@Property
 private SelectModel colorSelectModel;
 @Inject
@@ -195,7 +195,7 @@ public String toString() {
 </code></pre>
 </div></div><p>But that is contorting the purpose of the toString() method, 
and if you go to that much trouble you're already half way to the recommended 
practice: creating a ValueEncoder.</p><h2 
id="UsingSelectWithaList-ValueEncoder">ValueEncoder</h2><p>In addition to a 
SelectModel, your Select menu is likely to need a ValueEncoder. While a 
SelectModel is concerned only with how to construct a Select menu, a 
ValueEncoder is used when constructing the Select menu <em>and</em> when 
interpreting the encoded value that is submitted back to the server. A 
ValueEncoder is a converter between the type of objects you want to represent 
as options in the menu and the client-side encoded values that uniquely 
identify them, and vice-versa.</p><div class="navmenu" style="float:right; 
background:#eee; margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demo:</strong>
-    <span class="nobr"><a class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyobject";
 rel="nofollow">Easy Object Select<sup><img align="middle" class="rendericon" 
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt="" 
border="0"></sup></a></span></p></div>Most commonly, your ValueEncoder's 
toClient() method will return a unique ID (e.g. a database primary key, or 
perhaps a UUID) of the given object, and its toValue() method will return the 
<em>object</em> matching the given ID by doing a database lookup (ideally using 
a service or DAO method).<p>If you're using one of the ORM integration modules 
(<a href="hibernate.html">Tapestry-Hibernate</a>, <a 
href="integrating-with-jpa.html">Tapestry-JPA</a>, or <a class="external-link" 
href="http://code.google.com/p/tapestry5-cayenne/wiki/ValueEncoder"; 
rel="nofollow">Tapestry-Cayenne</a>), the ValueEncoder is automatically 
provided for each of your mapped entity classes. The Hiberna
 te module's implementation is typical: the primary key field of the object 
(converted to a String) is used as the client-side value, and that same primary 
key is used to look up the selected object.</p><p>That's exactly what you 
should do in your own ValueEncoders too:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>ColorEncoder.java (perhaps in your 
com.example.myappname.encoders package)</b></div><div class="codeContent 
panelContent pdl">
+    <span class="nobr"><a class="external-link" 
href="https://tapestry-jumpstart.org/jumpstart/examples/select/easyobject"; 
rel="nofollow">Easy Object Select<sup><img align="middle" class="rendericon" 
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt="" 
border="0"></sup></a></span></p></div>Most commonly, your ValueEncoder's 
toClient() method will return a unique ID (e.g. a database primary key, or 
perhaps a UUID) of the given object, and its toValue() method will return the 
<em>object</em> matching the given ID by doing a database lookup (ideally using 
a service or DAO method).<p></p><p>If you're using one of the ORM integration 
modules (<a href="hibernate.html">Tapestry-Hibernate</a>, <a 
href="integrating-with-jpa.html">Tapestry-JPA</a>, or <a class="external-link" 
href="http://code.google.com/p/tapestry5-cayenne/wiki/ValueEncoder"; 
rel="nofollow">Tapestry-Cayenne</a>), the ValueEncoder is automatically 
provided for each of your mapped entity classes. The Hibernat
 e module's implementation is typical: the primary key field of the object 
(converted to a String) is used as the client-side value, and that same primary 
key is used to look up the selected object.</p><p>That's exactly what you 
should do in your own ValueEncoders too:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>ColorEncoder.java (perhaps in your 
com.example.myappname.encoders package)</b></div><div class="codeContent 
panelContent pdl">
 <pre><code class="language-java">public class ColorEncoder implements 
ValueEncoder&lt;Color&gt;, ValueEncoderFactory&lt;Color&gt; { 
 
     @Inject

Modified: 
websites/production/tapestry/content/using-tapestry-with-hibernate.html
==============================================================================
--- websites/production/tapestry/content/using-tapestry-with-hibernate.html 
(original)
+++ websites/production/tapestry/content/using-tapestry-with-hibernate.html Mon 
Jul 11 07:12:07 2022
@@ -254,7 +254,7 @@ public class CreateAddress
     }
 }
 </code></pre>
-</div></div><p>The <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html";>Inject</a>
 annotation tells Tapestry to inject a service into the annotated field; 
Tapestry includes a sophisticated Inversion of Control container (similar in 
many ways to Spring) that is very good at locating available services by type, 
rather than by a string id. In any case, the Hibernate Session object is 
exposed as a Tapestry IoC service, ready to be injected (this is one of the 
things provided by the tapestry-hibernate module).</p><p>Tapestry automatically 
starts a transaction as necessary; however that transaction will be 
<em>aborted</em> at the end of the request by default. If we make changes to 
persistent objects, such as adding a new Address object, then it is necessary 
to commit the transaction.</p><p>The <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/hibernate/annotations/CommitAft
 er.html">CommitAfter</a> annotation can be applied to any component method; if 
the method completes normally, the transaction will be committed (and a new 
transaction started to replace the committed transaction).</p><p>After 
persisting the new address, we return to the main Index page of the 
application.</p><p><em>Note: In real applications, it is rare to have pages and 
components directly use the Hibernate Session. It is generally a better 
approach to define your own Data Access Object layer to perform common update 
operations and queries.</em></p><h2 
id="UsingTapestryWithHibernate-ShowingAddresses">Showing Addresses</h2><p>As a 
little preview of what's next, let's display all the Addresses entered by the 
user on the Index page of the application. After you enter a few names, it will 
look something like:</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
width="722" src="using-tapestry-with-hibernate.data/ind
 ex-grid-v1.png"></span></p><h2 
id="UsingTapestryWithHibernate-AddingtheGridtotheIndexpage">Adding the Grid to 
the Index page</h2><p>So, how is this implemented? Primarily, its accomplished 
by the <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Grid.html";>Grid</a>
 component.</p><p>The Grid component is based on the same concepts as the 
BeanEditForm component; it can pull apart a bean into columns. The columns are 
sortable, and when there are more entries than will fit on a single page, page 
navigation is automatically added.</p><p>A minimal Grid is very easy to add to 
the template. Just add this near the bottom of Index.tml:</p><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>src/main/webapp/Index.tml 
(partial)</b></div><div class="codeContent panelContent pdl">
+</div></div><p>The <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html";>Inject</a>
 annotation tells Tapestry to inject a service into the annotated field; 
Tapestry includes a sophisticated Inversion of Control container (similar in 
many ways to Spring) that is very good at locating available services by type, 
rather than by a string id. In any case, the Hibernate Session object is 
exposed as a Tapestry IoC service, ready to be injected (this is one of the 
things provided by the tapestry-hibernate module).</p><p>Tapestry automatically 
starts a transaction as necessary; however that transaction will be 
<em>aborted</em> at the end of the request by default. If we make changes to 
persistent objects, such as adding a new Address object, then it is necessary 
to commit the transaction.</p><p>The <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/hibernate/annotations/CommitAft
 er.html">CommitAfter</a> annotation can be applied to any component method; if 
the method completes normally, the transaction will be committed (and a new 
transaction started to replace the committed transaction).</p><p>After 
persisting the new address, we return to the main Index page of the 
application.</p><p><em>Note: In real applications, it is rare to have pages and 
components directly use the Hibernate Session. It is generally a better 
approach to define your own Data Access Object layer to perform common update 
operations and queries.</em></p><h2 
id="UsingTapestryWithHibernate-ShowingAddresses">Showing Addresses</h2><p>As a 
little preview of what's next, let's display all the Addresses entered by the 
user on the Index page of the application. After you enter a few names, it will 
look something like:</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
draggable="false" width="722" src="using-tapestry-with-
 hibernate.data/index-grid-v1.png"></span></p><h2 
id="UsingTapestryWithHibernate-AddingtheGridtotheIndexpage">Adding the Grid to 
the Index page</h2><p>So, how is this implemented? Primarily, its accomplished 
by the <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Grid.html";>Grid</a>
 component.</p><p>The Grid component is based on the same concepts as the 
BeanEditForm component; it can pull apart a bean into columns. The columns are 
sortable, and when there are more entries than will fit on a single page, page 
navigation is automatically added.</p><p>A minimal Grid is very easy to add to 
the template. Just add this near the bottom of Index.tml:</p><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>src/main/webapp/Index.tml 
(partial)</b></div><div class="codeContent panelContent pdl">
 <pre><code class="language-xml">  &lt;t:grid source="addresses"
          
include="honorific,firstName,lastName,street1,city,state,zip,phone"/&gt;
 </code></pre>
@@ -274,7 +274,7 @@ public class Index
     }
 }
 </code></pre>
-</div></div><p>Here, we're using the Hibernate Session object to find all 
Address objects in the database. Any sorting that takes place will be done in 
memory. This is fine for now (with only a handful of Address objects in the 
database). Later we'll see how to optimize this for very large result 
sets.</p><h2 id="UsingTapestryWithHibernate-What'sNext?">What's Next?</h2><p>We 
have lots more to talk about: more components, more customizations, built-in 
Ajax support, more common design and implementation patterns, and even writing 
your own components (which is easy!).</p><p class="confluence-link">Check out 
the many Tapestry resources available on the&#160;<a 
href="documentation.html">Documentation</a> page, including the&#160;<a 
href="getting-started.html">Getting Started</a> and <a 
href="frequently-asked-questions.html">FAQ</a> pages and the <a 
href="cookbook.html">Cookbook</a>. Be sure to peruse the <a 
href="user-guide.html">User Guide</a>, which provides comprehensive details on 
ne
 arly every Tapestry topic. Finally, be sure to visit (and bookmark) <a 
class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart"; 
rel="nofollow">Tapestry JumpStart</a>, which provides a nearly exhaustive set 
of tutorials.</p></div>
+</div></div><p>Here, we're using the Hibernate Session object to find all 
Address objects in the database. Any sorting that takes place will be done in 
memory. This is fine for now (with only a handful of Address objects in the 
database). Later we'll see how to optimize this for very large result 
sets.</p><h2 id="UsingTapestryWithHibernate-What'sNext?">What's Next?</h2><p>We 
have lots more to talk about: more components, more customizations, built-in 
Ajax support, more common design and implementation patterns, and even writing 
your own components (which is easy!).</p><p class="confluence-link">Check out 
the many Tapestry resources available on the&#160;<a 
href="documentation.html">Documentation</a> page, including the&#160;<a 
href="getting-started.html">Getting Started</a> and <a 
href="frequently-asked-questions.html">FAQ</a> pages and the <a 
href="cookbook.html">Cookbook</a>. Be sure to peruse the <a 
href="user-guide.html">User Guide</a>, which provides comprehensive details on 
ne
 arly every Tapestry topic. Finally, be sure to visit (and bookmark) <a 
class="external-link" href="https://tapestry-jumpstart.org/jumpstart"; 
rel="nofollow">Tapestry JumpStart</a>, which provides a nearly exhaustive set 
of tutorials.</p><p></p></div>
             </div>
             <!-- /// Content End -->
           </div>


Reply via email to