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 Wed Sep 
20 12:29:16 2017
@@ -27,6 +27,16 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' 
rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' 
type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushXml.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushPlain.js' 
type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -67,13 +77,15 @@
       </div>
 
       <div id="content">
-                <div 
id="ConfluenceContent"><plain-text-body>{scrollbar}</plain-text-body><parameter 
ac:name="hidden">true</parameter><parameter 
ac:name="atlassian-macro-output-type">BLOCK</parameter><rich-text-body><p>Using 
SelectModel, SelectModelFactory and ValueEncoder for Select menus populated 
from a database</p></rich-text-body><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="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-lin
 k" 
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><plain-text-body>&lt;t:select t:id="colorMenu" 
value="selectedColor" model="ColorSelectModel" encoder="colorEncoder" /&gt;
-</plain-text-body><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><plain-text-body>{float:right|background=#eee|padding=0
 1em}
-    *JumpStart Demos:*
-    [Total Control Object 
Select|http://jumpstart.doublenegative.com.au/jumpstart/examples/select/totalcontrolobject]
-    [ID 
Select|http://jumpstart.doublenegative.com.au/jumpstart/examples/select/id]
-    [Easy ID 
Select|http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyid]
-{float}</plain-text-body><p>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>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 Se
 lectModelFactory.</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><parameter 
ac:name="title">SelectWithListDemo.java (a page 
class)</parameter><plain-text-body>@Property
+                <div id="ConfluenceContent"><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="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" a
 nd "encoder" parameters:</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;">&lt;t:select t:id="colorMenu" value="selectedColor" 
model="ColorSelectModel" encoder="colorEncoder" /&gt;
+</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">
+<p>    <strong>JumpStart Demos:</strong><br clear="none">
+    <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/totalcontrolobject";
 rel="nofollow">Total Control Object Select</a><br clear="none">
+    <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/id"; 
rel="nofollow">ID Select</a><br clear="none">
+    <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyid"; 
rel="nofollow">Easy ID Select</a></p></div><p>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>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">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">@Property
 private SelectModel colorSelectModel;
 @Inject
 SelectModelFactory selectModelFactory;
@@ -85,15 +97,18 @@ void setupRender() {
     // create a SelectModel from my list of colors
     colorSelectModel = selectModelFactory.create(colors, "name");
 }
-</plain-text-body><p>The resulting SelectModel has a selectable option 
(specifically, an OptionModel) for every object in the original List. The label 
property name (the "name" property, in this example) determines the 
user-visible text of each menu option, and your ValueEncoder's toClient() 
method provides the encoded value (most commonly a simple number). If you don't 
provide a ValueEncoder, the result of the objects' toString() method 
(Color#toString() in this example) is used. Although not a recommended 
practice, you <em>could</em> set your toString() to return the object's ID for 
this purpose:</p><parameter ac:name="title">Color.java 
(partial)</parameter><plain-text-body>...
+</pre>
+</div></div><p>The resulting SelectModel has a selectable option 
(specifically, an OptionModel) for every object in the original List. The label 
property name (the "name" property, in this example) determines the 
user-visible text of each menu option, and your ValueEncoder's toClient() 
method provides the encoded value (most commonly a simple number). If you don't 
provide a ValueEncoder, the result of the objects' toString() method 
(Color#toString() in this example) is used. Although not a recommended 
practice, you <em>could</em> set your toString() to return the object's ID for 
this purpose:</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>Color.java (partial)</b></div><div class="codeContent panelContent 
pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">...
 @Override
 public String toString() {
     return String.valueOf(this.getId()); 
 }
-</plain-text-body><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><plain-text-body>{float:right|background=#eee|padding=0 1em}
-    *JumpStart Demo:*
-    [Easy Object 
Select|http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyobject]
-{float}</plain-text-body><p>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>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 Hibernate 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><parameter
  ac:name="title">ColorEncoder.java (perhaps in your 
com.example.myappname.encoders package)</parameter><plain-text-body>public 
class ColorEncoder implements ValueEncoder&lt;Color&gt;, 
ValueEncoderFactory&lt;Color&gt; { 
+</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><br clear="none">
+    <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyobject";
 rel="nofollow">Easy Object Select</a></p></div><p>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>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 Hibernate 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 p
 rimary 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 class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public class ColorEncoder implements 
ValueEncoder&lt;Color&gt;, ValueEncoderFactory&lt;Color&gt; { 
 
     @Inject
     private ColorService colorService;
@@ -116,7 +131,9 @@ public String toString() {
         return this; 
     }
 } 
-</plain-text-body><p>Alternatively, if you don't expect to need a particular 
ValueEncoder more than once in your app, you might want to just create it on 
demand, using an anonymous inner class, from the getter method in the component 
class where it is needed. For example:</p><parameter 
ac:name="title">SelectWithListDemo.java (a page class, 
partial)</parameter><plain-text-body>    . . .
+</pre>
+</div></div><p>Alternatively, if you don't expect to need a particular 
ValueEncoder more than once in your app, you might want to just create it on 
demand, using an anonymous inner class, from the getter method in the component 
class where it is needed. For example:</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, 
partial)</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">    . . .
 
     public ValueEncoder&lt;Color&gt; getColorEncoder() {
 
@@ -135,26 +152,35 @@ public String toString() {
             }
         }; 
     }
-</plain-text-body><p>Notice that the body of this anonymous inner class is the 
same as the body of the ColorEncoder top level class, except that we don't need 
a <code>create</code> method.</p><h2 
id="UsingSelectWithaList-ApplyingyourValueEncoderAutomatically">Applying your 
ValueEncoder Automatically</h2><p>If your ValueEncoder <em>implements 
ValueEncoderFactory</em> (as the ColorEncoder top level class does, above), you 
can associate your custom ValueEncoder with your entity class so that Tapestry 
will automatically use it every time a ValueEncoder is needed for items of that 
type (such as with the Select, RadioGroup, Grid, Hidden and AjaxFormLoop 
components). Just add lines like the following to your module class (usually 
AppModule.java):</p><parameter ac:name="title">AppModule.java 
(partial)</parameter><plain-text-body>...
+</pre>
+</div></div><p>Notice that the body of this anonymous inner class is the same 
as the body of the ColorEncoder top level class, except that we don't need a 
<code>create</code> method.</p><h2 
id="UsingSelectWithaList-ApplyingyourValueEncoderAutomatically">Applying your 
ValueEncoder Automatically</h2><p>If your ValueEncoder <em>implements 
ValueEncoderFactory</em> (as the ColorEncoder top level class does, above), you 
can associate your custom ValueEncoder with your entity class so that Tapestry 
will automatically use it every time a ValueEncoder is needed for items of that 
type (such as with the Select, RadioGroup, Grid, Hidden and AjaxFormLoop 
components). Just add lines like the following to your 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)</b></div><div class="codeContent panelContent 
pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">...
     public static void 
contributeValueEncoderSource(MappedConfiguration&lt;Class&lt;Color&gt;,
                         ValueEncoderFactory&lt;Color&gt;&gt; configuration) { 
         configuration.addInstance(Color.class, ColorEncoder.class);
     }
-</plain-text-body><p>If you are contributing more than one ValueEncoder, 
you'll have to use raw types, like this:</p><parameter 
ac:name="title">AppModule.java (partial)</parameter><plain-text-body>...
+</pre>
+</div></div><p>If you are contributing more than one ValueEncoder, you'll have 
to use raw types, like this:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div 
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">...
     public static void 
contributeValueEncoderSource(MappedConfiguration&lt;Class,
                         ValueEncoderFactory&gt; configuration)
     {
         configuration.addInstance(Color.class, ColorEncoder.class);
         configuration.addInstance(SomeOtherType.class, 
SomeOtherTypeEncoder.class);
     }
-</plain-text-body><h2 
id="UsingSelectWithaList-WhatifIomittheValueEncoder?">What if I omit the 
ValueEncoder?</h2><p>The Select component's "encoder" parameter is optional, 
but if the "value" parameter is bound to a complex object (not a simple String, 
Integer, etc.) and you don't provide a ValueEncoder with the "encoder" 
parameter (and one isn't provided automatically by, for example, the Tapestry 
Hibernate integration), you'll receive a "Could not find a coercion" exception 
(when you submit the form) as Tapestry tries to convert the selected option's 
encoded value back to the <em>object</em> in your Select's "value" parameter. 
To fix this, you'll either have to 1) provide a ValueEncoder, 2) provide a <a  
href="type-coercion.html">Coercion</a>, or 3) use a simple value (String, 
Integer, etc.) for your Select's "value" parameter, and then you'll have to add 
logic in the corresponding onSuccess event listener method:</p><parameter 
ac:name="title">SelectWithListDemo.tml (partial)</para
 meter><plain-text-body>&lt;t:select t:id="colorMenu" value="selectedColorId" 
model="ColorSelectModel" /&gt;
-</plain-text-body><parameter ac:name="title">SelectWithListDemo.java 
(partial)</parameter><plain-text-body>...
+</pre>
+</div></div><h2 id="UsingSelectWithaList-WhatifIomittheValueEncoder?">What if 
I omit the ValueEncoder?</h2><p>The Select component's "encoder" parameter is 
optional, but if the "value" parameter is bound to a complex object (not a 
simple String, Integer, etc.) and you don't provide a ValueEncoder with the 
"encoder" parameter (and one isn't provided automatically by, for example, the 
Tapestry Hibernate integration), you'll receive a "Could not find a coercion" 
exception (when you submit the form) as Tapestry tries to convert the selected 
option's encoded value back to the <em>object</em> in your Select's "value" 
parameter. To fix this, you'll either have to 1) provide a ValueEncoder, 2) 
provide a <a  href="type-coercion.html">Coercion</a>, or 3) use a simple value 
(String, Integer, etc.) for your Select's "value" parameter, and then you'll 
have to add logic in the corresponding onSuccess event listener method:</p><div 
class="code panel pdl" style="border-width: 1px;"><div class="code
 Header panelHeader pdl" style="border-bottom-width: 
1px;"><b>SelectWithListDemo.tml (partial)</b></div><div class="codeContent 
panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">&lt;t:select t:id="colorMenu" value="selectedColorId" 
model="ColorSelectModel" /&gt;
+</pre>
+</div></div><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>SelectWithListDemo.java (partial)</b></div><div class="codeContent 
panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">...
     public void onSuccessFromMyForm() {
         // look up the color object from the ID selected
        selectedColor = colorService.findById(selectedColorId);
        ...
     }
-</plain-text-body><p>But then again, you may as well create a ValueEncoder 
instead.</p><h2 id="UsingSelectWithaList-Whyisthissohard?">Why is this so 
hard?</h2><p>Actually, it's really pretty easy if you follow the examples 
above. But why is Tapestry designed to use SelectModels and ValueEncoders 
anyway? Well, in short, this design allows you to avoid storing (via @Persist, 
@SessionAttribute or @SessionState) the entire (potentially large) list of 
objects in the session or rebuilding the whole list of objects again (though 
only one is needed) when the form is submitted. The chief benefits are reduced 
memory use and <a  href="performance-and-clustering.html">more scalable 
clustering</a> due to having far less HTTP session data to replicate across the 
nodes of a cluster.</p></div>
+</pre>
+</div></div><p>But then again, you may as well create a ValueEncoder 
instead.</p><h2 id="UsingSelectWithaList-Whyisthissohard?">Why is this so 
hard?</h2><p>Actually, it's really pretty easy if you follow the examples 
above. But why is Tapestry designed to use SelectModels and ValueEncoders 
anyway? Well, in short, this design allows you to avoid storing (via @Persist, 
@SessionAttribute or @SessionState) the entire (potentially large) list of 
objects in the session or rebuilding the whole list of objects again (though 
only one is needed) when the form is submitted. The chief benefits are reduced 
memory use and <a  href="performance-and-clustering.html">more scalable 
clustering</a> due to having far less HTTP session data to replicate across the 
nodes of a cluster.</p></div>
       </div>
 
       <div class="clearer"></div>

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 Wed 
Sep 20 12:29:16 2017
@@ -27,6 +27,15 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' 
rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' 
type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushXml.js' 
type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -36,26 +45,13 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  
href="index.html">Home</a></li><li><a  href="getting-started.html">Getting 
Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  
href="download.html">Download</a></li><li><a  
href="about.html">About</a></li><li><a  class="external-link" 
href="http://www.apache.org/licenses/LICENSE-2.0";>License</a></li><li><a  
href="community.html">Community</a></li><li><a  class="external-link" 
href="http://www.apache.org/security/";>Security</a></li><li><a  
class="external-link" href="http://www.apache.org/";>Apache</a></li><li><a  
class="external-link" 
href="http://www.apache.org/foundation/sponsorship.html";>Sponsorship</a></li><li><a
  class="external-link" 
href="http://www.apache.org/foundation/thanks.html";>Thanks</a></li></ul></div>
-
-</div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  
href="index.html">Home</a></li><li><a  href="getting-started.html">Getting 
Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  
href="download.html">Download</a></li><li><a  
href="about.html">About</a></li><li><a  class="external-link" 
href="http://www.apache.org/licenses/LICENSE-2.0";>License</a></li><li><a  
href="community.html">Community</a></li><li><a  class="external-link" 
href="http://www.apache.org/security/";>Security</a></li><li><a  
class="external-link" href="http://www.apache.org/";>Apache</a></li><li><a  
class="external-link" 
href="http://www.apache.org/foundation/sponsorship.html";>Sponsorship</a></li><li><a
  class="external-link" 
href="http://www.apache.org/foundation/thanks.html";>Thanks</a></li></ul></div></div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" 
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; 
font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
-<form enctype="application/x-www-form-urlencoded" method="get" 
action="http://tapestry.apache.org/search.html";>
-  <input type="text" name="q">
-  <input type="submit" value="Search">
-</form>
-
-</div>
-
-
-<div class="emblem" style="float:left"><p><a  href="index.html"><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource" 
src="http://tapestry.apache.org/images/tapestry_small.png"; 
data-image-src="http://tapestry.apache.org/images/tapestry_small.png";></span></a></p></div>
-
-
-<div class="title" style="float:left; margin: 0 0 0 3em"><h1 
id="SmallBanner-PageTitle">Using Tapestry With Hibernate</h1></div>
-
-</div>
+            <div id="smallbanner"><div class="searchbox" 
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; 
font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form 
enctype="application/x-www-form-urlencoded" method="get" 
action="http://tapestry.apache.org/search.html";> 
+ <input type="text" name="q"> 
+ <input type="submit" value="Search"> 
+</form></div><div class="emblem" style="float:left"><p><a  
href="index.html"><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="http://tapestry.apache.org/images/tapestry_small.png"; 
data-image-src="http://tapestry.apache.org/images/tapestry_small.png";></span></a></p></div><div
 class="title" style="float:left; margin: 0 0 0 3em"><h1 
id="SmallBanner-PageTitle">Using Tapestry With Hibernate</h1></div></div>
       <div class="clearer"></div>
       </div>
 
@@ -67,7 +63,8 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>So, you fill in all the fields, 
submit the form (without validation errors) and voila: you get back the same 
form, blanked out. What happened, and where did the data go?</p><p>What 
happened is that we haven't told Tapestry what to do after the form is 
successfully submitted (by successful, we mean, with no validation errors). 
Tapestry's default behavior is to redisplay the active page, and that occurs in 
a new request, with a new instance of the Address object (because the address 
field is not a peristent field).</p><p>Well, since we're creating objects, we 
might as well store them somewhere ... in a database. We're going to quickly 
integrate Tapestry with <a  class="external-link" href="http://hibernate.org"; 
rel="nofollow">Hibernate</a> as the object/relational mapping layer, and 
ultimately store our data inside a <a  class="external-link" 
href="http://www.hsqldb.org/"; rel="nofollow">HyperSQL</a> (HSQLDB) database. 
HSQLDB is an embedde
 d database engine and requires no installation &#8211; it will be pulled down 
as a dependency by Maven.</p><h2 
id="UsingTapestryWithHibernate-Re-configuringtheProject">Re-configuring the 
Project</h2><p>We're going to bootstrap this project from a simple Tapestry 
project to one that uses Hibernate and HSQLDB.</p><h3 
id="UsingTapestryWithHibernate-UpdatingtheDependencies">Updating the 
Dependencies</h3><p>First, we must update the POM to list a new set of 
dependencies, that includes Hibernate, the Tapestry/Hibernate integration 
library, and the HSQLDB JDBC driver:</p><parameter 
ac:name="language">xml</parameter><parameter ac:name="title">src/pom.xml 
(partial)</parameter><plain-text-body>    &lt;dependencies&gt;
+                <div id="ConfluenceContent"><p>So, you fill in all the fields, 
submit the form (without validation errors) and voila: you get back the same 
form, blanked out. What happened, and where did the data go?</p><p>What 
happened is that we haven't told Tapestry what to do after the form is 
successfully submitted (by successful, we mean, with no validation errors). 
Tapestry's default behavior is to redisplay the active page, and that occurs in 
a new request, with a new instance of the Address object (because the address 
field is not a peristent field).</p><p>Well, since we're creating objects, we 
might as well store them somewhere ... in a database. We're going to quickly 
integrate Tapestry with <a  class="external-link" href="http://hibernate.org"; 
rel="nofollow">Hibernate</a> as the object/relational mapping layer, and 
ultimately store our data inside a <a  class="external-link" 
href="http://www.hsqldb.org/"; rel="nofollow">HyperSQL</a> (HSQLDB) database. 
HSQLDB is an embedde
 d database engine and requires no installation &#8211; it will be pulled down 
as a dependency by Maven.</p><h2 
id="UsingTapestryWithHibernate-Re-configuringtheProject">Re-configuring the 
Project</h2><p>We're going to bootstrap this project from a simple Tapestry 
project to one that uses Hibernate and HSQLDB.</p><h3 
id="UsingTapestryWithHibernate-UpdatingtheDependencies">Updating the 
Dependencies</h3><p>First, we must update the POM to list a new set of 
dependencies, that includes Hibernate, the Tapestry/Hibernate integration 
library, and the HSQLDB JDBC driver:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>src/pom.xml (partial)</b></div><div 
class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">    &lt;dependencies&gt;
 
         &lt;dependency&gt;
             &lt;groupId&gt;org.apache.tapestry&lt;/groupId&gt;
@@ -82,7 +79,9 @@
         &lt;/dependency&gt;
         ...
     &lt;/dependencies&gt;
-</plain-text-body><p>The tapestry-hibernate library includes, as transitive 
dependencies, Hibernate and tapestry-core. This means that you can simply 
replace "tapestry-core" with "tapestry-hibernate" inside the &lt;artifactId&gt; 
element.</p><p>After changing the POM and saving, Maven should automatically 
download the JARs for the new dependencies.</p><h3 
id="UsingTapestryWithHibernate-HibernateConfiguration">Hibernate 
Configuration</h3><p>Hibernate needs a master configuration file, 
hibernate.cfg.xml, used to store connection and other data. Create this in your 
src/main/resources folder:</p><parameter 
ac:name="language">xml</parameter><parameter 
ac:name="title">src/main/resources/hibernate.cfg.xml</parameter><plain-text-body>&lt;!DOCTYPE
 hibernate-configuration PUBLIC
+</pre>
+</div></div><p>The tapestry-hibernate library includes, as transitive 
dependencies, Hibernate and tapestry-core. This means that you can simply 
replace "tapestry-core" with "tapestry-hibernate" inside the &lt;artifactId&gt; 
element.</p><p>After changing the POM and saving, Maven should automatically 
download the JARs for the new dependencies.</p><h3 
id="UsingTapestryWithHibernate-HibernateConfiguration">Hibernate 
Configuration</h3><p>Hibernate needs a master configuration file, 
hibernate.cfg.xml, used to store connection and other data. Create this in your 
src/main/resources folder:</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>src/main/resources/hibernate.cfg.xml</b></div><div class="codeContent 
panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">&lt;!DOCTYPE hibernate-configuration PUBLIC
         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
         "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"&gt;
 &lt;hibernate-configuration&gt;
@@ -97,7 +96,9 @@
         &lt;property name="hibernate.format_sql"&gt;true&lt;/property&gt;
     &lt;/session-factory&gt;
 &lt;/hibernate-configuration&gt;
-</plain-text-body><p>Most of the configuration is to identify the JDBC driver 
and connection URL.</p><p>Note the connection URL. We are instructing HSQLDB to 
store its database files within our project's target directory. We are also 
instructing HSQLDB to flush any data to these files at shutdown. This means 
that data will persist across different invocations of this project, but if the 
target directory is destroyed (e.g., via "mvn clean"), then all the database 
contents will be lost.</p><p>In addition, we are configuring Hibernate to 
<em>update</em> the database schema; when Hibernate initializes it will create 
or even modify tables to match the entities. Finally, we are configuring 
Hibernate to output any SQL it executes, which is very useful when initially 
building an application.</p><p>But what entities? Normally, the available 
entities are listed inside hibernate.cfg.xml, but that's not necessary with 
Tapestry; in another example of convention over configuration, Tapestry locat
 es all entity classes inside the entities package 
("com.example.tutorial1.entities" in our case) and adds them to the 
configuration. Currently, that is just the Address entity.</p><h2 
id="UsingTapestryWithHibernate-AddingHibernateAnnotations">Adding Hibernate 
Annotations</h2><p>For an entity class to be used with Hibernate, some 
Hibernate annotations must be added to the class.</p><p>Below is the updated 
Address class, with the Hibernate annotations (as well as the Tapestry 
ones).</p><parameter ac:name="language">java</parameter><parameter 
ac:name="title">src/main/java/com/example/tutorial/entities/Address.java</parameter><plain-text-body>package
 com.example.tutorial1.entities;
+</pre>
+</div></div><p>Most of the configuration is to identify the JDBC driver and 
connection URL.</p><p>Note the connection URL. We are instructing HSQLDB to 
store its database files within our project's target directory. We are also 
instructing HSQLDB to flush any data to these files at shutdown. This means 
that data will persist across different invocations of this project, but if the 
target directory is destroyed (e.g., via "mvn clean"), then all the database 
contents will be lost.</p><p>In addition, we are configuring Hibernate to 
<em>update</em> the database schema; when Hibernate initializes it will create 
or even modify tables to match the entities. Finally, we are configuring 
Hibernate to output any SQL it executes, which is very useful when initially 
building an application.</p><p>But what entities? Normally, the available 
entities are listed inside hibernate.cfg.xml, but that's not necessary with 
Tapestry; in another example of convention over configuration, Tapestry locates 
all
  entity classes inside the entities package ("com.example.tutorial1.entities" 
in our case) and adds them to the configuration. Currently, that is just the 
Address entity.</p><h2 
id="UsingTapestryWithHibernate-AddingHibernateAnnotations">Adding Hibernate 
Annotations</h2><p>For an entity class to be used with Hibernate, some 
Hibernate annotations must be added to the class.</p><p>Below is the updated 
Address class, with the Hibernate annotations (as well as the Tapestry 
ones).</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>src/main/java/com/example/tutorial/entities/Address.java</b></div><div 
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">package com.example.tutorial1.entities;
 
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
@@ -142,7 +143,9 @@ public class Address
 
   public String phone;
 }
-</plain-text-body><p>The Tapestry annotations, @NonVisual and @Validate, may 
be placed on the setter or getter method or on the field (as we have done 
here). As with the Hibernate annotations, putting the annotation on the field 
requires that the field name match the corresponding property 
name.</p><ul><li><strong>@NonVisual</strong> &#8211; indicates a field, such as 
a primary key, that should not be made visible to the 
user.</li><li><strong>@Validate</strong> &#8211; identifies the validations 
associated with a field.</li></ul><p>At this point you should stop and restart 
your application.</p><h2 
id="UsingTapestryWithHibernate-UpdatingtheDatabase">Updating the 
Database</h2><p>So we have a database set up, and Hibernate is configured to 
connect to it. Let's make use of that to store our Address object in the 
database.</p><p>What we need is to provide some code to be executed when the 
form is submitted. When a Tapestry form is submitted, there is a whole series 
of events that get fir
 ed. The event we are interested in is the "success" event, which comes late in 
the process, after all the values have been pulled out of the request and 
applied to the page properties, and after all server-side validations have 
occurred.</p><p>The success event is only fired if there are no validation 
errors.</p><p>Our event handler must do two things:</p><ul><li>Use the 
Hibernate Session object to persist the new Address object.</li><li>Commit the 
transaction to force the data to be written to the database.</li></ul><p>Let's 
update our CreateAddress.java class:</p><parameter 
ac:name="language">java</parameter><parameter 
ac:name="title">src/main/java/com/example/tutorial/pages/address/CreateAddress.java</parameter><plain-text-body>package
 com.example.tutorial1.pages.address;
+</pre>
+</div></div><p>The Tapestry annotations, @NonVisual and @Validate, may be 
placed on the setter or getter method or on the field (as we have done here). 
As with the Hibernate annotations, putting the annotation on the field requires 
that the field name match the corresponding property 
name.</p><ul><li><strong>@NonVisual</strong> &#8211; indicates a field, such as 
a primary key, that should not be made visible to the 
user.</li><li><strong>@Validate</strong> &#8211; identifies the validations 
associated with a field.</li></ul><p>At this point you should stop and restart 
your application.</p><h2 
id="UsingTapestryWithHibernate-UpdatingtheDatabase">Updating the 
Database</h2><p>So we have a database set up, and Hibernate is configured to 
connect to it. Let's make use of that to store our Address object in the 
database.</p><p>What we need is to provide some code to be executed when the 
form is submitted. When a Tapestry form is submitted, there is a whole series 
of events that get fired. Th
 e event we are interested in is the "success" event, which comes late in the 
process, after all the values have been pulled out of the request and applied 
to the page properties, and after all server-side validations have 
occurred.</p><p>The success event is only fired if there are no validation 
errors.</p><p>Our event handler must do two things:</p><ul><li>Use the 
Hibernate Session object to persist the new Address object.</li><li>Commit the 
transaction to force the data to be written to the database.</li></ul><p>Let's 
update our CreateAddress.java class:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 
1px;"><b>src/main/java/com/example/tutorial/pages/address/CreateAddress.java</b></div><div
 class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">package com.example.tutorial1.pages.address;
 
 import com.example.tutorial1.entities.Address;
 import com.example.tutorial1.pages.Index;
@@ -171,9 +174,13 @@ public class CreateAddress
         return index;
     }
 }
-</plain-text-body><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/C
 ommitAfter.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"><img 
class="confluence-embedded-image confluence-content-image-border" 
src="using-tapestry-with-hibernate.data/index-g
 rid-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><parameter 
ac:name="language">xml</parameter><parameter 
ac:name="title">src/main/webapp/Index.tml 
(partial)</parameter><plain-text-body>  &lt;t:grid source="addresses"
+</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/CommitA
 fter.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"><img 
class="confluence-embedded-image confluence-content-image-border" 
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 class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">  &lt;t:grid source="addresses"
          
include="honorific,firstName,lastName,street1,city,state,zip,phone"/&gt;
-</plain-text-body><p>Note that the Grid component accepts many of the same 
parameters that we used with the BeanEditForm. Here we use the include 
parameter to specify the properties to show, and in what order.</p><p>Now all 
we have to do is supply the addresses property in the Java code. Here's how 
Index.java should look now:</p><parameter 
ac:name="language">java</parameter><parameter 
ac:name="title">src/main/java/com/example/tutorial/pages/Index.java</parameter><plain-text-body>package
 com.example.tutorial1.pages;
+</pre>
+</div></div><p>Note that the Grid component accepts many of the same 
parameters that we used with the BeanEditForm. Here we use the include 
parameter to specify the properties to show, and in what order.</p><p>Now all 
we have to do is supply the addresses property in the Java code. Here's how 
Index.java should look now:</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>src/main/java/com/example/tutorial/pages/Index.java</b></div><div 
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">package com.example.tutorial1.pages;
 import java.util.List;
 import org.apache.tapestry5.ioc.annotations.Inject;
 import org.hibernate.Session;
@@ -187,7 +194,8 @@ public class Index
         return session.createCriteria(Address.class).list();
     }
 }
-</plain-text-body><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>Check out the many Tapestry 
resources available on the <a  href="documentation.html">Documentation</a> 
page, including the <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 
nearly every Tapestry top
 ic. Finally, be sure to visit (and bookmark) <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart7/"; 
rel="nofollow">Tapestry JumpStart</a>, which provides a nearly exhaustive set 
of tutorials.</p><p>&#160;</p><p></p></div>
+</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>Check out the many Tapestry 
resources available on the <a  href="documentation.html">Documentation</a> 
page, including the <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 
nearly every Tapestry topic. Fi
 nally, be sure to visit (and bookmark) <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart7/"; 
rel="nofollow">Tapestry JumpStart</a>, which provides a nearly exhaustive set 
of tutorials.</p><p>&#160;</p><p></p></div>
       </div>
 
       <div class="clearer"></div>


Reply via email to