Modified: websites/production/tapestry/content/uploading-files.html
==============================================================================
--- websites/production/tapestry/content/uploading-files.html (original)
+++ websites/production/tapestry/content/uploading-files.html Tue Sep 26 
19:20:27 2017
@@ -27,16 +27,6 @@
       </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"/>
 
@@ -77,24 +67,20 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>Tapestry provides a file upload 
component based on <a  class="external-link" 
href="http://commons.apache.org/fileupload/";>Apache Commons FileUpload</a> to 
make it easier to handle files uploaded through web forms (via the standard 
&lt;input type="file"&gt; HTML element).</p><h1 
id="UploadingFiles-Downloading">Downloading</h1><p><strong>tapestry-upload</strong>
 is not automatically included in Tapestry applications because of the 
additional dependencies it requires. To include it, just add the 
<code>tapestry-upload</code> dependency to the pom of your application, 
something like this:</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">&lt;dependency&gt;
+                <div id="ConfluenceContent"><p>Tapestry provides a file upload 
component based on <a  class="external-link" 
href="http://commons.apache.org/fileupload/";>Apache Commons FileUpload</a> to 
make it easier to handle files uploaded through web forms (via the standard 
&lt;input type="file"&gt; HTML element).</p><h1 
id="UploadingFiles-Downloading">Downloading</h1><p><strong>tapestry-upload</strong>
 is not automatically included in Tapestry applications because of the 
additional dependencies it requires. To include it, just add the 
<code>tapestry-upload</code> dependency to the pom of your application, 
something like this:</p><parameter 
ac:name="language">xml</parameter><plain-text-body>&lt;dependency&gt;
     &lt;groupId&gt;org.apache.tapestry&lt;/groupId&gt;
     &lt;artifactId&gt;tapestry-upload&lt;/artifactId&gt;
     &lt;version&gt;${tapestry-release-version}&lt;/version&gt;
 &lt;/dependency&gt;
-</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><br clear="none">
-    <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/javascript/fileupload";
 rel="nofollow">File Upload</a></p></div><h2 
id="UploadingFiles-ComponentTemplate">Component Template</h2><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:form&gt;
+</plain-text-body><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><plain-text-body>{float:right|background=#eee|padding=0 1em}
+    *JumpStart Demo:*
+    [File 
Upload|http://jumpstart.doublenegative.com.au/jumpstart/examples/javascript/fileupload]
+{float}</plain-text-body><h2 id="UploadingFiles-ComponentTemplate">Component 
Template</h2><parameter ac:name="language">java</parameter><plain-text-body>    
&lt;t:form&gt;
         &lt;t:errors/&gt;
         &lt;input t:type="upload" t:id="file" t:value="file" 
validate="required"/&gt;
         &lt;br/&gt;
         &lt;input type="submit" value="Upload"/&gt;
-    &lt;/t:form&gt;</pre>
-</div></div><p>Here, because the value parameter was not bound, the component 
used the file property of its container (because the component's id is 'file'). 
If you want to upload as a different property, either bind the value parameter 
or change the component's id.</p><h2 id="UploadingFiles-Pageclass">Page 
class</h2><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">    public class UploadExample
+    &lt;/t:form&gt;</plain-text-body><p>Here, because the value parameter was 
not bound, the component used the file property of its container (because the 
component's id is 'file'). If you want to upload as a different property, 
either bind the value parameter or change the component's id.</p><h2 
id="UploadingFiles-Pageclass">Page class</h2><parameter 
ac:name="language">java</parameter><plain-text-body>    public class 
UploadExample
     {
         @Property
         private UploadedFile file;
@@ -105,9 +91,7 @@
             
             file.write(copied);
         }
-    }</pre>
-</div></div><h1 id="UploadingFiles-UploadExceptions">Upload 
Exceptions</h1><p>In some cases, file uploads may fail. This can be because of 
a simple communication exception, or more likely, because the configured 
maximum upload size was exceeded.</p><p>When a file upload exception occurs, 
Tapestry will trigger a "uploadException" event on the page to notify it of the 
error. All other normal processing is skipped (no "activate" event, no form 
submission, etc.).</p><p>The event handler should return a non-null object, 
which will be handled as a navigational result. Example:</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;">   @Persist(PersistenceConstants.FLASH)
+    }</plain-text-body><h1 id="UploadingFiles-UploadExceptions">Upload 
Exceptions</h1><p>In some cases, file uploads may fail. This can be because of 
a simple communication exception, or more likely, because the configured 
maximum upload size was exceeded.</p><p>When a file upload exception occurs, 
Tapestry will trigger a "uploadException" event on the page to notify it of the 
error. All other normal processing is skipped (no "activate" event, no form 
submission, etc.).</p><p>The event handler should return a non-null object, 
which will be handled as a navigational result. Example:</p><parameter 
ac:name="language">java</parameter><plain-text-body>   
@Persist(PersistenceConstants.FLASH)
     @Property
     private String message;
 
@@ -117,8 +101,7 @@
         message = "Upload exception: " + ex.getMessage();
 
         return this;
-    }</pre>
-</div></div><p>Note the importance of <code>return this;</code>. A void event 
handler method, or one that returns null, will result in the 
FileUploadException being reported to the user as an uncaught runtime 
exception.</p><h1 id="UploadingFiles-Configuration">Configuration</h1><p>Four 
values may be configured as <a  href="symbols.html">symbols</a>:</p><div 
class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" 
rowspan="1" class="confluenceTh"><p>upload.repository-location</p></th><td 
colspan="1" rowspan="1" class="confluenceTd"><p>The directory to which files 
that are too large to keep in memory will be written to. The default is from 
the java.io.tmpdir system property.</p></td></tr><tr><th colspan="1" 
rowspan="1" class="confluenceTh"><p>upload.repository-threshold</p></th><td 
colspan="1" rowspan="1" class="confluenceTd"><p>Upload size, in bytes, at which 
point the uploaded file is written to disk rather than kept in memory. The 
default is 10 kilobytes.</p></t
 d></tr><tr><th colspan="1" rowspan="1" 
class="confluenceTh"><p>upload.requestsize-max</p></th><td colspan="1" 
rowspan="1" class="confluenceTd"><p>Maximim size, in bytes, for the overall 
request. If exceeded, a FileUploadException will occur. The default is no 
maximum.</p></td></tr><tr><th colspan="1" rowspan="1" 
class="confluenceTh"><p>upload.filesize-max</p></th><td colspan="1" rowspan="1" 
class="confluenceTd"><p>Maximum size, in bytes, for any individual uploaded 
file. Again, a FileUploadException will occur if exceeded. The default is no 
maximum.</p></td></tr></tbody></table></div><p>The class <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/upload/services/UploadSymbols.html";>UploadSymbols</a>
 defines constants for all four of these.</p><h1 
id="UploadingFiles-PotentialIssues">Potential Issues</h1><p>The Commons 
FileUpload library uses the CommonsIO file cleaner service to remove temporary 
files when they are no longer needed. This s
 ervice creates a thread to carry out its work. If the commons-io library is 
shared amongst multiple applications (e.g. added to server classpath) it is 
possible for an application to terminate this thread prematurely and cause 
errors for the other applications. (see the <a  class="external-link" 
href="http://jakarta.apache.org/commons/fileupload/using.html";>Resource 
Cleanup</a> section in for more discussion)</p><p>Technically the file cleanup 
service is not needed by Tapestry Upload (which deletes temporary files at the 
end of request processing). However it is currently not possible to disable it 
(enhancement request has been filed as <a  class="external-link" 
href="https://issues.apache.org/jira/browse/FILEUPLOAD-133";>FILEUPLOAD-133</a>).</p></div>
+    }</plain-text-body><p>Note the importance of <code>return this;</code>. A 
void event handler method, or one that returns null, will result in the 
FileUploadException being reported to the user as an uncaught runtime 
exception.</p><h1 id="UploadingFiles-Configuration">Configuration</h1><p>Four 
values may be configured as <a  href="symbols.html">symbols</a>:</p><div 
class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" 
rowspan="1" class="confluenceTh"><p>upload.repository-location</p></th><td 
colspan="1" rowspan="1" class="confluenceTd"><p>The directory to which files 
that are too large to keep in memory will be written to. The default is from 
the java.io.tmpdir system property.</p></td></tr><tr><th colspan="1" 
rowspan="1" class="confluenceTh"><p>upload.repository-threshold</p></th><td 
colspan="1" rowspan="1" class="confluenceTd"><p>Upload size, in bytes, at which 
point the uploaded file is written to disk rather than kept in memory. The 
default is 10 kiloby
 tes.</p></td></tr><tr><th colspan="1" rowspan="1" 
class="confluenceTh"><p>upload.requestsize-max</p></th><td colspan="1" 
rowspan="1" class="confluenceTd"><p>Maximim size, in bytes, for the overall 
request. If exceeded, a FileUploadException will occur. The default is no 
maximum.</p></td></tr><tr><th colspan="1" rowspan="1" 
class="confluenceTh"><p>upload.filesize-max</p></th><td colspan="1" rowspan="1" 
class="confluenceTd"><p>Maximum size, in bytes, for any individual uploaded 
file. Again, a FileUploadException will occur if exceeded. The default is no 
maximum.</p></td></tr></tbody></table></div><p>The class <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/upload/services/UploadSymbols.html";>UploadSymbols</a>
 defines constants for all four of these.</p><h1 
id="UploadingFiles-PotentialIssues">Potential Issues</h1><p>The Commons 
FileUpload library uses the CommonsIO file cleaner service to remove temporary 
files when they are no longer nee
 ded. This service creates a thread to carry out its work. If the commons-io 
library is shared amongst multiple applications (e.g. added to server 
classpath) it is possible for an application to terminate this thread 
prematurely and cause errors for the other applications. (see the <a  
class="external-link" 
href="http://jakarta.apache.org/commons/fileupload/using.html";>Resource 
Cleanup</a> section in for more discussion)</p><p>Technically the file cleanup 
service is not needed by Tapestry Upload (which deletes temporary files at the 
end of request processing). However it is currently not possible to disable it 
(enhancement request has been filed as <a  class="external-link" 
href="https://issues.apache.org/jira/browse/FILEUPLOAD-133";>FILEUPLOAD-133</a>).</p></div>
       </div>
 
       <div class="clearer"></div>

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 Tue Sep 
26 19:20:27 2017
@@ -27,16 +27,6 @@
       </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"/>
 
@@ -77,15 +67,13 @@
       </div>
 
       <div id="content">
-                <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
+                <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
 private SelectModel colorSelectModel;
 @Inject
 SelectModelFactory selectModelFactory;
@@ -97,18 +85,15 @@ void setupRender() {
     // create a SelectModel from my list of colors
     colorSelectModel = selectModelFactory.create(colors, "name");
 }
-</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;">...
+</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>...
 @Override
 public String toString() {
     return String.valueOf(this.getId()); 
 }
-</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; { 
+</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; { 
 
     @Inject
     private ColorService colorService;
@@ -131,9 +116,7 @@ public String toString() {
         return this; 
     }
 } 
-</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;">    . . .
+</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>    . . .
 
     public ValueEncoder&lt;Color&gt; getColorEncoder() {
 
@@ -152,35 +135,26 @@ public String toString() {
             }
         }; 
     }
-</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;">...
+</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>...
     public static void 
contributeValueEncoderSource(MappedConfiguration&lt;Class&lt;Color&gt;,
                         ValueEncoderFactory&lt;Color&gt;&gt; configuration) { 
         configuration.addInstance(Color.class, ColorEncoder.class);
     }
-</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;">...
+</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>...
     public static void 
contributeValueEncoderSource(MappedConfiguration&lt;Class,
                         ValueEncoderFactory&gt; configuration)
     {
         configuration.addInstance(Color.class, ColorEncoder.class);
         configuration.addInstance(SomeOtherType.class, 
SomeOtherTypeEncoder.class);
     }
-</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;">...
+</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>...
     public void onSuccessFromMyForm() {
         // look up the color object from the ID selected
        selectedColor = colorService.findById(selectedColorId);
        ...
     }
-</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>
+</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>
       </div>
 
       <div class="clearer"></div>


Reply via email to